<?php
class OrdenVentaBL
{
    public function guardarDocumentoPorOrden( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            myUser::getUser()->validar_session();

            //primero buscamos la orden de venta
            $o_VTA_OrdenFN = new VTA_OrdenFN();
            $o_VTA_OrdenBN = $o_VTA_OrdenFN->selectByPK( $o_VTA_DocumentoBN->getDocumentoParentId() );

            if( $o_VTA_OrdenBN )
            {
                //validaciones
                if( $o_VTA_OrdenBN->getOrdenEstado() == "F" )
                {
                    throw new Exception( "La Orden de Venta ya se encuentra asociado a una Facturado." );
                }
                
                if( $o_VTA_OrdenBN->getOrdenEstado() != "C" )
                {
                    if( $o_VTA_DocumentoBN->getTipoVenta() != "ANT" )
                    {
                        if( !$o_VTA_DocumentoBN->esFacturacionDirecta() )
                        {
                            throw new Exception( "La Orden de Venta tiene que estar Cerrado para continuar con la Facturacion." );
                        }
                    }
                }

                //validaciones por el tipo de caracteres en el comentario
                $o_VTA_DocumentoBN->setComentario( utilString::limpiar_caracteres_para_imprimir( $o_VTA_DocumentoBN->getComentario() ) );

                //se busca el cliente
                $o_MST_PersonaMastFN = new MST_PersonaMastFN();
                $o_MST_PersonaMastBN = $o_MST_PersonaMastFN->selectByPK( $o_VTA_OrdenBN->getClienteId() );
                if( !$o_MST_PersonaMastBN )
                {
                    throw new Exception( "El Cliente no se encuentra registrado." );
                }
                
                $ClienteNombre       = $o_MST_PersonaMastBN->getNombreCompletoLLeno();
                $ClienteTipoDoc      = $o_MST_PersonaMastBN->getTipoDocumento();
                $ClienteRUC          = $o_MST_PersonaMastBN->getDocumento();
                $ClienteDireccion    = addslashes( $o_MST_PersonaMastBN->getDireccion() );
                $ClienteDistritoDesc = $o_MST_PersonaMastBN->getDistritoDesc();
                $UbigeoCod           = $o_MST_PersonaMastBN->getDistrito();
                $a_UbigeoDesc        = MST_UbigeoFN::getArrayDireccionCompleta( $UbigeoCod );
                $VendedorAsigna      = $o_MST_PersonaMastBN->getVendedorAsignado();
                $CanalCliente        = $o_MST_PersonaMastBN->getCanalCliente();
                $NivelPrecioCliente  = $o_MST_PersonaMastBN->getNivelPrecioCliente();
                $s_Contacto          = $o_MST_PersonaMastBN->getContacto();
                ////////////////////////////////////////////////////////////////////////////////////////
                //se setea los demas valores de la orden
                $o_VTA_DocumentoBN->setClienteNumero( ( string ) $o_VTA_OrdenBN->getClienteId() );
                $o_VTA_DocumentoBN->setClienteNombre( $o_VTA_OrdenBN->getClienteNombre() );
                $o_VTA_DocumentoBN->setClienteTipoDoc( $o_VTA_OrdenBN->getClienteDocCod() );
                $o_VTA_DocumentoBN->setClienteRUC( $o_VTA_OrdenBN->getClienteDocNum() );
                $o_VTA_DocumentoBN->setClienteDireccion( $o_VTA_OrdenBN->getFactDirec1() );
                $o_VTA_DocumentoBN->setClienteReferencia( $o_VTA_OrdenBN->getFactDirec2() );
                $o_VTA_DocumentoBN->setClienteContacto( $s_Contacto );
                if( $a_UbigeoDesc )
                {
                    $o_VTA_DocumentoBN->setDepartamento( $a_UbigeoDesc['Departamento'] );
                    $o_VTA_DocumentoBN->setProvincia( $a_UbigeoDesc['Provincia'] );
                    $o_VTA_DocumentoBN->setDistrito( $a_UbigeoDesc['Distrito'] );
                }
                $o_VTA_DocumentoBN->setUbigeo( $UbigeoCod );
                $o_VTA_DocumentoBN->setCanalVenta( $CanalCliente );

                ////////////////////////////////////////////////////////////////////////////////////////////////////////
                //AHORA SE RECUPERA LA FORMA DE PAGO
                $o_VTA_FormaPagoFN = new VTA_FormaPagoFN();
                $o_VTA_FormaPagoBN = $o_VTA_FormaPagoFN->selectByPK( $o_VTA_OrdenBN->getCondicionVentaId() );
                if( !$o_VTA_FormaPagoBN )
                {
                    throw new Exception( "Debe de seleccionar la Condicion de Venta." );
                }
                $o_VTA_DocumentoBN->setIdFormaPago( $o_VTA_FormaPagoBN->getIdFormaPago() );
                $o_VTA_DocumentoBN->setFormaPagoCod( $o_VTA_FormaPagoBN->getCodigo() );
                $o_VTA_DocumentoBN->setTerminoPago( $o_VTA_FormaPagoBN->getDias() );

                //AHORA VALIDAMOS LA FECHA DE VENCIMIENTO
                if( $o_VTA_FormaPagoBN->getDias() > 0 )
                {
                    $s_FechaVencimiento = UtilDate::sumarDias( $o_VTA_DocumentoBN->getFechaDocumento(), $o_VTA_FormaPagoBN->getDias() );
                    $o_VTA_DocumentoBN->setFechaVencimiento( $s_FechaVencimiento );
                }
                ////////////////////////////////////////////////////////////////////////////////////////////////////////

                $o_VTA_DocumentoBN->setOrdenCompraRef( $o_VTA_OrdenBN->getOrdenCompraRef() );
                $o_VTA_DocumentoBN->setVendedor( $o_VTA_OrdenBN->getVendedorOrden() );

                $o_VTA_DocumentoBN->setIdCompania( ( int ) $o_VTA_OrdenBN->getCiaCod() );
                $o_VTA_DocumentoBN->setIdSucursal( $o_VTA_OrdenBN->getIdSucursal() );
                $o_VTA_DocumentoBN->setSucursal( ( string ) $o_VTA_OrdenBN->getIdSucursal() );
                $o_VTA_DocumentoBN->setIdAlmacen( $o_VTA_OrdenBN->getAlmacenCod() );
                $o_VTA_DocumentoBN->setAlmacenDespacho( $o_VTA_OrdenBN->getAlmacenDespacho() );
                
                $o_VTA_DocumentoBN->setIdCaja( $o_VTA_OrdenBN->getIdCaja() );
                $o_VTA_DocumentoBN->setIdTurno( $o_VTA_OrdenBN->getIdTurno() );
                $o_VTA_DocumentoBN->setIdProyecto( $o_VTA_OrdenBN->getIdProyecto() );
                $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_PREPARACION ); //por defecto
                $o_VTA_DocumentoBN->setCobranzaEstado( VTA_DocumentoBN::ESTADO_COB_PENDIENTE ); //por defecto

                //VALIDACIONES PARA -> TIPO DE OPERACION SUJETA A DETRACCION
                if( $o_VTA_DocumentoBN->getTipoVenta() == "DET" )
                {
                    if( !$o_VTA_DocumentoBN->getDetraccionTipoId() )
                    {
                        throw new Exception( "Debe de seleccionar el Tipo de Detraccion" );
                    }

                    if( !$o_VTA_DocumentoBN->getDetraccionPorcentaje() )
                    {
                        throw new Exception( "Debe ingresar un Porcentaje para la Detraccion" );
                    }

                    if( !$o_VTA_DocumentoBN->getDetraccionMedPagoId() )
                    {
                        throw new Exception( "Debe de seleccionar el Medio de Pago para la Detraccion" );
                    }
                }

                //VALIDACION PARA LA RETENCION 2021-10-11
                if( $o_MST_PersonaMastBN->getEsAgenteRetenedor() )
                {
                    if( !$o_VTA_DocumentoBN->getRetencionTipoId() )
                    {
                        throw new Exception( "Debe de seleccionar el Tipo de Retencion" );
                    }
                    if( !$o_VTA_DocumentoBN->getRetencionBaseImponible() )
                    {
                        throw new Exception( "La Base Imponible de la Retencion esta mal" );
                    }
                    if( !$o_VTA_DocumentoBN->getRetencionTotal() )
                    {
                        throw new Exception( "El Total Retencion no es correcto" );
                    }

                    $a_DataRetencion = MST_PersonaMastBN::getArrayRetenciones( $o_VTA_DocumentoBN->getRetencionTipoId() );

                    $o_VTA_DocumentoBN->setEsAgenteRetenedor( 1 );
                    $o_VTA_DocumentoBN->setRetencionPorcentaje( $a_DataRetencion['Tasa'] );
                }
                else
                {
                    $o_VTA_DocumentoBN->setEsAgenteRetenedor( 0 );
                }
                
                //SE TIENE CAMBIAR EL PROCESO PARA ANTICIPOS
                if( $o_VTA_DocumentoBN->getTipoVenta() != "ANT" )
                {
                    $o_VTA_DocumentoBN->setTipodeCambio( $o_VTA_OrdenBN->getMonedaCambioValor() );
                    $o_VTA_DocumentoBN->setMonedaDocumento( $o_VTA_OrdenBN->getMonedaCod() );
                    //$o_VTA_DocumentoBN->setTipoVenta( $o_VTA_OrdenBN->getFactRegla() );

                    $o_VTA_DocumentoBN->setMontoExonerado( $o_VTA_OrdenBN->getMontoExonerado() );
                    $o_VTA_DocumentoBN->setMontoExoneradoMN( $o_VTA_OrdenBN->getMontoExoneradoMN() );
                    $o_VTA_DocumentoBN->setMontoAfecto( $o_VTA_OrdenBN->getOrdenAfecto() );
                    $o_VTA_DocumentoBN->setMontoAfectoMN( $o_VTA_OrdenBN->getOrdenAfectoMN() );
                    $o_VTA_DocumentoBN->setMontoNoAfecto( $o_VTA_OrdenBN->getOrdenInafecto() );
                    $o_VTA_DocumentoBN->setMontoNoAfectoMN( $o_VTA_OrdenBN->getOrdenInafectoMN() );
                    
                    $o_VTA_DocumentoBN->setMontoAnticipo( $o_VTA_OrdenBN->getMontoAnticipo() );
                    $o_VTA_DocumentoBN->setMontoAnticipoMN( $o_VTA_OrdenBN->getMontoAnticipoMN() );
                    $o_VTA_DocumentoBN->setMontoDescuentos( $o_VTA_OrdenBN->getOrdenDscto() );
                    $o_VTA_DocumentoBN->setMontoDescuentosMN( $o_VTA_OrdenBN->getOrdenDsctoMN() );
                    $o_VTA_DocumentoBN->setMontoSubTotal( $o_VTA_OrdenBN->getOrdenBaseImponible() );        //$o_VTA_OrdenBN->getOrdenVenta()
                    $o_VTA_DocumentoBN->setMontoSubTotalMN( $o_VTA_OrdenBN->getOrdenBaseImponibleMN() );    //$o_VTA_OrdenBN->getOrdenVentaMN()
                    $o_VTA_DocumentoBN->setMontoImpuestos( $o_VTA_OrdenBN->getOrdenImpuestoConDscto() );    //$o_VTA_OrdenBN->getOrdenImpuesto()
                    $o_VTA_DocumentoBN->setMontoImpuestoMN( $o_VTA_OrdenBN->getOrdenImpuestoConDsctoMN() ); //$o_VTA_OrdenBN->getOrdenImpuestoMN()
                    $o_VTA_DocumentoBN->setMontoTotal( $o_VTA_OrdenBN->getOrdenTotalaPagar() );             //$o_VTA_OrdenBN->getOrdenNeto()
                    $o_VTA_DocumentoBN->setMontoTotalMN( $o_VTA_OrdenBN->getOrdenTotalaPagarMN() );           //$o_VTA_OrdenBN->getOrdenNetoMN()
                    
                    $o_VTA_DocumentoBN->setMontoSaldo( $o_VTA_OrdenBN->getOrdenTotalaPagar() );
                    $o_VTA_DocumentoBN->setMontoSaldoMN( $o_VTA_OrdenBN->getOrdenTotalaPagarMN() );
                }
                else
                {
                    //ESTE PROCEDIMIENTO ES PARA EL ANTICIPO
                    if( $o_VTA_DocumentoBN->getMonedaDocumento() == "EX" )
                    {
                        //////////////////////////////////////////////////////////////////////////////////////////
                        //SE RECUPERA VALOR DE IGV ACTUAL
                        $f_ValorIGV = GSS_ParametroMastFN::getValorPorTipo( "AL", "IGV" ); //0.18
                        $f_ValorIGVMasUno = $f_ValorIGV + 1;  //1.18
                        //////////////////////////////////////////////////////////////////////////////////////////
                        
                        $f_TipodeCambio = $o_VTA_DocumentoBN->getTipodeCambio();
                        $f_TotalConIGV  = round( $o_VTA_DocumentoBN->getMontoTotal() * $f_TipodeCambio, 2 );
                        $f_MontoSubTotal = round( $f_TotalConIGV / $f_ValorIGVMasUno, 2 );
                        $f_MontoImpuesto = $f_TotalConIGV - $f_MontoSubTotal;
                        
                        $o_VTA_DocumentoBN->setMontoSubTotalMN( $f_MontoSubTotal );
                        $o_VTA_DocumentoBN->setMontoImpuestoMN( $f_MontoImpuesto );
                        $o_VTA_DocumentoBN->setMontoTotalMN( $f_TotalConIGV );
                    }
                    else
                    {
                        $o_VTA_DocumentoBN->setMontoSubTotalMN( $o_VTA_DocumentoBN->getMontoSubTotal() );
                        $o_VTA_DocumentoBN->setMontoImpuestoMN( $o_VTA_DocumentoBN->getMontoImpuestos() );
                        $o_VTA_DocumentoBN->setMontoTotalMN( $o_VTA_DocumentoBN->getMontoTotal() );
                    }
                    
                    $o_VTA_DocumentoBN->setIdFormaPago( "008" ); //SE IDENTIFICA COMO AL CONTADO
                    $o_VTA_DocumentoBN->setFormaPagoCod( "CON" );
                    $o_VTA_DocumentoBN->setTerminoPago( 0 );
                    
                    $o_VTA_DocumentoBN->setMontoAfecto( $o_VTA_DocumentoBN->getMontoSubTotal() );
                    $o_VTA_DocumentoBN->setMontoAfectoMN( $o_VTA_DocumentoBN->getMontoSubTotalMN() );
                    $o_VTA_DocumentoBN->setMontoNoAfecto( 0 );
                    $o_VTA_DocumentoBN->setMontoNoAfectoMN( 0 );
                    
                    $o_VTA_DocumentoBN->setMontoDescuentos( 0 );
                    $o_VTA_DocumentoBN->setMontoDescuentosMN( 0 );
                    $o_VTA_DocumentoBN->setMontoSubTotal( $o_VTA_DocumentoBN->getMontoSubTotal() );        //$o_VTA_OrdenBN->getOrdenVenta()
                    $o_VTA_DocumentoBN->setMontoSubTotalMN( $o_VTA_DocumentoBN->getMontoSubTotalMN() );    //$o_VTA_OrdenBN->getOrdenVentaMN()
                    $o_VTA_DocumentoBN->setMontoImpuestos( $o_VTA_DocumentoBN->getMontoImpuestos() );    //$o_VTA_OrdenBN->getOrdenImpuesto()
                    $o_VTA_DocumentoBN->setMontoImpuestoMN( $o_VTA_DocumentoBN->getMontoImpuestoMN() ); //$o_VTA_OrdenBN->getOrdenImpuestoMN()
                    $o_VTA_DocumentoBN->setMontoTotal( $o_VTA_DocumentoBN->getMontoTotal() );             //$o_VTA_OrdenBN->getOrdenNeto()
                    $o_VTA_DocumentoBN->setMontoTotalMN( $o_VTA_DocumentoBN->getMontoTotalMN() );           //$o_VTA_OrdenBN->getOrdenNetoMN()
                    
                    $o_VTA_DocumentoBN->setMontoSaldo( $o_VTA_DocumentoBN->getMontoTotal() );
                    $o_VTA_DocumentoBN->setMontoSaldoMN( $o_VTA_DocumentoBN->getMontoTotalMN() );
                }
                
                $this->iniciarDocumentoFactura( $o_VTA_DocumentoBN ); //se genera la cabecera del documento

                //ahora guarda los detalles segun la orden de venta
                $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                $o_OrdenVentaDetalleBL->iniciarGuardarDetallesPorOrden( $o_VTA_DocumentoBN );
                
                //ahora se procede a realizar la facturacion
                $this->cambiarOrdenFacturada( $o_VTA_DocumentoBN );
                
                if( $o_VTA_DocumentoBN->getTipoVenta() != "ANT" )
                {
                    //AHORA SE REALIZA ESTE PROCEDIMIENTO CUANDO NO SEA ANTICIPO
                    //se procede a cambiar el estado de orden asociada a facturada
                    $o_TMP_VTA_OrdenBN = new VTA_OrdenBN();
                    $o_TMP_VTA_OrdenBN->setOrdenId( $o_VTA_DocumentoBN->getDocumentoParentId() );
                    $o_TMP_VTA_OrdenBN->setReferenciaTipoDocId( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                    $o_TMP_VTA_OrdenBN->setDocReferenciaTipo( $o_VTA_DocumentoBN->getDocumentoCod() );
                    $o_TMP_VTA_OrdenBN->setDocReferenciaNum( $o_VTA_DocumentoBN->getDocumentoSerieNumero() );
                    $o_TMP_VTA_OrdenBN->setDocReferenciaId( $o_VTA_DocumentoBN->getNumeroDocumento() );
                    $o_TMP_VTA_OrdenBN->setDocReferenciaFecha( $o_VTA_DocumentoBN->getFechaDocumento() );
    
                    $o_CotizacionesBL = new CotizacionesBL();
                    $o_CotizacionesBL->cambiarOrdenFacturada( $o_TMP_VTA_OrdenBN );
                }
                else
                {
                    //CUANDO SE TRATE DE ANTICIPO, SE TIENE QUE ACTUALIZA EL MONTO DE ANTICIPO A LA COTIZACION
                    $f_MontoAnticipo   = $o_VTA_OrdenBN->getMontoAnticipo();
                    $f_MontoAnticipoMN = $o_VTA_OrdenBN->getMontoAnticipoMN();
                    
                    $f_MontoAnticipoDoc   = $o_VTA_DocumentoBN->getMontoSubTotal();
                    $f_MontoAnticipoDocMN = $o_VTA_DocumentoBN->getMontoSubTotalMN();
                    
                    $f_TipodeCambioDoc    = $o_VTA_DocumentoBN->getTipodeCambio();
                    
                    $o_VTA_OrdenDP = new VTA_OrdenDP();
                    $o_VTA_OrdenDP->setOrdenId( $o_VTA_DocumentoBN->getDocumentoParentId() );
                    
                    if( $o_VTA_OrdenBN->getMonedaCod() == "EX" )
                    {
                        if( $o_VTA_DocumentoBN->getMonedaDocumento() == "EX" )
                        {
                            $o_VTA_OrdenDP->setMontoAnticipo( $f_MontoAnticipo + $f_MontoAnticipoDoc );
                            $o_VTA_OrdenDP->setMontoAnticipoMN( $f_MontoAnticipoMN + $f_MontoAnticipoDocMN );
                        }
                        else
                        {
                            $f_MontoAnticipoDocDol = round( $f_MontoAnticipoDoc / $f_TipodeCambioDoc, 2 );
                            
                            $o_VTA_OrdenDP->setMontoAnticipo( $f_MontoAnticipo + $f_MontoAnticipoDocDol );
                            $o_VTA_OrdenDP->setMontoAnticipoMN( $f_MontoAnticipoMN + $f_MontoAnticipoDocMN );
                        }
                    }
                    else
                    {
                        if( $o_VTA_DocumentoBN->getMonedaDocumento() == "EX" )
                        {
                            $o_VTA_OrdenDP->setMontoAnticipo( $f_MontoAnticipo + $f_MontoAnticipoDocMN );
                            $o_VTA_OrdenDP->setMontoAnticipoMN( $f_MontoAnticipoMN + $f_MontoAnticipoDocMN );
                        }
                        else
                        {
                            $o_VTA_OrdenDP->setMontoAnticipo( $f_MontoAnticipo + $f_MontoAnticipoDoc );
                            $o_VTA_OrdenDP->setMontoAnticipoMN( $f_MontoAnticipoMN + $f_MontoAnticipoDocMN );
                        }
                    }
                    
                    $o_VTA_OrdenDP->setFechaActualizacion( date( "Y-m-d H:i:s" ) );
                    $o_VTA_OrdenDP->setUsuarioActualizacion( myUser::getUser()->getUserId() );
                    
                    $o_VTA_OrdenDP->update();
                    
                    if( $o_VTA_OrdenBN->getOrdenTipoClasificacionId() == VTA_OrdenBN::TIPO_PRODUCTOS_TERMINADOS )
                    {
                        VTA_OrdenDP::actualizarCabaceraMontos2( $o_VTA_DocumentoBN->getDocumentoParentId() );
                    }
                    else
                    {
                        VTA_OrdenDP::actualizarCabaceraMontos( $o_VTA_DocumentoBN->getDocumentoParentId() );
                    }
                }
            }

            $con->commit();
        }
        catch ( Exception $o_Exception )
        {
            //pr( $o_Exception );
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }

        return true;            
    }

    public function copiarOrdenVenta( VTA_DocumentoBN &$o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            myUser::getUser()->validar_session();

            $IdTipoDocumento  = $o_VTA_DocumentoBN->getIdTipoDocumentoRef();
            $TipoDocumentoCod = $o_VTA_DocumentoBN->getDocumentoCod();
            $FechaDocumento   = $o_VTA_DocumentoBN->getFechaDocumento();
            $DocumentoSerie   = $o_VTA_DocumentoBN->getDocumentoSerie();
            $DocumentoNumero  = $o_VTA_DocumentoBN->getDocumentoNumero();

            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_VTA_DocumentoBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );
            
            if( $o_VTA_DocumentoBN )
            {
                $i_OrdenPadre = $o_VTA_DocumentoBN->getNumeroDocumento();
                $o_TMP_VTA_DocumentoBN = clone $o_VTA_DocumentoBN;
                
                $o_TMP_VTA_DocumentoBN->setDocumentoParentId( intval( $i_OrdenPadre ) );

                $o_TMP_VTA_DocumentoBN->setIdTipoDocumento( $IdTipoDocumento );
                $o_TMP_VTA_DocumentoBN->setDocumentoCod( $TipoDocumentoCod );
                $o_TMP_VTA_DocumentoBN->setDocumentoSerie( $DocumentoSerie );
                $o_TMP_VTA_DocumentoBN->setDocumentoNumero( $DocumentoNumero );
                $o_TMP_VTA_DocumentoBN->setVendedor( myUser::getUser()->getUserId() );
                $o_TMP_VTA_DocumentoBN->setUsuarioCreacion( myUser::getUser()->getUserId() );
                $o_TMP_VTA_DocumentoBN->setFechaCreacion( date( "Y-m-d H:i:s" ) );
                $o_TMP_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );
                $o_TMP_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );

                $o_TMP_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_PREPARACION );
                $o_TMP_VTA_DocumentoBN->setNumeroDocumento( null );
                $o_TMP_VTA_DocumentoBN->setAnulacionComentario( "" );
                $o_TMP_VTA_DocumentoBN->setComentario( "" );
                if( $FechaDocumento )
                {
                    $o_TMP_VTA_DocumentoBN->setFechaDocumento( $FechaDocumento );
                }
                else
                {
                    $o_TMP_VTA_DocumentoBN->setFechaDocumento( date( "Y-m-d H:i:s" ) );
                }
                
                $this->iniciarDocumentoFactura( $o_TMP_VTA_DocumentoBN );
                $i_OrdenHijo = $o_TMP_VTA_DocumentoBN->getNumeroDocumento();

                //usleep( 1500000 );

                //ahora se genera los detalles
                $o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
                $o_VTA_DocumentoDetalleFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDetalleFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_DocumentoDetalleFN->setNumeroDocumento( $i_OrdenPadre );
                $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->select();
                foreach ( $a_VTA_DocumentoDetalle as $o_VTA_DocumentoDetalleBN ) 
                {
                    try
                    {
                        $o_VTA_DocumentoDetalleBN->setSecuencia( null );
                        $o_VTA_DocumentoDetalleBN->setNumeroDocumento( $i_OrdenHijo );
                        $o_VTA_DocumentoDetalleBN->setIdTipoDocumento( $IdTipoDocumento );
                        $o_VTA_DocumentoDetalleBN->setUsuarioCreacion( myUser::getUser()->getUserId() );
                        $o_VTA_DocumentoDetalleBN->setFechaCreacion( date( "Y-m-d H:i:s" ) );
                        $o_VTA_DocumentoDetalleBN->setUsuarioModificacion( myUser::getUser()->getUserId() );
                        $o_VTA_DocumentoDetalleBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                        
                        $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                        $o_OrdenVentaDetalleBL->iniciarProceso( $o_VTA_DocumentoDetalleBN );
                    }
                    catch ( Exception $e )
                    {
                        //pr( $e->getMessage() );
                    }
                }
            }

            $o_VTA_DocumentoBN->setIdTipoDocumento( $IdTipoDocumento );
            $o_VTA_DocumentoBN->setNumeroDocumento( $i_OrdenHijo );
            $o_VTA_DocumentoBN->setDocumentoParentId( intval( $i_OrdenPadre ) );
            //exit;
            $con->commit();
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }

        return true;
    }

    public function iniciarDocumentoFactura( VTA_DocumentoBN &$o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            myUser::getUser()->validar_session();

            if( $o_VTA_DocumentoBN->getMonedaDocumento() == "LO" )
            {
                if( !$o_VTA_DocumentoBN->getTipodeCambio() )
                {
                    $o_VTA_DocumentoBN->setTipodeCambio( 1 );
                }
            }

            //se agrega nuevos procedimiento [2019-07-02]
            //->Campor Periodo
            $o_VTA_DocumentoBN->setPeriodo( str_replace( "-", "", substr( $o_VTA_DocumentoBN->getFechaDocumento(), 0, 7 ) ) );

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //validaciones
            //se parametriza la opcion de caja
            if( GSS_ParametroMastFN::getValorParam( "VT", "FACT-CAJA" ) )
            {
                if( !$o_VTA_DocumentoBN->getIdCaja() )
                {
                    //throw new Exception( "Por favor selecciona la Caja." );
                }
            }
            
            //otras validaciones 2020-01-09
            if( $o_VTA_DocumentoBN->getIdTipoDocumento() == "FC" )
            {
                if( $o_VTA_DocumentoBN->getClienteTipoDoc() != "RUC" )
                {
                    throw new Exception( "El comprobante actual [FACTURA], solo permite el tipo de documento RUC." );
                }
                if( strlen( $o_VTA_DocumentoBN->getClienteRUC() ) != 11 )
                {
                    throw new Exception( "El comprobante actual [FACTURA], solo permite numero de documento RUC." );
                }
            }

            if( $o_VTA_DocumentoBN->getIdTipoDocumento() == "BV" )
            {
                if( $o_VTA_DocumentoBN->getClienteTipoDoc() == "RUC" )
                {
                    throw new Exception( "El Tipo de Documento del Cliente [RUC] no puede registrar un comprobante [BOLETA]." );
                }
                if( $o_VTA_DocumentoBN->getClienteTipoDoc() == "DNI" )
                {
                    if( strlen( $o_VTA_DocumentoBN->getClienteRUC() ) != 8 )
                    {
                        throw new Exception( "El comprobante actual [BOLETA], solo permite numero de documento DNI." );
                    }
                }
            }
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            //usleep( 100000 );

            if( !$o_VTA_DocumentoBN->getNumeroDocumento() )
            {
                //insert
                $s_FechaDocumento = date( "Y-m-d H:i:s" );
                if( !$o_VTA_DocumentoBN->getFechaDocumento() )
                {
                    $o_VTA_DocumentoBN->setFechaDocumento( $s_FechaDocumento );
                }
                if( !$o_VTA_DocumentoBN->getFechaVencimiento() )
                {
                    $o_VTA_DocumentoBN->setFechaVencimiento( $s_FechaDocumento );
                }
                $o_VTA_DocumentoBN->setUsuarioCreacion( myUser::getUser()->getUserId() );
                $o_VTA_DocumentoBN->setFechaCreacion( date( "Y-m-d H:i:s" ) );
                $o_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );
                $o_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );

                $i_Id = VTA_DocumentoFN::recuperarId();
                $o_VTA_DocumentoBN->setNumeroDocumento( $i_Id );
                
                $o_VTA_DocumentoDP = new VTA_DocumentoDP( $o_VTA_DocumentoBN );
                $o_VTA_DocumentoDP->save();
            }
            else
            {
                //update
                $o_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                $o_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );

                $o_VTA_DocumentoDP = new VTA_DocumentoDP( $o_VTA_DocumentoBN );
                $o_VTA_DocumentoDP->update();
            }

            //un procedimiento mas, cuando nace anulado
            if( $o_VTA_DocumentoBN->getEstado() == VTA_DocumentoBN::ESTADO_ANULADO )
            {
                //$o_OrdenVentaBL = new OrdenVentaBL();
                //$o_OrdenVentaBL->procesoNaceAnuladoOrden( $o_VTA_DocumentoBN );

                $this->incrementarDocumentoNumero( $o_VTA_DocumentoBN );
            }

            $con->commit();
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }

        return true;
    }

    public function cambiarOrdenFacturada( VTA_DocumentoBN &$o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            myUser::getUser()->validar_session();
            
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_VTA_DocumentoTmpBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );
        
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //aqui una validacion por el monto mayor a 700 soles tiene que tener DNI
            //VALIDACION POR MONTO
            if( $o_VTA_DocumentoTmpBN->getIdTipoDocumento() == VTA_DocumentoBN::TIPO_DOCUMENTO_BOLETA_VAL || $o_VTA_DocumentoTmpBN->getIdTipoDocumento() == VTA_DocumentoBN::TIPO_DOCUMENTO_TIBOLETA_VAL )
            {
                if( $o_VTA_DocumentoTmpBN->getMontoTotal() >= VTA_DocumentoBN::MONTO_VALIDACION )
                {
                    if( $o_VTA_DocumentoTmpBN->getClienteRUC() == VTA_DocumentoBN::CODIGO_CLIENTE_GENERICO )
                    {
                        $o_VTA_DocumentoBN->setNumeroError( "001" );
                        throw new Exception( "No se puede Emitir la Boleta, La Validacion por monto mayor a 700 Soles tiene que tener DNI." );
                    }
                }
            }
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //VALIDACION DE LOS DETALLES CON PRECIO IGUAL A 0 Y LA CANTIDAD NO MENOR AL STOCK
            $o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
            $o_VTA_DocumentoDetalleFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_VTA_DocumentoDetalleFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_VTA_DocumentoDetalleFN->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
            //$o_VTA_DocumentoDetalleFN->setTipoDetalle( VTA_DocumentoDetalleBN::TIPO_DETALLE );
            $o_VTA_DocumentoDetalleFN->addCondition( VTA_DocumentoDetalleFN::TipoDetalle, "IN", "('P','S')", false );
            $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->select();
            
            $a_VTA_DocumentoDetalleTMP = $a_VTA_DocumentoDetalle;
            if( count( $a_VTA_DocumentoDetalle ) <= 0 )
            {
                throw new Exception( "No tiene detalles para seguir con el Proceso." );
            }

            //UNA VALIDACION ENTRE CABCERAS, ORDEN Y DOCUMENTO, LOS TOTALES DEBEN DE SER IGUALES - 2022-03-16
            $o_TMP_VTA_OrdenBN = $o_VTA_DocumentoTmpBN->getObjectOrden();
            if( $o_TMP_VTA_OrdenBN )
            {
                if( $o_TMP_VTA_OrdenBN->getOrdenTotalaPagar() != $o_VTA_DocumentoTmpBN->getMontoTotal() )
                {
                    throw new Exception( "Se encontro un problema, los montos totales no concuerdan, por favor vuelta a Facturar." );
                }
            }
            else
            {
                throw new Exception( "No se encontro la Orden de Venta" );
            }

            $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
            foreach ( $a_VTA_DocumentoDetalle as $i_key => $o_VTA_DocumentoDetalleBN )
            {
                //VALIDACIONES DESDE EL BL
                $o_OrdenVentaDetalleBL->validacionesPorDetalles( $o_VTA_DocumentoDetalleBN );

                //AHORA SE AGREGA OTRA VALIDACION, LOS MONTOS ENTRE LOS DETALLES TIENE Q SER IGUAL - 2022-03-16
                //AQUI SE BUSCA LOS DETALLES DE LA ORDEN

            }

            //AHORA VALIDACION POR ITEM IGUALES PERO QUE LOTES DIFERENTES
            $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->buscarItemLoteRepetidos();
            if( $a_VTA_DocumentoDetalle )
            {
                foreach ( $a_VTA_DocumentoDetalle as $i_key => $o_VTA_DocumentoDetalleBN )
                {
                    if( $o_VTA_DocumentoDetalleBN->getTipoDetalle() == VTA_DocumentoDetalleBN::TIPO_DETALLE_COMENTARIO )
                    {
                        continue;
                    }
                    $s_ItemCodigo = $o_VTA_DocumentoDetalleBN->getItemCodigo();
                    $s_Lote       = $o_VTA_DocumentoDetalleBN->getLote();
                    throw new Exception( "No se puede Facturar, por que el Item ( $s_ItemCodigo ) Lote( $s_Lote ) se encuentra repetidos." );
                }
            }
            //////////////////////////////////////////////////
            //antes de generar la transaccion, se quita la reservas
            //como la referencia es una orden de venta, se tiene que liberar las reservas
            //si la guia_rem esta activo, en ese proceso recien se quita la reserva
            //if( !GSS_ParametroMastFN::getValorPorTipo( "VT", "GUIA_REM" ) )
            if( !myUser::getUser()->getObjectCompania()->getOpeDsctoStockEnGuiaR() )
            {
                $this->anularReservaPorDocumento( $o_VTA_DocumentoBN );
            }
            //////////////////////////////////////////////////

            /////////////////////////////////////////////////////////////////////////////////////////////////
            //Se incrementa el numero del documento.
            $o_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoTmpBN->getDocumentoSerie() );
            $o_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoTmpBN->getDocumentoNumero() );
            $this->incrementarDocumentoNumero( $o_VTA_DocumentoBN );
            /////////////////////////////////////////////////////////////////////////////////////////////////
            //AHORA SE ACTUALIZA EN LOS DOCUMENTOS DE REFERNECIA
            //$this->cambiarDataExternosRelacionados( $o_VTA_DocumentoBN );
            /////////////////////////////////////////////////////////////////////////////////////////////////

            //SE CAMBIA EL ESTADO DE LA ORDEN A FACTURADO:
            //PARAMETROS
            $ReferenciaTipoDocumento    = $o_VTA_DocumentoBN->getIdTipoDocumento();
            $IdCompania                 = $o_VTA_DocumentoBN->getIdCompania();
            $NumeroDocumento            = $o_VTA_DocumentoBN->getNumeroDocumento(); //

            ///////////////////////////////////
            //aqui se agrega el procedimiento de recuperar el turno actual, por si se encuantra en preparacion y se cambia de turno 2020-02-17
            $IdCajaSelect  = null;
            $IdTurnoSelect = null;
            //if( GSS_ParametroMastFN::getValorParam( "VT", "FACT-CAJA" ) ) //se agrega la condicion de uso de caja :: 2021-01-10
            //{
                //se tiene q tomar un IdCaja y IdTurno por Defecto
                $o_FCO_CierreFN = new FCO_CierreFN();
                $o_FCO_CierreFN->setEstado( FCO_CierreBN::ESTADO_ABIERTO );
                $o_FCO_CierreFN->setCodVendedor( myUser::getUser()->getUserId() );
                $a_FCO_Cierre = $o_FCO_CierreFN->select();
                if( count( $a_FCO_Cierre ) == 1 )
                {
                    $IdCajaSelect    = $a_FCO_Cierre[0]->getIdCaja();
                    //$DesCajaSelect   = $a_FCO_Cierre[0]->getObjectCaja()->getDescripcion();
                    $IdTurnoSelect   = $a_FCO_Cierre[0]->getIdTurno();
                    //$DescTurnoSelect = $a_FCO_Cierre[0]->getObjectTurno()->getDescripcion();
                }
                else
                {
                    throw new Exception( "No se encontro la Apertura de Caja." );
                }
            //}
            ///////////////////////////////////
            $o_VTA_DocumentoDP = new VTA_DocumentoDP();
            $o_VTA_DocumentoDP->setIdTipoDocumento( $ReferenciaTipoDocumento );
            $o_VTA_DocumentoDP->setIdCompania( ( int ) $IdCompania );
            $o_VTA_DocumentoDP->setIdCaja( $IdCajaSelect );
            $o_VTA_DocumentoDP->setIdTurno( $IdTurnoSelect );
            $o_VTA_DocumentoDP->setNumeroDocumento( $NumeroDocumento );
            $o_VTA_DocumentoDP->setIdAlmacen( $o_VTA_DocumentoBN->getIdAlmacen() );
            $o_VTA_DocumentoDP->setImpresionPendienteFlag( "N" ); //SON 3 ESTADOS -> P(PENDIENTE) N(NO IMPRESO) C(IMPRESO)  ---- EN ESTADO P TE PREGUNTA SI SE IMPRIMIO BIEN

            //se agrega el cambio de fecha del comprobante tomando la fecha y hora actual - 2020-01-27
            //$o_VTA_DocumentoDP->setFechaDocumento( date( "Y-m-d H:i:s" ) ); //SE CAMBIO POR QUE YA SE PUEDE CAMBIAR LA FECHA 2022-02-04
            //////////////////////////////////////////////////////////////////////////////////////////
            //aqui otro cambio, se agrega campo fecha y hora de facturacion -> 2020-02-17
            $o_VTA_DocumentoDP->setFechaFacturacion( date( "Y-m-d H:i:s" ) );
            //////////////////////////////////////////////////////////////////////////////////////////
            $o_VTA_DocumentoDP->setEstado( VTA_DocumentoBN::ESTADO_CERRADO );

            //aqui se agrega otras cosas, como el saldo del comprobante
            $o_VTA_DocumentoDP->setMontoSaldo( $o_VTA_DocumentoTmpBN->getMontoTotal() );
            $o_VTA_DocumentoDP->setMontoSaldoMN( $o_VTA_DocumentoTmpBN->getMontoTotalMN() );

            if( !$o_VTA_DocumentoTmpBN->getMontoAfecto() && $o_VTA_DocumentoTmpBN->getMontoNoAfecto() )
            {
                $o_VTA_DocumentoDP->setMontoAfecto( $o_VTA_DocumentoTmpBN->getMontoSubTotal() );
                $o_VTA_DocumentoDP->setMontoAfectoMN( $o_VTA_DocumentoTmpBN->getMontoSubTotalMN() );
            }

            $b_Result = $o_VTA_DocumentoDP->update();

            if( $b_Result )
            {
                $o_VTA_DocumentoDetalleDP = new VTA_DocumentoDetalleDP();
                $o_VTA_DocumentoDetalleDP->setIdTipoDocumento( $ReferenciaTipoDocumento );
                $o_VTA_DocumentoDetalleDP->setIdCompania( ( int ) $IdCompania );
                $o_VTA_DocumentoDetalleDP->setNumeroDocumento( $NumeroDocumento );
                $o_VTA_DocumentoDetalleDP->setEstado( VTA_DocumentoDetalleBN::ESTADO_CERRADO );
                $b_Result = $o_VTA_DocumentoDetalleDP->cambiarEstadoDetalles();
            }
            //FIN DEL CAMBIO DE ESTADO

            //////////////////////////////////////////////////
            // si no esta activa lo de Guia de Remision, se genera transaccion de salida del stock fisico
            $b_ControlTrnsaccion = false;
            //if( !GSS_ParametroMastFN::getValorPorTipo( "VT", "GUIA_REM" ) )
            if( !myUser::getUser()->getObjectCompania()->getOpeDsctoStockEnGuiaR() )
            {
                $b_ControlTrnsaccion = true;
            }

            if( $o_VTA_DocumentoBN->getforzarMovimientoInventario() )
            {
                $b_ControlTrnsaccion = true;
            }

            if( $b_ControlTrnsaccion )
            {
                //SE GENERA TRANSACCION DE INVENTARIO
                $o_Clone_VTA_DocumentoBN = clone $o_VTA_DocumentoBN;
                $o_Clone_VTA_DocumentoBN->setIdAlmacen( $o_VTA_DocumentoBN->getAlmacenDespacho() ); //ALMACEN ORIGEN - para despacho | 2021-01-29
                $o_Clone_VTA_DocumentoBN->setClienteNumero( $o_VTA_DocumentoTmpBN->getClienteNumero() );
                $o_Clone_VTA_DocumentoBN->setIdTipoDocumento( $o_VTA_DocumentoTmpBN->getIdTipoDocumento() );
                $o_Clone_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoBN->getDocumentoSerie() );
                $o_Clone_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoBN->getDocumentoNumero() );

                $o_Clone_VTA_DocumentoBN->setIdTipoDocumentoTransaccion( VTA_DocumentoBN::TIPO_DOCUMENTO );
                $o_Clone_VTA_DocumentoBN->setIdTransaccion( VTA_DocumentoBN::TRANSACCION_X_DEFECTO );
                $o_Clone_VTA_DocumentoBN->setIdTransaccionOperacion( VTA_DocumentoBN::TIPO_TRANSACCION_X_DEFECTO );

                $this->generarTransaccion( $o_Clone_VTA_DocumentoBN );
            }
            //FIN DE TRANSACCION DE INVENTARIO

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //AQUI SE AGREGA EL PROCEDIMIENTO PARA DESCONTAR LAS PROMOCIONES - 2019-12-13
            $o_TMP_VTA_DocumentoDetalleBN = new VTA_DocumentoDetalleBN();
            $o_TMP_VTA_DocumentoDetalleBN->setIdTipoDocumento( $ReferenciaTipoDocumento );
            $o_TMP_VTA_DocumentoDetalleBN->setIdCompania( ( int ) $IdCompania );
            $o_TMP_VTA_DocumentoDetalleBN->setNumeroDocumento( $NumeroDocumento );

            $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
            $o_OrdenVentaDetalleBL->descontarStockPromociones( $o_TMP_VTA_DocumentoDetalleBN );
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            //AHORA SE AGREGA EL PROCEDIMIENTO PARA LA FACTURACION ELECTRONICA
            //se registra en la tabla de factura electronica - bandeja
            if( $o_VTA_DocumentoBN->getIdTipoDocumento() == "FC" || $o_VTA_DocumentoBN->getIdTipoDocumento() == "BV" )
            {
                $o_VTA_FacturacionElectronicaBN = new VTA_FacturacionElectronicaBN();
                $o_VTA_FacturacionElectronicaBN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_FacturacionElectronicaBN->setFactElecId( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $o_VTA_FacturacionElectronicaBN->setTipo( $o_VTA_DocumentoBN->getIdTipoDocumento() );

                $o_FacturacionElectronicaBL = new FacturacionElectronicaBL();
                $o_FacturacionElectronicaBL->registrarBandeja( $o_VTA_FacturacionElectronicaBN );
            }
            //////////////////////////////////////////////////////////////////
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            ///SE  AGREGA UNA CONDICION, PARA TIPO ANTICIPO, NO SE DEBERIA DE GENERAR
            if( $o_VTA_DocumentoTmpBN->getTipoVenta() != "ANT" )
            {
                //AHORA SE REALIZA EL PROCEDIMIENTO PARA GENERAR CABECERA Y DETALLE MOVIMIENTO DE SERIES,
                //SI LOS DETALLES NO TRABAJA CON SERIE, SE NECESITA ESE REGISTRO PARA LA IMPRESION DE  GUIA. PERO PARA ATENCION INMEDIATA
                $s_ReferenciaTipo = $o_VTA_DocumentoTmpBN->getDocumentoCod();
                $s_ReferenciaNumero = $o_VTA_DocumentoTmpBN->getDocumentoSerie() . "-" . $o_VTA_DocumentoTmpBN->getDocumentoNumero();

                if ( $o_VTA_DocumentoTmpBN->getDocumentoParentCod() )
                {
                    $s_ReferenciaTipo   = "OS";
                    $s_ReferenciaNumero = $o_VTA_DocumentoTmpBN->getDocumentoParentCod();
                }

                //se agrega una busqueda primero para n o duplicar
                $o_SR_MovimientoFN = new SR_MovimientoFN();
                $o_SR_MovimientoFN->setTipoMovimiento( VTA_DocumentoBN::TRANSACCION_X_DEFECTO );
                $o_SR_MovimientoFN->setOperacion( ALM_TransaccionCabeceraBN::TIPO_SALIDA );
                //$o_SR_MovimientoFN->setAlmacen( $o_VTA_DocumentoTmpBN->getIdAlmacen() );
                $o_SR_MovimientoFN->setReferenciaTipo( $s_ReferenciaTipo );
                $o_SR_MovimientoFN->setReferenciaNumero( $s_ReferenciaNumero );
                $a_SR_Movimiento = $o_SR_MovimientoFN->select();
                if ( !$a_SR_Movimiento )
                {
                    $o_SR_MovimientoBN = new SR_MovimientoBN();
                    $o_SR_MovimientoBN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                    $o_SR_MovimientoBN->setTipoMovimiento( VTA_DocumentoBN::TRANSACCION_X_DEFECTO ); //referencia tabla ALM_TransaccionMast -> ROC, VTA
                    $o_SR_MovimientoBN->setOperacion( ALM_TransaccionCabeceraBN::TIPO_SALIDA );
                    $o_SR_MovimientoBN->setAlmacen( $o_VTA_DocumentoBN->getAlmacenDespacho() );
                    $o_SR_MovimientoBN->setReferenciaTipo( $s_ReferenciaTipo );
                    $o_SR_MovimientoBN->setReferenciaNumero( $s_ReferenciaNumero );
                    $o_SR_MovimientoBN->setReferenciaId( $o_VTA_DocumentoTmpBN->getNumeroDocumento() );
                    $o_SR_MovimientoBN->setReferenciaFecha( $o_VTA_DocumentoTmpBN->getFechaDocumento() );
                    $o_SR_MovimientoBN->setEstado( "C" );

                    if( !myUser::getUser()->getObjectCompania()->getAprobacionParaImpGuias() )
                    {
                        $o_SR_MovimientoBN->setEstadoAprob( SR_MovimientoBN::APROBACION_COMPLETADO );
                        $o_SR_MovimientoBN->setUsuarioAprob( myUser::getUser()->getUserId() );
                        $o_SR_MovimientoBN->setFechaAprob( date( "Y-m-d H:i:s" ) );
                        $o_SR_MovimientoBN->setComentarioAprob( "APROBACION DIRECTA" );
                    }

                    $b_ControSerie = false;
                    foreach ( $a_VTA_DocumentoDetalleTMP as $o_VTA_DocumentoDetalleBN )
                    {
                        $o_SR_MovimientoDetalleBN = new SR_MovimientoDetalleBN();
                        $o_SR_MovimientoDetalleBN->setProductoId( $o_VTA_DocumentoDetalleBN->getItemCodigo() );
                        $o_SR_MovimientoDetalleBN->setIdLote( $o_VTA_DocumentoDetalleBN->getLote() );
                        $o_SR_MovimientoDetalleBN->setCantidad( intval( $o_VTA_DocumentoDetalleBN->getCantidadPedida() ) );

                        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                        /// PREGUNTA SI UNO DE LOS PRODUCTOS MANEJA SERIE
                        $o_ALM_ItemMastBN = $o_VTA_DocumentoDetalleBN->getObjectItem();
                        if( $o_ALM_ItemMastBN->SiManejaSerie() )
                        {
                            $b_ControSerie = true;
                        }
                        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

                        $a_SR_MovimientoDetalle[] = $o_SR_MovimientoDetalleBN;
                    }
                    $o_SR_MovimientoBN->setMovimientoDetalleArray( $a_SR_MovimientoDetalle );

                    $o_SR_MovimientoBN->setControlEstadoSerie( SR_MovimientoBN::CTRL_ESTADO_SERIE_NOEXISTE );
                    if( $b_ControSerie )
                    {
                        $o_SR_MovimientoBN->setControlEstadoSerie( SR_MovimientoBN::CTRL_ESTADO_SERIE_PENDIENTE );
                    }

                    $o_SerieBL = new SerieBL();
                    $o_SerieBL->validarMovimientoH( $o_SR_MovimientoBN );
                }
            }
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //se agrega un procedimiento para documentos externos - 2019-10-20
            $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_CERRADO );
            $this->cambiarDataExternosRelacionados( $o_VTA_DocumentoBN );
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            $con->commit();
            
            return true;
        }
        catch ( Exception $o_Exception )
        {
            //pr( $o_Exception );
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }
    }

    public function anularReservaPorDocumento(  VTA_DocumentoBN $o_VTA_DocumentoBN  )
    {
        try
        {
            $o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
            $o_VTA_DocumentoDetalleFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_VTA_DocumentoDetalleFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_VTA_DocumentoDetalleFN->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
            $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->select();
            if( $a_VTA_DocumentoDetalle )
            {
                $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                foreach ( $a_VTA_DocumentoDetalle as $o_VTA_DocumentoDetalleBN )
                {
                    //aqui se podria revisar si tiene soporte para reserva
                    $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                    $o_OrdenVentaDetalleBL->iniciarReservaStockAlmacen( $o_VTA_DocumentoDetalleBN, "D" );
                }
            }
        }
        catch ( Exception $o_Exception )
        {
            throw new Exception( "GNC: ".$o_Exception->getMessage() );
        }
        return true;
    }
 
    public function generarNotaCredito( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            //PARA EL CONTROL DE SERIES, VA A DEPENDER DEL MOTIVO DE LA DEVOLUCION
            //////////////////////////////////////////////////////////////////////

            //VALIDACIONES POR LAS SERIES
            if( !$o_VTA_DocumentoBN->getDocumentoSerie() || !$o_VTA_DocumentoBN->getDocumentoNumero() )
            {
                throw new Exception( "No se puede genera la NC por no tener Serie generada." );
            }

            //SE RECUPERA LA FACTURA DE REFERENCIA
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_TmpVTA_DocumentoBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );
            if( !$o_TmpVTA_DocumentoBN )
            {
                throw new Exception( "No se puede generar NC por no encontrar Documento Referencia." );
            }

            //VALIDACION POR CLIENTE GENERICO
            if( $o_TmpVTA_DocumentoBN->getEsClienteGenerico() )
            {
                if( !$o_VTA_DocumentoBN->getClienteNumero() )
                {
                    throw new Exception( "No se puede generar NC a un Código de Cliente Generico." );
                }
                if( $o_VTA_DocumentoBN->getClienteNumero() )
                {
                    $s_CodClienteGenerico = $o_TmpVTA_DocumentoBN->getCodClienteGenerico();
                    if( $s_CodClienteGenerico == $o_VTA_DocumentoBN->getClienteNumero() )
                    {
                        throw new Exception( "No se puede generar NC, El Código pertence a Cliente Generico." );
                    }
                    
                    $o_MST_PersonaMastFN = new MST_PersonaMastFN();
                    $o_MST_PersonaMastBN = $o_MST_PersonaMastFN->selectByPK( $o_VTA_DocumentoBN->getClienteNumero() );
                    
                    $o_TmpVTA_DocumentoBN->setClienteNumero( ( string ) $o_MST_PersonaMastBN->getIdPersona() );
                    $o_TmpVTA_DocumentoBN->setClienteRUC( $o_MST_PersonaMastBN->getDocumento() );
                    $o_TmpVTA_DocumentoBN->setClienteDireccion( $o_MST_PersonaMastBN->getDireccion() );
                    $o_TmpVTA_DocumentoBN->setClienteNombre( $o_MST_PersonaMastBN->getNombreConcatenado() );
                }
            }
            
            $b_ControlNC = false;
            //VALIDACION DE QUE NO SE PUEDA GENERAR 2 NOTAS DE CREDITO
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_VTA_DocumentoFN->setIdTipoDocumento( VTA_DocumentoBN::TIPO_DOCUMENTO_NOTA_CREDITO );
            $o_VTA_DocumentoFN->setDocumentoParentId( $o_TmpVTA_DocumentoBN->getNumeroDocumento() );
            //$o_VTA_DocumentoFN->setCampoReferencia( $o_TmpVTA_DocumentoBN->getDocumentoTipoSerieNumero() ); //antes existia este campo
            $o_VTA_DocumentoFN->setDocumentoParentCod( $o_TmpVTA_DocumentoBN->getDocumentoSerieNumero() );
            $a_TmpHisVTA_Documento = $o_VTA_DocumentoFN->select();
            if( $a_TmpHisVTA_Documento )
            {
            	$b_ControlNC = true;
                //throw new Exception( "Ya se encuentra una NC asociado al Documento de Venta." );
            }
            
            $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_CERRADO );
            
            $this->validarValoresxDefecto( $o_VTA_DocumentoBN );
            
            //SE GUARDA LA CEBECERA
            $o_VTA_DocumentoBN->setIdTipoDocumento( VTA_DocumentoBN::TIPO_DOCUMENTO_NOTA_CREDITO );
            $o_VTA_DocumentoBN->setIdFormaPago( $o_TmpVTA_DocumentoBN->getIdFormaPago() );
            $o_VTA_DocumentoBN->setIdAlmacen( $o_TmpVTA_DocumentoBN->getIdAlmacen() );
            
            $o_VTA_DocumentoBN->setClienteNumero( $o_TmpVTA_DocumentoBN->getClienteNumero() );
            $o_VTA_DocumentoBN->setClienteTipoDoc( $o_TmpVTA_DocumentoBN->getClienteTipoDoc() );
            $o_VTA_DocumentoBN->setClienteNombre( $o_TmpVTA_DocumentoBN->getClienteNombre() );
            $o_VTA_DocumentoBN->setClienteRUC( $o_TmpVTA_DocumentoBN->getClienteRUC() );
            $o_VTA_DocumentoBN->setClienteDireccion( $o_TmpVTA_DocumentoBN->getClienteDireccion() );
            $o_VTA_DocumentoBN->setClienteReferencia( $o_TmpVTA_DocumentoBN->getClienteReferencia() );

            if( !$o_VTA_DocumentoBN->getFechaDocumento() )
            {
                $o_VTA_DocumentoBN->setFechaDocumento( $o_TmpVTA_DocumentoBN->getFechaDocumento() );
            }
            $o_VTA_DocumentoBN->setMonedaDocumento( $o_TmpVTA_DocumentoBN->getMonedaDocumento() );
            $o_VTA_DocumentoBN->setAnulacionComentario( $o_TmpVTA_DocumentoBN->getAnulacionComentario() );
            $o_VTA_DocumentoBN->setFechaVencimiento( $o_TmpVTA_DocumentoBN->getFechaVencimiento() );
            $o_VTA_DocumentoBN->setTipoVenta( $o_TmpVTA_DocumentoBN->getTipoVenta() );
            $o_VTA_DocumentoBN->setVendedor( $o_TmpVTA_DocumentoBN->getVendedor() );
            $o_VTA_DocumentoBN->setCanalVenta( $o_TmpVTA_DocumentoBN->getCanalVenta() );

            $o_VTA_DocumentoBN->setDocumentoCod( $o_VTA_DocumentoBN->getObjectTipoDocumento()->getTipoDocumentoCod() );
            $o_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoBN->getDocumentoSerie() );
            $o_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoBN->getDocumentoNumero() );
            $o_VTA_DocumentoBN->setNumeroComprobante( $o_VTA_DocumentoBN->getDocumentoSerieNumero() );

            $o_VTA_DocumentoBN->setDocumentoParentId( ( int ) $o_TmpVTA_DocumentoBN->getNumeroDocumento() );
            $o_VTA_DocumentoBN->setDocumentoParentCod( $o_TmpVTA_DocumentoBN->getDocumentoSerieNumero() );
            //$o_VTA_DocumentoBN->setCampoReferencia( $o_TmpVTA_DocumentoBN->getDocumentoTipoSerieNumero() );  //antes existia este campo


            $o_VTA_DocumentoBN->setPeriodo( str_replace( "-", "", substr( $o_VTA_DocumentoBN->getFechaDocumento(), 0, 7 ) ) );
            $o_VTA_DocumentoBN->setAlmacenDespacho( $o_TmpVTA_DocumentoBN->getAlmacenDespacho() );
            $o_VTA_DocumentoBN->setIdSucursal( $o_TmpVTA_DocumentoBN->getSucursal() );
            $o_VTA_DocumentoBN->setSucursal( $o_TmpVTA_DocumentoBN->getSucursal() );
            $o_VTA_DocumentoBN->setIdCaja( $o_TmpVTA_DocumentoBN->getIdCaja() );
            $o_VTA_DocumentoBN->setIdTurno( $o_TmpVTA_DocumentoBN->getIdTurno() );
            $o_VTA_DocumentoBN->setIdProyecto( $o_TmpVTA_DocumentoBN->getIdProyecto() );
            $o_VTA_DocumentoBN->setClienteContacto( $o_TmpVTA_DocumentoBN->getClienteContacto() );
            $o_VTA_DocumentoBN->setDepartamento( $o_TmpVTA_DocumentoBN->getDepartamento() );
            $o_VTA_DocumentoBN->setProvincia( $o_TmpVTA_DocumentoBN->getProvincia() );
            $o_VTA_DocumentoBN->setDistrito( $o_TmpVTA_DocumentoBN->getDistrito() );
            $o_VTA_DocumentoBN->setUbigeo( $o_TmpVTA_DocumentoBN->getUbigeo() );
            $o_VTA_DocumentoBN->setTipoFacturacion( $o_TmpVTA_DocumentoBN->getTipoFacturacion() );
            $o_VTA_DocumentoBN->setTipoVenta( $o_TmpVTA_DocumentoBN->getTipoVenta() );
            $o_VTA_DocumentoBN->setVendedor( $o_TmpVTA_DocumentoBN->getVendedor() );
            $o_VTA_DocumentoBN->setTipodeCambio( $o_TmpVTA_DocumentoBN->getTipodeCambio() );
            $o_VTA_DocumentoBN->setMonedaDocumento( $o_TmpVTA_DocumentoBN->getMonedaDocumento() );

            $o_VTA_DocumentoBN->setMontoAfecto( 0.00 );
            $o_VTA_DocumentoBN->setMontoNoAfecto( 0.00 );
            //$o_VTA_DocumentoBN->setMontoImpuestoVentas( 0.00 );
            $o_VTA_DocumentoBN->setMontoImpuestos( 0.00 );
            $o_VTA_DocumentoBN->setMontoDescuentos( 0.00 );
            $o_VTA_DocumentoBN->setMontoRedondeo( 0 );
            $o_VTA_DocumentoBN->setMontoTotal( 0.00 );
            $o_VTA_DocumentoBN->setMontoPagado( 0.00 );
            //$o_VTA_DocumentoBN->setMontoAdelantoSaldo( 0.00 );
            
            $o_VTA_DocumentoBN->setFechaCreacion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoBN->setUsuarioCreacion( myUser::getUser()->getUserId() );
            $o_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );

            $o_VTA_DocumentoDP = new VTA_DocumentoDP( $o_VTA_DocumentoBN );
            $b_Result = $o_VTA_DocumentoDP->save();
            
            //SI SE TIENE MAS DE 1 NC ASOCIADO SE BUSCA LA CANTIDAD DE DETALLES
            $a_DetallesMapHis = array();
            if( $b_ControlNC )
            {
            	foreach ( $a_TmpHisVTA_Documento as $i_Key => $o_TmpHisVTA_DocumentoBN )
            	{
            		$a_TmpHisVTA_DocumentoDetalle = $o_TmpHisVTA_DocumentoBN->getArrayObjectDetalles();
            		foreach ( $a_TmpHisVTA_DocumentoDetalle as $i_key2 => $o_TmpHisVTA_DocumentoDetalleBN )
            		{
            		    $i_KeyAsig = $o_TmpHisVTA_DocumentoDetalleBN->getSecuencia()."_".$o_TmpHisVTA_DocumentoDetalleBN->getItemCodigo();
            		    if( isset( $a_DetallesMapHis[$i_KeyAsig] ) )
            		    {
            		        $i_CantidadPedida = ( int ) $o_TmpHisVTA_DocumentoDetalleBN->getCantidadPedida();
            		        $a_DetallesMapHis[$i_KeyAsig] = $a_DetallesMapHis[$i_KeyAsig] + $i_CantidadPedida;
            		    }
            		    else 
            		    {
                			$a_DetallesMapHis[$i_KeyAsig] = ( int ) $o_TmpHisVTA_DocumentoDetalleBN->getCantidadPedida();
            		    }
            		}
            	}
            }
            
            //AHORA LOS DETALLES
            $a_VTA_DocumentoDetalle = $o_VTA_DocumentoBN->getArrayDocumentoDetalle();
            foreach ( $a_VTA_DocumentoDetalle as $i_Key => $o_VTA_DocumentoDetalleBN )
            {
            	//VALIDAR CANTIDADES DESDE LA FACTURA FUENTE
            	$o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
            	$o_Ref_VTA_DocumentoDetalleBN = $o_VTA_DocumentoDetalleFN->selectByPK( $o_TmpVTA_DocumentoBN->getIdTipoDocumento(), $o_TmpVTA_DocumentoBN->getIdCompania(), $o_TmpVTA_DocumentoBN->getNumeroDocumento(), $o_VTA_DocumentoDetalleBN->getSecuencia() );
            	if( $o_VTA_DocumentoDetalleBN->getCantidadPedida() > $o_Ref_VTA_DocumentoDetalleBN->getCantidadPedida() )
            	{
            		throw new Exception( "La cantidad para la NC del Item {$o_VTA_DocumentoDetalleBN->getItemCodigo()} es mayor a la Factura." );
            	}
            	if( $o_VTA_DocumentoDetalleBN->getCantidadPedida() <= 0 )
            	{
            		throw new Exception( "La cantidad para la NC del Item {$o_VTA_DocumentoDetalleBN->getItemCodigo()} tiene que ser mayor a 0." );
            	}
            	//CANTIDADES COMO MAXIMO POR HISTORIAL 
            	if( $b_ControlNC )
            	{
            	    //$a_DetallesMapHis[]
            	    if ( isset( $a_DetallesMapHis[$o_VTA_DocumentoDetalleBN->getSecuencia()."_".$o_VTA_DocumentoDetalleBN->getItemCodigo()] ) )
            	    {
            	        $i_CantidadPedida = ( int ) $o_VTA_DocumentoDetalleBN->getCantidadPedida();
            	        $i_CantidadTotal =  $a_DetallesMapHis[$o_VTA_DocumentoDetalleBN->getSecuencia()."_".$o_VTA_DocumentoDetalleBN->getItemCodigo()] + $i_CantidadPedida;
            	        
            	        if( $i_CantidadTotal > $o_Ref_VTA_DocumentoDetalleBN->getCantidadPedida() )
                    	{
                    		throw new Exception( "La cantidad para la NC del Item {$o_VTA_DocumentoDetalleBN->getItemCodigo()} es mayor a la Factura." );
                    	}
            	    }
            	}

                $o_VTA_DocumentoDetalleBN->setTipoDetalle( $o_Ref_VTA_DocumentoDetalleBN->getTipoDetalle() );
                $o_VTA_DocumentoDetalleBN->setIdUnidad( $o_Ref_VTA_DocumentoDetalleBN->getIdUnidad() );
                $o_VTA_DocumentoDetalleBN->setIdTipoPrecio( $o_Ref_VTA_DocumentoDetalleBN->getIdTipoPrecio() );
                $o_VTA_DocumentoDetalleBN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDetalleBN->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $o_VTA_DocumentoDetalleBN->setEstado( VTA_DocumentoDetalleBN::ESTADO_CERRADO );
                $o_VTA_DocumentoDetalleBN->setCondicion( $o_Ref_VTA_DocumentoDetalleBN->getCondicion() );
                $o_VTA_DocumentoDetalleBN->setEstado( $o_Ref_VTA_DocumentoDetalleBN->getEstado() );
                $o_VTA_DocumentoDetalleBN->setTipoIGV( $o_Ref_VTA_DocumentoDetalleBN->getTipoIGV() );
                $o_VTA_DocumentoDetalleBN->setIdTransaccionOperacion( VTA_DocumentoBN::TIPO_TRANSACCION_NOTA_CREDI );
                
                $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                $b_Result = $o_OrdenVentaDetalleBL->agregarLinea( $o_VTA_DocumentoDetalleBN );
                $o_OrdenVentaDetalleBL->actualizarMontosCabcecera( $o_VTA_DocumentoDetalleBN );
            }

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //SE GENERA TRANSACCION NEGATIVO PARA INVENTARIO
            $o_Clone_VTA_DocumentoBN = clone $o_VTA_DocumentoBN;
            $o_Clone_VTA_DocumentoBN->setIdAlmacen( $o_VTA_DocumentoBN->getIdAlmacen() ); //ALMACEN ORIGEN
            $o_Clone_VTA_DocumentoBN->setClienteNumero( $o_VTA_DocumentoBN->getClienteNumero() );
            
            $o_Clone_VTA_DocumentoBN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_Clone_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoBN->getDocumentoSerie() );
            $o_Clone_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoBN->getDocumentoNumero() );
            
            $o_Clone_VTA_DocumentoBN->setIdTipoDocumentoTransaccion( VTA_DocumentoBN::TIPO_DOCUMENTO_NC_TRANS );
            $o_Clone_VTA_DocumentoBN->setIdTransaccion( VTA_DocumentoBN::TRANSACCION_NOTA_CREDITO );
            $o_Clone_VTA_DocumentoBN->setIdTransaccionOperacion( VTA_DocumentoBN::TIPO_TRANSACCION_NOTA_CREDI );

            //////////////////////////////////////////////////
            // si no esta activa lo de Guia de Remision, se genera transaccion de salida del stock fisico
            $b_ControlTrnsaccion = false;
            //if( !GSS_ParametroMastFN::getValorPorTipo( "VT", "GUIA_REM" ) )
            if( !myUser::getUser()->getObjectCompania()->getOpeDsctoStockEnGuiaR() )
            {
                $b_ControlTrnsaccion = true;
            }

            if( $o_VTA_DocumentoBN->getforzarMovimientoInventario() )
            {
                $b_ControlTrnsaccion = true;
            }

            if( $b_ControlTrnsaccion )
            {
                $this->generarTransaccion( $o_Clone_VTA_DocumentoBN );
            }
            //FIN DE TRANSACCION DE INVENTARIO
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            $this->incrementarDocumentoNumero( $o_VTA_DocumentoBN );
            
            //SE GUARDA LA NC EN LA FACTURA COMO REFERENCIA:
            $o_VTA_DocumentoDP = new VTA_DocumentoDP();
            $o_VTA_DocumentoDP->setIdCompania( $o_TmpVTA_DocumentoBN->getIdCompania() );
            $o_VTA_DocumentoDP->setIdTipoDocumento( $o_TmpVTA_DocumentoBN->getIdTipoDocumento() );
            $o_VTA_DocumentoDP->setNumeroDocumento( $o_TmpVTA_DocumentoBN->getNumeroDocumento() );
            $o_VTA_DocumentoDP->setNotaCreditoDocumento( $o_VTA_DocumentoBN->getDocumentoTipoSerieNumero() );
            $o_VTA_DocumentoDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
            $o_VTA_DocumentoDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
            $b_Result = $o_VTA_DocumentoDP->update();
            ////////////////////////////////////////////////

            ////////////////////////////////////////////////
            ///AHORA SE RECUPERA DOCUMENTO EN TRAMITE PARA ACTUALIZAR EL SALDO y
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_TmpVTA_DocumentoBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );

            $o_VTA_DocumentoDP = new VTA_DocumentoDP();
            $o_VTA_DocumentoDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_VTA_DocumentoDP->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_VTA_DocumentoDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
            $o_VTA_DocumentoBN->setCobranzaEstado( VTA_DocumentoBN::ESTADO_COB_PENDIENTE ); //por defecto
            $o_VTA_DocumentoDP->setMontoSaldo( $o_TmpVTA_DocumentoBN->getMontoTotal() );
            $o_VTA_DocumentoDP->setMontoSaldoMN( $o_TmpVTA_DocumentoBN->getMontoTotalMN() );
            $o_VTA_DocumentoDP->setImpresionPendienteFlag( "N" );
            $o_VTA_DocumentoDP->setFechaFacturacion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
            $o_VTA_DocumentoDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );

            $b_Result = $o_VTA_DocumentoDP->update();
            ////////////////////////////////////////////////

            //AHORA SE AGREGA EL PROCEDIMIENTO PARA LA FACTURACION ELECTRONICA
            //se registra en la tabla de factura electronica - bandeja
            $o_VTA_FacturacionElectronicaBN = new VTA_FacturacionElectronicaBN();
            $o_VTA_FacturacionElectronicaBN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_VTA_FacturacionElectronicaBN->setFactElecId( $o_VTA_DocumentoBN->getNumeroDocumento() );
            $o_VTA_FacturacionElectronicaBN->setTipo( $o_VTA_DocumentoBN->getIdTipoDocumento() );

            $o_FacturacionElectronicaBL = new FacturacionElectronicaBL();
            $o_FacturacionElectronicaBL->registrarBandeja( $o_VTA_FacturacionElectronicaBN );
            //////////////////////////////////////////////////////////////////

            $con->commit();
            return true;
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( "GNC: ".$o_Exception->getMessage() );
        }
    }

    public function AnularDocumentoEstadoPR( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try 
        {
            $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_CANCELADO );
            $o_VTA_DocumentoBN->setImpresionPendienteFlag( "N" );
            $o_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d" ) );
            $o_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );

            $o_VTA_DocumentoDP = new VTA_DocumentoDP( $o_VTA_DocumentoBN );
            $b_Result = $o_VTA_DocumentoDP->update();
            
            if( $b_Result )
            {
                $o_VTA_DocumentoDetalleDP = new VTA_DocumentoDetalleDP();
                $o_VTA_DocumentoDetalleDP->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDetalleDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_DocumentoDetalleDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $o_VTA_DocumentoDetalleDP->setEstado( VTA_DocumentoDetalleBN::ESTADO_CANCELADO );
                $b_Result = $o_VTA_DocumentoDetalleDP->cambiarEstadoDetalles();

                //ahora se procede a quitar las reservas
                $o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
                $o_VTA_DocumentoDetalleFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDetalleFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_DocumentoDetalleFN->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->select();
                foreach ( $a_VTA_DocumentoDetalle as $key => $o_VTA_DocumentoDetalleBN ) 
                {
                    $o_OrdenVentaDetalleBL = new OrdenVentaDetalleBL();
                    $o_OrdenVentaDetalleBL->iniciarReservaStockAlmacen( $o_VTA_DocumentoDetalleBN, "D" );
                }

                ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                //se agrega un procedimiento para documentos externos
                $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_CANCELADO );
                $this->cambiarDataExternosRelacionados( $o_VTA_DocumentoBN );
                ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            }

            $con->commit();
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );            
        }
    }
    
    public function AnularDocumento( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            //antes de actualizar, se pregunta su estado
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_TMP_VTA_DocumentoBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );

            //se hace una validacion de estado
            if( $o_TMP_VTA_DocumentoBN->getEstado() == VTA_DocumentoBN::ESTADO_ANULADO )
            {
                throw new Exception( "OV-AD: El documento ya se encuentra Anulado." );
            }
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //se valida el estado, si esta en preparacion, se anular diferente
            if( $o_TMP_VTA_DocumentoBN->getEstado() == VTA_DocumentoBN::ESTADO_PREPARACION )
            {
                $this->AnularDocumentoEstadoPR( $o_TMP_VTA_DocumentoBN );
                $con->commit();
                return true;
            }
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //AQUI OTRA VALIDACION, SI L FECHA DE EMISION ES MAYOR A 7 DIAS SE EMITE UNA ADVERTENCIA - 2020-10-11
            $i_Dias = UtilDate::diferenciaEntreFecha( substr( $o_TMP_VTA_DocumentoBN->getFechaDocumento(), 0, 10 ), date( "Y-m-d" ) );
            if( $i_Dias > 3 )
            {
                throw new Exception( "La Fecha no puede ser mayor a 7 Dias." );
            }
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////

	    	$o_VTA_DocumentoDP = new VTA_DocumentoDP( $o_VTA_DocumentoBN );
	        $b_Result = $o_VTA_DocumentoDP->update();
	        
	        if( $b_Result )
	        {
	            $o_VTA_DocumentoDetalleDP = new VTA_DocumentoDetalleDP();
	            $o_VTA_DocumentoDetalleDP->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
	            $o_VTA_DocumentoDetalleDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
	            $o_VTA_DocumentoDetalleDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
	            $o_VTA_DocumentoDetalleDP->setEstado( VTA_DocumentoDetalleBN::ESTADO_ANULADO );
	            $b_Result = $o_VTA_DocumentoDetalleDP->cambiarEstadoDetalles();
	        }
	        
            //aqui se agrega un procedimiento para anular las aplicaciones y recibos asociado al comprobante 2020-02-20
            $o_FCO_AplicacionFN = new FCO_AplicacionFN();
            $o_FCO_AplicacionFN->setIdDocNumRef( $o_VTA_DocumentoBN->getNumeroDocumento() );
            //$o_FCO_AplicacionFN->setEstado( FCO_AplicacionBN::ESTADO_PENDINTE );
            $a_FCO_Aplicacion = $o_FCO_AplicacionFN->select();
            $a_Recibos = array();
            foreach ( $a_FCO_Aplicacion as $o_FCO_AplicacionBN ) 
            {
                $o_FCO_AplicacionDP = new FCO_AplicacionDP();
                $o_FCO_AplicacionDP->setIdAplicacion( $o_FCO_AplicacionBN->getIdAplicacion() );
                $o_FCO_AplicacionDP->setEstado( FCO_AplicacionBN::ESTADO_ANULADO );
                $o_FCO_AplicacionDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
                $o_FCO_AplicacionDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                $o_FCO_AplicacionDP->update();
                if( !isset( $a_Recibos[$o_FCO_AplicacionBN->getIdDocRecibo()] ) )
                {
                    $a_Recibos[$o_FCO_AplicacionBN->getIdDocRecibo()] = $o_FCO_AplicacionBN->getIdDocRecibo();
                    
                    //AQUI SE TIENE Q EVALUAR SI POR EJEMPLO ES DEPOSITO, POR Q LOS DEPOSITOS NO SE DEBE DE RECHAZAR SI ESTAN APROBADOS...
                    $o_FCO_DocReciboDP = new FCO_DocReciboDP();
                    $o_FCO_DocReciboDP->setIdDocRecibo( $o_FCO_AplicacionBN->getIdDocRecibo() );
                    $o_FCO_DocReciboDP->setEstado( FCO_DocReciboBN::ESTADO_ANULADO );
                    $o_FCO_DocReciboDP->setFlujoEstado( FCO_DocReciboBN::FLUESTADO_RECHAZADO );
                    $o_FCO_DocReciboDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                    $o_FCO_DocReciboDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
                    $o_FCO_DocReciboDP->update();
                }
            }
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////

            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_VTA_DocumentoBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //SE GENERA TRANSACCION NEGATIVO PARA INVENTARIO
            $o_Clone_VTA_DocumentoBN = clone $o_VTA_DocumentoBN;
            $o_Clone_VTA_DocumentoBN->setIdAlmacen( $o_VTA_DocumentoBN->getIdAlmacen() ); //ALMACEN ORIGEN
            $o_Clone_VTA_DocumentoBN->setClienteNumero( $o_VTA_DocumentoBN->getClienteNumero() );
            
            $o_Clone_VTA_DocumentoBN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_Clone_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoBN->getDocumentoSerie() );
            $o_Clone_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoBN->getDocumentoNumero() );
            
            $o_Clone_VTA_DocumentoBN->setIdTipoDocumentoTransaccion( VTA_DocumentoBN::TIPO_DOCUMENTO_NC_TRANS );
            $o_Clone_VTA_DocumentoBN->setIdTransaccion( VTA_DocumentoBN::TRANSACCION_MAST_X_ANULACION );
            $o_Clone_VTA_DocumentoBN->setIdTransaccionOperacion( VTA_DocumentoBN::TIPO_TRANSACCION_NOTA_CREDI );
            
            $this->generarTransaccion( $o_Clone_VTA_DocumentoBN );
            //FIN DE TRANSACCION DE INVENTARIO
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //AHORA EN LA ORDEN DE VENTA DE DEJA CERRADO
            if( $o_VTA_DocumentoBN->getDocumentoParentId() )
            {
                
                $o_VTA_OrdenBN = new VTA_OrdenBN();
                $o_VTA_OrdenBN->setOrdenId( $o_VTA_DocumentoBN->getDocumentoParentId() );
                $o_VTA_OrdenBN->setOrdenEstado( VTA_OrdenBN::ESTADO_ANULADO );
                $o_VTA_OrdenBN->setAnularDocumemtoreferencia( true ); //ESPECIFICA QUE ES UN PROCEDIMIENTO ESPECIAL, COMO ANULACION DE COMPROBANTE - 
                
                $o_CotizacionesBL = new CotizacionesBL();
                $o_CotizacionesBL->cambiarEstadoOrdenVenta( $o_VTA_OrdenBN );
                
            }
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            //ahora se agrega el procedimiento para la facturacion electronica
            try
            {
                if( $o_VTA_DocumentoBN->getIdTipoDocumento() == "FC" || $o_VTA_DocumentoBN->getIdTipoDocumento() == "BV" )
                {
                    $o_VTA_FacturacionElectronicaBN = new VTA_FacturacionElectronicaBN();
                    $o_VTA_FacturacionElectronicaBN->setFactElecId( $o_VTA_DocumentoBN->getNumeroDocumento() );
                    $o_VTA_FacturacionElectronicaBN->setEstadoWeb( VTA_DocumentoBN::ESTADO_ANULADO );
                    $o_VTA_FacturacionElectronicaBN->setAnuMotivo( $o_VTA_DocumentoBN->getAnulacionComentario() );

                    $o_FacturacionElectronicaBL = new FacturacionElectronicaBL();
                    $o_FacturacionElectronicaBL->anularComprobante( $o_VTA_FacturacionElectronicaBN );
                }
            }
            catch ( Exception $o_Exception )
            {
            }
            ////////////////////////////////////////////////////////////////////

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //se agrega un procedimiento para documentos externos
            $o_VTA_DocumentoBN->setEstado( VTA_DocumentoBN::ESTADO_ANULADO );
            $this->cambiarDataExternosRelacionados( $o_VTA_DocumentoBN );
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	        
            $con->commit();
            return true;
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }
    }

    public function cambiarDataExternosRelacionados( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //se implemento por el caso del proyecto - hotel [2019-10-28]
        //los procedimientos se pueden mejorar si llaman a un bl y un metodo y dentro tenga lo que se quiere hacer
        $o_SRV_UbicacionClienteDetDP = new SRV_UbicacionClienteDetDP();
        $o_SRV_UbicacionClienteDetDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );

        if( $o_VTA_DocumentoBN->getDocumentoCod() ) $o_SRV_UbicacionClienteDetDP->setDocumentoCod( $o_VTA_DocumentoBN->getDocumentoCod() );
        if( $o_VTA_DocumentoBN->getDocumentoSerie() ) $o_SRV_UbicacionClienteDetDP->setDocumentoSerie( $o_VTA_DocumentoBN->getDocumentoSerie() );
        if( $o_VTA_DocumentoBN->getDocumentoNumero() ) $o_SRV_UbicacionClienteDetDP->setDocumentoNumero( $o_VTA_DocumentoBN->getDocumentoNumero() );

        $o_SRV_UbicacionClienteDetDP->setEstado( $o_VTA_DocumentoBN->getEstado() );
        $o_SRV_UbicacionClienteDetDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
        $o_SRV_UbicacionClienteDetDP->actualizarCamposPorRemoto();
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }
    
    private function validarValoresxDefecto( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $i_Id = VTA_DocumentoFN::recuperarId();
        $o_VTA_DocumentoBN->setNumeroDocumento( $i_Id );
        $o_VTA_DocumentoBN->setUsuarioCreacion( myUser::getUser()->getUserId() );
        $o_VTA_DocumentoBN->setFechaCreacion( date( "Y-m-d H:i:s" ) );
        $o_VTA_DocumentoBN->setUsuarioModificacion( myUser::getUser()->getUserId() );
        $o_VTA_DocumentoBN->setFechaModificacion( date( "Y-m-d H:i:s" ) );
        
        $f_TipoCambio = GSS_TipoCambioFN::getStaticTipoCambioCobranza();
        if( !$f_TipoCambio )
        {
            throw new Exception( "Debe de registrar el Tipo de Cambio de hoy." );
        }
        $o_VTA_DocumentoBN->setTipodeCambio( floatval( $f_TipoCambio ) );
    }
    
    public function procesoNaceAnuladoOrden( VTA_DocumentoBN $o_VTA_DocumentoBN )
    {
        $con = Conexion::getConexion();
        $con->begin();
        try
        {
            $o_VTA_DocumentoFN = new VTA_DocumentoFN();
            $o_VTA_DocumentoTmpBN = $o_VTA_DocumentoFN->selectByPK( $o_VTA_DocumentoBN->getIdTipoDocumento(), $o_VTA_DocumentoBN->getIdCompania(), $o_VTA_DocumentoBN->getNumeroDocumento() );
            if( $o_VTA_DocumentoTmpBN )
            {
                //SE CAMBIA EL ESTADO DE LA ORDEN:
                $o_VTA_DocumentoDP = new VTA_DocumentoDP();
                $o_VTA_DocumentoDP->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_DocumentoDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $o_VTA_DocumentoDP->setIdAlmacen( $o_VTA_DocumentoBN->getIdAlmacen() );
                $o_VTA_DocumentoDP->setEstado( $o_VTA_DocumentoBN->getEstado() );
                $o_VTA_DocumentoDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
                $o_VTA_DocumentoDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                $o_VTA_DocumentoDP->update();

                $o_VTA_DocumentoBN->setDocumentoSerie( $o_VTA_DocumentoTmpBN->getDocumentoSerie() );
                $o_VTA_DocumentoBN->setDocumentoNumero( $o_VTA_DocumentoTmpBN->getDocumentoNumero() );
                
                $this->incrementarDocumentoNumero( $o_VTA_DocumentoBN );
            }
            else
            {
                throw new Exception( "El documento de venta no existe." );
            }

            $con->commit();
            return true;
        }
        catch ( Exception $o_Exception )
        {
            $con->rollback();
            throw new Exception( $o_Exception->getMessage() );
        }
    }
    
    public function incrementarDocumentoNumero( VTA_DocumentoBN &$o_VTA_DocumentoBN )
    {
        $o_GSS_UsuarioSucuDocumentoBN = null;

        if( $o_VTA_DocumentoBN->getEsTransferencia() )
        {
            $o_GSS_SucursalDocumentoFN = new GSS_SucursalDocumentoFN();
            $o_GSS_SucursalDocumentoFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_GSS_SucursalDocumentoFN->setIdSucursal( $o_VTA_DocumentoBN->getIdSucursal() );
            $o_GSS_SucursalDocumentoFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $a_GSS_SucursalDocumento = $o_GSS_SucursalDocumentoFN->select();
            if( $a_GSS_SucursalDocumento )
            {
                if( count( $a_GSS_SucursalDocumento ) > 1 )
                {
                    throw new Exception( "Se encontro varios detalles de Serie SucursalDocumento." );
                }
                $o_GSS_UsuarioSucuDocumentoBN = new GSS_UsuarioSucuDocumentoBN;
                $o_GSS_SucursalDocumentoBN = $a_GSS_SucursalDocumento[0];
            }
        }
        elseif ( $o_VTA_DocumentoBN->getEsGuiaRemision() ) 
        {
            $o_GSS_SucursalDocumentoFN = new GSS_SucursalDocumentoFN();
            $o_GSS_SucursalDocumentoFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_GSS_SucursalDocumentoFN->setIdSucursal( $o_VTA_DocumentoBN->getIdSucursal() );
            $o_GSS_SucursalDocumentoFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $a_GSS_SucursalDocumento = $o_GSS_SucursalDocumentoFN->select();
            if( $a_GSS_SucursalDocumento )
            {
                if( count( $a_GSS_SucursalDocumento ) > 1 )
                {
                    throw new Exception( "Se encontro varios detalles de Serie SucursalDocumento." );
                }
                $o_GSS_UsuarioSucuDocumentoBN = new GSS_UsuarioSucuDocumentoBN;
                $o_GSS_SucursalDocumentoBN = $a_GSS_SucursalDocumento[0];
            }
        }
        else
        {
            $o_GSS_UsuarioSucuDocumentoFN = new GSS_UsuarioSucuDocumentoFN();
            $o_GSS_UsuarioSucuDocumentoFN->setIdusuario( myUser::getUser()->getUserId() );
            $o_GSS_UsuarioSucuDocumentoFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_GSS_UsuarioSucuDocumentoFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
            $o_GSS_UsuarioSucuDocumentoFN->setSerieDocumento( $o_VTA_DocumentoBN->getDocumentoSerie() );
            $a_GSS_UsuarioSucuDocumento = $o_GSS_UsuarioSucuDocumentoFN->select();

            if( $a_GSS_UsuarioSucuDocumento )
            {
                if( count( $a_GSS_UsuarioSucuDocumento ) == 1 )
                {
                    $o_GSS_UsuarioSucuDocumentoBN = $a_GSS_UsuarioSucuDocumento[0];

                    $o_GSS_SucursalDocumentoFN = new GSS_SucursalDocumentoFN();
                    $o_GSS_SucursalDocumentoBN = $o_GSS_SucursalDocumentoFN->selectByPK( $o_GSS_UsuarioSucuDocumentoBN->getIdSucursalDocumento() );
                }
                else
                {
                    throw new Exception( "Se encontro varios detalles de Serie UsuarioSucuDocumento." );
                }
            }
            else
            {
                throw new Exception( "Se encontro problemas al buscar UsuarioSucuDocumento." );
            }
        }

        //AHORA SE INCREMENTA EL CORRELATIVO DE LA SERIE POR EL TIPO DE DOCUMENTO SELECCIONADO
        /*
        $o_GSS_SucursalDocumentoFN = new GSS_SucursalDocumentoFN();
        $o_GSS_SucursalDocumentoFN->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
        $o_GSS_SucursalDocumentoFN->setIdSucursal( $o_VTA_DocumentoBN->getIdSucursal() );
        $o_GSS_SucursalDocumentoFN->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
        $a_GSS_SucursalDocumento = $o_GSS_SucursalDocumentoFN->select();
        */
        if( $o_GSS_UsuarioSucuDocumentoBN )
        {
            //$o_GSS_SucursalDocumentoBN = $a_GSS_SucursalDocumento[0];
            if( !$o_GSS_SucursalDocumentoBN )
            {
                throw new Exception( "No se encontro la Referencia del Punto de Venta para la Sucursal actual." );
            }

            $i_IdSucursalDocumento = $o_GSS_SucursalDocumentoBN->getIdSucursalDocumento();
        
            $s_Serie  = $o_GSS_SucursalDocumentoBN->getSerieFormatoFinal();
            $i_NumeroActual = $o_GSS_SucursalDocumentoBN->getNumeroActual() + 1;
            //$s_Numero = str_pad( $i_NumeroActual, 8, "0", STR_PAD_LEFT );
            $s_Numero = $o_GSS_SucursalDocumentoBN->getNumeroActualFormato();

            //se valida que el documento de vigenta tenga la misma serie

            if( $o_VTA_DocumentoBN->getEsTransferencia() )
            {
                if( $o_VTA_DocumentoBN->getDocumentoSerie() == $s_Serie && $o_VTA_DocumentoBN->getDocumentoNumero() != $s_Numero )
                {
                    $o_VTA_DocumentoBN->setDocumentoNumero( $s_Numero );
                }
            }

            if( $o_VTA_DocumentoBN->getDocumentoSerie() == $s_Serie && $o_VTA_DocumentoBN->getDocumentoNumero() == $s_Numero )
            {
                //se incrementa
                $o_GSS_SucursalDocumentoDP = new GSS_SucursalDocumentoDP();
                $o_GSS_SucursalDocumentoDP->setIdSucursalDocumento( $i_IdSucursalDocumento );
                $o_GSS_SucursalDocumentoDP->setNumeroActual( $i_NumeroActual );
                $o_GSS_SucursalDocumentoDP->update();
            }
            else 
            {
                if( $o_VTA_DocumentoBN->getEsTransferencia() )
                {
                    throw new Exception( "No se puede actualizar el Documento por ser Transferencia." );
                }
                //se agrega un procedimiento para actualizar el documento si por a o b se mueve el correlativo
                $o_VTA_DocumentoDP = new VTA_DocumentoDP();
                $o_VTA_DocumentoDP->setIdTipoDocumento( $o_VTA_DocumentoBN->getIdTipoDocumento() );
                $o_VTA_DocumentoDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
                $o_VTA_DocumentoDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
                $o_VTA_DocumentoDP->setIdAlmacen( $o_VTA_DocumentoBN->getIdAlmacen() );
                $o_VTA_DocumentoDP->setDocumentoNumero( $s_Numero );
                $o_VTA_DocumentoDP->setNumeroComprobante( $s_Serie."-".$s_Numero );
                $o_VTA_DocumentoDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
                $o_VTA_DocumentoDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
                $o_VTA_DocumentoDP->update();                

                $o_VTA_DocumentoBN->setDocumentoNumero( $s_Numero );
                $o_VTA_DocumentoBN->setNumeroComprobante( $s_Serie."-".$s_Numero );

                //se incrementa
                $o_GSS_SucursalDocumentoDP = new GSS_SucursalDocumentoDP();
                $o_GSS_SucursalDocumentoDP->setIdSucursalDocumento( $i_IdSucursalDocumento );
                $o_GSS_SucursalDocumentoDP->setNumeroActual( $i_NumeroActual );
                $o_GSS_SucursalDocumentoDP->update();
                //por proceso se realiza el cambio
                //throw new Exception( "El documento tiene la Serie y Numeracion distinta al correlativo actual." );
            }
        }

        return true;
    }
    
    public function generarTransaccion( VTA_DocumentoBN $o_VTA_DocumentoBN, $a_VTA_DocumentoDetalle = null, $b_CtrlGuia = false )
    {
        myUser::getUser()->validar_session();
        
        //validaciones
        if( !$o_VTA_DocumentoBN->getIdAlmacen() )
        {
            throw new Exception( "El Almacen de Despacho esta vacio." );
        }
        
        //TRANSACCION DE VENTA - PARAMETROS
        $IdCompania                 = $o_VTA_DocumentoBN->getIdCompania();
        $IdTipoDocumento            = $o_VTA_DocumentoBN->getIdTipoDocumentoTransaccion(); //VTA_DocumentoBN::TIPO_DOCUMENTO;
        $NumeroDocumento            = $o_VTA_DocumentoBN->getNumeroDocumento(); //
        
        $IdTransaccion              = $o_VTA_DocumentoBN->getIdTransaccion(); //VTA_DocumentoBN::TRANSACCION_X_DEFECTO;
        $IdAlmacen                  = $o_VTA_DocumentoBN->getAlmacenDespacho(); //$o_VTA_DocumentoTmpBN->getIdAlmacen(); //ALMACEN PARA LA TRANSACCION
        $AlmacenTraslado            = ""; //ALMACEN DE DESTINO
        
        $IdTransaccionOperacion     = $o_VTA_DocumentoBN->getIdTransaccionOperacion(); //VTA_DocumentoBN::TIPO_TRANSACCION_X_DEFECTO;
        //$FechaDocumento             = $o_VTA_DocumentoBN->getFechaDocumento();
        $FechaDocumento             = date( "Y-m-d H:i:s" ); //CUANDO SE TRATA DE REALIZAR TRANSACCIONES DE INVENTARIO, AHORA LA FECHA TIENE Q SER EL ACTUAL

        $ReferenciaTipoDocumento    = $o_VTA_DocumentoBN->getIdTipoDocumento();
        $ReferenciaNumeroDocumento  = $o_VTA_DocumentoBN->getNumeroDocumento(); //
        
        $GuiaProveedor              = "";
        $Comentario                 = "";
        
        if( $o_VTA_DocumentoBN->getNumeroGuia() )
        {
            $GuiaProveedor = $o_VTA_DocumentoBN->getNumeroGuia();
        }
        
        //$TipodeCambio               = GSS_TipoCambioFN::getStaticTipoCambioCobranza(); //aqui se tiene que hacer una pregunta
        $TipodeCambio               = $o_VTA_DocumentoBN->getTipodeCambio(); //aqui se tiene que hacer una pregunta, si va o no el tipo de cambio de documento de referencia
        $MonedaDocumento            = $o_VTA_DocumentoBN->getMonedaDocumento();
        
        $CodigoCliente              = $o_VTA_DocumentoBN->getClienteNumero(); //$o_VTA_DocumentoTmpBN->getClienteNumero();
        //$TipoDocumentoFiscal        = $o_VTA_DocumentoBN->getDocumentoCod(); //$o_VTA_DocumentoTmpBN->getIdTipoDocumento();   //se realiza el cambio :: 2021-01-13
        $SerieDocumentoFiscal       = is_null( $o_VTA_DocumentoBN->getSerieDocumentoFiscal() ) ? $o_VTA_DocumentoBN->getDocumentoSerie() : $o_VTA_DocumentoBN->getSerieDocumentoFiscal();
        $NumeroDocumentoFiscal      = is_null( $o_VTA_DocumentoBN->getNumeroDocumentoFiscal() ) ? $o_VTA_DocumentoBN->getDocumentoNumero() : $o_VTA_DocumentoBN->getNumeroDocumentoFiscal();
        $ConcatCodSerieNumero       = $o_VTA_DocumentoBN->getDocumentoTipoSerieNumero();
        $TipoDocumentoFiscal        = is_null( $o_VTA_DocumentoBN->getTipoDocumentoFiscal() ) ? $ReferenciaTipoDocumento : $o_VTA_DocumentoBN->getTipoDocumentoFiscal();
        //FIN PARAMETROS PARA LA TRANSACCION
        
        //SETEO CABACERA TRANSACCION
        $o_ALM_TransaccionCabeceraBN = new ALM_TransaccionCabeceraBN();
        $o_ALM_TransaccionCabeceraBN->setIdCompania( ( int ) $IdCompania );
        $o_ALM_TransaccionCabeceraBN->setIdTipoDocumento( $IdTipoDocumento );
        $o_ALM_TransaccionCabeceraBN->setIdTransaccion( $IdTransaccion );
        $o_ALM_TransaccionCabeceraBN->setAlmacenTraslado( $AlmacenTraslado );
        $o_ALM_TransaccionCabeceraBN->setIdAlmacen( $IdAlmacen );
        $o_ALM_TransaccionCabeceraBN->setIdTransaccionOperacion( $IdTransaccionOperacion );
        $o_ALM_TransaccionCabeceraBN->setFechaDocumento( $FechaDocumento );
        $o_ALM_TransaccionCabeceraBN->setMonedaCod( $MonedaDocumento );
        $o_ALM_TransaccionCabeceraBN->setTipodeCambio( floatval( $TipodeCambio ) );
        $o_ALM_TransaccionCabeceraBN->setReferenciaTipoDocumento( $ReferenciaTipoDocumento );
        $o_ALM_TransaccionCabeceraBN->setReferenciaNumeroDocumento( $ReferenciaNumeroDocumento );
        $o_ALM_TransaccionCabeceraBN->setIdProyecto( $o_VTA_DocumentoBN->getIdProyecto() );
        $o_ALM_TransaccionCabeceraBN->setGuiaProveedor( $GuiaProveedor );
        $o_ALM_TransaccionCabeceraBN->setComentario( $Comentario );
        $o_ALM_TransaccionCabeceraBN->setCodigoCliente( $CodigoCliente );
        
        $o_ALM_TransaccionCabeceraBN->setTipoDocumentoFiscal( $TipoDocumentoFiscal );
        $o_ALM_TransaccionCabeceraBN->setSerieDocumentoFiscal( $SerieDocumentoFiscal );
        $o_ALM_TransaccionCabeceraBN->setNumeroDocumentoFiscal( $NumeroDocumentoFiscal );
        $o_ALM_TransaccionCabeceraBN->setReferenciaNumeroInterno( $ConcatCodSerieNumero );
        //FIN SETEO CABECERA
        
        //una validacion para que no se duplique el comprobante
        
        
        //SE BUSCA LOS DETALLES, si no viene por parametro, por defecto es facturacion seguna las cantidades
        if( !$a_VTA_DocumentoDetalle )
        {
            $o_VTA_DocumentoDetalleFN = new VTA_DocumentoDetalleFN();
            $o_VTA_DocumentoDetalleFN->setIdTipoDocumento( $ReferenciaTipoDocumento );
            $o_VTA_DocumentoDetalleFN->setIdCompania( $IdCompania );
            $o_VTA_DocumentoDetalleFN->setNumeroDocumento( $NumeroDocumento );
            $a_VTA_DocumentoDetalle = $o_VTA_DocumentoDetalleFN->select();
            
            foreach ( $a_VTA_DocumentoDetalle as $i_Key => $o_VTA_DocumentoDetalleBN )
            {
                $a_VTA_DocumentoDetalle[$i_Key]->setCantidadaDescontar( $o_VTA_DocumentoDetalleBN->getCantidadPedida() );
            }
        }
        
        if( count( $a_VTA_DocumentoDetalle ) <= 0 )
        {
            throw new Exception( "No se encontro detalles para realizar la Facturación." );
        }
        $a_MovientoDetalle = array();
        foreach ( $a_VTA_DocumentoDetalle as $o_VTA_DocumentoDetalleBN )
        {
            if( $o_VTA_DocumentoDetalleBN->getTipoDetalle() == VTA_DocumentoDetalleBN::TIPO_DETALLE_COMENTARIO )
            {
                continue;
            }

            $IdAlmacen = $o_VTA_DocumentoDetalleBN->getAlmacenCodigo(); //ALMACEN ORIGEN
        
            //SETEO DETALLE
            $IdItem             = $o_VTA_DocumentoDetalleBN->getItemCodigo();
            $Cantidad           = $o_VTA_DocumentoDetalleBN->getCantidadPedida();
            $CantidadRec        = $o_VTA_DocumentoDetalleBN->getCantidadRecibida();
            $CantidadTrx        = $o_VTA_DocumentoDetalleBN->getCantidadaDescontar();
            $s_IdLote           = $o_VTA_DocumentoDetalleBN->getLote();
            $s_FechaVencimiento = $o_VTA_DocumentoDetalleBN->getFechaVencimiento();
            $s_LoteAlias        = $o_VTA_DocumentoDetalleBN->getLoteAlias();
            //$UnidadCodigo   = $o_VTA_DocumentoDetalleBN->getObjectUnidad()->getIdUnidad();
            $UnidadCodigo       = ( string ) $o_VTA_DocumentoDetalleBN->getIdUnidad();
            $IdSecuencia        = $o_VTA_DocumentoDetalleBN->getSecuencia();
            $PrecioUnitario     = $o_VTA_DocumentoDetalleBN->getPrecioUnitario();
            $MontoSubTotal      = $o_VTA_DocumentoDetalleBN->getMontoSubTotal();
        
            //validaciones adicionales
            if( $CantidadTrx <= 0 )
            {
                continue;
            }
            if( $CantidadTrx > $Cantidad )
            {
                throw new Exception( "La [$IdItem] cantida pedida no puede ser mayor al comprobante." );
            }
        
            $o_ALM_TransaccionDetalleBN = new ALM_TransaccionDetalleBN();
            $o_ALM_TransaccionDetalleBN->setIdItem( $IdItem );
            $o_ALM_TransaccionDetalleBN->setCantidad( $CantidadTrx );
            $o_ALM_TransaccionDetalleBN->setLote( $s_IdLote );
            $o_ALM_TransaccionDetalleBN->setFechaVencimiento( $s_FechaVencimiento );
            $o_ALM_TransaccionDetalleBN->setLoteProduccion( $s_LoteAlias );
            $o_ALM_TransaccionDetalleBN->setReferenciaCompaniaSocio( $ConcatCodSerieNumero );
            $o_ALM_TransaccionDetalleBN->setUnidadCodigo( $UnidadCodigo );
            $o_ALM_TransaccionDetalleBN->setIdSecuencia( $IdSecuencia );
            $o_ALM_TransaccionDetalleBN->setReferenciaTipoDocumento( $ReferenciaTipoDocumento );
            $o_ALM_TransaccionDetalleBN->setReferenciaNumeroDocumento( $ReferenciaNumeroDocumento );
            $o_ALM_TransaccionDetalleBN->setReferenciaSecuencia( $IdSecuencia );
            //$o_ALM_TransaccionDetalleBN->setPrecioUnitario( round( $PrecioUnitario, 2) );
            //$o_ALM_TransaccionDetalleBN->setMontoTotal( $MontoSubTotal );
            //FIN SETEO DETALLE

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //PROCEDIMIENTO PARA PROMOCIONES -> 2019-12-13
            //SE ESPECIFICA QUE POR LA CONDICION, SE ESPECIFICA QUE TIPO PROMOCION SE ESTA CONFIGURANDO, AHORA POR DEFECTO ES 1
            $o_ALM_ItemTipoFN = new ALM_ItemTipoFN();
            $o_ALM_ItemTipoBN = $o_ALM_ItemTipoFN->selectByPK( $o_VTA_DocumentoDetalleBN->getIdItemTipo() );
            //if ( substr( $o_VTA_DocumentoDetalleBN->getItemCodigo(), 0, 1 ) == "#" )  //promocion grupal
            if ( $o_ALM_ItemTipoBN->getIngenieriaFlag() )  //promocion grupal, Pack de Producto
            {
                $o_MKT_PromocionCabFN = new MKT_PromocionCabFN();
                $o_MKT_PromocionCabBN = $o_MKT_PromocionCabFN->selectByPK( $o_VTA_DocumentoDetalleBN->getRefParent() );
                if( $o_MKT_PromocionCabBN )
                {
                    //$o_ALM_TransaccionDetalleBN->setPrecioUnitario( $o_MKT_PromocionCabBN->getPrecioSinIGVPromo() );
                    //$o_ALM_TransaccionDetalleBN->setMontoTotal( $o_MKT_PromocionCabBN->getPrecioConIGVPromo() );
                }
            }
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            //ahora se actualiza la cantidad recibida
            $o_VTA_DocumentoDetalleDP = new VTA_DocumentoDetalleDP();
            $o_VTA_DocumentoDetalleDP->setIdTipoDocumento( $o_VTA_DocumentoDetalleBN->getIdTipoDocumento() );
            $o_VTA_DocumentoDetalleDP->setIdCompania( $o_VTA_DocumentoDetalleBN->getIdCompania() );
            $o_VTA_DocumentoDetalleDP->setNumeroDocumento( $o_VTA_DocumentoDetalleBN->getNumeroDocumento() );
            $o_VTA_DocumentoDetalleDP->setSecuencia( $o_VTA_DocumentoDetalleBN->getSecuencia() );
            $o_VTA_DocumentoDetalleDP->setCantidadRecibida( $CantidadRec );
            $o_VTA_DocumentoDetalleDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
            $o_VTA_DocumentoDetalleDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoDetalleDP->update();
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        
            $a_MovientoDetalle[] = $o_ALM_TransaccionDetalleBN;
        }
        $o_ALM_TransaccionCabeceraBN->setArrayMovientoDetalle( $a_MovientoDetalle );
        
        if( $b_CtrlGuia )
        {
            $o_VTA_DocumentoDP = new VTA_DocumentoDP();
            $o_VTA_DocumentoDP->setIdTipoDocumento( $ReferenciaTipoDocumento );
            $o_VTA_DocumentoDP->setIdCompania( $o_VTA_DocumentoBN->getIdCompania() );
            $o_VTA_DocumentoDP->setNumeroDocumento( $o_VTA_DocumentoBN->getNumeroDocumento() );
            $o_VTA_DocumentoDP->setImpresionPendienteFlag( "C" ); //SON 3 ESTADOS -> P(PENDIENTE) N(NO IMPRESO) C(IMPRESO)  ---- EN ESTADO P TE PREGUNTA SI SE IMPRIMIO BIEN
            $o_VTA_DocumentoDP->setFechaImpresion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoDP->setImpresionGuiaRemFlag( "C" ); //SON 3 ESTADOS -> P(PENDIENTE) N(NO IMPRESO) C(IMPRESO)  ---- EN ESTADO P TE PREGUNTA SI SE IMPRIMIO BIEN
            $o_VTA_DocumentoDP->setFechaImpresionGuiRem( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoDP->setFechaModificacion( date( "Y-m-d H:i:s" ) );
            $o_VTA_DocumentoDP->setUsuarioModificacion( myUser::getUser()->getUserId() );
            $o_VTA_DocumentoDP->update();
        }

        //SE REALIZA LA TRANSACCION
        $o_MovimientoBL = new MovimientoBL();
        $o_MovimientoBL->GuardarMovientoTransaccion( $o_ALM_TransaccionCabeceraBN );
        //FIN DE LA TRANSACCION
        return $o_ALM_TransaccionCabeceraBN;
    }
}