// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//
//  InvFis.rpt
//  Nombre del reporte en el sistema: Inventario Físico vs Existencia
//
//  Sistema: AdminPAQ v1.1 
// 
//  Este reporte perteneciente al módulo de movimientos deinventarios, 
//  despliega el inventario físico vs Existencia Congelada (comparativo)
//
//  
//  
//  Elaboró:    Gabriela Cuevas Jurado
//  Fecha:       28 de Octubre del 2001
//
//  Historia de revisiones:
//          Se incluye un nuevo reporte "Existencias"
//  Autor:  Gabriela Cuevas Jurado
//  Fecha:  15 de febrero del 2002
//              Se incluye el manejo de productos con caracteristicas y series, 
//    Caracteristicas y capas
//  Autor:  Hector Valencia Aguilar
//  Fecha:       20 de Mayo del 2002
//  Autor:  Hector Valencia Aguilar
//  Fecha:       28 de Mayo del 2002
//  Autor:  Luis Palau
//  Fecha:       29 de Mayo del 2002
// 31/07/2002   EOD     SC 150      Debido a la SC 150 todos los movtos ahora se
//                                  afectan en línea y se permiten existencias 
//                                  negativas protegiendo al costo. Por lo tanto
//                                  ya no se imprimen movtos sin afectar, de hoy
//                                  en adelante se afectan en línea todos los 
//                                  movimientos y los movimientos no afectados 
//                                  son erroneos. Esta modificación incluye 
//                                  quitar todas las modificaciones efectuadas
//                                  por la ND 585 y la SC 35
// 17/09/2002   RPC     ND 946      Al pedir sólo los productos con existencias
//                                  incluye productos que no tienen
// 25/07/2003   CILA    ND2357      Se modifico las funciones fProcesaCapa y
//                                  fProcesaProducto para agregar el caso de los
//                                  productos que manejan Lotes y Pedimentos.
// 17/09/2003   CILA   N.D.2386     Se modifico la funcion fProcesaCapa para
//                                  imprimir correctamente en el caso de Inven-
//                                  tario fisico vs. Exitencias los valores
//                                  de existencias y captura de inventario
//                                  fisico.
// 26/09/2003   EGV     2434        Se cambió el ancho de las columnas para el
//                                  despliegue del reporte Inventario
//                                  Actual/Existencia por Almacén ya que el
//                                  reporte era excesivamente ancho y no se
//                                  utilizaban todas las columnas. Esto provocaba
//                                  mala estética hacer una impresión del
//                                  reporte. (EGV)
// 11/12/2003   CILA    2591        Se modificaros las funciones fProcesaCapa y
//                                  fProcesaProducto para cuando la capa tiene
//                                  existencia 0 no imprima dicha capa si en el
//                                  filtro del reporte dice no imprimir capas y
//                                  productos con caracteristicas.
// 08/03/2004   EGV     2719        Cuando se ejecuta el reporte de Existencias
//                                  por Almacén, y se debe desplegar un Producto
//                                  con Series, se despliegan éstas con todo y
//                                  su Pedimento y/o Lote si es que lo tienen.
//                                  Además, se despliegan como disponibles las
//                                  series remisionadas en un Almacén. (EGV)
// 15/03/2004   LAP      2725       Reporte de Existencias por Almacén: Mostrar 
//                                  una leyenda de información para las series
//                                  huerfanas vendidas a las cuales se les
//                                  capturo su entrada en un almacén distinto al
//                                  de la venta. Restar dichas unidades a la
//                                  existencia total.
//                                  - fImprimeInformacionSeries
//                                  - fProcesaNormal
//                                  - fProcesaProducto
// 15/12/2005   LAP      3682       Utilización de una nueva función para obtener
//                                  la existencia a una fecha
// 21/05/2007   JAAM     N.C.147    Esquema de adicion de unidades de compra y venta
// 13/07/2009   ELVS     N.D.4455   ERROR INVENTARIO FISICO NO CALCULA CORRECTAMENTE
//                                  LAS  CANTIDADES DE ACUERDO A LA EXISTENCIA ACTUAL
//                                  Y LA CAPTURADA EN LA VENTANA DE CAPTIRA DE INVENTARIO
//																  FISICO ESTO EN EL REPORTE DE INVENTARIO FISICO CONTRA
//                                  EXISTENCIA. Se agrega columna de movimiento sugerido.
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


// *****************************************************************************
// Funciones de librería

Incluye LibAdminPAQ.Rpt
Incluye LibInventarios.Rpt


// *****************************************************************************
//  Parámetros del reporte:

//Parametro pFechaCorte = '20011231'    // Fecha utilizada para el cálculo de existencias
Parametro pAlmacenInicial = ' '         // Código del almacén inicial del rango (' ' = Todos)
Parametro pAlmacenFinal = ' '           // Código del almacén final del rango (' ' = Todos)
Parametro pProductoInicial = ' '        // Código del producto inicial del rango (' ' = Todos)
Parametro pProductoFinal = ' '          // Código del producto final del rango (' ' = Todos)

Parametro pImprimirProductos = 0        // Productos a imprimir:
                                        // 0 = Todos
                                        // 1 = Capturados en inventario Físico (Con existencias)
Parametro pCaracteristicas = 1          // Imprimir características de productos
                                        // 0 = No imprimir características
                                        // 1 = Imprimir características
Parametro pSeries = 1                   // Imprimir series de productos
                                        // 0 = No imprimir series
                                        // 1 = Imprimir series
Parametro pLotes = 1                    // Imprimir lotes de productos
                                        // 0 = No imprimir lotes
                                        // 1 = Imprimir lotes
Parametro pPedimentos = 1               // Imprimir pedimentos de productos
                                        // 0 = No imprimir pedimentos
                                        // 1 = Imprimir pedimentos
Parametro pUnidad = 0                   // Unidad de medida y peso para expresar el reporte
                                        // 0 = Unidad base del producto
                                        // 1 = Unidad no equivalente del producto
                                        // 2 = Unidad equivalente (ver parámetro pIdUnidad)
                                        // 3 = Unidad de Compra
                                        // 4 = Unidad de Venta
Parametro pIdUnidad = 0                 // Id de la unidad equivalente
Parametro pIdClase1 = 0                 // Clasificaciones del produto (0 = Ninguna)
Parametro pIdClase2 = 0                 // Estos seis parámetros corresponden a las seis clasificaciones
Parametro pIdClase3 = 0                 // del producto, y pueden contener una lista de IDs
Parametro pIdClase4 = 0                 // de clasificaciones separados por coma.
Parametro pIdClase5 = 0               
Parametro pIdClase6 = 0               
Parametro pTipoReporte = 2              // 0 = Inventario Físico vs existencias
                                        // 1 = Proforma
                                        // 2 = Existencias
// *****************************************************************************
//  Tablas a utilizar e Indices de búsqueda por omisión

UsaEmpresa tEmpresa;'ADMINPAQW'                   // Parámetros

UsaTabla tProducto = tEmpresa['MGW10005']         // Productos
tProducto.Usaindice['iCodigoTipo']                // cCodigoProducto+cTipoProducto

UsaTabla tAlmacen = tEmpresa['MGW10003']          // Almacenes
tAlmacen.Usaindice['cCodigoAlmacen']              // cCodigoAlmacen

UsaTabla tDetalleProducto = tEmpresa['MGW10004']  // Productos
tDetalleProducto.Usaindice['iProdPadreValoresCarac']  // cIdProductoPadre+cIdValorCaracteristica1+cIdValorCaracteristica2+cIdValorCaracteristica3

UsaTabla tDocumento = tEmpresa['MGW10008']        // Documentos
tDocumento.Usaindice['']                          // Indice primario: cIdDocumento

UsaTabla tMovtoOwner = tEmpresa['MGW10010'] Alias 'MovtoOwner'  // Movimientos
tMovtoOwner.Usaindice['']                         // Indice primario: cIdMovimiento

UsaTabla tMovimiento = tEmpresa['MGW10010'] Alias 'Movto'       // Movimientos
tMovimiento.Usaindice['iProductoFechaAfecta']     // cIdProducto+cFecha+cAfectaExistencia

UsaTabla tMovtoSinAfectar = tEmpresa['MGW10010'] Alias 'MovtoSinAfectar'  // Movimientos sin afectar
tMovtoSinAfectar.Usaindice['iProductoDoctoDeAfecFecha']    // cIdProducto+cIdDocumentoDe+cAfectadoInventario+cFecha

UsaTabla tInventario = tEmpresa['MGW10033']       // Inventario
tInventario.Usaindice['iAlmacenProducto']    // cIdAlmacen + cIdProducto

UsaTabla tSerieInventario = tEmpresa['MGW10040'] Alias 'tSerieInv'     // Series
tSerieInventario.Usaindice['iAlmacenProductoSerie']      // cIdAlmacen + cIdProducto + cNumeroSerie

UsaTabla tSerie = tEmpresa['MGW10032']            // Series
tSerie.Usaindice['iProdAlmacenSerie']             // cIdProducto+cIdAlmacen+cNumeroSerie

UsaTabla tLoteInventario = tEmpresa['MGW10040'] Alias 'tLote'     // Lotes
tLoteInventario.Usaindice['iAlmacenProductoLote']      // cIdAlmacen + cIdProducto + cNumeroLote

UsaTabla tCapaLote = tEmpresa['MGW10025'] Alias 'tExisLotes'  // Capas
tCapaLote.Usaindice['iProductoAlmacenLote']      // cIdProducto + cIdlmacen + cNumeroLote

UsaTabla tPedimentoInventario = tEmpresa['MGW10040'] Alias 'tPedimento'     // Pedimento
tPedimentoInventario.Usaindice['iAlmacenProductoPedimento']      // cIdAlmacen + cIdProducto + cPedimento

UsaTabla tCapaPedimento = tEmpresa['MGW10025'] Alias 'tExisPedimento'  // Capas
tCapaPedimento.Usaindice['iProdAlmacenPedimentoLote']      // cIdProducto + cIdlmacen + cPedimento + cNumeroLote

UsaTabla tEjercicio = tEmpresa['MGW10031']        // Ejercicios
tEjercicio.Usaindice['']                          // Indice primario: cIdEjercicio

UsaTabla tExistencia = tEmpresa['MGW10030']       // Existencia
tExistencia.Usaindice['iProdEjerAlmacenTipo']     // cIdProducto+cIdEjercicio+cIdAlmacen+cTipoExistencia

UsaTabla tUnidad = tEmpresa['MGW10026']           // Unidades de peso y medida
tUnidad.Usaindice['']                             // Indice primario: cIdUnidad

UsaTabla tEquivalencia = tEmpresa['MGW10027']     // Equivalencia de unidades de peso y medida
tEquivalencia.Usaindice['']                       // Indice primario: cIdUnidad1+cIdUnidad2

UsaTabla tCaracteristica = tEmpresa['MGW10021']       // Características
tCaracteristica.Usaindice['']                         // Indice primario: cIdPadreCaracteristica

UsaTabla tValorCaracteristica = tEmpresa['MGW10022']  // Valores de características
tValorCaracteristica.Usaindice['']                    // Indice primario: cIdValorCaracteristica

UsaTabla tValoresDeClasif = tEmpresa['MGW10020']
tValoresDeClasif.UsaIndice['']                    // Indice primario: cIdValorClasificacion

UsaTabla tParametros = tEmpresa['MGW10000']       // Parámetros de la empresa
tParametros.Usaindice['']                         // Indice primario: cIdEmpresa


// *****************************************************************************
// Definiciones y asumidos globales para el reporte

// Ancho de columnas = caracteres / 17 * 2.54
// Se consideran columnas intermedias de un espacio
// C0 (Código del producto o almacén) = 14 caracteres
// C2 (Nombre del producto o almacén) = 51
// C4 (Unidad de medida o peso) = 3 caracteres
// C6 Existencia = 14 caracteres
// Inventario Físico vs Existencia
// C8 Inventario = 14 caracteres
// C10 Diferencia = 14 caracteres
// C12 Movimiento Sugerido = 20 caracteres //N.D.4455
// Proforma
// C8 Conteo Final = 10 
// C10 Entradas = 8
// C12 Salidas = 8
// C14 Existencia Real = 10
// C16 (Número de Error) = EOD - SC 150: Indica el número de error del producto si tiene
Si pTipoReporte = 0
  Columnas 16;2.09,0.15,7.62,0.15,0.45,0.15,2.09,0.15,2.09,0.15,2.09,0.15,3.00 //N.D.4455
FinSi
Si pTipoReporte = 1
  Columnas 15;2.09,0.15,7.62,0.15,0.45,0.15,2.09,0.15,1.49,0.15,1.20,0.15,1.20,0.15,1.50
FinSi
Si pTipoReporte = 2
  Columnas 11;4.62,0.15,7.62,0.15,0.45,0.15,2.09,0.15,2.09,0.0,0.0
FinSi

Usaletra 'Arial'
Altura 9
[C6,C8,C10].Coma


// *****************************************************************************
//  Variables de ámbito global:

gIdioma = 0               // Idioma del reporte
                          // 0 = Español
                          // 1 = Inglés
// Las siguientes variables se utilizan en el cuerpo principal del reporte
gPeriodo = 0              // Numero de período que corresponde a la fecha de corte del reporte
gIdEjercicio = 0          // ID del ejercicio que contiene la fecha de corte del reporte
gFechaCorteMasUnDia = 0   // Fecha de corte más un día
gUnidad = pUnidad         // Almacenamiento del parámetro pUnidad
gIdUnidad = pIdUnidad     // Almacenamiento del parámetro pIdUnidad
gMascarillaProducto = ''  // Mascarilla para el código del producto
gMascarillaAlmacen = ''   // Mascarilla para el código del almacén
gExistenciaAlmacen = 0    // Total por almacén
gInventarioAlmacen = 0    // Total por almacén
gExistenciaGeneral = 0    // Total general
gExistenciaInventario = 0    // Total general
gImprimeTotal         = 0  // Bandera que indica si de imprimiran los totales


// =================================================================================================
// Función área sensible al contexto
// =================================================================================================
DefFunc ContextoDetalleProductoAlm(aNumeroColumna; aValor)
    EJECUTA tEmpresa->SysDirDatos & '\Reportes\AdminPAQ\Kardex.RTW';gFechaIniHistoria,gFechaFinHistoria,@Escoge(aValor;0),@Escoge(aValor;0),@Escoge(aValor;1),@Escoge(aValor;1),0,0,pUnidad,pIdUnidad,pIdClase1,pIdClase2,pIdClase3,pIdClase4,pIdClase5,pIdClase6,1,2;tEmpresa->Directorio
FinFunc

// *****************************************************************************
//  fImprimeSeriesRepExistencias
//
//  Esta función imprime las Series con Pedimentos y Lotes si es que los tiene.
//
//  Parámetros 
//
//  Salidas
//
//  Consideraciones: Sólo aplica para el reporte 3. Existencias por Almacén. 
// *****************************************************************************
DefFunc fImprimeSeriesRepExistencias( aSerie1; aPedimento; aLote )
Local vImprime
  Local ColumnasImpresas

  Columnas 7;2.09,0.15,4.48,0.15,4.48,0.15,4.48
  vImprime = ' '[C0..C5]
  vImprime = @col(aSerie1;0)[C2]
  lColumnasImpresas = 1

  Si aPedimento != ''
    vImprime = @col( aPedimento;0)[c4]
    lColumnasImpresas = lColumnasImpresas + 1
  FinSi

  Si aLote != ''
    Si lColumnasImpresas = 1
      vImprime = @col( aLote;0)[c4]
    Sino
      vImprime = @col( aLote;0)[c6]
    FinSi
  FinSi

  Lista vImprime
  Columnas 11;4.62,0.15,7.62,0.15,0.45,0.15,2.09,0.15,2.09,0.0,0.0

FinFunc

// *****************************************************************************
// Proceso: Impresión de una leyenda para los productos con series.
// Entrada:
// Salida:
// Historial de cambios
// 15/03/2004  2725    LAP       Implementación inicial
// *****************************************************************************
DefFunc fImprimeInformacionSeries(aMensaje; aTotal)
Local	lImprime

  lImprime = ' '[C0..C10]
  lImprime = @Col(aMensaje;0)[C2]
	lImprime = @Col(aTotal;0)[C6]
	Lista lImprime
FinFunc

// *****************************************************************************
//  fConfiguraDecimales
//
//  Configura el número de decimales de las columnas de importes, basado en
//  en los parámetros de la empresa.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fConfiguraDecimales()

  // Busca el registro de la empresa
  tParametros.Busca Primero
  Si tParametros->Encontro // Si lo encontró
    [C6,C8,C10].Decimales tParametros(cDecimalesUnidades) // Decimales para existencias
    gMascarillaAlmacen = tParametros(cMascarillaAlmacen) // mascarilla para el código del almacen
    gMascarillaProducto = tParametros(cMascarillaProducto) // mascarilla para el código del producto
  Sino // Si no encontró el registro de la empresa
    [C6,C8,C10].Decimales 2
  FinSi
FinFunc

// *****************************************************************************
//  fImprimeDatoProducto
//
//  Esta función imprime los datos del producto
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeDatoProducto(atProducto: Tabla; aExistencia; aInventario; aImprimir)
Local vImprime, lCodigoEditado, lDiferencia, lFechaSinAfectar, lExistenciaCongelada

  vImprime = ' '[C0..C10]

  // Codigo y nombre del producto
  lCodigoEditado = fMascarilla(atProducto(cCodigoProducto); gMascarillaProducto)
  vImprime = @Col(lCodigoEditado;0)[C0]
  vImprime = atProducto(cNombreProducto)[C2]
  
    // Imprime unidad de medida y peso
  Escoge pUnidad
    Caso 0 // Unidad base
      tUnidad.Busca[@Str(atProducto(cIdUnidadBase);0)]      
    FinCaso
    Caso 1 // Unidad no equivalente
      tUnidad.Busca[@Str(atProducto(cIdUnidadNoConvertible);0)]        
    FinCaso
    Caso 2 // Unidad equivalente
      tEquivalencia.Busca[atProducto(cIdUnidadBase) & ':' & pIdUnidad]
      Si tEquivalencia->Encontro // Si encontró una equivalencia con la unidad base
        tUnidad.Busca[@Str(pIdUnidad;0)] // Busca la unidad equivalente
      Sino // Si no encontró la unidad equivalente, Busca la unidad base
        tUnidad.Busca[@Str(atProducto(cIdUnidadBase);0)]
      FinSi
    FInCaso
  FinEscoge
  Si tUnidad->Encontro // Encontró el registro de la unidad de medida y peso
    Si tUnidad(cIdUnidad) y tUnidad(cDespliegue) != ''
      vImprime = tUnidad(cDespliegue)[C4]
    FinSi
  FinSi
    
  Si aImprimir = 0
    Lista vImprime
  FinSi

  Si aImprimir = 1
    vImprime = @Col(aExistencia;0)[C6]
    vImprime = @Col(aInventario;0)[C8]
    lDiferencia = aExistencia - aInventario
    vImprime = @Col(lDiferencia;0)[C10]
    //N.D.4455
    Si lDiferencia < 0 //Es negativo
     	vImprime = 'Entrada'[C12]                
    SiNo
     	vImprime = 'Salida'[C12]                
    FinSi                   
    
    Lista vImprime
  FinSi

  Si aImprimir = 2
    vImprime = @Col(aExistencia;0)[C6]

    Si pTipoReporte = 2 // Reporte de Existencias
      DEFREGION ContextoDetalleProductoAlm
      [C6].REGIONINFO atProducto(cCodigoProducto) & ',' & tAlmacen(cCodigoAlmacen)
      // EOD - SC 150 Verificar si el producto tiene algún error y sí es así 
      // desplegar el error.
      vImprime = ''[C8]
  
      // Verificar si hay existencias congeladas
      lExistenciaCongelada = fVerificarExistenciaCongelada(atProducto(cIdProducto); tAlmacen(cIdAlmacen); tParametros(cIdEjercicioActual); tExistencia)
  
      // Si no hay existencias congeladas verificar si hay movimientos sin afectar.
      // Cuando hay existencias congeladas no se revisan movimientos sin afectar 
      // porque pueden deberse a dicha existencia congelada
      Si !lExistenciaCongelada
        // Verificar si hay movimientos sin afectar y en que fecha
        lFechaSinAfectar = fVerificarMovtosSinAfectar(atProducto(cIdProducto); tMovtoSinAfectar; tMovtoOwner; tDocumento)
      SiNo  
        vImprime = '(7)'[C8]
        lFechaSinAfectar = ''
      FinSi
  
      // Si hay error de existencias y no hay movtos sin afectar O
      // el error de existemcias  ocurrió antes de los movtos sin afectar
      // entonces se despliega el error de costos
      Si ( atProducto(cErrorCosto) Y !lFechaSinAfectar) O ( lFechaSinAfectar Y atProducto(cErrorCosto) Y atProducto(cFechaErrorCosto) < lFechaSinAfectar )
        vImprime = '(' & atProducto(cErrorCosto)& ')'[C8]
      FinSi // Si hay error de costos
      
      // Si hay movtos sin afectar y no hay errores de existencias O
      // los movtos sin afectar ocurrieron antes del error de existencias
      // entonces se despliega el error de movtos sin afectar
      Si ( lFechaSinAfectar Y !atProducto(cErrorCosto) ) O ( lFechaSinAfectar Y atProducto(cErrorCosto) Y lFechaSinAfectar <= atProducto(cFechaErrorCosto) )
        vImprime = '(6)'[C8]
      FinSi
      // FIN EOD - SC 150
    FinSi  // Si es Reporte de Existencias

    Lista vImprime
  FinSi

  Si pTipoReporte = 1 Y aImprimir
    Texto C8;'@L{8}'
    Texto C10;'@L{10}'
    Texto C12;'@L{12}'
    Texto C14;'@L{14}'
    Imprime
  FinSi 
FinFunc


// *****************************************************************************
//  fImprimeCaracteristicas
//
//  Esta función imprime los datos de una combinación de características.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************

DefFunc fImprimeCaracteristicas(atDetalleProducto: Tabla; aImprimirExistencias; aExistencia; aInventario; aTextoCaracteristicas; atProducto: Tabla;aPrimeravez)
Local vImprime, lValoresCaracteristicas, lTextoCaracteristicas, lDiferencia

  // Procesa solo si existen valores de características
  Si atDetalleProducto(cIdValorCaracteristica1) o atDetalleProducto(cIdValorCaracteristica2) o atDetalleProducto(cIdValorCaracteristica3)
    vImprime = ' '[C0..C10]
    lValoresCaracteristicas = ' '
    lTextoCaracteristicas = ' '

    // Lee los valores de las características
    // Caracteristica 1
    Si atDetalleProducto(cIdValorCaracteristica1)
      tValorCaracteristica.Busca[@Str(atDetalleProducto(cIdValorCaracteristica1);0)]
      Si tValorCaracteristica->Encontro
        lValoresCaracteristicas = tValorCaracteristica(cValorCaracteristica)
        // Verifica si leer el nombre de la caracteristica
        Si !aTextoCaracteristicas
          tCaracteristica.Busca[@Str(tValorCaracteristica(cIdPadreCaracteristica);0)]
          Si tCaracteristica->Encontro
            lTextoCaracteristicas = tCaracteristica(cNombreCaracteristica)
          FinSi
        FinSi
      FinSi
    FinSi

    // Caracteristica 2
    Si atDetalleProducto(cIdValorCaracteristica2)
      tValorCaracteristica.Busca[@Str(atDetalleProducto(cIdValorCaracteristica2);0)]
      Si tValorCaracteristica->Encontro
        lValoresCaracteristicas = lValoresCaracteristicas & '-' & tValorCaracteristica(cValorCaracteristica)
        // Verifica si leer el nombre de la caracteristica
        Si !aTextoCaracteristicas
          tCaracteristica.Busca[@Str(tValorCaracteristica(cIdPadreCaracteristica);0)]
          Si tCaracteristica->Encontro
            lTextoCaracteristicas = lTextoCaracteristicas & '-' & tCaracteristica(cNombreCaracteristica)
          FinSi
        FinSi
      FinSi
    FinSi

    // Caracteristica 3
    Si atDetalleProducto(cIdValorCaracteristica3)
      tValorCaracteristica.Busca[@Str(atDetalleProducto(cIdValorCaracteristica3);0)]
      Si tValorCaracteristica->Encontro
        lValoresCaracteristicas = lValoresCaracteristicas & '-' & tValorCaracteristica(cValorCaracteristica)
        // Verifica si leer el nombre de la caracteristica
        Si !aTextoCaracteristicas
          tCaracteristica.Busca[@Str(tValorCaracteristica(cIdPadreCaracteristica);0)]
          Si tCaracteristica->Encontro
            lTextoCaracteristicas = lTextoCaracteristicas & '-' & tCaracteristica(cNombreCaracteristica)
          FinSi
        FinSi
      FinSi
    FinSi

    // Imprime características y valores
    // Verifica si se imprime la leyenda 
    Si !aTextoCaracteristicas
      vImprime = @Substr(lTextoCaracteristicas;0;14)[C0]
      // Enciende bandera de que el texto ya fue impreso
      aTextoCaracteristicas = 1
    FinSi
    vImprime = @Col(lValoresCaracteristicas;0)[C2]
   


   // Si atProducto(cControlExistencia) <= 3 // modificacion hva defecto 528
   // lepc se retira

       vImprime = @Col(aExistencia;0)[C6]
  //  FinSi

    //lepc
    //Si !pTipoReporte
        //lepc
        Si atProducto(cControlExistencia) = 2 O atProducto(cControlExistencia) = 3 O atProducto(cControlExistencia) = 6 O atProducto(cControlExistencia) = 10 O atProducto(cControlExistencia) = 14 O atProducto(cControlExistencia) = 18 O atProducto(cControlExistencia) = 30 O atProducto(cControlExistencia) = 26 O atProducto(cControlExistencia) = 27 O atProducto(cControlExistencia) = 11 O atProducto(cControlExistencia) = 19  O atProducto(cControlExistencia) = 22// defecto 528
          //lepc si trae pedimento y lote no suma el pedimento porque sino se duplica
          Si atProducto(cControlExistencia) = 26 O atProducto(cControlExistencia) = 27 //O atProducto(cControlExistencia) = 30 =es serie
            vImprime = ''[C6]
            vImprime = ''[C8]
            vImprime = ''[C10]
          sino
            //Si !pTipoReporte
            //se brica los  cl clu cp
            Si  atProducto(cControlExistencia) = 18 O atProducto(cControlExistencia) = 19 O atProducto(cControlExistencia) = 10 
              vImprime = ''[C6]
              vImprime = ''[C8]
              vImprime = ''[C10]
            sino
              // solo si es caracteristica
              // si aPrimeravez =0 y atProducto(cControlExistencia) = 2
              //   vImprime = ''[C6]
              //   vImprime = ''[C8]
              //   vImprime = ''[C10]
              // sino
              Si !pTipoReporte
                vImprime = @Col(aInventario;0)[C8]
                lDiferencia = @Col(aExistencia;0) - @Col(aInventario;0) [c0]
                vImprime = @Col(lDiferencia;0)[C10]
              sino
                vImprime = ''[C8]
                vImprime = ''[C10]
              finsi
                //finsi 
            finsi
            //sino
              //validacion para no imprimir nada en proforma e invfis
              //   vImprime = ''[C8]
              //   vImprime = ''[C10]
            //finsi 
          finsi
        finSi
    //FinSi
  
    Lista vImprime


    Si pTipoReporte = 1 Y atProducto(cControlExistencia) <= 3  // modificacion hva defecto 528
      Texto C8;'@L{8}'
      Texto C10;'@L{10}'
      Texto C12;'@L{12}'
      Texto C14;'@L{14}'
      Imprime
    FinSi   
  FinSi

FinFunc


// *****************************************************************************
//  fImprimeAlmacen
//
//  Esta función imprime los datos del Almacén
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeAlmacen(atAlmacen: Tabla)
Local vImprime, lCodigoEditado

  vImprime = ' '[C0..C10]

  SaltaLin
  NEGRITAS TRUE

  vImprime = 'Almacén: '[C0]
  lCodigoEditado = fMascarilla(atAlmacen(cCodigoAlmacen); gMascarillaAlmacen)
  vImprime = @Col(lCodigoEditado;0)[C2]
  Lista vImprime
  
  vImprime = 'Nombre: '[C0]
  vImprime = atAlmacen(cNombreAlmacen)[C2]
  Lista vImprime
  
  NEGRITAS FALSE

  SaltaLin
FinFunc

// *****************************************************************************
//  fImprimeTotales
//
//  Esta función imprime los totales por producto.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeTotales(aExistencia; aInventario; aTexto; aGranTotal)
Local vImprime, lDiferencia, lSubRaya

  Si !aGranTotal
    Texto C6;'@L{6}'
    Si pTipoReporte != 2
      Texto C8;'@L{8}'
      Texto C10;'@L{10}'
    FinSi
    Imprime
  FinSi
  
  vImprime = ' '[C0..C10]
  vImprime = @Col(aTexto;0)[C2]
  vImprime = @Col(aExistencia;0)[C6]
  Si !pTipoReporte
    vImprime = @Col(aInventario;0)[C8]
    lDiferencia = aExistencia - aInventario
    vImprime = @Col(lDiferencia;0)[C10]
  FinSi

  Si aGranTotal
    lSubRaya = ''
    lSubRaya = '================='[C6]
    Si pTipoReporte != 2
      lSubRaya = '================='[C6,C8,C10]
    FinSi
    Imprime lSubRaya
  FinSi
  Lista vImprime

  Saltalin
 
FinFunc
// *****************************************************************************
//  fImprimeSeries
//
//  Esta función imprime las Series
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeSeries(aSerie1; aSerie2)
Local vImprime


  Columnas 5;2.09,0.15,4.48,0.15,4.48
  vImprime = ' '[C0..C5]
  vImprime = @col(aSerie1;0)[C2]
  Si pTipoReporte = 1 O pTipoReporte = 0 // //hva agregue el reporte de inv vs exist = 0
    vImprime = @col(aSerie2;0)[C4]
  FinSi
  Lista vImprime
  Si pTipoReporte < 2
    Texto C2;'@L{2}'
    Texto C4;'@L{4}'
    Imprime
  FinSi
  Si pTipoReporte = 0
    Columnas 16;2.09,0.15,7.62,0.15,0.45,0.15,2.09,0.15,2.09,0.15,2.09,0.15,3.00 //N.D.4455
  FinSi
  Si pTipoReporte = 1
    Columnas 15;2.09,0.15,7.62,0.15,0.45,0.15,2.09,0.15,1.49,0.15,1.20,0.15,1.20,0.15,1.50
  FinSi
  Si pTipoReporte = 2
    Columnas 11;4.62,0.15,7.62,0.15,0.45,0.15,2.09,0.15,2.09,0.0,0.0
  FinSi

FinFunc
// *****************************************************************************
//  fImprimeCapa
//
//  Esta función imprime los pedimentos o lotes
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeCapa(aCapa; aExistencia; aInventario)
Local vImprime, lDiferencia

  vImprime = ' '[C0..C10]
  vImprime = @Col(aCapa;0)[C2]
  vImprime = @Col(aExistencia;0)[C6]
  Si !pTipoReporte
    vImprime = @Col(aInventario;0)[C8]
    lDiferencia = aExistencia - aInventario
    vImprime = @Col(lDiferencia;0)[C10]    
  FinSi

  Lista vImprime

  Si pTipoReporte = 1
    Texto C8;'@L{8}'
    Texto C10;'@L{10}'
    Texto C12;'@L{12}'
    Texto C14;'@L{14}'
    Imprime
  FinSi 

FinFunc
// *****************************************************************************
//  fConvierteUnidad
//
//  Salidas 
// *****************************************************************************
DefFunc fConvierteUnidad(aUnidad;atProducto:tabla)
local  lUnidad
   lUnidad = aUnidad

   Si pUnidad = 2  Y atProducto(cidUnidadBase) != 0
     //el Producto tiene Unidad de Medida y Peso
     //  Unificar vCantidad de acuerdo a la unidad deseada en el reporte.
     //  EquivalenciaUnidadMedidayPeso.BUSCA[Productos(cIdUnidadBase)+cIdUnidad]  
     tEquivalencia.busca[@str(atProducto(cIdUnidadBase);0) &':'& @str(pIdUnidad;0)]
     Si tEquivalencia->encontro
       lUnidad = lUnidad * tEquivalencia(cFactorConversion)
       lsihubocambio =1
     Finsi
   Finsi
   Retorna lUnidad
FinFunc

// *****************************************************************************
//  fProcesaCapa
//
//  Esta función calcula las existencias y el inventario para un producto
//  con lotes o pedimentos
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fProcesaCapa(atCapa:Tabla; atInventario:Tabla; atProducto:Tabla; aIdAlmacen; aTipo)
  Local lInventario, lExistencia
  Local lTotalInventario, lTotalExistencia
  Local lValor
  lInventario = 0.00
  lExistencia = 0.00  
  lTotalInventario = 0.00
  lTotalExistencia = 0.00

  Si aTipo = 'L'
    Lista 'Lotes Existencia'[C2]
  SiNo  
    Si aTipo = 'P'
      Lista 'Pedimentos Existencia'[C2]
    SiNo
      Lista 'Pedimentos y Lotes Existencia'[C2]
    FinSi
  FinSi
  
  Mientras [atCapa.Busca[@str(atProducto(cIdProducto);0) & ':' & @str(aIdAlmacen;0)]; atCapa->Encontro; atCapa.Busca Siguiente[2]]
	Si aTipo = 'L'
      Si atCapa(cTipoCapa) != 3 y atCapa(cTipoCapa) != 4
        Continua
      FinSi
      lValor = atCapa(cNumeroLote)
    SiNo
      Si aTipo = 'P'
        Si atCapa(cTipoCapa) != 2 y atCapa(cTipoCapa) != 4
          Continua
        FinSi
        lValor = atCapa(cPedimento)
      SiNo
        lValor = atCapa(cPedimento) & '  --  ' & atCapa(cNumeroLote)
      FinSi
    FinSi
	lExistencia = fConvierteUnidad(atCapa(cExistencia) ;tProducto)
	// acumula al total
    lTotalExistencia   = lTotalExistencia + lExistencia
	
	Si pTipoReporte = 0
	//  capas capturadas en el inventario físico
		Mientras [atInventario.Busca[ @str(aIdAlmacen;0)];atInventario->Encontro;atInventario.Busca Siguiente[1]]
			Si atInventario(cIdCapa) = atCapa(cIdCapa)
				lInventario = fConvierteUnidad(atInventario(cCantidad) ;tProducto)
				lTotalInventario = lTotalInventario + lInventario
				FinCiclo
			FinSi
		FinMientras
    FinSi
	
	//FImprimeCapa(lValor; lExistencia; lInventario)
    Si pTipoReporte = 1 O pImprimirProductos = 0 // Proforma o imprimir todas las capas
      FImprimeCapa(lValor; lExistencia; lInventario)
    SiNo // Existencia por Almacen
      Si lExistencia > 0 //imprimir productos solo con existencia
        FImprimeCapa(lValor; lExistencia; lInventario)
      FinSi
    FinSi
	
	lInventario = 0.00
	lExistencia = 0.00  
  FinMientras
  
    // Imprime los totales del producto
  fImprimeTotales(lTotalExistencia; lTotalInventario;'^Total producto:'; 0)
  saltalin

FinFunc

// *****************************************************************************
//  fProcesaNormal
//
//  Esta función calcula las existencias y el inventario para un producto
//  sin series, lotes, pedimentos o caracteristicas
//  Parámetros 
//
//  Salidas 
// *****************************************************************************

DefFunc fProcesaNormal(atProducto:Tabla; atInventario:Tabla; aIdAlmacen)
Local lExistencia, lInventario

  //!N.D.3682 lExistencia = fExistenciaInicialProducto(atProducto(cIdProducto); aIdAlmacen; gFechaCorteMasUnDia; gIdEjercicio; gPeriodo; pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia)[c0]
  // N.D.3682 Utilizar fExistenciaProducto para obtener la existencia a la fecha indicada (Incluye los movtos de dicho dia)
  lExistencia = fExistenciaProducto(atProducto(cIdProducto); aIdAlmacen; gFechaFinHistoria; pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia; tEjercicio)[c0]
  // N.D.2725 Inicio
  gExistenciaProducto = lExistencia
  // N.D.2725 Fin
  gExistenciaAlmacen = gExistenciaAlmacen + @col(lExistencia;0)
  gExistenciaReporte = gExistenciaReporte + @col(lExistencia;0)
  Si pTipoReporte
    fImprimeDatoProducto(atProducto; @col(lExistencia;0); ''; 2)
    Retorna         
  FinSi
  atInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(atProducto(cIdProducto);0)]
  Si atInventario->Encontro
    lInventario = fUnidades(pUnidad; atProducto(cIdUnidadBase); pIdUnidad; atInventario; tEquivalencia)[c0]
    gInventarioAlmacen = gInventarioAlmacen + @col(lInventario;0)
    gInventarioReporte = gInventarioReporte + @col(lInventario;0)
 FinSi
 fImprimeDatoProducto(atProducto; @col(lExistencia;0); @col(lInventario;0); 1)
FinFunc

// *****************************************************************************
//  fProcesaProducto
//
//  Esta función procesa el reporte de inventario vs existencias
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fProcesaProducto(aIdAlmacen; atProducto:Tabla; atInventario:Tabla)
  Local lInventario, lExistencia, lImprimirNormal
  Local lTextoCaracteristicas, lTotalExistencia, lTotalInventario
  Local lSerieInventario
  Local lControlExist
  Local lSeriesDisponibles      // N.D.2725
  Local lSeriesHuerfanasEntrada // N.D.2725

  // Si el producto es normal o tiene series imprime el renglon completo
  Si atProducto(cControlExistencia) = 1 O atProducto(cControlExistencia) = 0 O atProducto(cControlExistencia) = 4 O atProducto(cControlExistencia) = 20 O atProducto(cControlExistencia) = 12 O atProducto(cControlExistencia) = 28
    fProcesaNormal(atProducto; atInventario; aIdAlmacen)

    // N.D.2725
    lSeriesDisponibles[0] = 0

    // Imprime Series
    Si pSeries Y atProducto(cControlExistencia) != 0 Y atProducto(cControlExistencia) != 1
      // Inventario Físico y Proforma.
      Si pTipoReporte = 0 O pTipoReporte = 1
        FImprimeSeries('Series en Existencia'; 'Series en Inventario')
      FinSi

      // Existencia por Almacén.
      Si pTipoReporte = 2
        lControlExist = atProducto(cControlExistencia)
        
        Si lControlExist = 4
          fImprimeSeriesRepExistencias( 'Series en existencia'; ''; '' )
        FinSi
        
        Si lControlExist = 12
          fImprimeSeriesRepExistencias( 'Series en existencia'; 'Pedimento'; '' )
        FinSi
        
        Si lControlExist = 20
          fImprimeSeriesRepExistencias( 'Series en existencia'; ''; 'Número de Lote' )
        FinSi
        
        Si lControlExist = 28
          fImprimeSeriesRepExistencias( 'Series en existencia'; 'Pedimento'; 'Número de Lote' )
        FinSi
      FinSi

      // Imprime las series disponibles y si están capturadas en el inventario
      Mientras [ tSerie.Busca[@str(atProducto(cIdProducto);0) & ':' & @str(aIdAlmacen;0)]; tSerie->Encontro; tSerie.Busca Siguiente[2]]
        lSerieInventario = ''
        Si !pTipoReporte
          tSerieInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(atProducto(cIdProducto);0) & ':' & tSerie(cNumeroSerie)]
          Si tSerieInventario->Encontro
            lSerieInventario = tSerieInventario(cNumeroSerie)
            // El número de serie ya no esta disponible, pero se capturó en el inventario
            Si tSerie(cEstado) != 1 Y tSerie(cEstado) != 2 Y tSerie(cEstado) != 8
              FImprimeSeries(''; tSerieInventario(cNumeroSerie))
              Continua
            FinSi
          FinSi
        FinSi
        // Si el numero de serie está disponible imprimelo
        // N.D.2725 Considerar las series huerfanas-consignadas como disponibles
        Si tSerie(cEstado) = 1 O tSerie(cEstado) = 2 O tSerie(cEstado) = 8 O tSerie(cEstado) = 5
          // Inventario Físico y Proforma.
          Si pTipoReporte = 0 O pTipoReporte = 1
            FImprimeSeries(tSerie(cNumeroSerie); lSerieInventario)
          FinSi
          // Existencia por Almacén.
          Si pTipoReporte = 2
            fImprimeSeriesRepExistencias( tSerie(cNumeroSerie); tSerie(cPedimento); tSerie(cNumeroLote) )
            // N.D.2725
            lSeriesDisponibles[C0] = @Col(lSeriesDisponibles;0) + 1
          FinSi         
        FinSi
      FinMientras

      Si !pTipoReporte
        // Imprime las series capturadas en el inventario físico que no estan disponibles
        Mientras [ tSerieInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(atProducto(cIdProducto);0)]; tSerieInventario->Encontro; tSerieInventario.Busca Siguiente[2]]  
          tSerie.Busca[@str(atProducto(cIdProducto);0) & ':' & @str(aIdAlmacen;0) & ':' & tSerieInventario(cNumeroSerie)]
          Si !tSerie->Encontro
            FImprimeSeries(''; tSerieInventario(cNumeroSerie))
          FinSi
        FinMientras
      FinSi

      // N.D.2725 Inicio
      Si pTipoReporte = 2 Y atProducto(cErrorCosto) = 4
        lSeriesHuerfanasEntrada = @Col(lSeriesDisponibles;0) - gExistenciaProducto
        Si gExistenciaProducto > @Col(lSeriesDisponibles;0) 
          fImprimeInformacionSeries('Series huerfanas vendidas en otro almacén:'; lSeriesHuerfanasEntrada)
        FinSi
        Si gExistenciaProducto < @Col(lSeriesDisponibles;0)
          fImprimeInformacionSeries('Series huerfanas con entrada en otro almacén:'; lSeriesHuerfanasEntrada)
        FinSi
        gExistenciaAlmacen = gExistenciaAlmacen + @col(lSeriesHuerfanasEntrada;0)
        gExistenciaReporte = gExistenciaReporte + @col(lSeriesHuerfanasEntrada;0)
      FinSi
      // N.D.2725 Fin
    FinSi

    Saltalin // salta una línea para separarlo del producto siguiente hva
  SiNo
    // Si el producto tiene caracteristicas
    // Si atProducto(cControlExistencia) = 2 O atProducto(cControlExistencia) = 3 
    // inicia modificado hva
//lista atProducto(cControlExistencia)
    Si atProducto(cControlExistencia) = 2 O atProducto(cControlExistencia) = 3 O atProducto(cControlExistencia) = 6 O atProducto(cControlExistencia) = 10 O atProducto(cControlExistencia) = 14 O atProducto(cControlExistencia) = 18 O atProducto(cControlExistencia) = 30 O atProducto(cControlExistencia) = 26 O atProducto(cControlExistencia) = 27 O atProducto(cControlExistencia) = 11 O atProducto(cControlExistencia) = 19  O atProducto(cControlExistencia) = 22// defecto 528

    // termina modificado hva
      Si !pCaracteristicas
        fProcesaNormal(atProducto; atInventario; aIdAlmacen)
        Saltalin // salta una línea para separarlo del producto siguiente hva
      SiNo
        fProcesaNormal(atProducto; atInventario; aIdAlmacen)
//        fImprimeDatoProducto(atProducto; 0; 0; 0)
        // No se ha impreso el texto de las caracteristicas
        lTextoCaracteristicas = 0
        lTotalExistencia = 0
        lTotalInventario = 0
        Primeravez = 0
        // Recorre los detalles de características
        Mientras [ tDetalleProducto.Busca[@Str(atProducto(cIdProducto);0)]; tDetalleProducto->Encontro; tDetalleProducto.Busca Siguiente[1] ]
          //!N.D.3682 lExistencia = fExistenciaInicialProducto(tDetalleProducto(cIdProducto); aIdAlmacen; gFechaCorteMasUnDia; gIdEjercicio; gPeriodo; pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia)[c0]
          // N.D.3682 Utilizar fExistenciaProducto para obtener la existencia a la fecha indicada (Incluye los movtos de dicho dia)
          lExistencia = fExistenciaProducto(tDetalleProducto(cIdProducto); aIdAlmacen; gFechaFinHistoria; pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia; tEjercicio)[c0]
          lTotalExistencia = lTotalExistencia + @col(lExistencia;0)
        
//          gExistenciaAlmacen = gExistenciaAlmacen + lExistencia
//          gExistenciaReporte = gExistenciaReporte + lExistencia
          Si pTipoReporte
            // Imprime la combinación de caracterísicas de ese producto
            // N.D. 2591 CILA Inicio -------------------------------------------
            //fImprimeCaracteristicas(tDetalleProducto; 1; @col(lExistencia;0); ''; &lTextoCaracteristicas; atProducto;1)
            Si pTipoReporte = 1 O pImprimirProductos = 0 // Proforma o imprimir todas las capas
              fImprimeCaracteristicas(tDetalleProducto; 1; @col(lExistencia;0); ''; &lTextoCaracteristicas; atProducto;1)
            SiNo // existencias por almacen o solo con existencia
              Si lExistencia > 0 //imprimir productos solo con existencia
                fImprimeCaracteristicas(tDetalleProducto; 1; @col(lExistencia;0); ''; &lTextoCaracteristicas; atProducto;1)
              FinSi
            FinSi
            // N.D. 2591 CILA Fin ----------------------------------------------
          SiNo
            //  Continua se lo quite hva
            atInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(tDetalleProducto(cIdProducto);0)]
            Si atInventario->Encontro
              lInventario = fUnidades(pUnidad; atProducto(cIdUnidadBase); pIdUnidad; atInventario; tEquivalencia)
            SiNo
              lInventario =0.00
            FinSi
            // Imprime la combinación de caracterísicas de ese producto
            fImprimeCaracteristicas(tDetalleProducto; 1; @col(lExistencia;0); lInventario; &lTextoCaracteristicas; atProducto;Primeravez)
            Primeravez = 1
            // acumula al total
            lTotalInventario = lTotalInventario + lInventario
            //gInventarioAlmacen = gInventarioAlmacen + lInventario
            //gInventarioReporte = gInventarioReporte + lInventario
          FinSi
        
          // inicia modificado hva
          // si el producto tiene series imprimirlas
          Si atProducto(cControlExistencia) = 6 O atProducto(cControlExistencia) = 14 O atProducto(cControlExistencia) = 30 O atProducto(cControlExistencia) = 22
            gExistenciaAlmacen = gExistenciaAlmacen + @col(lExistencia;0)
            gExistenciaReporte = gExistenciaReporte + @col(lExistencia;0)
            FImprimeSeries('Series Existencia'; 'Series Inventario')
          
            // Imprime las series disponibles y si están capturadas en el inventario
            Mientras [ tSerie.Busca[@str(tDetalleProducto(cIdProducto);0) & ':' & @str(aIdAlmacen;0)]; tSerie->Encontro; tSerie.Busca Siguiente[2]]  
              lSerieInventario = ''
              Si !pTipoReporte
                tSerieInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(tDetalleProducto(cIdProducto);0) & ':' & tSerie(cNumeroSerie)]
                Si tSerieInventario->Encontro
                  lSerieInventario = tSerieInventario(cNumeroSerie)
                  // El número de serie ya no esta disponible, pero se capturó en el inventario
                  Si tSerie(cEstado) != 1 Y tSerie(cEstado) != 2
                    FImprimeSeries(''; tSerieInventario(cNumeroSerie))
                    Continua
                  FinSi
                FinSi
              FinSi
              // Si el numero de serie está disponible imprimelo
              Si tSerie(cEstado) = 1 O tSerie(cEstado) = 2 
                FImprimeSeries(tSerie(cNumeroSerie); lSerieInventario)
              FinSi
            FinMientras
            Si !pTipoReporte
              // Imprime las series capturadas en el inventario físico que no estan disponibles
              Mientras [ tSerieInventario.Busca[@str(aIdAlmacen;0) & ':' & @str(tDetalleProducto(cIdProducto);0)]; tSerieInventario->Encontro; tSerieInventario.Busca Siguiente[2]]  
                // buscar la serie capturada en el inventario fisico en la tabla de series
                tSerie.Busca[@str(tDetalleProducto(cIdProducto);0) & ':' & @str(aIdAlmacen;0) & ':' & tSerieInventario(cNumeroSerie)]
                Si !tSerie->Encontro
                  FImprimeSeries(''; tSerieInventario(cNumeroSerie))
                FinSi
              FinMientras
            FinSi
          FinSi
         
          Si atProducto(cControlExistencia) = 18 O atProducto(cControlExistencia) = 10 O atProducto(cControlExistencia) = 26 O atProducto(cControlExistencia) = 27 O atProducto(cControlExistencia) = 19 // modificacion hva defecto 528
            Si atProducto(cControlExistencia) = 18 O atProducto(cControlExistencia) = 19 // modificacion defecto 528 hva
              fProcesaCapa(tCapaLote; tLoteInventario; tDetalleProducto; aIdAlmacen; 'L')
            Sino
              fProcesaCapa(tCapaPedimento; tPedimentoInventario; tDetalleProducto; aIdAlmacen; 'P')
            FinSi
          FinSi
          // termina modificado hva
      
        FinMientras

        // Imprime los totales del producto
        fImprimeTotales(lTotalExistencia; lTotalInventario; '^Total producto:'; 0)
        Saltalin // salta una línea para separarlo del producto siguiente
      FinSi
  
    SiNo

      // Si el producto tiene lotes o Pedimentos
      // N.D.2357 Inicio -------------------------------------------------------
      //Si !pLotes o !pPedimentos
      Si !pLotes y !pPedimentos
      // N.D.2357 Fin ----------------------------------------------------------
        fProcesaNormal(atProducto; atInventario; aIdAlmacen)
        Saltalin // salta una línea para separarlo del producto siguiente hva
      SiNo
//      fImprimeDatoProducto(atProducto; 0; 0; 0)
        fProcesaNormal(atProducto; atInventario; aIdAlmacen)

        Si ( atProducto(cControlExistencia) = 16 o atProducto(cControlExistencia) = 17 ) y pLotes // Lotes
          fProcesaCapa(tCapaLote; tLoteInventario; atProducto; aIdAlmacen; 'L')
        SiNo // Pedimentos
          // N.D.2357 Inicio ---------------------------------------------------
          //fProcesaCapa(tCapaPedimento; tPedimentoInventario; atProducto; aIdAlmacen; 'P')
          
          Si ( atProducto(cControlExistencia) = 8 o atProducto(cControlExistencia) = 9 ) y pPedimentos // Pedimentos
            fProcesaCapa(tCapaPedimento; tPedimentoInventario; atProducto; aIdAlmacen; 'P')
          SiNo
            Si atProducto(cControlExistencia) = 24 o atProducto(cControlExistencia) = 25  y pPedimentos // Pedimentos
              Si pLotes = 1 y pPedimentos = 0 
	              fProcesaCapa(tCapaLote; tLoteInventario; atProducto; aIdAlmacen; 'L') // Lotes
	            SiNo
	              Si pLotes = 0 y pPedimentos = 1 
	                fProcesaCapa(tCapaPedimento; tPedimentoInventario; atProducto; aIdAlmacen; 'P') // Pedimentos
                SiNo
                  fProcesaCapa(tCapaPedimento; tPedimentoInventario; atProducto; aIdAlmacen; 'A') // Ambos
	              FinSi
              FinSi
            FinSi
          FinSi
          // N.D.2357 Fin ------------------------------------------------------
        FinSi
        Saltalin
      FinSi
    FinSi
  FinSi
FinFunc

// *****************************************************************************
//  fVerificaParametros
//
//  Esta función verifica los parámetros pProductoInicial, pProductoFinal,
//  pAlmacenInicial y pAlmacenFinal.
//  Si están vacíos toma el primer y último registro de la tabla.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fVerificaParametros()

  // Si el rango inicial es el primer producto, recupera el código del primero
  Si pProductoInicial = ' '
    tProducto.Busca Primero
    Si tProducto->Encontro
      pProductoInicial = tProducto(cCodigoProducto)
    FinSi
  FinSi

  // Si el rango final es el último producto, recupera el código del último
  Si pProductoFinal = ' '
    tProducto.Busca Ultimo
    Si tProducto->Encontro
      pProductoFinal = tProducto(cCodigoProducto)
    FinSi
  FinSi

  // Si el rango inicial es el primer almacén, recupera el código del primero
   Si pAlmacenInicial = ' '
    tAlmacen.Busca Primero
    Si tAlmacen->Encontro
      pAlmacenInicial = tAlmacen(cCodigoAlmacen)
      // Si el almacén inicial es el almacén cero, lee el siguiente
      Si !tAlmacen(cIdAlmacen)
        tAlmacen.Saltareg[1]
        Si tAlmacen->Encontro
          pAlmacenInicial = tAlmacen(cCodigoAlmacen)
        FinSi
      FinSi
    FinSi
  FinSi

  // Si el rango final es el último almacén, recupera el código del último
  Si pAlmacenFinal = ' '
    tAlmacen.Busca Ultimo
    Si tAlmacen->Encontro
      pAlmacenFinal = tAlmacen(cCodigoAlmacen)
    FinSi
  FinSi

FinFunc


// *****************************************************************************
// Encabezado del reporte

Encab
  Texto '@TC{255,0,0}@S{8}AdminPAQ'
  Hoja '"@TC{0,0,0}@S{8}Hoja: '
  Imprime
  Texto '"@TC{0,0,0}@S{8}Fecha: ' & fFormateaFecha(@Hoy();gIdioma)
  Imprime

  Texto '^@TC{0,0,0}@S{22}' & tEmpresa->Nombre
  Imprime

  Si pTipoReporte = 0
     Texto '^@TC{0,0,0}@S{16}INVENTARIO FISICO VS EXISTENCIAS'
  FinSi
  Si pTipoReporte = 1
    Texto '^@TC{0,0,0}@S{16}PROFORMA DE INVENTARIO FISICO'
  FinSi
  Si pTipoReporte = 2
    Texto '^@TC{0,0,0}@S{16}EXISTENCIAS'
  FinSi
  Imprime

  // Se Revisan las clasificaciones, para recuperarlas e imprimirlas en el encabezado
  fRevisaClases(tValoresDeClasif)
  Saltalin

  NEGRITAS TRUE
  Texto '@TC{0,0,0}@L{-1}'
  Imprime
  Si pTipoReporte = 0
    Texto C0;'Código'
     Texto C2;'Nombre (Producto)'
     Texto C6;'^Existencia*'
    Texto C8;'^Inventario'
    Texto C10;'^Diferencia'
    Texto C12;'Movimiento Sugerido'  //N.D.4455
  FinSi
  Si pTipoReporte = 1
    Texto C8;'^Conteo'
    Texto C14;'^Existencia'
    Imprime
    Texto C0;'Código'
    Texto C2;'Nombre (Producto)'
    Texto C6;'^Existencia*'
    Texto C8;'^Final'
    Texto C10;'^Entradas'
    Texto C12;'^Salidas'
    Texto C14;'^Real'
  FinSi
  Si pTipoReporte = 2
    Texto C0;'Código'
    Texto C2;'Nombre (Producto)'
    Texto C6;'^Existencia*'
    // EOD - SC 150 En los reportes de existencias se usa una columna extra 
    // para mostrar si hay error de existencias o costos
    Texto C8;'Error'
    // FIN EOD - SC 150
  FinSi
    
  Imprime
  Texto '@TC{0,0,0}@L{-1}'
  Imprime 1
  NEGRITAS FALSE

  Color @RGB(0;0;0)
  Altura 9
FinEncab


// *****************************************************************************
// Cuerpo del reporte

// Configura los decimales del reporte
fConfiguraDecimales()

// Verifica el rango de productos del reporte
fVerificaParametros()

// A partir de la fecha de corte del reporte, obtiene el ejercicio y periodo correspondiente
// esto es util para el cálculo de la existencia del reporte
// Debido a que se utilizará la función de librería para cálculo de existencia inicial,
// se suma un día a la fecha de corte
fIniFechasHistoria(tEjercicio)
fEjercicioPeriodo(gFechaFinHistoria; &gPeriodo; &gIdEjercicio; tEjercicio) 
gFechaCorteMasUnDia = fFechaSiguiente(gFechaFinHistoria)

gExistenciaGeneral = 0.00
gInventarioGeneral = 0.00
gImprimeTotal  = 0

// Obtiene los almacenes en el rango especificado en los parámetros del reporte
Mientras [ tAlmacen.Busca[pAlmacenInicial & '..' & pAlmacenFinal]; tAlmacen->Encontro; tAlmacen.Busca Siguiente[1] ]
  gImprimeTotal  = 0
  lImprimeAlmacen = 1
  gExistenciaAlmacen = 0.00
  gInventarioAlmacen = 0.00

  // Obtiene los productos en el rango especificado en los parámetros del reporte
  Mientras [ tProducto.Busca[pProductoInicial & '..' & pProductoFinal]; tProducto->Encontro; tProducto.Busca Siguiente[1] ]

    // Solo busca productos, descarta paquetes y servicios
    Si tProducto(cTipoProducto) != 1
      Continua
    FinSi

    // Verifica si el producto cumple con las clasificaciones especificadas 
    Si gNumDeClases > 0
      Si !fMiembroDeUnaClase(tProducto; gNumDeClases; gListIdDeClases; 2)
        // Discrimina el producto por no pertenecer a alguna de las clasificaciones
        Continua
      FinSi
    FinSi

    // Verifica el parámetro de imprimir productos (todos o solo con captura de inventario
    Si pTipoReporte = 0  // Inventario físico vs existencia actual
      Si pImprimirProductos
        tInventario.Busca[@str(tAlmacen(cIdAlmacen);0) & ':' & @str(tProducto(cIdProducto);0)]
        Si !tInventario->Encontro
          Continua
        FinSi
      SiNo  // Imprime sólo aquellos productos que tengan existencias congeladas
        tExistencia.Busca[@str(tProducto(cIdProducto);0) & ':' & @str(gIdEjercicio;0) & ':' & @str(tAlmacen(cIdAlmacen);0) & ':1']
        Si !tExistencia->Encontro O tExistencia(cBanCongelado) != 1
          Continua
        FinSi  
      FinSi
    FinSi

    Si pTipoReporte = 1 Y pImprimirProductos // Proforma
      tExistencia.Busca[@str(tProducto(cIdProducto);0) & ':' & @str(gIdEjercicio;0) & ':' & @str(tAlmacen(cIdAlmacen);0) ]
      Si tExistencia->Encontro 
        Si pTipoReporte = 1 Y tExistencia(cBanCongelado) != 1
          Continua
        FinSi
      SiNo
        Continua
      FinSi
    FinSi

    // RPC - ND 946 Para revisar si un producto tiene existencias se revisa la 
    // existencia del producto a la fecha final de la historia
    Si pTipoReporte = 2 Y pImprimirProductos  // Existencia por almacén
      //!N.D.3682 lExistencia = fExistenciaInicialProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); gFechaCorteMasUnDia; gIdEjercicio; gPeriodo; 0; tProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia)[C0]
      // N.D.3682 Utilizar fExistenciaProducto para obtener la existencia a la fecha indicada (Incluye los movtos de dicho dia)
      lExistencia = fExistenciaProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); gFechaFinHistoria; 0; tProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia; tEjercicio)[C0]
      Si lExistencia = 0
        Continua
      FinSi
    FinSi
    
    Si lImprimeAlmacen
      fImprimeAlmacen(tAlmacen)
      lImprimeAlmacen = 0
    FinSi

    // Verifica parámetro pUnidad
    fVerificaUnidad(tProducto)
    fProcesaProducto(tAlmacen(cIdAlmacen);tProducto;tInventario)
    gImprimeTotal = 1

  FinMientras
  // Se imprimen totales por almacén solo en el caso de que se hayan impreso productos
  Si gImprimeTotal
    fImprimeTotales(gExistenciaAlmacen; gInventarioAlmacen;'^Total almacén:';0)
  FinSi

FinMientras

fImprimeTotales(gExistenciaReporte; gInventarioReporte;'^Total general:'; 1)

Saltalin
Texto ' * Nota: Las Existencias corresponden a todos los movimientos registrados (entradas y salidas)'
Imprime

// EOD - SC 150 Inicio
Si pTipoReporte = 2 // Reporte de Existencias
  Columnas 4;0.14,19.0,0.0
  Saltalin
  Lista '', 'Errores de existencias o costos:'[C1]
  Lista '', ' (1) Captura en desorden de entradas'[C1]
  Lista '', ' (2) Captura en desorden de salidas'[C1]
  Lista '', ' (3) Existencias negativas'[C1]
  Lista '', ' (4) Series sin movimiento de entrada'[C1]
  Lista '', ' (5) Series sin costo'[C1]
  Lista '', ' (6) Movimientos sin afectar'[C1]
  Lista '', ' (7) En proceso de levantamiento de inventario físico'[C1]
  Saltalin
  Lista '', 'En caso de captura en desorden de entradas se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
  Lista '', 'En caso de captura en desorden de salidas se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
  Lista '', 'En caso de existencias Negativas se recomienda registrar las entradas necesarias y ejecutar el proceso "Recosteo" para los productos con errores'[C1]
  Lista '', 'En caso de series sin movimiento de entrada la existencia puede no coincidir con las series desplegadas, se recomienda registrar la entrada de las series pendientes'[C1]
  Lista '', 'En caso de series sin costo se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
  Lista '', 'En caso de movimientos sin afectar se recomienda consultar el reporte "Movimientos sin Afectar"'[C1]
  Lista '', 'En caso de inventario físico se recomienda aplicar el inventario físico'[C1]
Finsi
// EOD - SC 150 Final

