// ******************************************************************************************************************************
// Sistema:     	ADMINPAQ 
// Version:     	v1.0 Windows 
// Reporte:     	Plantilla impresión de documentos
// Archivo:     	Pre-Plantilla-Documentos.Rpt
// Realizo:     	Leonardo Aguilar Pizano
// Fecha:       	Junio/2006
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Historia de modificaciones
//  Fecha      Nombre   IDLotus                     Descripcion
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// 04/03/2009    ND5673 ERROR NO IMPRIME EL RFC DEL CLIENTE AL EJECUTAR EL REPORTE COMPROBANTES FISCALES
//               DIGITALES PARA NOTAS DE CREDITO Y FORMATO EXCEL. (IYPZ)
// 13/05/2009    N.D.5761 ERROR NO SE IMPRIMIE A IMPRESORA LA FACTURA ELECTRONICA AL SELECCIONAR 
//               LA OPCION ENTREGAR. (ELVS)
// 12/01/2011    NC350 SUGERENCIA PARA CAMBIAR EN LAS PLANTILLAS DE FORMATO AMIGABLE LA LEYENDA DE: 
//               ESTE DOCUMENTO ES UNA IMPRESION DE UN COMPROBANTE FISCAL DIGITAL POR LA LEYENDA: 
//               ESTE DOCUMENTO ES UNA REPRESENTACION IMPRESA DE UN CFD. (ALRH)
// ******************************************************************************************************************************

// ==============================================================================================================================
    Incluye LibFormas.rpt
    gAnchoHoja = 21    // estas varibles las redefine el editor al generar el RPT 
    gNumeroCopias = 1  // podrian no ir aqui, pero sirven para probar la plantilla

constante kLeyendaCFD            'Este documento es una impresión de un comprobante fiscal digital.'
constante kLeyendaCopiaCFD       'Este documento es una copia de un comprobante fiscal digital.'
// N.C.350
constante kLeyendaRepcionCFD     'Este documento es una representación impresa de un CFD'

// ==============================================================================================================================
//  INICIO PARAMETROS   
    Parametro pDelaFecha      = '20050101'   // Por omisión debe ser el día actual
    Parametro pAlaFecha       = '20051231'   // Por omisión debe ser el día actual
    Parametro pSerie          = ' '          // puede ser en blanco, 
    Parametro pDelFolio       = 0
    Parametro pAlFolio        = 999999999
    Parametro pIdConcepto     = 0            // Id del Concepto del Documento	    
    Parametro pCuales         = 0            // 0 = Todos, 1 = Impresos 2 = No Impresos
    Parametro pFormato        = 0            // 0 - Pantalla
                                             // 1 - Excel
    Parametro pCadenaOriginal = ' '          // Cadena original
    Parametro pSelloDigital   = ' '          // Sello original
    Parametro pSerieSello     = ' '          // Serie del Sello Digital
    
// ==============================================================================================================================
//VARIABLES GLOBALES 
// Inserción de Variables Definidas *** desde la Forma *** //#$VariablesGlobales
    gDetalleDinamico = 0
    gColumnasHoja = 110
    gAnchoHoja = 23
    gNumeroCopias = 1
   
    // F A C T U R A		
    pTipoDeDocumento = 4   //#$SubTipoReporte
    gRenglonesHoja = 51
    
    gRenglonesEncabezado = 19
    gRenglonesDetalle    = 20
    gRenglonesPiePagina  = 12
    
    gRenglonesSubdetalle     = 3
    gPrimerRenglonEncabezado = 1
    gPrimerRenglonPiePagina  = 45

    gNumImpuestoIVA = 0
    gIvaTasa10 = 0
    gIvaTasa15 = 0
    gIvaOtrasTasas = 0
  
    // D E V O L U C I O N   S O B R E   V E N T A
    //pTipoDeDocumento = 5   //#$SubTipoReporte
    //gRenglonesHoja = 51

    //gRenglonesEncabezado = 19
    //gRenglonesDetalle    = 20
    //gRenglonesPiePagina  = 12
    
    //gRenglonesSubdetalle     = 3
    //gPrimerRenglonEncabezado = 1
    //gPrimerRenglonPiePagina  = 45

    // N O T A   D E   C A R G O
    //pTipoDeDocumento = 13   //#$SubTipoReporte
    //gRenglonesHoja = 29

    //gRenglonesEncabezado = 17
    //gRenglonesDetalle    = 0
    //gRenglonesPiePagina  = 12
    
    //gRenglonesSubdetalle     = 0
    //gPrimerRenglonEncabezado = 1
    //gPrimerRenglonPiePagina  = 18

    // N O T A   D E   C R E D I T O
    //pTipoDeDocumento = 7   //#$SubTipoReporte
    //gRenglonesHoja = 29

    //gRenglonesEncabezado = 17
    //gRenglonesDetalle    = 0
    //gRenglonesPiePagina  = 12
    
    //gRenglonesSubdetalle     = 0
    //gPrimerRenglonEncabezado = 1
    //gPrimerRenglonPiePagina  = 18

// Fin de la Inserción de variables *** definidas desde la forma ***

// ==============================================================================================================================
//  INICIO TABLAS
   // Archivos a utilizar:
  UsaEmpresa tEmpresa;'AdminpaqW'
   
  // Parametros de la empresa
  UsaTabla tParametros = tEmpresa['mgw10000']

  // Documentos
  UsaTabla tDocumentos = tEmpresa['mgw10008'] Alias 'Doctos1'
  tDocumentos.Usaindice['iDocumentoDeFechaSerieFol']// cIDDocumentoDe + cFecha + cSerieDocumento + cFolio 
                    // ['iDoctoDeSerieFolio']       // cIDDocumentoDe +cSerieDocumento+cFolio
                    
  // Movimientos
  UsaTabla tMovimientos = tEmpresa['mgw10010'] Alias 'Movtos1'
  tMovimientos.Usaindice['iDoctoNumeroMovto']       // cIdDocumento + cNumeroMovimiento

  UsaTabla tMovtosFolios = tEmpresa['mgw10010'] Alias 'Movtos4'
  tMovtosFolios.Usaindice['iDoctoNumeroMovto']      // cIdDocumento + cNumeroMovimiento

  UsaTabla tDetalleProductos = tEmpresa['mgw10004']
  tDetalleProductos.Usaindice['']

  // Clientes y Provedores
  UsaTabla tClientes = tEmpresa['mgw10002']
  tClientes.Usaindice['']

  // Productos 
  UsaTabla tProductos = tEmpresa['mgw10005']
  tProductos.Usaindice['']

  UsaTabla tDirClientes = tEmpresa['mgw10011'] Alias 'Dir1'
  tDirClientes.Usaindice['iCatTipoCatTipoDir']

  UsaTabla tDirEmpresa = tEmpresa['mgw10011'] Alias 'Dir2'
  tDirEmpresa.Usaindice['iCatTipoCatTipoDir']

  UsaTabla tDirDocumentosFis = tEmpresa['mgw10011'] Alias 'Dir4'
  tDirDocumentosFis.Usaindice['iCatTipoCatTipoDir']

  UsaTabla tDirSucursal = tEmpresa['mgw10011'] Alias 'Dir5'
  tDirSucursal.Usaindice['']

  UsaTabla tMonedas = tEmpresa['mgw10034']
  tMonedas.UsaIndice['']
   
  UsaTabla tMovtosSeries = tEmpresa['mgw10036']
  tMovtosSeries.Usaindice['']

  UsaTabla tNumerosSeries = tEmpresa['mgw10032']
  tNumerosSeries.UsaIndice['']  

  UsaTabla tMovtosCapas = tEmpresa['mgw10028']
  tMovtosCapas.UsaIndice['']

  UsaTabla tCapas = tEmpresa['mgw10025']
  tCapas.UsaIndice['']  

  UsaTabla tUnidades = tEmpresa['mgw10026']  // en los siguientes se usa el indice primario
  tUnidades.UsaIndice['']

  UsaTabla tConceptos = tEmpresa['mgw10006'] // para leer nombre y cod. de ConcepDocumentos
  tConceptos.UsaIndice['']

  UsaTabla tFoliosDigitales = tEmpresa['MGW10045']  // Folios Digitales
  tFoliosDigitales.Usaindice['cIdDocto']            // cIdDocto


// ==============================================================================================================================
  Columnas 1;gAnchoHoja
  Usaletra 'Courier New'
  Altura 8

// ==============================================================================================================================
// ********Variables de la Plantilla *******
// Esta variables globales siempre deben estar presentes, En cualquier plantilla. 
// pero se pueden cambiar de acuerdo a las necesidades especificas del reporte. 
  gNombreMonedaSing = 'Peso'
  gNombreMonedaPlu  = 'Pesos'
  gDescrProtegida   = 'M.N'
  
  // N.D.4580 Tasa del Impuesto de los movimientos
  gNumeroMovimientos = 0
  gTasaImpuesto1 = 0
  gTasaImpuesto2 = 0
  gTasaImpuesto3 = 0

// ==============================================================================================================================
// Variables globales, propias de esta plantilla reporte
  gImprimirSeries = 0   // controlan la impresion de Series y Caracteristicas, para los 

  gNumRenSeries = 0
  gPosSeries  = 0
  gLongSeries = 0

  gEntroDetPaq = 0
  gRegActSer = 0
  gRegActCap = 0

// ******************************************************************************************************************************
// ********************************  FUNCIONES PARA IMPRESION  ******************************************************************
// ******************************************************************************************************************************
// ==============================================================================================================================
// fImprimeEncabezado (Procedimiento)
// Descripcion : Esta funcion sustituye el uso de la instruccion ENCAB-FINENCAB, esto se debe a que en formas preimpresas se 
//               necesita imprimir en el encabezado algunos datos que varian y requieren ser recalculados en cada iteración del 
//               ciclo principal del reporte
// ==============================================================================================================================
Deffunc fImprimeEncabezado()
Local lRenglon, lNumRenglon
Local lRenglonSiguiente

  Usaletra 'Courier New'
  Altura 8
  
  lRenglon = ''  
  lRenglonSiguiente = gPrimerRenglonEncabezado
  // Inicio del area de insercion de datos  //#$Encabezado  
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Fecha Emisión:';68;14;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;fFormateaFecha(tFoliosDigitales(cFechaEmi); 9) & ' ' & tFoliosDigitales(cHoraEmi);83;28;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Aprobación Año: ' & @SubStr(tFoliosDigitales(cFecAprob);0;4) & ' No: ';68;25;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tFoliosDigitales(cNoAprob);93;12;1;0;'N';0;'D')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Serie:';68;6;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tFoliosDigitales(cSerie);75;10;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Folio:';86;6;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cFolio);93;12;1;0;'N';0;'D')
      lNumRenglon = lRenglonSiguiente 
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Emisor:';0.5;10;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreEmpresa);11;60;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente 
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'RFC:';0.5;10;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cRfcEmpresa);11;15;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      // N.D.4580 Ajustes de acuerdo al SAT: Reestructuración del domicilio
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Domicilio Fiscal:';0.5;30;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Lugar de Expedición:';60;30;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirEmpresa(cNombreCalle) & ' #' & tDirEmpresa(cNumeroExterior) & ' ' & tDirEmpresa(cNumeroInterior);5;50;1;0;'A';0;'I')
      // N.D.4580 Ajustes de acuerdo al SAT: Lugar de Expedición      
      Si tConceptos(cIdDirSucu) > 0
        tDirSucursal.Busca[@Str(tConceptos(cIdDirSucu);0)]
        Si tDirSucursal->Encontro
          lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirSucursal(cNombreCalle) & ' #' & tDirSucursal(cNumeroExterior) & ' ' & tDirSucursal(cNumeroInterior);60;50;1;0;'A';0;'I')
        FinSi
      FinSi
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirEmpresa(cColonia) & ', ' & tDirEmpresa(cCiudad) & ', ' & tDirEmpresa(cMunicipio);5;60;1;0;'A';0;'I')
      // N.D.4580 Ajustes de acuerdo al SAT: Lugar de Expedición      
      Si tConceptos(cIdDirSucu) > 0 Y tDirSucursal->Encontro
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirSucursal(cColonia) & ', ' & tDirSucursal(cCiudad) & ', ' & tDirSucursal(cMunicipio);60;60;1;0;'A';0;'I')
      FinSi
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
            
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirEmpresa(cEstado) & ', ' & tDirEmpresa(cPais) & ' ' & tDirEmpresa(cCodigoPostal);5;20;1;0;'A';0;'I')
      // N.D.4580 Ajustes de acuerdo al SAT: Lugar de Expedición      
      Si tConceptos(cIdDirSucu) > 0 Y tDirSucursal->Encontro
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirSucursal(cEstado) & ', ' & tDirSucursal(cPais) & ' ' & tDirSucursal(cCodigoPostal);60;20;1;0;'A';0;'I')
      FinSi
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglonSiguiente = lRenglonSiguiente + 1
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Cliente:';0.5;10;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;fMascarilla(tClientes(cCodigoCliente);tParametros(cMascarillaClientes));14;14;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Razón Social:';0.5;13;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cRazonSocial);14;54;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'RFC:';0.5;5;1;0;'A';0;'I')
      //ND5673 Si el RFC del documento es vacio, se utiliza el RFC del cliente
      lRenglon = fAgregaCampoAlRenglon(lRenglon;(tDocumentos(cRFC)!=''?tDocumentos(cRFC):tClientes(cRFC));14;14;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      // N.D.4580 Ajustes de acuerdo al SAT: Reestructuración del Domicilio
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Domicilio:';0.5;15;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirDocumentosFis(cNombreCalle) & ' #' & tDirDocumentosFis(cNumeroExterior) & ' ' & tDirDocumentosFis(cNumeroInterior);14;54;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirDocumentosFis(cColonia) & ', ' & tDirDocumentosFis(cCiudad) & ', ' & tDirDocumentosFis(cMunicipio);14;55;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDirDocumentosFis(cEstado) & ', ' & tDirDocumentosFis(cPais) & ' ' & tDirDocumentosFis(cCodigoPostal);14;55;1;0;'A';0;'I')
      lNumRenglon = lRenglonSiguiente 
      lRenglonSiguiente = lRenglonSiguiente + 1
      fImprimeRenglon(&lNumRenglon;&lRenglon;'E')

      Si gRenglonesDetalle > 0       
        lRenglonSiguiente = lRenglonSiguiente + 1
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Cantidad';0.5;10;1;0;'A';0;'I')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Descripción';13;35;1;0;'A';0;'I')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Valor Unitario';70;15;1;0;'A';0;'I')
        // N.D.4580 Ajustes de acuerdo al SAT: Leyenda Importe Total
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Importe Total';95;19;1;0;'A';0;'I')
        lNumRenglon = lRenglonSiguiente 
        lRenglonSiguiente = lRenglonSiguiente + 1
        fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'___________________________________________________________________________________________________________________________________';0.5;110;1;0;'A';0;'I')
        lNumRenglon = lRenglonSiguiente
        lRenglonSiguiente = lRenglonSiguiente + 1
        fImprimeRenglon(&lNumRenglon;&lRenglon;'E')
      FinSi
      
      // Actualizacion de los renglones del Encabezado
      gRenglonesEncabezado = lRenglonSiguiente - 1
      //Texto de DEBUG a fin de identificar si el Encabezado realmente esta bien definido, recordar que al inicio
      // del reporte se definio la constante del inventario
      //texto gRenglonesEncabezado
      //imprime      
  // fin del area de inserción de datos
  // N.D.4580 Tasa del Impuesto de los movimientos
  gNumeroMovimientos = 0
  gTasaImpuesto1 = 0
  gTasaImpuesto2 = 0
  gTasaImpuesto3 = 0
Finfunc

// ==============================================================================================================================
// fImprimePiePagina (Procedimiento)
// Descripcion : Imprime el subdetalle asociado a el movimiento activo
// ==============================================================================================================================
Deffunc fImprimePiePagina()
Local lRenglon, lNumRenglon
Local lLeyendaCFD
Local lTamano 
Local lPosicion

  Usaletra 'Courier New'
  Altura 8

  lNumRenglon = gPrimerRenglonPiePagina
  lRenglon = ''
  // Inicio de la inserción de campos que se imprimen en el Pie de pagina //#$PiePagina
    lRenglon = fAgregaCampoAlRenglon(lRenglon;'___________________________________________________________________________________________________________________________________';0.5;110;1;0;'A';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1

    // N.D.4869 se modificaron las llamadas de la funcion para hacer mas espacio en las cantidades

    lRenglon = fAgregaCampoAlRenglon(lRenglon;gCantidadProtegida;1;95;88;-1;'A';2;'I')
    lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cNeto);90;19;1;2;'N';2;'D')
    lRenglon = fAgregaCampoAlRenglon(lRenglon;'Subtotal:';77;12;1;0;'A';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1


    lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cDescuentoMov);90;19;1;2;'N';2;'D')
    lRenglon = fAgregaCampoAlRenglon(lRenglon;'Descuentos:';77;12;1;0;'A';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1

// N.D.4357 Inicio   
    Si pCadenaOriginal = ' ' y pSelloDigital = ' '
      lLeyendaCFD = kLeyendaCopiaCFD
    Sino
      // N.C.350
      Si (tFoliosDigitales(cFechaEmi) < '20110101')
        lLeyendaCFD = kLeyendaCFD
      Sino
        lLeyendaCFD = kLeyendaRepcionCFD
      FinSi
    FinSi

    Si gNumImpuestoIVA = 1
      Si gIvaTasa10
        lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa10;90;19;1;2;'N';2;'D')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto1)& ' ' & 10 & '%:';77;12;1;0;'A';0;'I')
        fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        lNumRenglon = lNumRenglon + 1
      Finsi
      
      Si gIvaTasa15
        lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa15;90;19;1;2;'N';2;'D')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto1)& ' ' & 15 & '%:';77;12;1;0;'A';0;'I')
        fImprimeRenglon(&lNumRenglon;&lRenglon;'P')      
        lNumRenglon = lNumRenglon + 1
      Finsi
      
      Si gIvaOtrasTasas
        lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaOtrasTasas;90;19;1;2;'N';2;'D')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto1)& ' (Otras tasas)%:';77;22;1;0;'A';0;'I')
        fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        lNumRenglon = lNumRenglon + 1
      Finsi
      
      Si !(gIvaTasa10 + gIvaTasa15 + gIvaOtrasTasas)
        lRenglon = fAgregaCampoAlRenglon(lRenglon;0.00;90;19;1;2;'N';2;'D')
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto1)& ' :';77;12;1;0;'A';0;'I')
        fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        lNumRenglon = lNumRenglon + 1
      Finsi
    sino
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cImpuesto1);90;19;1;2;'N';2;'D')
      //Tasa del Impuesto de los movimientos
      gTasaImpuesto1 = gTasaImpuesto1 / gNumeroMovimientos
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto1)& ' ' & gTasaImpuesto1 & '%:';77;12;1;0;'A';0;'I')
      //La leyenda de CFD se imprime en el último impuesto impreso
      fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
      lNumRenglon = lNumRenglon + 1
    Finsi

    //Solo imprimir los Impuestos 2 y 3 en caso de que existan
    Si tDocumentos(cImpuesto2) > 0.0000001
      Si gNumImpuestoIVA = 2
        Si gIvaTasa10
        	lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa10;90;19;1;2;'N';2;'D')
        	lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto2)&' ' & 10 & '%:';77;12;1;0;'A';0;'I')
        	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')    	
      	  lNumRenglon = lNumRenglon + 1
      	Finsi      	
      	
        Si gIvaTasa15
        	lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa15;90;19;1;2;'N';2;'D')
        	lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto2)&' ' & 15 & '%:';77;12;1;0;'A';0;'I')
        	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')    	
      	  lNumRenglon = lNumRenglon + 1
      	Finsi      	
      	
        Si gIvaOtrasTasas
        	lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaOtrasTasas;90;19;1;2;'N';2;'D')
          lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto2)&' (Otras tasas)%:';77;22;1;0;'A';0;'I')
      	  fImprimeRenglon(&lNumRenglon;&lRenglon;'P')    	
      	  lNumRenglon = lNumRenglon + 1
      	Finsi
      	
        Si !(gIvaTasa10 + gIvaTasa15 + gIvaOtrasTasas)
          lRenglon = fAgregaCampoAlRenglon(lRenglon;0.00;90;19;1;2;'N';2;'D')
          lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto2)& ' :';77;12;1;0;'A';0;'I')
          fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
          lNumRenglon = lNumRenglon + 1
        Finsi
      sino
      	lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cImpuesto2);90;19;1;2;'N';2;'D')
        //Tasa del Impuesto de los movimientos
        gTasaImpuesto2 = gTasaImpuesto2 / gNumeroMovimientos
      	lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto2)&' ' & gTasaImpuesto2 & '%:';77;12;1;0;'A';0;'I')
        //La leyenda de CFD se imprime en el último impuesto impreso
      	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')    	
      	lNumRenglon = lNumRenglon + 1
      Finsi
    FinSi

    Si tDocumentos(cImpuesto3) > 0.0000001
      Si gNumImpuestoIVA = 3
        Si gIvaTasa10
          lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa10;90;19;1;2;'N';2;'D')
	        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto3)&' ' & 10 & '%:';77;12;1;0;'A';0;'I')
        	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        	lNumRenglon = lNumRenglon + 1
      	Finsi
      	      	
        Si gIvaTasa15      	
          lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaTasa15;90;19;1;2;'N';2;'D')
	        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto3)&' ' & 15 & '%:';77;12;1;0;'A';0;'I')
        	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        	lNumRenglon = lNumRenglon + 1
      	Finsi      	
      	
        Si gIvaOtrasTasas      	
          lRenglon = fAgregaCampoAlRenglon(lRenglon;gIvaOtrasTasas;90;19;1;2;'N';2;'D')
	        lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto3)&' (Otras tasas)%:';77;22;1;0;'A';0;'I')
        	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
        	lNumRenglon = lNumRenglon + 1
      	Finsi
      	
        Si !(gIvaTasa10 + gIvaTasa15 + gIvaOtrasTasas)
          lRenglon = fAgregaCampoAlRenglon(lRenglon;0.00;90;19;1;2;'N';2;'D')
          lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto3)& ' :';77;12;1;0;'A';0;'I')
          fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
          lNumRenglon = lNumRenglon + 1
        Finsi
      sino
        lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cImpuesto3);90;19;1;2;'N';2;'D')
        //Tasa del Impuesto de los movimientos
        gTasaImpuesto3 = gTasaImpuesto3 / gNumeroMovimientos
	      lRenglon = fAgregaCampoAlRenglon(lRenglon;tParametros(cNombreImpuesto3)&' ' & gTasaImpuesto3 & '%:';77;12;1;0;'A';0;'I')
      	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
      	lNumRenglon = lNumRenglon + 1
      Finsi 
    FinSi

    lRenglon = fAgregaCampoAlRenglon(lRenglon;tDocumentos(cTotal);90;19;1;2;'N';2;'D')
    lRenglon = fAgregaCampoAlRenglon(lRenglon;'Total:';77;12;1;0;'A';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1
    
    gCantidadProtegida = fCantidadProtegida(tDocumentos(cTotal);0)
    lRenglon = fAgregaCampoAlRenglon(lRenglon;gCantidadProtegida;1;100;1;-1;'A';2;'I')
    //Ajustes de acuerdo al SAT: Leyenda Sub-Total
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1

    lRenglon = fAgregaCampoAlRenglon(lRenglon;lLeyendaCFD;1;70;1;0;'A';0;'I')
   	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
   	lNumRenglon = lNumRenglon + 1 

    Si pSerieSello != ' '
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Serie del Certificado del Sello Digital:';0.5;41;1;0;'A';0;'I')
      lRenglon = fAgregaCampoAlRenglon(lRenglon;pSerieSello;43;80;1;0;'A';0;'I')
      fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
      lNumRenglon = lNumRenglon + 1
    FinSi   
       
    Si tDocumentos(cImpuesto2) > 0.0000001
      Si tDocumentos(cImpuesto3) <= 0.0000001
       lRenglon = fAgregaCampoAlRenglon(lRenglon;lLeyendaCFD;1;65;1;0;'A';0;'I')
      FinSi
    	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')    	
    	lNumRenglon = lNumRenglon + 1
    FinSi

    Si tDocumentos(cImpuesto3) > 0.0000001
	    lRenglon = fAgregaCampoAlRenglon(lRenglon;lLeyendaCFD;1;70;1;0;'A';0;'I')
    	fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    	lNumRenglon = lNumRenglon + 1
    FinSi
     
  Usaletra 'Courier New'
  Altura 7
    Si pCadenaOriginal = ' '
      lRenglon = fAgregaCampoAlRenglon(lRenglon;' ';0.5;16;1;0;'A';0;'I')
    Sino
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Cadena Original:';0.5;17;1;0;'A';0;'I')
    FinSi
    lRenglon = fAgregaCampoAlRenglon(lRenglon;pCadenaOriginal;17;92;1;0;'M';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1
    lTamano = @Len(pCadenaOriginal)
    lPosicion = 93
    Mientras lPosicion < lTamano
      lRenglon = fAgregaCampoAlRenglon(lRenglon;pCadenaOriginal;16;93;lPosicion;0;'M';0;'I')
      fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
      lNumRenglon = lNumRenglon + 1
      lPosicion = lPosicion + 93
    FinMientras

    Si pSelloDigital = ' '
      lRenglon = fAgregaCampoAlRenglon(lRenglon;' ';0.5;16;1;0;'A';0;'I')
    Sino
      lRenglon = fAgregaCampoAlRenglon(lRenglon;'Sello Digital:';0.5;16;1;0;'A';0;'I')
    FinSi
    lRenglon = fAgregaCampoAlRenglon(lRenglon;pSelloDigital;16;92;1;0;'M';0;'I')
    fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
    lNumRenglon = lNumRenglon + 1
    lTamano = @Len(pSelloDigital)
    lPosicion = 93
    Mientras lPosicion < lTamano
      lRenglon = fAgregaCampoAlRenglon(lRenglon;pSelloDigital;16;93;lPosicion;0;'M';0;'I')
      fImprimeRenglon(&lNumRenglon;&lRenglon;'P')
      lNumRenglon = lNumRenglon + 1
      lPosicion = lPosicion + 93
    FinMientras
// N.D.4357 Fin

    // Actualizacion de los renglones del Encabezado
    gRenglonesPiePagina = lNumRenglon - 1 - gPrimerRenglonPiePagina
    //Texto de DEBUG a fin de identificar si el Encabezado realmente esta bien definido, recordar que al inicio
    // del reporte se definio la constante del inventario
    //texto gRenglonesPiePagina
    //imprime      
FinFunc

// ==============================================================================================================================
// fCambiaPagina()
// Esta función es llamada desde el detalle y desde el subdetalle, siempre se debe invocar antes de imprimir una renglón del 
// detalle o del subdetalle, esta función es parte de la estructura de la plantilla, debe estár presente en todas las plantillas.
// ==============================================================================================================================
Deffunc fCambiaPagina()
  
  // Revisa el primer caso, cuando se va a imprimir el primer detalle de cada hoja
  Si gRenglonAImprimir = 1 Y gRenglonesEncabezado > 0
    fImprimeEncabezado()
  Finsi

  // Se revisa si el detalle ya alcanzó el cambio de página
  // Si todavia no alcanza su turno, para cambiar de hoja, se regresa sin imprimir nada
  Si gRenglonAImprimir <= (gRenglonesEncabezado + gRenglonesDetalle) 
    Retorna 0
  Finsi

  // Dado que si lo alcanzó, imprime el pie de pagina, cambia de página e imprime el encabezado
  Si gRenglonesPiePagina > 0
    FinForma = 0
    fImprimePiePagina()
  Finsi

  fAlcanzaFinalHoja(gRenglonesHoja)

  Si gRenglonesEncabezado > 0
    // Inicializa las variables para iniciar la impresión de una nueva hoja
    gNumeroDeHoja = gNumeroDeHoja + 1
    gRenglonAImprimir = 1 
    SI gImpresionGrafica = 1
       SALTAHOJ
    FINSI
    fImprimeEncabezado()
  Finsi

  Retorna 1
FinFunc

// ==============================================================================================================================
// fImprimeDetalle (Procedimiento)
// Descripcion : Imprime un renglón del detalle, en este caso son los datos del producto
// ==============================================================================================================================
Deffunc fImprimeDetalle(tMovimientos:Tabla;tProductos:TABLA)
Local lrenglon, lNumRenglon, lRegresa
  
  Usaletra 'Courier New'
  Altura 8
  lRenglon = ''  

  // Inicio de la inserción de los datos que se imprimirán //#$Detalle1

  //N.D.4559  Francisco Noriega. Se cambió el parametro de decimales de 0 al actual para que imprima cantidades con decimales.
  lRenglon = fAgregaCampoAlRenglon(lRenglon;tMovimientos(cUnidadesCapturadas);0.5;8;1;0;'N';tParametros(cDecimalesUnidades);'D')
  // N.D.4580 Ajustes de acuerdo al SAT: Impresión de la unidad
  Si tMovimientos(cIdUnidad)
    tUnidades.Busca[@Str(tMovimientos(cIdUnidad);0)]
    Si tUnidades->Encontro
      lRenglon = fAgregaCampoAlRenglon(lRenglon;tUnidades(cDespliegue);9;3;1;0;'A';0;'I')
    FinSi
  FinSi  
  lRenglon = fAgregaCampoAlRenglon(lRenglon;tProductos(cNombreProducto);13;47;1;0;'A';0;'I')
  lRenglon = fAgregaCampoAlRenglon(lRenglon;tMovimientos(cPrecioCapturado);70;15;1;2;'N';2;'D')
  // N.D.4580 Ajustes de acuerdo al SAT: Impresión del importe Neto
  lRenglon = fAgregaCampoAlRenglon(lRenglon;tMovimientos(cNeto);90;19;1;2;'N';2;'D')
  lNumRenglon = 20
  fCambiaPagina()
  fImprimeRenglon(&lNumRenglon;&lRenglon;'D')
  // Fin de los datos que se insertaron
   
   
  // N.D.4580 Tasa del Impuesto de los movimientos
  gNumeroMovimientos = gNumeroMovimientos + 1

  Si gNumImpuestoIVA = 1
    Si tMovimientos(cPorcentajeImpuesto1) = 10
      gIvaTasa10 = gIvaTasa10 + tMovimientos(cImpuesto1)
    Sino
      Si tMovimientos(cPorcentajeImpuesto1) = 15
        gIvaTasa15 = gIvaTasa15 + tMovimientos(cImpuesto1)
      Sino
        gIvaOtrasTasas = gIvaOtrasTasas + tMovimientos(cImpuesto1)
      Finsi
    finsi
  Sino
    Si gNumImpuestoIVA = 2
      Si tMovimientos(cPorcentajeImpuesto2) = 10
        gIvaTasa10 = gIvaTasa10 + tMovimientos(cImpuesto2)
      Sino
        Si tMovimientos(cPorcentajeImpuesto2) = 15
         gIvaTasa15 = gIvaTasa15 + tMovimientos(cImpuesto2)
        Sino
          gIvaOtrasTasas = gIvaOtrasTasas + tMovimientos(cImpuesto2)
        Finsi
      finsi
    Sino
      Si tMovimientos(cPorcentajeImpuesto3) = 10
        gIvaTasa10 = gIvaTasa10 + tMovimientos(cImpuesto3)
      Sino
        Si tMovimientos(cPorcentajeImpuesto3) = 15
         gIvaTasa15 = gIvaTasa15 + tMovimientos(cImpuesto3)
        Sino
          gIvaOtrasTasas = gIvaOtrasTasas + tMovimientos(cImpuesto3)
        Finsi
      finsi
    Finsi
  Finsi

 
  gTasaImpuesto1 = gTasaImpuesto1 + tMovimientos(cPorcentajeImpuesto1)
  gTasaImpuesto2 = gTasaImpuesto2 + tMovimientos(cPorcentajeImpuesto2)
  gTasaImpuesto3 = gTasaImpuesto3 + tMovimientos(cPorcentajeImpuesto3)
FinFunc

// ==============================================================================================================================
// fAgregaSubDetalle (Procedimiento)
// Descripcion : Agrega al renglón la información de campos definidos en el subdetalle
// Entrada: tMovimientos:  es el movimiento del cual se imprimirá el subdetalle
// Salida : Regresa el renglón con la información de campos agregados
// ==============================================================================================================================
Deffunc fAgregaSubDetalle(tMovimientos:TABLA;tProductos:TABLA;aMiRenglon;aRenSub;aRegTab)
Local lRenglon, lTipoSubDetalle

  Si aRegTab = 0
    Retorna aMiRenglon
  FinSi

  lTipoSubDetalle = tProductos(cControlExistencia)
  // Se revisa si tiene Series, Series-Pedimentos, Series-Lotes,Series-Pedimentos-Lotes
  //                    00100 , 01100,             10100,       11100   
  //Si lTipoSubDetalle = 4 O lTipoSubDetalle = 12 O lTipoSubDetalle = 20 O lTipoSubDetalle=28 
  Si (lTipoSubDetalle >4) Y ((lTipoSubDetalle%16)%8) = 4 // que tenga series o series y ped y/o lotes
    Si aRegTab = 1 O aRegTab < gRegActSer
      tMovtosSeries.Busca Primero
      tMovtosSeries.Busca[@Str(tMovimientos(cIdMovimiento);0)]
      gRegActSer = 1
    FinSi
  
    lEncontro = 0
    Mientras tMovtosSeries->Encontro
      Si gRegActSer = aRegTab
        lEncontro = 1
        aRegTab = aRegTab + 1
        FinCiclo
      FinSi
      gRegActSer = gRegActSer + 1
      tMovtosSeries.Busca Siguiente[1]
    FinMientras

    Si lEncontro = 0
      aRegTab = 0
      Retorna aMiRenglon
    FinSi

    lRenglon = aMiRenglon
    tNumerosSeries.Busca[@Str(tMovtosSeries(cIdSerie);0)]
    Si tNumerosSeries->Encontro
      // Inicio de la impresión de datos de Numeros de Serie //#$SubDetalle1
      Si aRenSub = 1
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Pedimento: ' & tNumerosSeries(cPedimento) & '  ' & 'Aduana: ' & tNumerosSeries(cAduana) & '  ' & 'Fecha: ' & fFormateaFecha(tNumerosSeries(cFechaPedimento); 3);11;70;1;0;'A';0;'I')       
      FinSi
      // Fin de la impresión de datos de numeros de series
      // Fin de la impresión de datos de numeros de series
    FinSi
    Si lRenglon != aMiRenglon
      Retorna lRenglon
    FinSi
  Finsi  // si lTipo = 4,12,20,28
  // Se revisa si tiene pedimentos, lotes, pedimentos y lotes (ocupan el mismo registro)
  //                      01000,    10000,  11000
  //      pedimentos y unidades, lotes y unidades, pedimentos y lotes y unidades
  //                      01001,    10001,         11001
  Si (lTipoSubDetalle >= 8) Y ((((lTipoSubDetalle%16)%8) = 0) O lTipoSubDetalle = 9 O lTipoSubDetalle = 17 O lTipoSubDetalle = 25) // que tenga solo ped y/o lotes
    Si aRegTab = 1 O aRegTab < gRegActCap
      tMovtosCapas.Busca Primero
      tMovtosCapas.Busca[@Str(tMovimientos(cIdMovimiento);0)]
      gRegActCap = 1
    FinSi
  
    lEncontro = 0
    Mientras tMovtosCapas->Encontro
      Si gRegActCap = aRegTab
        lEncontro = 1
        aRegTab = aRegTab + 1
        FinCiclo
      FinSi
      gRegActCap = gRegActCap + 1
      tMovtosCapas.Busca Siguiente[1]
    FinMientras

    Si lEncontro = 0
      aRegTab = 0
      Retorna aMiRenglon
    FinSi

    lRenglon = aMiRenglon
    tCapas.Busca[@Str(tMovtosCapas(cIdCapa);0)]
    Si tCapas->Encontro
      // Inicio de la impresión de datos de Numeros de Serie //#$SubDetalle2
      Si aRenSub = 1
        lRenglon = fAgregaCampoAlRenglon(lRenglon;'Pedimento: ' & tCapas(cPedimento) & '  ' & 'Aduana: ' & tCapas(cAduana) & '  ' & 'Fecha: ' & fFormateaFecha(tCapas(cFechaPedimento); 3);11;70;1;0;'A';0;'I')       
      FinSi
      // Fin de la impresión de datos de numeros de series
    FinSi
    Si lRenglon != aMiRenglon
      Retorna lRenglon
    FinSi
  Finsi   // si lTipo = 8,16,24
  aRegTab = 0
  Retorna aMiRenglon
FinFunc

// ==============================================================================================================================
// fRenglonBlanco  (Procedimiento)
//   Esta función imprime un renglón en blanco
// ==============================================================================================================================
Deffunc  fRenglonBlanco(aNumRen;aPos;aLong)
Local lRenglon,lNumRenglon,lNumRenglon
  
  lRenglon = '  '  // 
  lNumRenglon = aNumRen
  // Cambio de pagina, siempre presente antes de una instrucción fImprimeRenglon()
  fCambiaPagina()
  // imprime un renglón en blanco, el renglon numero aNumRen, y como solo es del Subdetalle 
  // se le pasa una 'S'
  fImprimeRenglon(&lNumRenglon;&lRenglon;'S')

FinFunc

// ==============================================================================================================================
// fDiscriminaMovtos : regresa un 1 cuando el movto se debe disrcriminar, ya que dada su naturaleza, puede estár duplicado.
// ==============================================================================================================================
Deffunc fDiscriminaMovtos(tMovto:TABLA)
Local lRegresa 

  lRegresa = 0
  // Verifica si el documento es una remisión o una devolución de remisiones (clientes) o un traspaso
  // En este caso al ser un traspaso entre almacenes, tenemos que discriminar uno de los movimientos
  Si pTipoDeDocumento = 3 O pTipoDeDocumento = 34 // Si es una remisión o un traspaso
    // Discrimina los movimientos de Entrada
    Si tMovto(cAfectaExistencia) = 1
     lRegresa = 1
    FinSi
  FinSi
  Si pTipoDeDocumento = 6 // Si es una devolución de remisión
    // Discrimina los movimientos de Salida
    Si tMovto(cAfectaExistencia) = 2
     lRegresa = 1
    FinSi
  FinSi
  // el producto (Ninguno) no se imprime.
  Si tMovto(cIdProducto)= 0
    lRegresa = 1
  Finsi

  Retorna lRegresa

FinFunc

// ==============================================================================================================================
// fSeriesHorizontal  (Procedimiento)
// Esta función imprime los numeros de serie relacionados al movimiento, los arma en una sola cadena y luego los imprime, los 
// imprime en tantos renglones de longitud igual a aLong sean necesarios 
// ==============================================================================================================================
Deffunc fSeriesHorizontal(tMovimientos:TABLA; tProductos:TABLA; aNumRen; aPos; aLong) 
Local lRenglon, lTipoSubDetalle, lRenglonesOcupa, lCont
Local lNumero, lRenTemp, lNumRenglon, lRenImprimir 

  // Aquí asignar variables globales para control de impresión
  // Levanta la bandera que indica que si se elijió la función
  gImprimirSeries = 1
  Si (aNumRen <= 0) // solo es cero cuando se llama desde Detalles de paquete
    aNumRen = gNumRenSeries
    aPos = gPosSeries 
    aLong = gLongSeries
  Sino        // Se asignan los valores para que al imprimir componente se tomen esos valores
    gNumRenSeries = aNumRen
    gPosSeries = aPos
    gLongSeries = aLong
  Finsi

  lNumero = ''
  lRenglon = 'No. de Series:'

  lTipoSubDetalle = tProductos(cControlExistencia)

  // Si el producto no maneja series, se regresa, no busca nada mas
  Si (lTipoSubDetalle!=4 Y lTipoSubDetalle!=12  Y lTipoSubDetalle!=20 Y lTipoSubDetalle!=28 )
    Retorna
  Finsi

  Mientras[tMovtosSeries.Busca[@Str(tMovimientos(cIdMovimiento);0)];tMovtosSeries->Encontro;tMovtosSeries.Busca Siguiente[1]]
    tNumerosSeries.Busca[@Str(tMovtosSeries(cIdSerie);0)]
    Si tNumerosSeries->Encontro
      lNumero = @Str(tNumerosSeries(cNumeroSerie);0)
      lRenglon = lRenglon & lNumero & ', '
    Finsi
  FinMientras
  // Si al menos hubo uno
  Si lNumero != ''
    // Quita la última coma
    lRenglon = @SubStr(lRenglon;0;@Len(lRenglon)-1)

    // obtiene el Numero de renglones de Longitud=aLong, que se necesitan para imprimir lRenglon 
    lRenglonesOcupa = @Len(lRenglon)
    lRenglonesOcupa = lRenglonesOcupa/aLong
    lRenglonesOcupa = @Int(lRenglonesOcupa)+1 
                                        
    lNumRenglon = aNumRen
    lRenImprimir = ''
    lCont = 0
    Mientras lRenglonesOcupa > 0
      lRenTemp = @SubStr(lRenglon;0+(lCont*aLong);aLong)
      lRenImprimir = fAgregaCampoAlRenglon(lRenImprimir;lRenTemp;aPos;aLong;1;0;'A';0;'I')
      Si fCambiaPagina()
        lNumRenglon = aNumRen
      FinSi
      Si gImpresionGrafica = 1 
// INSTRUCCION_TEXTO_SeriesHorizontal
      FinSi      
      fImprimeRenglon(&lNumRenglon;&lRenImprimir ;'S') // Numero de renglon y cadena para imprimir          
      lCont = lCont + 1
      lRenglonesOcupa = lRenglonesOcupa -1
    FinMientras
  Finsi
FinFunc


// ==============================================================================================================================
// fExtraePalabra
// Saca una palabra de longitud aLong de aCadena y la regresa como resultado de la función, pero además deja aCadena sin dicha palabra
// ==============================================================================================================================
DefFunc fExtraePalabra(aCadena;aTamCadena;aLong;aCant)
Local lPalabra, lCaracter, lCantCh

  lPalabra = ''
  Si @Len(aCadena) = 0
    Retorna lPalabra
  FinSi
  lCantCh = 0
  Mientras aLong > 0
    lCaracter = @SubStr(aCadena;lCantCh;1)
    // Si se encuentra con un salto de línea, simplemente completa la 
    // longitud con espacios para imprimir el renglón
    Si @Asc(lCaracter) = 13 O @Asc(lCaracter) = 10
      aLong = aCant - lCantCh
      Mientras aLong > 0
        lPalabra = lPalabra & ' '
        aLong = aLong - 1
      FinMientras
      lCantCh = lCantCh + 1
      aCant = aCant + 1
      Si ((aTamCadena-lCantCh) > 0) Y (@Asc(@SubStr(aCadena;lCantCh;1)) = 13 O @Asc(@SubStr(aCadena;lCantCh;1)) = 10)
        lCantCh = lCantCh + 1
        aCant = aCant +1
      FinSi
      FinCiclo
    FinSi
    lCantCh = lCantCh + 1
    lPalabra = lPalabra & lCaracter
    Si lCaracter = ' ' O lCaracter = '.' O lCaracter = ',' O lCaracter = ';' O lCaracter = ':'
      FinCiclo
    FinSi
    aLong = aLong - 1
  FinMientras
  Si (@Len(lPalabra) <= aCant) O (@Len(lPalabra) = (aCant+1) Y lCaracter = ' ')
    aTamCadena = aTamCadena - lCantCh
    aCadena = @SubStr(aCadena;lCantCh;aTamCadena)
  SiNo
    lPalabra = ''
  FinSi
  Retorna lPalabra
FinFunc

// ==============================================================================================================================
// fImprimeSubDetalle()
// Aquí se inserta el llamado a la funciones, de acuerdo a lo que se seleccione en el editor de de formas preimpresas, solo es un 
// agrupador, para insertar los llamados a las Fx en una sola área.
// ==============================================================================================================================
Deffunc fImprimeSubDetalle(tMovimientos:TABLA;tProductos:TABLA)
Local lRenglon
Local lImpDetPaq
Local lRenAImp

  lImpDetPaq = 0

  lRenglon = ''
  lRenAImp = gRenglonAImprimir
  // Inicio de la inserción de las funciones de subdetalle //#$SubDetalle3
  // Solo las funciones que se eligieron aparecerán en esta área
      lRegTab1 = 1
      lRenglon = fAgregaSubDetalle(tMovimientos;tProductos;lRenglon;1;&lRegTab1)
    Si lRenglon != '' O gImpresionGrafica = 1
      lNumRenglon = 20 + ((lRenAImp - gRenglonesEncabezado - 2) * (gEntroDetPaq = 0 ? 1: 0))
      fImprimeRenglon(&lNumRenglon;&lRenglon;'S')
    FinSi

      lRenglon = fAgregaSubDetalle(tMovimientos;tProductos;lRenglon;1;&lRegTab1)
    Si lRenglon != '' O gImpresionGrafica = 1
      lNumRenglon = 21 + ((lRenAImp - gRenglonesEncabezado - 2) * (gEntroDetPaq = 0 ? 1: 0))
      fImprimeRenglon(&lNumRenglon;&lRenglon;'S')
    FinSi

      lRenglon = fAgregaSubDetalle(tMovimientos;tProductos;lRenglon;1;&lRegTab1)
    Si lRenglon != '' O gImpresionGrafica = 1
      lNumRenglon = 22 + ((lRenAImp - gRenglonesEncabezado - 2) * (gEntroDetPaq = 0 ? 1: 0))
      fImprimeRenglon(&lNumRenglon;&lRenglon;'S')
    FinSi

      Mientras (lRegTab1) > 0
        lRenglon = fAgregaSubDetalle(tMovimientos;tProductos;lRenglon;1;&lRegTab1)
        Si lRenglon != ''
          lNumRenglon = gRenglonAImprimir
          Si fCambiaPagina() = 1
            lNumRenglon = gRenglonesEncabezado + 1
          FinSi
          fImprimeRenglon(&lNumRenglon;&lRenglon;'S')
        FinSi
      FinMientras
      //fSeriesHorizontal(tMovimientos;tProductos; lNumRenglon; 11; 87)

  // Fin de la inserción de las funciones del subdetalle que se imprimen 

  Retorna lImpDetPaq
FinFunc


// ==============================================================================================================================
// Funcion que controla el flujo de la impresion del encabezado y del Pie de página
//  Siempre se debe utilizar aunque la forma no tenga encabezado o pie de pagina Y en el caso
//  de que la forma si tenga detalle, siempre va antes que la función fControlFormaConDetalle
//  salida : 1 = No hay detalle, se imprimió el encabezado y/o el pie de pagina
//           0 = Si hay detalle, no se imprimio el encabezado ni el pie de pagina
// ==============================================================================================================================
Deffunc fControlFormaSinDetalle()
Local lRegreso

  // asume que si hay detalle
  lRegreso = 0
  // Si no hay Detalle para esta forma
  Si  gRenglonesDetalle  = 0
    // En caso de tener encabezado, lo imprime
    Si gRenglonesEncabezado > 0
      fImprimeEncabezado()      
    Finsi
    // EN caso de tener Pie de pagina, lo imprime
    Si gRenglonesPiePagina > 0
      FinForma = 1
      fImprimePiePagina()
    FinSi
    fAlcanzaFinalHoja(gRenglonesHoja)
    // inicializa renglones de control
    gNumeroDeHoja = gNumeroDeHoja + 1
    gRenglonAImprimir = 1    
    // Finalmente, Si entró aqui es por que no hubo detalle
    lRegreso = 1
  Finsi
  Retorna lRegreso
FinFunc

// ==============================================================================================================================
// Funcion que controla el flujo de la impresion del Detalle y SubDetalle, 
// Se debe usar siempre aunque la forma no requiera imprimir ningún detalle.
// ==============================================================================================================================
Deffunc fControlFormaConDetalle()

  // Area del detalle, siempre se debe verificar antes de hacer cualquier cosa
  Si gRenglonesDetalle > 0
    // Se debe buscar el primer movimiento de la factura
    tMovimientos.busca[@Str(tDocumentos(cIdDocumento);0)]     
    Mientras tMovimientos->Encontro
      Si fDiscriminaMovtos(tMovimientos) = 1
        tMovimientos.Busca Siguiente[1]  
        Continua
      Finsi
      // Ahora sí, se accesan las tablas y se validan los hechos necesarios para imprimir el 
      // detalle y el subdetalle, según las condiciones propias del reporte.
      tProductos.busca[@Str(tMovimientos(cIdProducto);0)] 
      Si tProductos->Encontro
        fImprimeDetalle(tMovimientos;tProductos)
        gEntroDetPaq = 0
        fImprimeSubDetalle(tMovimientos;tProductos)
      FinSi
      tMovimientos.Busca Siguiente[1]  
    FinMientras   // Mientras tMovimientos->Encontro
  Finsi
FinFunc

// ==============================================================================================================================
// Controla la impresió al final la impresión de una hoja, siempre se llama despues de haber impreso una forma completamente
// ==============================================================================================================================
Deffunc fControlPostDetalle()

  // Se imprime un encabezado, existe el registro se definió la forma con detalle, pero este
  // Docto no tuvo detalle, por lo tanto tampo se ha impreso el encabezado. Ya que el encabezado
  // se imprime al imprimir el primer detalle.
  Si (gRenglonesEncabezado > 0) Y (gRenglonesDetalle > 0) Y gRenglonAImprimir = 1
    fImprimeEncabezado()
  FinSi

  si gDetalleDinamico = 1
     gRenglonAImprimir =(gRenglonesEncabezado +gRenglonesDetalle)
  finsi


  // Un cambio de hoja normal, cuando se llegó al fin del detalle sin llegar al fin del area
  // definida para el detalle, pero se debe cambiar de hoja, y dejar listo para que empiece la
  // nueva hoja.
  Si (gRenglonesPiePagina > 0) Y (gRenglonesDetalle > 0)
    FinForma = 1
    fImprimePiePagina()
    fAlcanzaFinalHoja(gRenglonesHoja)
    gNumeroDeHoja = gNumeroDeHoja + 1
    gRenglonAImprimir = 1    
  FinSi

FinFunc

// ******************************************************************************************************************************
// ******************************************************************************************************************************
//    INICIO  DE LAS FUNCIONES PROPIAS DEL TIPO DE REPORTE,  
// ******************************************************************************************************************************
// ******************************************************************************************************************************
// ==========================================================================================
//	fFechaSiguiente
//	Esta función recibe una fecha AAAAMMDD y devuelve el dia siguiente en AAAAMMDD
// ========================================================================================== 
DefFunc fFechaSiguiente(Fecha)
Local vMes, vDia, vAno
Local vRegreso

	// Obtiene el día, mes y año
	vDia = @SubStr(Fecha;6;2)
	vMes = @SubStr(Fecha;4;2)
	vAno = @SubStr(Fecha;0;4)

	// verifica los meses de 31 días
	Si vMes = 1 o vMes = 3 o vMes = 5 o vMes = 7 o vMes = 8 o vMes = 10 o vMes = 12
		Si vDia = 31 // se llego a fin de mes
			// entonces el siguiente dia es primero
			vDia = 1[C0]
			// incrementa el mes siempre que no sea diciembre
			Si vMes != 12
				vMes = vMes + 1[C0]
			SiNo 
				// Si es Diciembre incrementa el año y pone el mes en Enero
				vMes = 1[C0]
				vAno = vAno + 1[C0]
			FinSi
		SiNo
			// Si no es fin de mes simplemente incrementa el dia
			vDia = vDia + 1[C0]
		FinSi
   Sino
   	// verifica los meses de 30 días
	   Si vMes = 4 o vMes = 6 o vMes = 9 o vMes = 11
   		Si vDia = 30 // se llego a fin de mes
	   		// entonces el siguiente dia es primero
		   	vDia = 1[C0]
			   vMes = vMes + 1[C0]
   		SiNo
	   		// Si no es fin de mes simplemente incrementa el dia
		   	vDia = vDia + 1[C0]
   		FinSi
	   Sino
   	   // verifica el caso especial de Febrero
      	// Verifica la condición de año bisiesto
    		Si vAno % 4 = 0 // Ojo: Esta condición solo funciona hasta el año 2099
	      	// Si es bisiesto entonces verificar la condicion con 29 dias
     			Si vDia = 29 // se llego a fin de mes?
	      		// entonces el siguiente dia es primero
     				vDia = 1[C0]
	      		vMes = vMes + 1[C0]
     			SiNo
     				// Si no es fin de mes simplemente incrementa el dia
	      		vDia = vDia + 1[C0]
     			FinSi
     		SiNo
	      	// No es bisiesto entonces verificar la condicion con 28 dias
     			Si vDia = 28 // se llego a fin de mes?
	      		// entonces el siguiente dia es primero
     				vDia = 1[C0]
	      		vMes = vMes + 1[C0]
     			SiNo
	      		// Si no es fin de mes simplemente incrementa el dia
     				vDia = vDia + 1[C0]
	      	FinSi
     		FinSi // Año bisiesto
   	FinSi // Condición meses de 30 días
   Finsi // Condición meses de 31 días

	// arma la nueva fecha
   vMes = @Val(vMes)[C0]
   vDia = @Val(vDia)[C0]
	vRegreso = vAno & (vMes <= 9? '0' & vMes : vMes) & (vDia <= 9? '0' & vDia : vDia)[C0]

  Retorna vRegreso
FinFunc

// ==========================================================================================
// fBuscaAlgunReg
// Descripcion : Busca algun registro que coincida con el campo aIDBuscado, y alguna de las 
//               fechas que sea menor o igual que aFechaFin.
// Salida : modifica el argumento aFechaIni, para regresar la fecha en que se encontro el 1er.
//          registro que coincide
// ==========================================================================================
Deffunc BuscaAlgunReg(aFechaIni;aFechaFin;aIdBuscado;aTblDeBusqueda:TABLA)
  Mientras aFechaIni <= aFechaFin Y !aTblDeBusqueda->ENCONTRO 
    aTblDeBusqueda.BUSCA[aIdBuscado &':'&aFechaIni]
    Si !aTblDeBusqueda->Encontro
      aFechaIni = fFechaSiguiente(aFechaIni)
    Finsi
  FinMientras
Finfunc

// ******************************************************************************************************************************
// fImprimeDocumento  (Procedimiento)
// Descripcion : Practicamente es solo un extención del recorrido principal
// 
// ******************************************************************************************************************************
Deffunc fImprimeDocumento()

  // Se abren las tablas que pueden ser utilizadas en el encabezado,
  // Además de las tablas de tEmpresa y la tabla sobre la que se hace el recorrido principal

  // Inicializa datos de la moneda y generales del reporte
  // Se busca la moneda del documento      
  tMonedas.busca[@Str(tDocumentos(cIdMoneda);0)]  
  gNombreMonedaPlu  = tMonedas(cPlural)
  gNombreMonedaSing = tMonedas(cSingular)
  gDescrProtegida   = tMonedas(cDescripcionProtegida)

  // Se buscan los datos del cliente
  tClientes.busca[@Str(tDocumentos(cIdClienteProveedor);0)]

  // Se busca la direccion fiscal del Cliente.Solo por compatibilidad con la primer versión, porque 
  // ya se es necesario, el documento por default tiene la direccion del cliente.
  tDirClientes.Busca[tClientes(cIDClienteProveedor)&':'&'1:0']// Busca la del cliente  
  Si tDocumentos(cUsaProveedor) = 1
    Si tDirClientes->encontro = 0
      tDirClientes.Busca[tClientes(cIDClienteProveedor)&':'&'2:0']// Busca la del proveedor  
    Finsi
  finsi

  // se busca la direccion fiscal del documento
  tDirDocumentosFis.Busca[tDocumentos(cIDDocumento)&':'&'3:0']
  Si @Len(tDirDocumentosFis(cNombreCalle)) < 3 // Se considera que no tuvo dirección fiscal el docto
    tDirDocumentosFis.Busca[tClientes(cIDClienteProveedor)&':'&'1:0']  // Busca la del cliente  
    Si tDocumentos(cUsaProveedor) = 1 
      Si tDirDocumentosFis->encontro = 0
        tDirDocumentosFis.Busca[tClientes(cIDClienteProveedor)&':'&'2:0']  // Busca la del Proveedor  
      Finsi 
    Finsi
  Finsi

  //  Busca el concepto documento del documento
  tConceptos.Busca[@Str(tDocumentos(cIdConceptoDocumento);0)]

  // La siguiente iteración debe ir en todas las plantillas no importa que no lleven detalle, o que no lleven pie de pagina, o encabezado.
  gCont = 1 // aqui se define y se inicializa, siempre debe de ir.
  Mientras gCont <= gNumeroCopias  
    // Revisa si se definió algún detalle para la forma
    Si (fControlFormaSinDetalle() = 0)
      fControlFormaConDetalle()    
      fControlPostDetalle()
    Finsi
    gCont = gCont + 1
  FinMientras

FinFunc

// ******************************************************************************************************************************
//  fDiscriminaDocumento
//	Esta función verifica el estado de cancelación y afectación del documento, y así determinar si se imprime o no el documento.
//  Salidas:  0 = Imprimir el documento (No discriminarlo)
//            1 = No imprimir el documento (Si discriminarlo)
// ******************************************************************************************************************************
DefFunc fDiscriminaDocumento(atDocumento: Tabla)
Local lRegreso

  lRegreso = 0 

  //N.D.5761 Verifica que el concepto del documento encontrado sea del mismo que se desea imprimir
  Si atDocumento(CIDCONCEPTODOCUMENTO) != pIdConcepto Y pIdConcepto != 0
  	lRegreso = 1  	
  FinSi
  
  //N.D.5761 Verifica que el documento sea CFD si no lo discrima
  Si tDocumentos(CESCFD) != 1
  	lRegreso = 1
  FinSi  
  
  // Si no esta afectado, no se imprime
  Si atDocumento(cAfectado) = 0
    lRegreso = 1
  Sino
    // Si no pidieron todos y No coincide con los solicitado (0 =Todos,1=Impresos,2=No impresos)
    Si (pCuales != 0) Y (atDocumento(cImpreso) != pCuales%2 )
      lRegreso = 1
    Sino
      // Si no tiene folio
      Si atDocumento(cFolio) = 0
        lRegreso = 1
      Finsi
    Finsi
  FinSi
  Retorna lRegreso
FinFunc

// ==============================================================================================================================
// fProcesaPorSerie  (Procedimiento)
// 
// ==============================================================================================================================
Deffunc fProcesaPorSerie()

  // Establece el índice de recorrido
  tDocumentos.Usaindice['iDoctoDeSerieFolio'] // cIdDocumentoDe+cSerie+cFolio

  // Obtiene los documentos en el rango de folios especificado en el reporte
  Mientras pDelFolio <= pAlFolio     
    // Si encontro algún documento en esa fecha, recupera todos los documentos en esa fecha
    tDocumentos.Busca[pTipoDeDocumento & ':' & pSerie & ':' & pDelFolio]
    Si tDocumentos->Encontro
      Si fDiscriminaDocumento(tDocumentos)
        //N.D.5761 Si el documento fue discriminado busca el siguiente
        tDocumentos.Busca Siguiente[1]        
        pDelFolio = tDocumentos(cFolio)
      FinSi
      
      // Localiza su Folio Digital      
      tFoliosDigitales.Busca[@Str(tDocumentos(cIdDocumento);0)]    
      Si tFoliosDigitales->Encontro
      	fImprimeDocumento()
      	//N.D.5761 Si detecta que el Folio Inicial es Igual al Final se sale del ciclo
      	Si pDelFolio = pAlFolio 
      	 FinCiclo
      	FinSi 
      FinSi            
    Finsi
  FinMientras
FinFunc

// ==============================================================================================================================
// fProcesaPorFecha  (Procedimiento)
// 
// ==============================================================================================================================
Deffunc fProcesaPorFecha()

  tDocumentos.Usaindice['iDocumentoDeFechaSerieFol']
  gFechaBusqueda = pDelaFecha
  // busca Algun docto , que coincida con el subtipo y con la fecha de inicio o mas cercana
  // Si encontro tDocumentos queda en el registro encontrado y gFechaBusqueda en la fecha en 
  // que se encontro
  BuscaAlgunReg(&gFechaBusqueda;pAlaFecha;pTipoDeDocumento;&tDocumentos)

  // Cuando es por fechas se barren todas las fechas a partir de la primera encontrada, para 
  // barrer todos los documentos por cada uno de los días dentro del rango
  Mientras gFechaBusqueda <= pAlaFecha
    // Se posisciona en el primero encontrado
    tDocumentos.Busca[pTipoDeDocumento &':'& gFechaBusqueda]
    // EN caso de encontrar uno, busca todos los documentos en esa fecha
    Mientras (tDocumentos->Encontro)
      // Discrimina documentos según parámetro de cancelación y afectación
      Si fDiscriminaDocumento(tDocumentos)
        tDocumentos.Busca Siguiente[2]
        Continua
      FinSi
      
      // Localiza su Folio Digital
      tFoliosDigitales.Busca[@Str(tDocumentos(cIdDocumento);0)]    
      Si tFoliosDigitales->Encontro
        fImprimeDocumento()   
      FinSi
      // Por fechas,son  dos campo los que intervienen en la busqueda
      tDocumentos.Busca Siguiente[2]
    FinMIentras   // tDocumentos->Encontro
    gFechaBusqueda = fFechaSiguiente(gFechaBusqueda)
  FinMientras      // fecha sea menor
FinFunc


// ==============================================================================================================================
// PRINCIPAL
  // Parametros de la empresa
  tParametros.Busca Primero
  // se busca la direccion fiscal de la empresa Tipo = 4, fiscal = 0
  tDirEmpresa.Busca[tParametros(cIdEmpresa)&':'&'4:0']
  gNumImpuestoIVA = tParametros(cNumImpuestoIVA) 
  // Si el folio viene en cero, asume que se buscará por fechas
  Si pDelFolio = 0
    fProcesaPorFecha()
  Sino
    fProcesaPorSerie()
  Finsi
// FIN PRINCIPAL
