// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//
//  ExistAlmacen.rpt
//  Nombre del reporte en el sistema: Inventario Actual del Almacén por 
//                                    Producto en Excel
//
//  Sistema: AdminPAQ v1.1 
// 
//  Este reporte perteneciente al módulo de inventarios, despliega el 
//  inventario inicial, movimientos de entrada y salida, así como el 
//  inventario final por productos agrupados por almacén tanto en unidades 
//  como en importes. Este reporte sustituye al reporte de existencias por 
//  periodo de Megapaq
//
//  Elaboró:    Ricardo Paláu Castañeda basado en el reporte RelEntSal
//  Fecha:      11 de Febrero del 2003
//
//  Modificacion:    HVA
//  Fecha:      09 de Marzo del 2005 ND 3138
//  Modificacion:    HVA 
//  Fecha:      04 de Octubre del 2005 ND 3472 (Parametro solo con existencias)
//  Modificacion Hva ND 3527 16/11/2005 Es muy lento el reporte en un rango de fechas amplio
//  Fecha       N.D.  Autor   Descripción
//  16/11/2005  3010  LAP     Nuevo esquema de búsquedas parciales para agilizar los reportes
//                            - fProcesaPorAlmacen
// 23/02/2006   HVA     N.D.3868    Se duplican los costos cuando el producto tiene unidadades no convertibles.
// 05/02/2008   JENL    N.D.5062    ERROR TARDA 6 MINUTOS AL MOMENTO DE CONVERTIR UN PEDIDO EN FACTURA
//                                  Se modifico:
//                                  -fProcesaPorAlmacen
// 03/12/2008   ELVS    N.C.224     Se deben considerar los movimientos que están con el 
//                                  campo cAfectadoInventario = 2, se agrega marca y leyenda
//                                  de que esos movimientos están en captura.
// 05/03/2009   ELVS    N.D.4738    ERROR IMPORTES INCORRECTOS EN EL REPORTE INVENTARIO ACTUAL DEL ALMACEN
//                                  POR PRODUCTO(EN EXCEL) CUANDO SE MANEJA MONEDA DOLARES Y EN EL RANGO DE
//                                  FECHAS NO SE INCLUYE LA FECHA DE CREACION DEL DOCUMENTO.
//  19/03/2009  ELVS    N.D.5725    REPORTES DE INVENTARIO En Excel - CUANDO EL PRODUCTO ESTA EN CAPTURA,
//                                  Aparece -8 cargado a las derecha en el reporte Inventario actual del
//                                  almacen por producto se espera que aparezca entre parentesis (8).
//  03/04/2009  ELVS    N.D.5724    REPORTES DE INVENTARIO En Excel - CUANDO EL PRODUCTO ESTA EN CAPTURA
//                                  Hace falta el nombre de la columna "Error"  Rep de Diario de ventas
//                                  detallado /compras detallado,  inventario actual por alm/ global en importes.
//	01/07/2009  MAJU		N.D.4538		ERROR SE MUESTRAN CANTIDADES INCORRECTAS A PARTIR DE UN PRODUCTO QUE NO TIENE 
//  																LA MISMA UNIDAD NO EQUIVALENTE  QUE EL RESTO CUANDO SE PIDE EL REPORTE POR 
//																	UNIDAD NO EQUIVALENTE  AL GENERAR EL REPORTE INVENTARIO ACTUAL DEL ALMACEN 
//																	POR PRODUCTO (EXCEL) Se modifica: Cuerpo del reporte.
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

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

Incluye LibAdminPAQ.Rpt
Incluye LibInventarios.Rpt


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

Parametro pFechaInicial = '20030101'    // Fecha inicial del rango
Parametro pFechaFinal = '20031231'      // Fecha final del rango
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 = Con Movimientos o existencias
Parametro pCosto = 0                    // Método de Costeo:
                                        // 0 = Definido por el producto
                                        // 1 = Costo Promedio (Global)
                                        // 2 = Costo Promedio (Por Almacén)
                                        // 3 = Ultimo Costo (Global)
                                        // 4 = Ultimo Costo (Por Almacén)
Parametro pEstadoProducto = 0           // Incluir productos con estado:
                                        // 0 = Todos
                                        // 1 = Activos
                                        // 2 = Inactivos
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)
Parametro pIdUnidad = 2                 // 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 pIdMoneda = 1                 // Id de la moneda a expresar el reporte

// *****************************************************************************
//  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 tDocumento = tEmpresa['MGW10008']        // Documentos
tDocumento.Usaindice['']                          // Indice primario: cIdDocumento

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

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

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

UsaTabla tEjercicio = tEmpresa['MGW10031']        // Ejercicios
tEjercicio.Usaindice['cNumeroEjercicio']          // cNumeroEjercicio

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

UsaTabla tCostoHistorico = tEmpresa['MGW10017']   // Costo histórico
tCostoHistorico.Usaindice['iProdAlmacenFecha']    // cIdProducto+cIdAlmacen+cFechaCostoH+cTipoCosto

UsaTabla tMoneda = tEmpresa['MGW10034']           // Monedas
tMoneda.Usaindice['']                             // Indice primario: cIdMoneda

UsaTabla tTipoCambio = tEmpresa['MGW10035']       // Tipo de cambio
tTipoCambio.Usaindice['iMonedaFecha']             // cIdMoneda+cFecha

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 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

Columnas 27;1

Usaletra 'Arial'
Altura 9
[C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15].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
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
gTotalInventario = 0.0
gTotalEntradas = 0.0
gTotalSalidas = 0.0
gTotalImporteInventario = 0.0
gTotalImporteEntradas = 0.0
gTotalImporteSalidas = 0.0
gTotalImporteCalculado = 0.0
vImprime = ''


// *************************************
// Definicion de constantes de EXCEL
// *************************************
constante xlCentrarEnSeleccion   7
constante xlAutomatico          -4105
constante xlManual              -4135
constante xlInferior            -4107
constante xlSubrayadoDoble      -4119
constante xlIzquierda           -4131
constante xlMediano             -4138
constante xlNinguno             -4142
constante xlDerecha             -4152
constante xlSuperior            -4160
constante xlHojaCalculo         -4167
constante xlLineaSimple          1
constante xlBordeSuperior        8
constante xlBordeInferior        9
constante xlBordeIzquierda       7
constante xlBordeDerecha         10
constante xlCentro              -4108

// *************************************
// Inicializa EXCEL
// *************************************
// Accesa objetos de excel. Crea un objeto de Excel con la funcion @CreaObjeto(). A esta funcion
// se le pasa un identificador de OLE de la aplicacion que se desea crear. En este caso el identificador
// es Excel.Application.5
Objeto Excel = @CreaObjeto('Excel.Application')

// Invoca el metodo de EXCEL Libros y luego el metodo Agregar para crear un libro de hoja de calculo
// representado por la constante de EXCEL (xlHojaCalculo).
// Es importante notar que estos metodos NO LOS EJECUTA EL REPORTEADOR sino que los hace EXCEL
// y estan documentados en el Help de EXCEL
Objeto wb = Excel.WorkBooks.Add(xlHojaCalculo)

// Accesa la hoja de calculo (HojasCalculo) numero 1 del Libro creado anteriormente
// y representado por la variable wb, de la instruccion anterior
Objeto ws = wb.Worksheets(1)

// Hace visible a EXCEL. Para Excel, TRUE o VERDADERO es -1, FALSE o FALSO es 0
Excel.ActiveWindow.DisplayGridlines = FALSE[C0]
Excel.Visible = -1[C0]

RenActual = 1

// Pone la longitud de cada columna
ws.Columns(1).ColumnWidth  =  1[C0]
ws.Columns(2).ColumnWidth  = 20[C0]
ws.Columns(3).ColumnWidth  = 35[C0]
ws.Columns(4).ColumnWidth  = 15[C0]
ws.Columns(5).ColumnWidth  =  6[C0]
ws.Columns(6).ColumnWidth  = 15[C0]
ws.Columns(7).ColumnWidth  = 15[C0]
ws.Columns(8).ColumnWidth  = 15[C0]
ws.Columns(9).ColumnWidth  = 15[C0]
ws.Columns(10).ColumnWidth = 15[C0]
ws.Columns(11).ColumnWidth = 15[C0]
ws.Columns(12).ColumnWidth = 15[C0]
ws.Columns(13).ColumnWidth = 15[C0]
ws.Columns(14).ColumnWidth = 15[C0]
ws.Columns(15).ColumnWidth = 15[C0]
ws.Columns(16).ColumnWidth =  5[C0]
ws.Columns(17).ColumnWidth =  5[C0] //N.D.5724


// *****************************************************************************
//  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()
Local lDigDecimales, lDecs, lFormato

  lDigsDecimales = '0000000000'

  // Busca el registro de la empresa
  tParametros.Busca Primero
  Si tParametros->Encontro // Si lo encontró
    lDecs = @SUBSTR(lDigsDecimales;1;tParametros(cDecimalesUnidades))
    lFormato = '#,##0.' & lDecs & '_);(#,##0.' & lDecs & ')'
    ws.Columns(6).NumberFormat = lFormato[C0]
    ws.Columns(7).NumberFormat = lFormato[C0]
    ws.Columns(8).NumberFormat = lFormato[C0]
    ws.Columns(9).NumberFormat = lFormato[C0]

    lDecs = @SUBSTR(lDigsDecimales;1;tParametros(cDecimalesCostos))
    lFormato = '#,##0.' & lDecs & '_);(#,##0.' & lDecs & ')'
    ws.Columns(10).NumberFormat = lFormato[C0]
    ws.Columns(11).NumberFormat = lFormato[C0]
    ws.Columns(12).NumberFormat = lFormato[C0]
    ws.Columns(13).NumberFormat = lFormato[C0]
    ws.Columns(14).NumberFormat = lFormato[C0]
    ws.Columns(15).NumberFormat = lFormato[C0]

    gMascarillaAlmacen =  tParametros(cMascarillaAlmacen)     // Mascarilla para el código del almacen
    gMascarillaProducto = tParametros(cMascarillaProducto)    // Mascarilla para el código del cliente/proveedor
  Sino // Si no encontró el registro de la empresa
    [C7,C9,C11,C13].Decimales 2
    ws.Columns(6).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(7).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(8).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(9).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(10).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(11).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(12).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(13).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(14).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
    ws.Columns(15).NumberFormat = '#,##0.00_);(#,##0.00)'[C0]
  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 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(cCodigoAlmacen)
        tAlmacen.Saltareg[1]
        Si tAlmacen->Encontro
          pAlmacenInicial = tAlmacen(cCodigoAlmacen)
        FinSi
      FinSi  // Si el almacén inicial es el almacén cero
    FinSi  // Si se encontró el primer qalmacén
  FinSi  // Si el almacén inicial esta vacío

  // 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

  // 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
FinFunc


// *****************************************************************************
//  fImprimeDatosAlmacen
//
//  Esta función imprime los datos del almacén para el reporte por almacén.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeDatosAlmacen(atAlmacen: Tabla)
Local lCodigoEditado

  // Avanza de renglon
  RenActual = RenActual + 1[C0]
  ws.Range('B' & RenActual & ':D' & RenActual).Font.FontStyle = 'Negrita'[C0]
  ws.Range('B' & RenActual ).Value = 'Almacén:'[C0]
  lCodigoEditado = fMascarilla(atAlmacen(cCodigoAlmacen); gMascarillaAlmacen)
  ws.Range('C' & RenActual ).Value = @Chr(39) & @Col(lCodigoEditado;0)[C0]
  
  // Avanza de renglon
  RenActual = RenActual + 1[C0]
  ws.Range('B' & RenActual & ':D' & RenActual).Font.FontStyle = 'Negrita'[C0]
  ws.Range('B' & RenActual ).Value = 'Nombre:'[C0]
  ws.Range('C' & RenActual ).Value = @Chr(39) & atAlmacen(cNombreAlmacen)[C0]
FinFunc


// *****************************************************************************
//  fImprimeProducto
//
//  Esta función imprime los datos y la existencia de un producto 
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeProducto(atProducto: Tabla; aInvInicial; aEntradas; aSalidas; aImporteInicial; aImporteEntradas; aImporteSalidas; aUltCosto; aCostoCalculado )
Local lCodigoEditado, lInvFinal, lFechaSinAfectar

  // Avanza de renglon
  RenActual = RenActual + 1[C0]
  //N.D.5724 Junta la columna M y N para poner los Errores.
  ws.Range('B' & RenActual & ':O' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
  ws.Range('B' & RenActual & ':O' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]
  ws.Range('B' & RenActual & ':O' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
  ws.Range('B' & RenActual & ':O' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
  ws.Range('B' & RenActual & ':O' & RenActual).Font.FontStyle = 'Negrita'[C0]    
  ws.Range('P' & RenActual & ':O' & RenActual).HorizontalAlignment = xlCentro[C0]
  
  //N.D.5724 Junta la columna M y N para poner los Errores.
  // Pone el titulo de cada columna en EXCEL
  ws.Range('P' & RenActual & ':Q' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
  ws.Range('P' & RenActual & ':Q' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]     
  ws.Range('P' & RenActual & ':Q' & RenActual).Font.FontStyle = 'Negrita'[C0]      
  ws.Range('P' & RenActual & ':Q' & RenActual).HorizontalAlignment = xlDerecha[C0]
  ws.Range('P' & RenActual & ':Q' & RenActual).HorizontalAlignment = xlCentro[C0]
  ws.Range('Q' & RenActual & ':Q' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]


  vImprime = ''[C0..C26]

  lCodigoEditado = fMascarilla(atProducto(cCodigoProducto); gMascarillaProducto)
  ws.Range('B' & RenActual ).Value = @Chr(39) & @Col(lCodigoEditado;0)[C0]
  ws.Range('C' & RenActual ).Value = @Chr(39) & atProducto(cNombreProducto)[C0]
  
  Escoge atProducto(cMetodoCosteo)
    Caso 1
      vImprime = 'Costo Promedio'[C1]
    FinCaso
    Caso 2
      vImprime = 'Costo Promedio por Almacén'[C1]
    FinCaso
    Caso 3
      vImprime = 'Ultimo Costo'[C1]
    FinCaso
    Caso 4
      vImprime = 'UEPS'[C1]
    FinCaso
    Caso 5
      vImprime = 'PEPS'[C1]
    FinCaso
    Caso 6
      vImprime = 'Costo Específico'[C1]
    FinCaso
    Caso 7
      vImprime = 'Costo Estándar'[C1]
    FinCaso
  FinEscoge
  ws.Range('D' & RenActual ).Value = @COL(vImprime;1)[C0]

  // 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]
      ws.Range('E' & RenActual ).Value = @COL(vImprime;4)[C0]
    FinSi
  FinSi

  vImprime = @Col(aInvInicial;0)[C6]
  vImprime = @Col(aEntradas;0)[C8]
  vImprime = @Col(aSalidas;0)[C10]
  // calcula el inventario final
  lInvFinal = aInvInicial + aEntradas - aSalidas
  vImprime = @Col(lInvFinal;0)[C12]

  ws.Range('F' & RenActual ).Value = @COL(vImprime;6)[C0]
  ws.Range('G' & RenActual ).Value = @COL(vImprime;8)[C0]
  ws.Range('H' & RenActual ).Value = @COL(vImprime;10)[C0]
  ws.Range('I' & RenActual ).Value = @COL(vImprime;12)[C0]

  vImprime = @Col(aImporteInicial;0)[C14]
  vImprime = @Col(aImporteEntradas;0)[C16]
  vImprime = @Col(aImporteSalidas;0)[C18]
  // calcula el inventario final
  lImporteFinal = aImporteInicial + aImporteEntradas - aImporteSalidas
  vImprime = @Col(lImporteFinal;0)[C20]

  ws.Range('J' & RenActual ).Value = @COL(vImprime;14)[C0]
  ws.Range('K' & RenActual ).Value = @COL(vImprime;16)[C0]
  ws.Range('L' & RenActual ).Value = @COL(vImprime;18)[C0]
  ws.Range('M' & RenActual ).Value = @COL(vImprime;20)[C0]

  vImprime = @Col(aUltCosto;0)[C22]
  vImprime = @Col(aCostoCalculado;0)[C24]

  ws.Range('N' & RenActual ).Value = @COL(vImprime;22)[C0]
  ws.Range('O' & RenActual ).Value = @COL(vImprime;24)[C0]

  // Verificar si el producto tiene algún error y sí es así desplegar el error.
  // Verificar si hay existencias congeladas
  // N.D. 8675 Es necesario enviar como parametro el Id del almacen "tAlmacen(cIdAlmacen)" en ves de el valor de 0, para que dentro de la función 
  // se verifiquen sólo las existencias para ese IdAlmacen
  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)'[C25]
    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)& ')'[C25]
  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)'[C25]
  FinSi

  ws.Range('P' & RenActual ).Value = @Chr(39) & @COL(vImprime;25)[C0]
  
  //N.C.224
  Si gTieneMovtosEnCaptura = 1
    vImprime = '(8)'[C25] //N.D.5725
    ws.Range('Q' & RenActual).Value = @Chr(39) & @COL(vImprime;25)[C0] 	
  FinSi
FinFunc


// *****************************************************************************
//  fImprimeTotales
//
//  Esta función imprime los totales generales del reporte.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeTotales(aInvInicial; aEntradas; aSalidas; aImporteInicial; aImporteEntradas; aImporteSalidas; aCostoCalculado)

  // Avanza de renglon
  RenActual = RenActual + 1[C0]
  ws.Range('F' & RenActual & ':M' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0] 
  ws.Range('F' & RenActual & ':M' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
  ws.Range('F' & RenActual & ':M' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
  ws.Range('F' & RenActual & ':M' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
  ws.Range('D' & RenActual & ':O' & RenActual).Font.FontStyle = 'Negrita'[C0]

  ws.Range('E' & RenActual).Value = 'Total:'[C0]

  ws.Range('F' & RenActual).Value = @Col(aInvInicial;0)[C0]
  ws.Range('G' & RenActual).Value = @Col(aEntradas;0)[C0]
  ws.Range('H' & RenActual).Value = @Col(aSalidas;0)[C0]
  ws.Range('I' & RenActual).Value = @Col(aInvInicial;0) + @Col(aEntradas;0) - @Col(aSalidas;0)[C0]

  ws.Range('J' & RenActual).Value = @Col(aImporteInicial;0)[C0]
  ws.Range('K' & RenActual).Value = @Col(aImporteEntradas;0)[C0]
  ws.Range('L' & RenActual).Value = @Col(aImporteSalidas;0)[C0]
  ws.Range('M' & RenActual).Value = @Col(aImporteInicial;0) + @Col(aImporteEntradas;0) - @Col(aImporteSalidas;0)[C0]

  ws.Range('O' & RenActual & ':O' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0] 
  ws.Range('O' & RenActual & ':O' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
  ws.Range('O' & RenActual & ':O' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
  ws.Range('O' & RenActual & ':O' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]

  ws.Range('O' & RenActual).Value = @Col(aCostoCalculado;0)[C0]

  // Avanza de renglon
  RenActual = RenActual + 1[C0]
FinFunc


// *****************************************************************************
//  fCancelado    
//
//  Verifca si el movto es de un docto cancelado, 
//
//  Parámetros 
//
//  Salidas 1 = cancelado, 0 = no cancelado
// *****************************************************************************
Deffunc fCancelado(atMovimiento:Tabla)
  local lValorRegreso, lIdDocumento

  // lee el documento del movimiento
  Si atMovimiento(cIdDocumento)
    tDocumento.Busca[@Str(atMovimiento(cIdDocumento);0)]
  Sino // es un movimiento oculto
    // Busca el ID del documento en el movimiento owner
    lIdDocumento = fIdDocumentoMovtoOwner(atMovimiento; tMovtoOwner) 
    tDocumento.Busca[@Str(lIdDocumento;0)]
  FinSi
  lvalorregreso = 1 // cancelado en caso de no encontrar el docto.
  Si tDocumento->Encontro
    lvalorregreso =  tDocumento(cCancelado)    // Regresa el estado del campo
  Finsi

  Retorna lValorRegreso
FinFunc


//--------------------------------------------------------------------------------
// Nombre:  fProcesaPorAlmacen
// Proceso: Esta función procesa el reporte de stock máximo por almacén.

// Entradas:
// Salidas:

// Consideraciones:

//  Historia de Revisiones:
//  Fecha         Autor     ID-Lotus        Descripción
//--------------------------------------------------------------------------------
//  05/02/2008    JENL      N.D.5062        Se cambio el indice iProductoAlmacenFechaAfec por iProductoAlmacenAfecFecha
//--------------------------------------------------------------------------------
DefFunc fProcesaPorAlmacen(atProducto: Tabla)
Local lInvInicial, lEntradas, lSalidas 
Local lImporteInicial, lImporteEntradas, lImporteSalidas
Local lUltCosto, lCostoCalculado
Local lTotalInvInicial, lTotalEntradas, lTotalSalidas
Local lTotalImporteInicial, lTotalImporteEntradas, lTotalImporteSalidas, lTotalCostoCalculado
Local lFecha, lUnidades, lCosto, lTotal, lIdAlmacen, lAlMenosUno

  // Inicia los acumulados por almacén
  lTotalInvInicial      = 0.0
  lTotalEntradas        = 0.0
  lTotalSalidas         = 0.0
  lTotalImporteInicial  = 0.0 
  lTotalImporteEntradas = 0.0 
  lTotalImporteSalidas  = 0.0 
  lTotalCostoCalculado  = 0.0
  
  // Obtiene los productos en el rango especificado en los parámetros del reporte
  Mientras[atProducto.Busca[pProductoInicial & '..' & pProductoFinal]; atProducto->Encontro; atProducto.Busca Siguiente[1]] 
    // Solo busca productos, descarta paquetes y servicios
    Si atProducto(cTipoProducto) != 1
      Continua
    FinSi
  
    // Verifica si el producto es candidato a imprimirse en función de su estado
    // tProducto(cStatusProducto) = 0 (Inactivo)
    // tProducto(cStatusProducto) = 1 (Activo)
    Si pEstadoProducto y pEstadoProducto != @Abs(atProducto(cStatusProducto) - 2)
      Continua
    FinSi
  
    // Verifica si el producto cumple con las clasificaciones especificadas 
    Si gNumDeClases > 0
      Si !fMiembroDeUnaClase(atProducto; gNumDeClases; gListIdDeClases; 2)
        // Discrimina el producto por no pertenecer a alguna de las clasificaciones
        Continua
      FinSi
    FinSi
  
    // Verifica parámetro pUnidad
    //N.D.4538 (MAJU)
    //Al elegir como filtro “Unidad no equivalente” Si uno de los productos a mostrar 
    //no tiene asignada Unidad No Equivalente no se mostrara en el reporte.
  	Si pUnidad = 1 y atProducto(cIdUnidadNoConvertible) = 0
   		Continua
   	Sino
      fVerificaUnidad(atProducto)
    FinSi

    // Inicia acumulados por producto
    lEntradas        = 0.00
    lSalidas         = 0.00
    lImporteEntradas = 0.00 
    lImporteSalidas  = 0.00 

    lAlMenosUno = False

    // Encuentra el inventario inicial del producto en ese almacén
    // Establece el indice necesario para la rutina de inventario inicial
    tMovimiento.Usaindice['iProductoFechaAfecta'] // cIdProducto+cFecha+cAfectaExistencia
    lInvInicial     = fExistenciaInicialProducto(atProducto(cIdProducto); tAlmacen(cIdAlmacen); pFechaInicial; gIdEjercicio; gPeriodo; pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia)
    // Si el costo es por producto y su método es Estándar se calcula en base a las unidades y el valor del costo estándar en el producto
    Si pCosto = 0 Y atProducto(cMetodoCosteo) = 7
    	//N.D.4738
    	//Si la moneda del reporte es moneda extranjera
    	Si pIdMoneda != 1
        //Convierte al tipo de cambio más cercano a la fecha final que recibe como parámetro
				//en caso de no encontrar alguno, regresa el valor de 1.00				
    		lImporteInicial = lInvInicial * fConvierteTipoCambio(atProducto(cCostoEstandar); 1; pIdMoneda; pFechaFinal; tTipoCambio)    		    		
    	Sino
    	  lImporteInicial = lInvInicial * atProducto(cCostoEstandar)
    	FinSi 
    	//Fin N.D.4738 
    SiNo
      lImporteInicial = fCostoInicialProducto(atProducto(cIdProducto); tAlmacen(cIdAlmacen); pFechaInicial; gIdEjercicio; gPeriodo; atProducto; tMovimiento; tExistencia; tCostoHistorico; tTipoCambio; pIdMoneda)
    FinSi
   
    // N.D.3010 Inicio
//! // Inicializa la Fecha de inicio del rango de fechas del reporte
//! lFecha = pFechaInicial 
//! // Recorre todas las fechas en el rango de fechas del reporte
//! Mientras lFecha <= pFechaFinal
//!    // Busca el primer movimiento en esa fecha      
//!    // Si encontro al menos un movimiento, sigue buscando otros movimientos en esa misma fecha
//!    Mientras [ tMovimiento.Busca[atProducto(cIdProducto) & ':' & tAlmacen(cIdAlmacen) & ':' & lFecha]; tMovimiento->Encontro; tMovimiento.Busca Siguiente[3] ]
    // Búsqueda de un movimiento del producto a la fecha inicial del reporte
    gFechaBusqueda = pFechaInicial
    // NOTA: Es obligatorio volver a fijar el índice a fin de que las búsquedas parciales funcionen correctamente
    tMovimiento.Usaindice['iProductoAlmacenFechaAfec']
    tMovimiento.Busca[atProducto(cIdProducto) & ':' & tAlmacen(cIdAlmacen) & ':' & gFechaBusqueda]
    Si !tMovimiento->ENCONTRO
      // Busquedas parciales: Cursor en el registro más cercano que cumple con la llave
      // NOTA: La propiedad Llave de la tabla nos regresa la llave más cercana que cumple con el criterio de la búsqueda
      //       La llave está en formato cadena y no tiene ningún separador entre los campos, por lo que es necesario revisar
      //      en FoxPro la definición del índice para descomponer los elementos de la Llave
      // Revisar si la llave actual corresponde al Producto / Almacén y al Rango de Fechas.
      Si atProducto(cIdProducto) = @Val(@SUBSTR(tMovimiento->Llave;0;11))
        Si tAlmacen(cIdAlmacen) = @Val(@SUBSTR(tMovimiento->Llave;11;11))
          Si @SUBSTR(tMovimiento->Llave;22;8) >= pFechaInicial Y @SUBSTR(tMovimiento->Llave;22;8) <= pFechaFinal
            // Realizar nuevamente la búsqueda a fin de posicionarnos en el registro y activar la propiedad Encontro
            gFechaBusqueda = @SUBSTR(tMovimiento->Llave;22;8)
            tMovimiento.Busca[atProducto(cIdProducto) & ':' & tAlmacen(cIdAlmacen) & ':' & gFechaBusqueda]
          FinSi
        FinSi
      FinSi        
    FinSi

    // N.D.3010 Recorrer los movimientos hasta que sea diferente producto, almacén o se rompa el rango de fechas
    Mientras tMovimiento->Encontro Y (tMovimiento(cFecha) <= pFechaFinal)
      // Discrimina los movimientos que no son entradas ni salidas
      Si tMovimiento(cAfectaExistencia) != 1 y tMovimiento(cAfectaExistencia) != 2
        // N.D.3010 Búsqueda del siguiente registro que cumpla con el producto / almacén
        tMovimiento.BUSCA SIGUIENTE[2]
        Continua
      FinSi
  
      //N.C.224
      //Se deben considerar las unidades que afectaron el inventario 
      //aunque todavía no se afecte el costo, esto sucede cuando todavía se tienen 
      //movimientos en captura.      
      // Se verifica si está o no afectado en inventarios 
      Si tMovimiento(cAfectadoInventario) = 0
        // N.D.3010 Búsqueda del siguiente registro que cumpla con el producto / almacén
        tMovimiento.BUSCA SIGUIENTE[2]
        Continua
      FinSi
  
      //N.C.224 Debe marcar con una leyenda el movimiento que está siendo capturado en el momento      
      Si tMovimiento(cAfectadoInventario) = 2
        gTieneMovtosEnCaptura = 1
      FinSi	  
  
      // Descarta los movtos de doctos cancelados
      Si fCancelado(tMovimiento)
        // N.D.3010 Búsqueda del siguiente registro que cumpla con el producto / almacén
        tMovimiento.BUSCA SIGUIENTE[2]
        Continua
      Finsi
  
      lUnidades = fUnidades(pUnidad; atProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tEquivalencia)
      lIdAlmacen = 0
      Si pCosto = 2 o pCosto = 4  // Costo Promedio por almacén o último costo
        lIdAlmacen = tMovimiento(cIdAlmacen)
      FinSi
      Si pCosto = 0 
        lCosto = fCostoMovimiento(atProducto; tMovimiento; tCostoHistorico; tTipoCambio; pIdMoneda)
      Sino
        Si pCosto = 1 o pCosto = 2 // Costo promedio
          lCosto = fCostoHistorico(atProducto(cIdProducto);lIdAlmacen;lFecha;1;tCostoHistorico;tTipoCambio;pIdMoneda)
        Sino // Ultimo costo
          lCosto = fCostoHistorico(atProducto(cIdProducto);lIdAlmacen;lFecha;3;tCostoHistorico;tTipoCambio;pIdMoneda)
        FinSi
        lCosto = lCosto * tMovimiento(cUnidades)
      FinSi     
  
      Si tMovimiento(cAfectaExistencia) = 1 // Es una entrada?
        lEntradas        = lEntradas + lUnidades
        lImporteEntradas = lImporteEntradas + lCosto
      Sino
        lSalidas        = lSalidas + lUnidades
        lImporteSalidas = lImporteSalidas + lCosto
      FinSi
      lAlMenosUno = True
      
      // N.D.3010 Búsqueda del siguiente registro que cumpla con el producto / almacén
      tMovimiento.BUSCA SIGUIENTE[2]
    FinMientras
//!   FinMientras // Hay Movimientos del día
//!   // Incrementa un día a la fecha
//!   lFecha = fFechaSiguiente(lFecha)
//! FinMientras // lFecha <= pFechaFinal
    // N.D.3010 Fin

    // Calcular el costo total del almacén a último costo
    lUltCosto = fCostoHistorico(atProducto(cIdProducto);lIdAlmacen;pFechaFinal;3;tCostoHistorico;tTipoCambio;pIdMoneda)
    lCostoCalculado = lUltCosto * (lInvInicial + lEntradas - lSalidas)

    // Si se imprimen todos los productos
    lEncontrado = 0 // bandera para saber si se cumplio alguna condicion y sumar o no al final
    Si pImprimirProductos = 0
      lEncontrado = 1
      fImprimeProducto(atProducto; lInvInicial; lEntradas; lSalidas; lImporteInicial; lImporteEntradas; lImporteSalidas; lUltCosto; lCostoCalculado)
    FinSi

    // Si se imprimen sólo productos con existencias o con movimientos 
    Si pImprimirProductos = 1 Y ( @Col(lInvInicial;0) != 0 O lAlMenosUno ) Y !lDatosProducto
      // Imprime los datos del producto
      lEncontrado = 1
      fImprimeProducto(atProducto; lInvInicial; lEntradas; lSalidas; lImporteInicial; lImporteEntradas; lImporteSalidas; lUltCosto; lCostoCalculado)
    FinSi

    Si pImprimirProductos = 2 Y ( @Col(lInvInicial;0) + lEntradas - lSalidas > 0 ) Y !lDatosProducto //solo con existencias
      // Imprime los datos del producto
      lEncontrado = 1
      fImprimeProducto(atProducto; lInvInicial; lEntradas; lSalidas; lImporteInicial; lImporteEntradas; lImporteSalidas; lUltCosto; lCostoCalculado)
    FinSi

    Si pImprimirProductos = 3 Y ( lAlMenosUno ) Y !lDatosProducto
      // Imprime los datos del producto
      lEncontrado = 1
      fImprimeProducto(atProducto; lInvInicial; lEntradas; lSalidas; lImporteInicial; lImporteEntradas; lImporteSalidas; lUltCosto; lCostoCalculado)
    FinSi

    Si lEncontrado = 1
      // acumula al total del producto
      lTotalInvInicial = lTotalInvInicial + lInvInicial
      lTotalEntradas   = lTotalEntradas   + lEntradas
      lTotalSalidas    = lTotalSalidas    + lSalidas

      lTotalImporteInicial  = lTotalImporteInicial  + lImporteInicial
      lTotalImporteEntradas = lTotalImporteEntradas + lImporteEntradas  
      lTotalImporteSalidas  = lTotalImporteSalidas  + lImporteSalidas  
      lTotalCostoCalculado  = lTotalCostoCalculado  + lCostoCalculado 
    FinSi
    
    //N.C.224
    gTieneMovtosEnCaptura = 0
  FinMientras // Hay productos

  // Imprime el total del almacén
  fImprimeTotales(lTotalInvInicial; lTotalEntradas; lTotalSalidas; lTotalImporteInicial; lTotalImporteEntradas; lTotalImporteSalidas; lTotalCostoCalculado)

  // Actualiza totales generales
  gTotalInventario = gTotalInventario + lTotalInvInicial
  gTotalEntradas   = gTotalEntradas   + lTotalEntradas
  gTotalSalidas    = gTotalSalidas    + lTotalSalidas

  gTotalImporteInventario = gTotalImporteInventario + lTotalImporteInicial 
  gTotalImporteEntradas   = gTotalImporteEntradas   + lTotalImporteEntradas
  gTotalImporteSalidas    = gTotalImporteSalidas    + lTotalImporteSalidas 
  gTotalImporteCalculado  = gTotalImporteCalculado  + lTotalCostoCalculado 
FinFunc  // fProcesaPorAlmacen


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

Encab
    // Pone el nombre del sistema
    ws.Range('A' & RenActual).Font.Color = @RGB(255;0;0)[C0]
    ws.Range('A' & RenActual).Font.Size = 10[C0]
    ws.Range('A' & RenActual).Value = 'AdminPAQ'[C0]

    // Pone el nombre de la empresa
    ws.Range('C' & RenActual).Font.Size = 14[C0]
    ws.Range('C' & RenActual).Font.FontStyle = 'Negrita'[C0]
    // Lo centra en las columnas C a la N
    ws.Range('C' & RenActual & ':N' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]
    ws.Range('C' & RenActual ).Value = tEmpresa->Nombre

    // Avanza de renglon
    RenActual = RenActual + 1[C0]

    // Pone el titulo del reporte en EXCEL
    ws.Range('A' & RenActual).Font.Size = 12[C0]
    ws.Range('A' & RenActual).Font.FontStyle = 'Negrita'[C0]
    ws.Range('A' & RenActual ).Value = 'I N V E N T A R I O  A C T U A L  D E L  A L M A C E N  P O R  P R O D U C T O'[C0]
    // Lo centra en las columnas A a la P
    ws.Range('A' & RenActual & ':P' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]

    // Avanza de renglon
    RenActual = RenActual + 1[C0]
    ws.Range('A' & RenActual).Font.Size = 12[C0]
    ws.Range('A' & RenActual).Font.FontStyle = 'Negrita'[C0]
    Si pCosto = 0
      ws.Range('A' & RenActual ).Value = '(COSTO DEFINIDO POR EL PRODUCTO)'[C0]
    FinSi
    Si pCosto = 1
      ws.Range('A' & RenActual ).Value = '(COSTO PROMEDIO GLOBAL)'[C0]
    FinSi
    Si pCosto = 2
      ws.Range('A' & RenActual ).Value = '(COSTO PROMEDIO POR ALMACEN)'[C0]
    FinSi
    Si pCosto = 3
      ws.Range('A' & RenActual ).Value = '(ULTIMO COSTO GLOBAL)'[C0]
    FinSi
    Si pCosto = 4
      ws.Range('A' & RenActual ).Value = '(ULTIMO COSTO POR ALMACEN)'[C0]
    FinSi
    // Lo centra en las columnas A a la P
    ws.Range('A' & RenActual & ':P' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]

    // Avanza de renglon
    RenActual = RenActual + 1[C0]

    // Pone el titulo del reporte en EXCEL
    ws.Range('A' & RenActual).Font.Size = 12[C0]
    ws.Range('A' & RenActual).Font.FontStyle = 'Negrita'[C0]    
    ws.Range('A' & RenActual ).Value = 'Del: ' & fFormateaFecha(pFechaInicial;gIdioma) & ' Al: ' & fFormateaFecha(pFechaFinal;gIdioma)[C0]
    // Lo centra en las columnas A a la P
    ws.Range('A' & RenActual & ':P' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]

    // Avanza de renglon
    RenActual = RenActual + 1[C0]

    // Se Revisan las clasificaciones, para recuperarlas e imprimirlas en el encabezado
    // ===== se arman los ID en una LIsta para poder recorrerlos en una iteración
    gClasesRecibidas = fCuentaClases(&gNumClasesPorTipo;pIdClase1;pIdClase2;pIdClase3;pIdClase4;pIdClase5;pIdClase6)
    // se cargan las clasificaciones validas y se obtiene el número de clases validas
    gNumDeClases = fCargaClases(tValoresDeClasif;&gListNombreDeClases; &gListIdDeClases; gClasesRecibidas)

    tMoneda.Busca[@Str(pIdMoneda;0)]
    Si tMoneda->Encontro
      ws.Range('N' & RenActual ).Value = 'Moneda: ' & tMoneda(cNombreMoneda)[C0]
    FinSi

    // Avanza de renglon
    RenActual = RenActual + 1[C0]

    // Pone los titulos de Unidades 
    ws.Range('F' & RenActual & ':I' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]
    ws.Range('F' & RenActual & ':I' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
    ws.Range('F' & RenActual & ':I' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]
    ws.Range('F' & RenActual & ':I' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
    ws.Range('F' & RenActual & ':I' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
    ws.Range('F' & RenActual & ':I' & RenActual).Interior.ColorIndex = 3[C0]    
    ws.Range('F' & RenActual).Font.Color = @RGB(255;255;255)[C0]
    ws.Range('F' & RenActual).Font.FontStyle = 'Negrita'[C0]    
    ws.Range('F' & RenActual ).Value = 'EN UNIDADES'[C0]

    // Pone los titulos de Importes
    ws.Range('J' & RenActual & ':M' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]
    ws.Range('J' & RenActual & ':M' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
    ws.Range('J' & RenActual & ':M' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]
    ws.Range('J' & RenActual & ':M' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
    ws.Range('J' & RenActual & ':M' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
    ws.Range('J' & RenActual & ':M' & RenActual).Interior.ColorIndex = 3[C0]    
    ws.Range('J' & RenActual).Font.Color = @RGB(255;255;255)[C0]
    ws.Range('J' & RenActual).Font.FontStyle = 'Negrita'[C0]    
    ws.Range('J' & RenActual ).Value = 'EN IMPORTES'[C0]

    // Pone los titulos de Revaluación
    ws.Range('N' & RenActual & ':O' & RenActual).HorizontalAlignment = xlCentrarEnSeleccion[C0]
    ws.Range('N' & RenActual & ':O' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
    ws.Range('N' & RenActual & ':O' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]
    ws.Range('N' & RenActual & ':O' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
    ws.Range('N' & RenActual & ':O' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
    ws.Range('N' & RenActual & ':O' & RenActual).Interior.ColorIndex = 3[C0]    
    ws.Range('N' & RenActual).Font.Color = @RGB(255;255;255)[C0]
    ws.Range('N' & RenActual).Font.FontStyle = 'Negrita'[C0]    
    ws.Range('N' & RenActual ).Value = 'REVALUACION'[C0]

    // Avanza de renglon
    RenActual = RenActual + 1[C0]

    //N.D.5724 Junta la columna M y N para poner los Errores.
    // Pone el titulo de cada columna en EXCEL
    ws.Range('A' & RenActual & ':O' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
    ws.Range('A' & RenActual & ':O' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]
    ws.Range('A' & RenActual & ':O' & RenActual).Borders(xlIzquierda).LineStyle = xlLineaSimple[C0]
    ws.Range('A' & RenActual & ':O' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
    ws.Range('A' & RenActual & ':Q' & RenActual).Interior.ColorIndex = 55[C0]    
    ws.Range('A' & RenActual & ':Q' & RenActual).Font.FontStyle = 'Negrita'[C0]    
    ws.Range('A' & RenActual & ':Q' & RenActual).Font.Color = @RGB(255;255;255)[C0]
    
    //N.D.5724 Junta la columna M y N para poner los Errores.
    // Pone el titulo de cada columna en EXCEL
    ws.Range('P' & RenActual & ':Q' & RenActual).Borders(xlInferior).LineStyle = xlLineaSimple[C0]
    ws.Range('P' & RenActual & ':Q' & RenActual).Borders(xlSuperior).LineStyle = xlLineaSimple[C0]     
    ws.Range('P' & RenActual & ':Q' & RenActual).Font.FontStyle = 'Negrita'[C0]      
    ws.Range('P' & RenActual & ':Q' & RenActual).HorizontalAlignment = xlDerecha[C0]
    ws.Range('P' & RenActual & ':Q' & RenActual).HorizontalAlignment = xlCentro[C0]
    ws.Range('Q' & RenActual & ':Q' & RenActual).Borders(xlDerecha).LineStyle = xlLineaSimple[C0]
		
    ws.Range('F' & RenActual & ':O' & RenActual).HorizontalAlignment = xlDerecha[C0]
    ws.Range('A' & RenActual & ':P' & RenActual).Value = '','Código Producto','Nombre Producto','Costeo','','Inventario Inicial','Entradas','Salidas','Existencia','Inventario Inicial','Entradas','Salidas','Costo Total','Ultimo Costo', 'Total Ult. Costo', 'Error'
   
    Excel.Rows('8:8').Select
    Excel.ActiveWindow.FreezePanes = True
    ws.Range('A' & RenActual).Select
FinEncab


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

// Inicializa valores globales para la biblioteca LibAdminPAQ.rpt
fIniFechasHistoria(tEjercicio)

// Configura los decimales del reporte
fConfiguraDecimales()

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

fEjercicioPeriodo(pFechaInicial; &gPeriodo; &gIdEjercicio; tEjercicio) 

gTotalInventario = 0.0
gTotalEntradas   = 0.0
gTotalSalidas    = 0.0

// Recorre los almacenes en el rango
Mientras [ tAlmacen.Busca[pAlmacenInicial & '..' & pAlmacenFinal]; tAlmacen->Encontro; tAlmacen.Busca Siguiente[1] ]    
  // Imprime los datos del almacén
  fImprimeDatosAlmacen(tAlmacen)

  // Calcular las existencias de cada producto en el almacén
  fProcesaPorAlmacen(tProducto)

FinMientras

fImprimeTotales(gTotalInventario; gTotalEntradas; gTotalSalidas; gTotalImporteInventario; gTotalImporteEntradas; gTotalImporteSalidas; gTotalImporteCalculado)

// Imprime al final la leyenda con los errores de existencias o costos
ws.Range('A' & (RenActual + 2 )).Value = 'Errores de existencias o costos:'
ws.Range('B' & (RenActual + 3 )).Value = '(1)  Captura en desorden de entradas'  
ws.Range('B' & (RenActual + 4 )).Value = '(2)  Captura en desorden de salidas'
ws.Range('B' & (RenActual + 5 )).Value = '(3)  Existencias negativas'
ws.Range('B' & (RenActual + 6 )).Value = '(4)  Series sin movimiento de entrada'[C1]
ws.Range('B' & (RenActual + 7 )).Value = '(5)  Series sin costo'[C1]
ws.Range('B' & (RenActual + 8 )).Value = '(6)  Movimientos sin afectar'[C1]
ws.Range('B' & (RenActual + 9 )).Value = '(7)  En proceso de levantamiento de inventario físico'[C1]
//N.C.224
ws.Range('B' & (RenActual + 10 )).Value = '(8)  Este producto está incluido en algún movimiento que actualmente está en captura, motivo por el cual dicho movimiento solo está afectado en existencia y no en costo'[C1]  

ws.Range('A' & (RenActual + 11 )).Value = 'En caso de captura en desorden de entradas se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
ws.Range('A' & (RenActual + 12 )).Value = 'En caso de captura en desorden de salidas se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
ws.Range('A' & (RenActual + 13 )).Value = 'En caso de existencias Negativas se recomienda registrar las entradas necesarias y ejecutar el proceso "Recosteo" para los productos con errores'[C1]
ws.Range('A' & (RenActual + 14 )).Value = '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]
ws.Range('A' & (RenActual + 15 )).Value = 'En caso de series sin costo se recomienda ejecutar el proceso "Recosteo" para los productos con errores'[C1]
ws.Range('A' & (RenActual + 16 )).Value = 'En caso de movimientos sin afectar se recomienda consultar el reporte "Movimientos sin Afectar"'[C1]
ws.Range('A' & (RenActual + 17 )).Value = 'En caso de inventario físico se recomienda aplicar el inventario físico'[C1]
//N.C.224
ws.Range('A' & (RenActual + 18 )).Value = 'En este caso se recomienda consultar el reporte en cuanto se termine de capturar el documento'[C1]
// Fin Reporte
