// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Reporte :           FUNCIONES DE USO COMUN EN LOS REPORTES DE                 LibCliProv.rpt
//                        CLIENTES Y PROVEEDORES ADMINPAQ
// Sistema:     ADMINPAQ  Versión v1.0 Windows
//
// Descripcion:En este archivo se guardan todas las funciones de uso común en los reportes
//             de   Clientes y ProveedoreAdminPAQ, son funciones de edición, de busqueda y de
//             cálculo que se incluyen en los reportes de AdminPAQ
//
// Creación  :  18/junio/2001
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Historia de modificaciones
//  Fecha      Nombre   IDLotus    Descripcion
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// 30/05/2002   EGV     N.D. 523   Se modificó la funcion: fSaldoInicial para
//                                 que cuando se calcule el saldo inicial del
//                                 Cliente/Proveedor, se excluyan sus Documentos
//                                 que estén cancelados. (EGV)
// 16/03/2005   HVA     N.D. 3023   Se modificó la funcion: fSaldoInicial para
//                                 que calcule los saldos en 2 monedas que haga conversiones adecuadas en los movimientos 
//                                 y que ademas considere las utilidades y perdidas cambiarias en el saldo cuando son movtos.
// 02/12/2005   LAP     N.D.3010   Nuevo esquema de búsquedas parciales para agilizar los reportes
//                                 - fSaldoInicial
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

Columnas 1; 1
// FUNCIONES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// ==========================================================================================
// fAcumulado : Regresa el importe acumulado, del periodo numPeriodo, para el ejercicio en 
//              donde este posicionado la tabla de acumulados.
//              El offset del primer campo de importes es  loffset = 8
//             Ejemplo: Si NumPeriodo = 2
//            lOffset + (Numperiodo-1) es igual a 9, corresponde al campo cImportePeriodo2.
// ==========================================================================================
Deffunc fAcumulado(aTblAcumulados:TABLA; aNumPeriodo)
 
  Local loffset,lregreso

  loffset = 8

  // si el periodo = 1 el saldo inicial se obtiene del importe inicial del ejercicio
  // Nota: EL acumulado se encuentra en la moneda del cliente
  Si aNumPeriodo <= 0
    lRegreso = aTblAcumulados(cImporteInicial)
  Sino
    // cuando es>1,el saldo inicial se obtiene del saldo final del periodo inmediato anterior
    lRegreso =  aTblAcumulados->CampoVal[loffset + (aNumPeriodo - 1)] 
  Finsi

  Retorna lRegreso
Finfunc


// ==========================================================================================
// fSaldoInicial
// Descripción:  A partir de una fecha de corte se obtiene el saldo de un cliente
//               Este saldo estára expresado de acuerdo a la moneda del reporte
// Entrada:      aId del Cliente o Proveedor, Ejercicio, Periodo, Moneda, Fecha de Corte, 
//               aTipo ( 0 = Cliente, 1 = Proveedor)
//
// Regresa:      Saldo del Cliente y/o Proveedor, ya expresado en la moneda del reporte (aIdMoneda)
//
// Indices:  aTblAcumulados  ( cAcumulado+cIdClienteProveedor+IdOwner2 + cIdEjercicio)
//           aTblDoctos      ( IdClienteProveedor+cAfecta+cFecha+cSerie+cFolio)
//           aTblTiposCambio ("iMonedaFecha, iMonedaFechaDesc" :internamente se cambian)
// Algoritmo
//    Incializa Varible del Saldo del Cliente/Proveedor en 0
//    Obten del archivo Acumulados el Saldo del Cliente/Proveedor del Periodo Anterior al solicitado
//    Incluye al Saldo obtenido todos los documentos desde el inicio del Periodo solicitado 
//    hasta un día antes de la Fecha requerida.
//    Reglas:
//       N.D. 523 Se excluyen los Documentos no afectados. (EGV) 31/05/2002
//       Si es un Saldo de Proveedor suma Aboxnos y Resta Cargos
//       Si es un Saldo de Cliente suma Cargos y Resta Abonos
//       Actualiza el Saldo de acuerdo a la Moneda requerida
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Historia de modificaciones
//  Fecha      Nombre   IDLotus    Descripcion
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// 02/12/2005  LAP    N.D.3010      Nuevo esquema de búsquedas parciales para agilizar los reportes
// ==========================================================================================
Deffunc fSaldoInicial(aTblClientes:TABLA; aIdEjercicio; aPeriodo; aIdMoneda; aFechaBase;aTipo;aTblAcumulados:TABLA;aTblDoctos:TABLA;aTblTiposCambio:Tabla)
LOCAL lFechaInicio, lFechaFin, lDia, lSaldo, lImporteTemporal
LOCAL lTipoCambio, lFechaDeCambio, lFechaBusqueda
  
  lSaldo = 0

  Si (aPeriodo < 1) O (aPeriodo > 12)
    Retorna lSaldo
  FinSi
  
  Si aTipo = 0
    // Cliente
  	aTblAcumulados.BUSCA['57' & ':25:' & aTblClientes(cIdClienteProveedor) & ':0:' & aIdEjercicio & ':' & aIdMoneda]	
  Sino
    // Proveedor
   	aTblAcumulados.BUSCA['139' & ':25:' & aTblClientes(cIdClienteProveedor) & ':0:' & aIdEjercicio & ':' &  aIdMoneda]	
  Finsi

  Si aTblAcumulados->ENCONTRO
    // Obtiene el saldo inicial del periodo, que es el acumulado del mes anterior o el inicial del ejer.
    lSaldo = fAcumulado(aTblAcumulados; aPeriodo-1)
    // La fecha de cambio = (Primer dia del periodo)-1 = fecha del ultimo dia del periodo anterior
    Si @VAL(@SUBSTR(aFechaBase;6;2)) > 1                                          
      lFechaInicio = (@SUBSTR(aFechaBase; 0; 6) & '01' )// se forma el primer dia del periodo
    Sino
      lFechaInicio = aFechaBase
    Finsi
    // Se convierte la moneda al tipo de cambio del dia ultimo del periodo del acumulado
    // lFechaDeCambio = fFechaAnterior(lFechaInicio)
    // lSaldo = fConvierteTipoCambio(lSaldo; aTblClientes(cIdMoneda); aIDMoneda; lFechaDeCambio; aTblTiposCambio)
  Finsi
      
  // Para obtener el Saldo se recorreran los documentos desde el inicio del mes hasta un dia antes de la fecha de corte
  // Si la fecha corte comienza en día primero, el saldo fue correctamente calculado con los acumulados por lo que no se requieren más cálculos
  Si @VAL(@SUBSTR(aFechaBase; 6; 2)) > 1
    // Fecha Inicio es el día Primero del Periodo
    lFechaInicio = @SUBSTR(aFechaBase;0;6) & '01'
    // Fecha Final es un día antes de la FechaIni
    lDia = @STR((@VAL(@SUBSTR(aFechaBase;6;2)) - 1);0)
    Si @LEN(lDia) = 1
   	  lDia = '0' & lDia
 		Finsi
    lFechaFin = @SUBSTR(aFechaBase;0;6) & lDia

    // N.D.3010 Inicio
    // Busca los documentos del cliente en el periodo seleccionado, únicamente se consideran aquellos documentos que estén Afectados
    lFechaBusqueda = lFechaInicio

    // NOTA: Es obligatorio volver a fijar el índice a fin de que las búsquedas parciales funcionen correctamente
    aTblDoctos.Usaindice['iClienteProveedorFecha']
    aTblDoctos.Busca[aTblClientes(cIdClienteProveedor) & ':' & lFechaBusqueda]
    Si !aTblDoctos->ENCONTRO
      // Busquedas parciales: Cursor en el registro más cercano que cumple con la llave
      // NOTA: La propiedad Llave de la tabla nos regresa la llave más cercana que cumple con el criterio de la búsqueda
      //       La llave está en formato cadena y no tiene ningún separador entre los campos, por lo que es necesario revisar
      //      en FoxPro la definición del índice para descomponer los elementos de la Llave
      // Revisar si la llave actual corresponde al Producto / Almacén y al Rango de Fechas.
      Si aTblClientes(cIdClienteProveedor) = @Val(@SUBSTR(aTblDoctos->Llave;0;11))
        Si @SUBSTR(aTblDoctos->Llave;11;8) >= lFechaInicio Y @SUBSTR(aTblDoctos->Llave;11;8) <= lFechaFin
          // Realizar nuevamente la búsqueda a fin de posicionarnos en el registro y activar la propiedad Encontro
          lFechaBusqueda = @SUBSTR(aTblDoctos->Llave;11;8)
          aTblDoctos.Busca[aTblClientes(cIdClienteProveedor) & ':' & lFechaBusqueda]
        FinSi
      FinSi        
    FinSi

    // La tabla de documentos ya está posicianada en el primer documento del cliente en el rango de fechas
    // Recorrer los documentos hasta que sea diferente cliente/proveedor o se rompa el rango de fechas
    Mientras aTblDoctos->Encontro Y (aTblDoctos(cFecha) <= lFechaFin)

      // N.D.4004 En caso de saldo de clientes, descartar los movimientos como proveedor y viceversa
      Si aTblDoctos(cUsaProveedor) = 1 Y aTblDoctos(cUsaCliente) = 1 // Si ambas banderas están prendidas es necesario descartar por documento modelo
         Si (aTipo = 0 Y aTblDoctos(cIdDocumentoDe) != 28 Y aTblDoctos(cIdDocumentoDe) != 29 ) O (aTipo = 1 Y aTblDoctos(cIdDocumentoDe) != 30 Y aTblDoctos(cIdDocumentoDe) != 31)
            aTblDoctos.BUSCA SIGUIENTE[1]
            Continua
         FinSi   
      SiNo
        Si (aTipo = 0 Y aTblDoctos(cUsaProveedor) = 1) O (aTipo = 1 Y aTblDoctos(cUsaCliente) = 1)
            aTblDoctos.BUSCA SIGUIENTE[1]
            Continua
        FinSi
      FinSi

      // Salta documentos como  Pedidos, Remisiones, Cotizaciones
      Si aTblDoctos(cNaturaleza) = 2 Y aTblDoctos(cIdDocumentoDe) != 28 Y aTblDoctos(cIdDocumentoDe) != 29 Y aTblDoctos(cIdDocumentoDe) != 30 Y aTblDoctos(cIdDocumentoDe) != 31
        // Búsqueda del siguiente registro que cumpla con el cliente
        aTblDoctos.BUSCA SIGUIENTE[1]
        Continua
      Finsi
      // las utilidades y perdidas solo se muestran en reportes en moneda local
      Si aIdMoneda != 1 Y (aTblDoctos(cIdDocumentoDe) = 28 O aTblDoctos(cIdDocumentoDe) = 29 O aTblDoctos(cIdDocumentoDe) = 30 O aTblDoctos(cIdDocumentoDe) = 31)
        // Búsqueda del siguiente registro que cumpla con el cliente
        aTblDoctos.BUSCA SIGUIENTE[1]
        Continua
      Finsi
      // Se salta los documentos no afectados en saldos.
      Si aTblDoctos(cAfectado) = 0
        // Búsqueda del siguiente registro que cumpla con el cliente
        aTblDoctos.BUSCA SIGUIENTE[1]
        Continua
      Finsi

      
      lImporteTemporal = aTblDoctos(cTotal)
      // Si el Documento está en una moneda distinta a la requerida conviertela en la Moneda Base
      // Si el reporte es requerido en una Moneda distinta a la Moneda Base
      Si aTblDoctos(cIdMoneda) != aIdMoneda
        Si aIdMoneda != 1
          Si aTblDoctos(cIdMoneda)  = 1 Y aTblDoctos(cTipoCambio) = 1 
            lTipoCambio      = fTipoCambio(aTblDoctos(cFecha);aIdMoneda;aTblTiposCambio)
            lImporteTemporal = aTblDoctos(cTotal) / lTipoCambio
          Sino 
            lImporteTemporal = aTblDoctos(cTotal) / aTblDoctos(cTipoCambio)
          FinSi
        Sino
          lImporteTemporal = aTblDoctos(cTotal) * aTblDoctos(cTipoCambio)
        FinSi
      FinSi          
      
      lNaturaleza = aTblDoctos(cNaturaleza)
      Si aTblDoctos(cIdDocumentoDe) = 28 O aTblDoctos(cIdDocumentoDe)= 30
        lNaturaleza = 0 // Cargos
      Finsi
      Si aTblDoctos(cIdDocumentoDe) = 29 O aTblDoctos(cIdDocumentoDe)= 31
        lNaturaleza = 1 // Abonos
      Finsi
      
      Si lNaturaleza = 0
        // Documento de Cargo
        Si aTipo = 0
          // Clientes
          lSaldo = @COL(lSaldo;0) + @COL(lImporteTemporal;0)
        Sino
          // Proveedores
          lSaldo = @COL(lSaldo;0) - @COL(lImporteTemporal;0)
        FinSi
      Sino
        // Documento de Abono
        Si aTipo = 0
          // Clientes
          lSaldo = @COL(lSaldo;0) - @COL(lImporteTemporal;0)
        Sino
          // Proveedores
          lSaldo = @COL(lSaldo;0) + @COL(lImporteTemporal;0)
        FinSi
      FinSi
      
      // Búsqueda del siguiente registro que cumpla con el cliente
      aTblDoctos.BUSCA SIGUIENTE[1]
    FinMientras
    // N.D.3010 Fin
  Finsi
  
  Retorna lSaldo      
FINFUNC



// ==========================================================================================
// Descripción:  Obtiene el Saldo de un Documento de acuerdo a las siguientes reglas:
//               1) Si se envia un rango de fechas únicamente se considerarán los documentos 
//                  creados en ese rango.
//               2) Si la fecha Inicial está en blanco únicamente se considerará la fecha final
//                  como una fecha de Corte.
//               Esta función regresa el saldo en la Moneda del Documento
// Entrada:  Registro del Documento, Fecha Inicial, Fecha Final,
//           aTblDoctoActivo = es el Docto del cual se obtendra el saldo
//           aTblDoctoLib = Es el handle de la tabla doctos para realizar las busquedas internas
//
// Regresa:  Saldo del Documento, Expresado en la moneda del documento.
//
// Indices:  aTblCargo (iDoctoCargoAbono, iDoctoAbonoCargo ) NOta: Internamente se cambian
//           aTblDoctos (Indiferente, se requiere la tabla solo para leer el docto activo)
//           aTblDoctosLib (cIdDocumento)
// COmentarios: Esta función es igual, tanto para clientes, como para proveedores.
// Algoritmo
// Incializa Varible del Saldo del Documento en 0
// SI el documento es un Cargo
//    Busca los Abonos asociados al Cargo mediante el archivo CargosAbonos_Cargos
//    Busca en documentos el abono y actualiza el Saldo del Documento
// SI el documento es un Abono
//    Busca los Cargos asociados al Abono mediante el archivo CargosAbonos_Abonos
//    Busca en documentos el cargo y actualiza el Saldo del Documento
// ========================================================================================== 

DEFFUNC FSaldoDocumento(aFechaInicial;aFechaFinal;aTblCargos:TABLA; aTblDoctoActivo:TABLA;aTblDoctos:TABLA)
  LOCAL lTotal

  lTotal = aTblDoctoActivo(cTotal)

  // Documentos de Cargo
  SI aTblDoctoActivo(cNaturaleza) = 0 
    aTblCargos.UsaIndice['iDoctoCargoAbono']
    aTblCargos.Busca Primero
  Sino
    aTblCargos.UsaIndice['' ]  // el indice por omisión es el de iDoctoAbono+IDDoctoCargo
    aTblCargos.Busca Primero    
  Finsi

  // Calcula el Saldo del Documento de Cargo, se busca en la tabla relaciones para recuperar 
  // los importes abonados a este documento, los cuales estan expresados en la misma moneda
  aTblCargos.BUSCA[@Str(aTblDoctoActivo(cIdDocumento);0)]
  Mientras aTblCargos->ENCONTRO  

    Si aTblDoctoActivo(cNaturaleza) = 0
      // busca el documento de abono asociado, para obtener la fecha del docto, no la del abono
      aTblDoctos.BUSCA[@Str(aTblCargos(cIdDocumentoAbono);0)]
    Sino
      // busca el documento de cargo asociado, para obtener la fecha del docto, no la del abono
      aTblDoctos.BUSCA[@Str(aTblCargos(cIdDocumentoCargo);0)]
    Finsi


    Si aTblDoctos->Encontro
    // valida la fecha que este dentro del rango, o que solo se busquen a una fecha de corte
      Si (aFechaInicial = '' O aTblDoctos(cFecha) >= aFechaInicial) Y (aTblDoctos(cFecha) <= aFechaFinal)
        Si aTblDoctoActivo(cNaturaleza) = 0
            lTotal = lTotal - aTblCargos(cImporteCargo)	// El importe Cargo esta en la misma moneda
        Sino
          lTotal = lTotal - aTblCargos(cImporteAbono)	// El importe Cargo esta en la misma moneda          
        Finsi
      Finsi                                         // del docto de cargo
    Finsi

    aTblCargos.BUSCA SIGUIENTE[1]
  FinMientras

  RETORNA lTotal
FINFUNC

DEFFUNC FOtroSaldoDocumento(aFechaInicial;aFechaFinal;aTblCargos:TABLA; aTblDoctoActivo:TABLA;aTblDoctos:TABLA)
  LOCAL lTotal

  lTotal = aTblDoctoActivo(cTotal)

  // Documentos de Cargo
  SI aTblDoctoActivo(cNaturaleza) = 0
    aTblCargos.UsaIndice['iDoctoCargoAbono']
    aTblCargos.Busca Primero
  Sino
    aTblCargos.UsaIndice['' ]  // el indice por omisión es el de iDoctoAbono+IDDoctoCargo
    aTblCargos.Busca Primero    
  Finsi

  // Calcula el Saldo del Documento de Cargo, se busca en la tabla relaciones para recuperar 
  // los importes abonados a este documento, los cuales estan expresados en la misma moneda
  aTblCargos.BUSCA[@Str(aTblDoctoActivo(cIdDocumento);0)]
  Mientras aTblCargos->ENCONTRO  

    Si aTblDoctoActivo(cNaturaleza) = 0
      // busca el documento de abono asociado, para obtener la fecha del docto, no la del abono
      aTblDoctos.BUSCA[@Str(aTblCargos(cIdDocumentoAbono);0)]
    Sino
      // busca el documento de cargo asociado, para obtener la fecha del docto, no la del abono
      aTblDoctos.BUSCA[@Str(aTblCargos(cIdDocumentoCargo);0)]
    Finsi

    Si aTblDoctos->Encontro
    // valida la fecha que este dentro del rango, o que solo se busquen a una fecha de corte
      Si (aFechaInicial = '' O aTblDoctos(cFecha) >= aFechaInicial) Y (aTblDoctos(cFecha) <= aFechaFinal)
        Si aTblDoctoActivo(cNaturaleza) = 0
          lTotal = lTotal - aTblCargos(cImporteCargo)	// El importe Cargo esta en la misma moneda
        Sino
          lTotal = lTotal - aTblCargos(cImporteAbono)	// El importe Cargo esta en la misma moneda          
        Finsi
      Finsi                                         // del docto de cargo
    Finsi

    aTblCargos.BUSCA SIGUIENTE[1]
  FinMientras

  RETORNA lTotal
FINFUNC

