// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//
//	ExCostos.rpt
//	Nombre del reporte en el sistema: Existencias y Costos
//
//  Sistema: AdminPAQ v1.1
// 
//	Este reporte perteneciente al módulo de inventarios, despliega un rango
//  de productos así como su existencia y costo a una fecha determinada
//  valuados a costo promedio o último costo.
//
//	Consideraciones especiales:
//  Este reporte aunque está programado como uno solo, representa en realidad
//  dos reportes en el ámbito del sistema, Costo total de acuerdo al costo
//  promedio y Costo total de acuerdo al último costo.
//  
//	Elaboró:    Eduardo Pérez Figueroa
//	Fecha: 	    05 de Agosto del 2001
//
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// Historia de modificaciones
//  Fecha      Nombre   IDLotus                     Descripcion
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// 15/02/2002   Gabriela Cuevas     Se incluyeron totales por existencia
// 15/10/2002   RPC     SC 150      Incluir en los errores de costeo los 
//                                  movimientos sin afectar
//         Arquitectura S.C.216     Adición del filtro de rango de almacenes.
// 31/10/2002   LAP     N.D.1469    Eliminación del mensaje de ** cuando se se
//                                  selecciona el almacen 0 como primer rango
// 09/09/2004   LAP     N.D.2922    Corrección para manejar el costo promedio
//                                  en base a la nueva función de LibInventarios
//                                  - fCostoPromedioProducto
// 21/05/2007   JAAM    N.C.147     Esquema de adicion de unidades de compra y venta  
//  23/04/2009  JENL    N.D.5766    COSTOS INICIALES INCORRECTOS AL EJECUTAR LOS REORTES DE EXISTENCIAS
//                                  Y COSTOS (COSTO PROMEDIO) Y EXISTENCIAS Y COSTOS (ULTIMO COSTO) 
//                                  Se modifico: Cuerpo del reporte
//                                  Se agrego:
//                                  -gPeriodoCorte
//                                  -gIdEjercicioCorte
//	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.
//  11/02/2010  ELVS    N.D.6198    Reportes - ERROR EL REPORTE DE EXISTENCIAS Y COSTOS (COSTO TOTAL DE ACUERDO
//                                  AL COSTO PROMEDIO) NO ACUMULA LAS ENTRADAS DEL  MES DE DICIEMBRE.	
//  09/06/2010  ELVS    N.D.6308    Reportes - ERROR EL REPORTE DE EXISTENCIAS Y COSTOS (COSTO TOTAL DEACUERDO
//                                  AL COSTO PROMEDIO) MUESTRA LA EXISTENCIA INICIAL MAS NO LA EXISTENCIA REAL
//                                  NO TOMA ENCUENTA LOS MOVIMIENTOS DEL DIA. (ELVS)
// 31/08/2010   ELVS    N.D.6343    Reportes - ERROR NO COINCIDE EL COSTO TOTAL DE LA MAYORIA DE LOS PRODUCTOS
//                                  AL EMITIR EL KARDEX CONTRA EL REPORTE DE COSTOS EXISTENCIAS Y COSTOS (COSTO
//                                  TOTAL DE ACUERDO AL COSTO PROMEDIO)
// 20/12/2010   ALRH    N.D.6695    ERROR EL KARDEX Y EL REPORTE D EXISTECIAS Y COSTOS DE ACUERDO AL 
//                                  COSTO PROMEDIO NO COINCIDEN EN DOS PRODUCTOS 
// 08/06/2011   FPP     N.D.7087    Reportes - ERROR NO MUESTRA LAS UNIDADES CORRECTAS DE EQUIVALENCIA AL EJECUTAR
//									EXISTENCIAS Y COSTOS COSTO TOTAL DEACUREDO AL COSTO PROMEDIO CUANDO SE 
//                                  MANEJAN UNIDADES  NO EQUIVALENTES.
// 07/01/2012   ALRH    N.D.7797    ERROR EL REPORTE EXISTENCIAS Y COSTOS (COSTO TOTAL DE ACUERDO AL COSTO PROMEDIO)  
//                                  Y EL REPORTE EXSTENCIAS Y COSTOS (COSTO TOTAL DE ACUERDO AL ULTIMO COSTO)
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


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

Incluye LibAdminPAQ.Rpt
Incluye LibInventarios.Rpt


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

Parametro pFechaCorte = '20011030'      // Fecha de corte o final del reporte
Parametro pProductoInicial = ' '        // Código del producto inicial del rango (' ' = Todos)
Parametro pProductoFinal = ' '          // Código del producto final del rango (' ' = Todos)
// S.C.216 Inicio
Parametro pAlmacenInicial = ' '        
Parametro pAlmacenFinal   = ' '
// S.C.216 Fin
Parametro pImprimirProductos = 0        // Productos a imprimir:
                                        // 0 = Todos
                                        // 1 = Solo productos con existencias 
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 producto (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
Parametro pTipoReporte = 0              // Tipo de Reporte (este parámetro es interno a AdminPAQ)
                                        // 0 = Costo total de acuerdo al costo promedio
                                        // 1 = Costo total de acuerdo al último costo

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

UsaTabla tMovimiento = tEmpresa['MGW10010']       // 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

// S.C.216 Inicio
UsaTabla tAlmacen = tEmpresa['MGW10003']         // Tabla de almacenes
tAlmacen.Usaindice['cCodigoAlmacen']             // Indice: Codigo del almacén
// S.C.216 Fin

// *****************************************************************************
// 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) = 14 caracteres
// C2 (Nombre del producto) = 50 caracteres
// C4 (Costo promedio o último costo) = 15 caracteres
// C6 (Existencia) = 15 caracteres
// C8 (Unidad) = 3 caracteres
// C10 (Costo total) = 15 caracteres
// C12 (Observaciones) = 4 caracteres
Columnas 14;2.09,0.15,7.47,0.15,2.24,0.15,2.24,0.15,0.45,0.15,2.24,0.15,0.60,0.15

Usaletra 'Arial'
Altura 9
[C4,C6,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
gTotalCosto = 0.0         // Costo Total
gCostoPorAlMacen = 0.0    // S.C.216 Costo del almacen
gExistencia = 0           // Existencia del producto
gExistenciaBase = 0       // Existencia del producto en unidades base
gCosto = 0                // Costo del producto
gMascarillaProducto = ''  // Mascarilla para el código del producto
gMascarillaAlmacen = ''   // S.C.216 Mascarilla para el código del almacen
gObservaciones = 0        // Imprimir notas de las observaciones de errores en costos
gPeriodoCorte = 0//N.D.5766
gIdEjercicioCorte = 0//N.D.5766


// =================================================================================================
// Función área sensible al contexto
// =================================================================================================
DefFunc ContextoDetalleProductoAlm(aNumeroColumna; aValor)
    EJECUTA tEmpresa->SysDirDatos & '\Reportes\AdminPAQ\Kardex.RTW';gFechaIniHistoria,pFechaCorte,@Escoge(aValor;0),@Escoge(aValor;0),@Escoge(aValor;1),@Escoge(aValor;1),0,0,@Escoge(aValor;2),@Escoge(aValor;3),pIdClase1,pIdClase2,pIdClase3,pIdClase4,pIdClase5,pIdClase6,1,@Escoge(aValor;2);tEmpresa->Directorio
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ó
		// Decimales para costos
		[C4,C10].Decimales tParametros(cDecimalesCostos) 
		// Decimales para existencias
		[C6].Decimales tParametros(cDecimalesUnidades) 
		// mascarilla para el código del producto
		gMascarillaProducto = tParametros(cMascarillaProducto) 
		// S.C.216 mascarilla para el código del almacen
		gMascarillaAlmacen = tParametros(cMascarillaAlmacen) 
	Sino // Si no encontró el registro de la empresa
		[C4,C6,C10].Decimales 2
	FinSi
FinFunc

// *****************************************************************************
//  fImprimeObservaciones
//
//	Esta función imprime las observaciones de errores en costos en productos.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeObservaciones()
	Si gObservaciones
		// RPC - SC 150 Cambiar las observaciones para que sean iguales al resto de los reportes de inventario
		//    Saltalin
		//    Texto '*** Observaciones de errores en costos'
		//    Imprime
		//    Texto '*** Se recomienda ejecutar el proceso "Recosteo" para los productos con observaciones'
		//    Imprime
		//    Saltalin
		//    Texto '- Caso 1: Captura en desorden de entradas'
		//    Imprime
		//    Texto '- Caso 2: Captura en desorden de salidas'
		//    Imprime
		//    Texto '- Caso 3: Existencias negativas'
		//    Imprime
		//    Texto '- Caso 4: Series huérfanas'
		//    Imprime
		//    Texto '- Caso 5: Series sin costo'
		//    Imprime
		Columnas 14;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]
		// FIN RPC SC - 150    
	FinSi
FinFunc

// *****************************************************************************
//  fImprimeProducto
//
//	Esta función imprime los datos del producto.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeProducto(atProducto: Tabla; aCosto; aExistencia)
	Local vImprime, vCostoTotal, lCodigoEditado
	vImprime = ' '[C0..C13]

	// Codigo y nombre del producto
	lCodigoEditado = fMascarilla(atProducto(cCodigoProducto); gMascarillaProducto)
	vImprime = @Col(lCodigoEditado;0)[C0]
	vImprime = atProducto(cNombreProducto)[C2]

	// Costo
	vImprime = @Col(aCosto;0)[C4]

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

	// 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 equialente, Busca la unidad base
				tUnidad.Busca[@Str(atProducto(cIdUnidadBase);0)]
			FinSi
		FInCaso
	FinEscoge
	Si tUnidad->Encontro y tUnidad(cIdUnidad) != 0 // Encontró el registro de la unidad de medida y peso
		vImprime = tUnidad(cDespliegue)[C8]
	FinSi

	// Costo total
	vCostoTotal = aCosto * aExistencia

	// S.C.216 Inicio
	gCostoPorAlmacen = @Col(gCostoPorAlmacen;10) + @Col(vCostoTotal;0)[C10]
	gCostoPorAlmacen = @Col(gCostoPorAlmacen;6) + @Col(aExistencia;0)[C6]
	// S.C.216 Fin

	vImprime = @Col(vCostoTotal;0)[C10]
	DEFREGION ContextoDetalleProductoAlm
	[C6].REGIONINFO atProducto(cCodigoProducto) & ',' & tAlmacen(cCodigoAlmacen) & ',2' & ',' & pUnidad & ',' & pIdUnidad
	[C10].REGIONINFO atProducto(cCodigoProducto) & ',' & tAlmacen(cCodigoAlmacen) & ',3' & ',' & pUnidad & ',' & pIdUnidad
	
	// Observaciones
	// RPC - SC 150 Verificar si el producto tiene algún error y sí es así 
	// desplegar en la última columna el número de error
	vImprime = ''[C12]

	// Verificar si hay existencias congeladas
	lExistenciaCongelada = fVerificarExistenciaCongelada(atProducto(cIdProducto); 0; 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)'[C12]
		lFechaSinAfectar = ''
		gObservaciones = 1
	FinSi

	// Si hay error de costos y no hay movtos sin afectar O
	// el error de costos 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) & ')'[C12]
		gObservaciones = 1
	FinSi // Si hay error de costos

	// Si hay movtos sin afectar y no hay errores de costos O
	// los movtos sin afectar ocurrieron antes del error de costos
	// 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)'[C12]
		gObservaciones = 1
	FinSi
	// FIN RPC - SC 150

	// acumula al total general
	gTotalCosto[10] = @Col(gTotalCosto;10) + @Col(vImprime;10)
	gTotalCosto[6]  = @Col(gTotalCosto;6)  + @Col(vImprime;6)
	// Imprime los datos
	Lista vImprime
FinFunc

// *****************************************************************************
//  fImprimeTotal
//
//	Esta función imprime los totales por producto.
//
//  Parámetros 
//
//  Salidas 
// *****************************************************************************
DefFunc fImprimeTotal(aTotal)
	Local vImprime, lSubRaya
	lSubRaya = ''
 	lSubRaya = '================='[C6,C10]
	Imprime lSubRaya
	vImprime = ' '[C0..C13]
	vImprime = @Col(aTotal;6)[C6]
	vImprime = @Col(aTotal;10)[C10]
	Lista vImprime
FinFunc

// *****************************************************************************
//  fVerificaParametros
//
//  Esta función verifica los parámetros pProductoInicial y pProductoFinal.
//  Si están vacíos toma el primer y último producto 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

	// S.C.216 Inicio
	// Si el rango inicial es el primer almacen, recupera el código del primero
	Si pAlmacenInicial = ' '
		tAlmacen.Busca Primero
		Si tAlmacen->Encontro
			Si tAlmacen(cIdAlmacen) = 0
				// N.D.1469 Texto '**'
				// N.D.1469 Imprime
				tAlmacen.SaltaReg [1]
			FinSi
			pAlmacenInicial = tAlmacen(cCodigoAlmacen)
		FinSi
	FinSi

	// Si el rango final es el último almacen, recupera el código del último
	Si pAlmacenFinal = ' '
		tAlmacen.Busca Ultimo
		Si tAlmacen->Encontro
			pAlmacenFinal = tAlmacen(cCodigoAlmacen)
		FinSi
	FinSi
	// S.C.216 Fin  
FinFunc

// *****************************************************************************
// Encabezado del reporte
Encab
	Texto '@TC{255,0,0}@S{8}AdminPAQ'
	Hoja '"@TC{0,0,0}@S{8}Hoja: '
	Imprime
	// lee la moneda del reporte
	tMoneda.Busca[@Str(pIdMoneda;0)]
	Si tMoneda->Encontro
		Texto '@TC{0,0,0}@S{8}Moneda: ' & tMoneda(cNombreMoneda)
	FinSi
	Texto '"@TC{0,0,0}@S{8}Fecha: ' & fFormateaFecha(@Hoy();gIdioma)
	Imprime
	Texto '^@TC{0,0,0}@S{22}' & tEmpresa->Nombre
	Imprime
	Texto '^@TC{0,0,0}@S{16}EXISTENCIAS Y COSTOS'
	Imprime
	Si pTipoReporte = 0 // Costo promedio?
		Texto '^@TC{0,0,0}@S{16}COSTO TOTAL DE ACUERDO AL COSTO PROMEDIO'
	Sino // Kardex en importes
		Texto '^@TC{0,0,0}@S{16}COSTO TOTAL DE ACUERDO AL ULTIMO COSTO'
	Finsi  
	Imprime 
	Texto '^@TC{0,0,0}@S{16}Al: ' & fFormateaFecha(pFechaCorte;gIdioma)
	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 // Costo promedio?
		Texto C4;'^Costo'
	Sino
		Texto C4;'^Último'
	FinSi
	Texto C10;'^Costo'
	Imprime
	Texto C0;'Código'
	Texto C2;'Nombre (Producto)'
	Si pTipoReporte = 0 // Costo promedio?
		Texto C4;'^Promedio'
	Sino
		Texto C4;'^Costo'
	FinSi
	Texto C6;'^Existencia'
	Texto C10;'^Total'
	Texto C12;'Obs.'
	Imprime
	Texto '@TC{0,0,0}@L{-1}'
	Imprime 1
	NEGRITAS FALSE

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

//--------------------------------------------------------------------------------------------------
//  Nombre: Cuerpo del reporte
//  Proceso: Cuerpo del reporte
//  Entradas: 
//  Salidas: 
//  Consideraciones:
//
//  Historial de revisiones
//    Fecha     ID_SitePruebas              Descripción
//--------------------------------------------------------------------------------------------------
//  23/04/2009    N.D.5766        Debe calcular el costo promedio del producto con el periodo y
//                                ejercicio de la fecha de corte (JENL).
//--------------------------------------------------------------------------------------------------
// N.D.2922 Inicio
lCostoTotal = 0
lExistenciaTotal = 0
// N.D.2922 Fin

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

// 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
gFechaCorteMasUnDia = fFechaSiguiente(pFechaCorte)
fEjercicioPeriodo(gFechaCorteMasUnDia; &gPeriodo; &gIdEjercicio; tEjercicio) 
fEjercicioPeriodo(pFechaCorte;&gPeriodoCorte;&gIdEjercicioCorte; tEjercicio)//N.D.5766
//N.D.6308 En la función fEjercicioPeriodo cuando no existe el ejercicio de la fecha 
//regresa en gIdEjercicio el id del último registro encontrado lo cual es incorrecto
//porque según está implementado debiera dejar en cero dicho valor
// Si no se encontró el ejercico, puede ser porque la fecha cae en dos ejercicios futuros,
// Por tanto obtiene el ejercicio y período de la fecha de corte
Si !gIdEjercicio
	fEjercicioPeriodo(pFechaCorte; &gPeriodo; &gIdEjercicio; tEjercicio) 
	// Suma uno al período debido a que se manda llamar funciones de existencia o costo inicial
	gPeriodo = gPeriodo + 1
FinSi
// S.C.216 Inicio
Mientras [ tAlmacen.Busca[pAlmacenInicial & '..' & pAlmacenFinal]; tAlmacen->Encontro; tAlmacen.Busca Siguiente[1] ]
	
	vImprime = ' '[C0..C13]
	// Codigo y nombre del almacen
	lCodigoEditado = fMascarilla(tAlmacen(cCodigoAlmacen); gMascarillaAlmacen)
	vImprime = 'Almacen'[C0]
	vImprime = @Col(lCodigoEditado;0)[C2]
	[C0].NEGRITAS TRUE
	Lista vImprime
	[C0].NEGRITAS FALSE
	vImprime = tAlmacen(cNombreAlmacen)[C2]
	Lista vImprime
	SaltaLin

	// 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 es candidato a imprimirse en función de su estado
		// tProducto(cStatusProducto) = 0 (Inactivo)
		// tProducto(cStatusProducto) = 1 (Activo)
		Si pEstadoProducto y pEstadoProducto != @Abs(tProducto(cStatusProducto) - 2)
			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 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 tProducto(cIdUnidadNoConvertible) = 0
			Continua
		Sino
			fVerificaUnidad(tProducto)
		FinSi
		//N.D.6308 Debe verificar el año de la FechaCorteMasUnDia porque si esta fecha tiene
		//la de un ejercicio no existente en la tabla de ejercicios y periodos, se debe usar 
		//la pFechaCorte en lugar de la pFechaCortaMasUnDia	
		tEjercicio.Usaindice['']   
		lAnio = @SubStr(pFechaCorte;0;4)
		lEjercicioNoExiste = 1
		tEjercicio.BUSCA ULTIMO
		lUltimoRegistro = tEjercicio(cIdEjercicio)
		tEjercicio.BUSCA PRIMERO
		lFinArchivo = 1
		lSale = 0

		//Recorre la tabla de ejercicios y periodos para verificar el año de pFechaCorte vs
		//el cEjercicio y si no coincide se lEjercicioNoExiste debe ser igual a 1
		Mientras lSale = 0 //lFinArchivo != lUltimoRegistro      
			Si lAnio != tEjercicio(cEjercicio)
				Si lFinArchivo != lUltimoRegistro
					tEjercicio.SALTAREG[1]
					lFinArchivo = lFinArchivo + 1
				SiNo
					lEjercicioNoExiste = 0
					lSale = 1          
				FinSi  
			SiNo //Lo encontró
				FinCiclo     
			FinSi
		FinMientras
		//Fin N.D.6308    	
		//Regresa a usar el índice original
		tEjercicio.Usaindice['cNumeroEjercicio']          // cNumeroEjercicio

		// S.C.216 Inicio
		// Existencia inicial en el almacén actual
		//N.D.6308 Si el ejercicio de gFechaCorteMasUnDia no existe se debe usar pFechaCorte
		
		//N.D.6198 Se manda la fecha de corte tal cual en lugar de la fecha de corte más un día    
		
		//N.D.6343 Se toma la existencia real del producto y no la inicial
		//gExistencia = fExistenciaProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); pFechaCorte; pIdUnidad; tProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia; tEjercicio )
		
		//N.D.7087: Cambio del parámetro IdUnidad por pUnidad para que muestre las existencias con unidades no equivalentes
		gExistencia = fExistenciaProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); pFechaCorte; pUnidad; tProducto(cIdUnidadBase); pUnidad; tMovimiento; tExistencia; tEquivalencia; tEjercicio )
		// S.C.216 Fin

		Si !pImprimirProductos o gExistencia != 0.0
			// calcula el costo unitario del producto
			// El primer parámetro de la siguiente función es el método de costeo y los valores permitidos son:
			// 1 = Costo promedio
			// 3 = Ultimo costo
			// S.C.216 Inicio
			// Costo Historico en el almacén actual
			// N.D.2922 Inicio
			Si pTipoReporte = 1 
				//gCosto = fCostoHistorico(tProducto(cIdProducto); tAlmacen(cIdAlmacen) ; pFechaCorte; pTipoReporte? 3 : 1; tCostoHistorico; tTipoCambio; pIdMoneda) N.D.5766
				//gCosto = fCostoHistorico(tProducto(cIdProducto); tAlmacen(cIdAlmacen) ; pFechaCorte; 3; tCostoHistorico; tTipoCambio; pIdMoneda)

				//N.D.6343
				gCosto = fCostoHistorico(tProducto(cIdProducto); tAlmacen(cIdAlmacen) ; pFechaCorte; 3; tCostoHistorico; tTipoCambio; pIdMoneda)        
			Sino
				//gCosto = fCostoPromedioProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); pFechaCorte; gIdEjercicioCorte; gPeriodoCorte; tMovimiento; tExistencia; tProducto; tCostoHistorico; tTipoCambio; pIdMoneda; lCostoTotal; lExistenciaTotal) //N.D.5766        
				// N.D.6695 (ALRH) Se manda un día más de la fecha de corte, puesto que la función calcula a un día antes de la fecha que se le envía como parámetro
				ldiaCorteStr = ''
				Si (@SUBSTR(gFechaCorteMasUnDia;6;2) = '01')
					ldiaCorte = @VAL(@SUBSTR(pFechaCorte;6;2)) + 1
					ldiaCorteStr = @STR(ldiaCorte;0)
					Si (ldiaCorte < 10)
						ldiaCorteStr = ldiaCorteStr & '0'
					FinSi
					lFechaCorte = @SUBSTR(pFechaCorte;0;6) & ldiaCorteStr
				Sino
					lFechaCorte = gFechaCorteMasUnDia
				FinSi
				gCosto = fCostoPromedioProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); lFechaCorte; gIdEjercicioCorte; gPeriodoCorte; tMovimiento; tExistencia; tProducto; tCostoHistorico; tTipoCambio; pIdMoneda; lCostoTotal; lExistenciaTotal)
			FinSi
			// N.D.2922 Fin
			// S.C.216 Fin
			// Si el reporte se pidio en unidades no convertibles o equivalentes
			Si pUnidad != 0
				// calcula la existencia en la unidad base
				// S.C.216 Inicio
				// Existencia inicial en el almacén actual
				//N.D.6308 Si el ejercicio de gFechaCorteMasUnDia no existe se debe usar pFechaCorte        
				//N.D.6198 Se manda la fecha de corte tal cual en lugar de la fecha de corte más un día        

				//N.D.6343
				// N.D.7797 Se manda un día posterior a la fecha de corte, porque procesa documentos de hasta un día antes
				// fExistenciaInicialProducto procesa hasta un día antes de la fecha que recibe, 
				// por lo que se manda fecha, Id de ejercicio y periodo de un día posterior.
				gExistenciaBase = fExistenciaInicialProducto(tProducto(cIdProducto); tAlmacen(cIdAlmacen); gFechaCorteMasUnDia; gIdEjercicio; gPeriodo; pUnidad; tProducto(cIdUnidadBase); pIdUnidad; tMovimiento; tExistencia; tEquivalencia)            
				// S.C.216 Fin

				// El costo unitario deberá expresarse en términos de la relación que existe entre la unidad base y la unidad equivalente o no convertible
				//gCosto = gCosto * gExistenciaBase / gExistencia 
				// N.D.7797 gExistencia son las unidades base
				gCosto = gCosto * (gExistencia / gExistenciaBase)
			FinSi

			//N.D.6343 Cuando el ejercicio no existe manda la leyenda
			Si lEjercicioNoExiste = 0        
				vImprime = @Col('Ejercicio no existe';0)[C4]
				vImprime = @Col('Ejercicio no existe';0)[C6]        
				Lista vImprime
			SiNo
				Si pUnidad = 0
					// Imprime los datos del producto
					fImprimeProducto(tProducto; gCosto; gExistencia)
				Sino
					// N.D.7797 gExistenciaBase es la unidad equivalente
					fImprimeProducto(tProducto; gCosto; gExistenciaBase)
				FinSi
			Finsi	
		FinSi
	FinMientras
	// Fin recorrido de los productos
	
	// S.C.216 Inicio
	// Imprime el total por almacen
	fImprimeTotal(gCostoPorAlmacen)
	gCostoPorAlmacen = 0.0 [C0..C10]
	// S.C.216 Fin
FinMientras
// Fin recorrido de los almacenes
// S.C.216 Fin

// Imprime el total general
fImprimeTotal(gTotalCosto)

//Imprime tipo de unidad usada
vImprime= 'Unidad utilizada:' [C0] //N.D.7087
vImprime= @str(tUnidad(cNombreUnidad);0) [C2]  //N.D.7087 Agrega las unidades 
Lista vImprime

// Observaciones de errores en costos
fImprimeObservaciones()
