{ ------------------------------------------------------------------------------- PROGRAMA : INPRRP013 OBJETIVO : REPORTE DIAS DE INVENTARIOS PROGRAMADOR : Ing. Juan Francisco Soto FECHA REALIZACION : Agosto 19, 1992 MODIFICADO POR : Ing. Juan Fco. Soto FECHA ULT. MODIFICA : Agosto 20, 2026. DESCRIPCION : Agregar Columna Costo Standard para cantidades mayores a una cantidad de dias especificada. AGOSTO 20, 2026 - ANALISIS DE MARGEN Y ROTACION: 1. MARGEN DE BENEFICIO: se calcula el precio de venta REAL promedio del periodo (ponderado por cantidad, neto del descuento de cabecera) desde vetb00002/ vetb00003, y el margen % sobre precio: margen = (precio - costo) / precio * 100 El costo es el costo estandar (iptb00004), igual que antes. Se movio el calculo del costo ANTES del calculo del valor de exceso para que ese valor use el costo real (antes usaba costo = 0). 2. ROTACION: igual que en ipprrp014: rotacion = consumo / existencia rotacion_anual = rotacion * (365 / dias del periodo) En este reporte el consumo son las SALIDAS del periodo (movs 30,31,55,56,40), que es la base correcta para la rotacion de inventario. 3. CLASIFICACION por cuadrante (margen x rotacion): ESTRELLA = alto margen + alta rotacion VOLUMEN = bajo margen + alta rotacion NICHO = alto margen + baja rotacion REVISAR = bajo margen + baja rotacion (candidato a descontinuar / renegociar costo) SIN COSTO = producto sin costo estandar cargado Umbrales configurables (g_margen_min, g_rot_min). 4. Se agregan valor_inv (existe*costo), ventas_valor (consumo*precio) y ganancia (consumo*(precio-costo)) para poder totalizar el margen PONDERADO por CLASE en el disenio .4rp (grupo por cod_n). NOTA: el layout .4rp debe actualizarse en GST arrastrando los nuevos campos (ver guia adjunta). ------------------------------------------------------------------------------- } GLOBALS "ipprgb000.4gl" DEFINE sale CHAR(1) DEFINE p_ano CHAR(4) DEFINE fecha2 DATE DEFINE dias1 SMALLINT, m_meses SMALLINT, conmes,valor1 DECIMAL(12,2) # ------------------------------------------------------------------------------ # Umbrales de clasificacion (ajustables aqui, o promover a campos del form). # g_margen_min : margen % sobre precio a partir del cual se considera "alto" # g_rot_min : rotacion ANUALIZADA (veces/anio) a partir de la cual es "alta" # ------------------------------------------------------------------------------ DEFINE g_margen_min DECIMAL(6,2) DEFINE g_rot_min DECIMAL(6,2) # Acumulador por CLASE para el reporte Resumen (una fila por cod_n). # A nivel de modulo para que emite_clase() y ipprrp013() lo compartan. DEFINE rc RECORD cod_n INTEGER, nombre_clase CHAR(30), categoria CHAR(30), c_prod INTEGER, c_estrella INTEGER, c_revisar INTEGER, c_valor_inv DECIMAL(16,2), c_ventas DECIMAL(16,2), c_ganancia DECIMAL(16,2), c_margen DECIMAL(12,2), c_rot_prom DECIMAL(12,4) END RECORD DEFINE rc_rot_sum DECIMAL(16,4) MAIN DEFER INTERRUPT CALL ARG_VAL(1) RETURNING usuarios CALL ARG_VAL(2) RETURNING clave CONNECT to "smarmotech" USER usuarios USING clave SELECT a.* INTO p_companias.* FROM companias a CALL ipprrp013() END MAIN FUNCTION ipprrp013() # Variable que toma el valor de los dias que se va a valorar el reporte DEFINE c_dias INTEGER # Combo para elegir Detallado / Resumen DEFINE cbtipo ui.ComboBox DEFINE prev_cod_n INTEGER # Variables varias para el control de busqueda de las informaciones DEFINE selec1,select_bal string # Record para el consumo de los materiales DEFINE consume RECORD cod_n SMALLINT, cod_grupo SMALLINT, cod_tipo SMALLINT, cod_sec SMALLINT, existe DECIMAL(14,2) END RECORD # Record para la impresion del reporte, estas variables se validan con el # select que esta en la variable selec DEFINE estadis RECORD cod_n LIKE intb00001.cod_n, cod_grupo LIKE intb00001.cod_grupo, cod_tipo LIKE intb00001.cod_tipo, cod_sec LIKE intb00001.cod_sec, descrip_esp LIKE intb00001.descrip_esp, unidad_med LIKE iptb00002.unidad_med, consumo LIKE iptb00006.cantidad_2, grupo CHAR(30), tipo CHAR(30), categoria CHAR(30), fecha date, existe DEC(12,4), valor DECIMAL(12,4), costo DECIMAL(12,4), dias INTEGER, pcodigo char(25), cantidad_orden,pcantidadConduce,transito,existencia,reservado,disponible DEC(12,2), # --- Analisis margen / rotacion (Agosto 2026) --- precio DEC(12,4), -- precio venta real prom. neto del periodo margen DEC(12,2), -- % sobre precio = (precio-costo)/precio*100 rotacion DEC(12,4), -- consumo / existencia rotacion_anual DEC(12,4), -- rotacion * (365 / dias del periodo) valor_inv DEC(14,2), -- existencia * costo (valor inventario) ventas_valor DEC(14,2), -- consumo * precio (venta del periodo) ganancia DEC(14,2), -- consumo * (precio - costo) clasificacion CHAR(12) -- ESTRELLA/VOLUMEN/NICHO/REVISAR/SIN COSTO END RECORD DEFINE handler om.SaxDocumentHandler, -- return value from fgl_report_commitCurrentSettings() r_filename STRING, -- filename of Report Design Document including .4rp extension r_output STRING, -- output format option preview INTEGER -- TRUE/FALSE, to set preview option # WHENEVER ERROR CONTINUE OPTIONS FORM LINE 8, ERROR LINE 23, COMMENT LINE 21 OPEN FORM ipfmrp013 FROM "ipfmrp013" DISPLAY FORM ipfmrp013 #CALL pantalla() DISPLAY "ipprrp013" AT 4,3 ATTRIBUTE(RED) DISPLAY "Dias de Inventarios" AT 6,33 ATTRIBUTE(BLACK) LET tipo_papel = 2 CALL msgrp000(tipo_papel) # Umbrales de clasificacion margen/rotacion (ver DEFINE arriba) LET g_margen_min = 25.00 LET g_rot_min = 2.00 INPUT BY NAME fecha1,fecha2,c_dias,m_meses,tipo_reporte BEFORE INPUT # Llena el combo Detallado / Resumen (mismo patron que categorias()) LET cbtipo = ui.ComboBox.forName("formonly.tipo_reporte") IF cbtipo IS NOT NULL THEN CALL cbtipo.clear() CALL cbtipo.addItem("D","Detallado (por producto)") CALL cbtipo.addItem("R","Resumen (por clase)") END IF # Por defecto el reporte DETALLADO IF tipo_reporte IS NULL OR tipo_reporte = " " THEN LET tipo_reporte = "D" END IF DISPLAY BY NAME tipo_reporte AFTER FIELD c_dias IF c_dias is null THEN LET numero_msg = 16 CALL msg(numero_msg) NEXT FIELD c_dias END IF AFTER FIELD fecha1 IF fecha1 IS NULL THEN LET numero_msg = 16 CALL msg(numero_msg) NEXT FIELD fecha1 END IF AFTER FIELD fecha2 IF fecha2 IS NULL THEN LET numero_msg = 16 CALL msg(numero_msg) NEXT FIELD fecha2 END IF AFTER FIELD m_meses IF m_meses IS NULL THEN LET numero_msg = 16 CALL msg(numero_msg) NEXT FIELD m_meses END IF AFTER FIELD tipo_reporte IF tipo_reporte IS NULL OR tipo_reporte = " " THEN LET tipo_reporte = "D" DISPLAY BY NAME tipo_reporte END IF END INPUT IF int_flag THEN LET numero_msg = 2 CALL msg(numero_msg) LET int_flag = false RETURN END IF LET dias1 = fecha2 - fecha1 LET dias1 = dias1 + 1 DISPLAY BY NAME dias1 SELECT MAX(a.ano) INTO p_ano FROM prdtable a WHERE a.fecha_corte <= fecha2 #LET p_ano = "2001" #LET p_ano1 = "2002" #LET p_ano = year(fecha2) CONSTRUCT criterio ON x.cod_categoria,a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec FROM cod_cat,cod_n,cod_grupo,cod_tipo,cod_sec BEFORE CONSTRUCT CALL categorias() AFTER CONSTRUCT IF int_flag THEN LET numero_msg = 2 CALL msg(numero_msg) LET int_flag = FALSE RETURN END IF EXIT CONSTRUCT END CONSTRUCT DELETE FROM tmpipprrp013 # CREACION TABLA TEMPORAL LET select_bal = { "SELECT a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_Sec,a.descrip_esp,a.unidad_med,SUM(b.cantidad_2),", "d.descripcion,f.descripcion ", "FROM ", "iptb00034 x INNER JOIN iptb00035 x1 ON x.cod_categoria = x1.cod_cat RIGHT OUTER JOIN", " iptb00002 a LEFT OUTER JOIN iptb00006 b ON a.cod_n = b.cod_n AND ", " a.cod_grupo = b.cod_grupo AND a.cod_tipo = b.cod_tipo AND a.cod_sec = b.cod_sec ", " AND b.cod_mov in (30,31,55,56,40) ", " AND CONVERT(DATE,b.fecha,103) between ? AND ? ", ",iptb00029 d,iptb00024 f", " WHERE ", criterio CLIPPED, " AND a.cod_grupo = d.cod_grupo and", " a.cod_tipo = f.cod_tipo and", " b.status_t IS NULL AND ", " a.status_t is null ", " GROUP BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_Sec,a.descrip_esp,", " f.descripcion,d.descripcion,a.unidad_med ", "ORDER BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_Sec" 106-1818 } " SELECT a.cod_n, a.cod_grupo, a.cod_tipo, a.cod_sec, a.descrip_esp, a.unidad_med, ISNULL(SUM(b.cantidad_2),0), d.descripcion, f.descripcion,x.descripcion FROM iptb00034 x INNER JOIN iptb00035 x1 ON x.cod_categoria = x1.cod_cat RIGHT OUTER JOIN iptb00002 AS a LEFT OUTER JOIN iptb00006 AS b ON a.cod_n = b.cod_n AND a.cod_grupo = b.cod_grupo AND a.cod_tipo = b.cod_tipo AND a.cod_sec = b.cod_sec AND b.cod_mov IN (30, 31, 55, 56, 40) AND b.fecha BETWEEN ? AND ? INNER JOIN iptb00029 AS d ON a.cod_grupo = d.cod_grupo INNER JOIN iptb00024 AS f ON a.cod_tipo = f.cod_tipo ON x1.cod_n = a.cod_n WHERE ", criterio CLIPPED, " and (b.status_t IS NULL) AND (a.status_t IS NULL) GROUP BY a.cod_n, a.cod_grupo, a.cod_tipo, a.cod_sec, a.descrip_esp, f.descripcion, d.descripcion, a.unidad_med,x.descripcion ORDER BY a.cod_n, a.cod_grupo, a.cod_tipo, a.cod_sec" PREPARE comando2 FROM select_bal DECLARE accion CURSOR FOR comando2 OPEN accion USING fecha1,fecha2 # Busqueda de los costos de los materiales LET selec1 = "SELECT max(a.mes_ini),max(a.mes_fin),a.cod_n,a.cod_grupo,a.cod_tipo,", " a.cod_sec,SUM(a.material+a.labor+a.gastos) ", "FROM ", " iptb00034 x INNER JOIN iptb00035 x1 ON x.cod_categoria = x1.cod_cat RIGHT OUTER JOIN ", "iptb00004 a ON a.cod_n = x1.cod_n ", "WHERE ", " a.ano = ? AND ", criterio CLIPPED, "GROUP BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec ORDER BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec" DISPLAY "<< Estoy Buscando Costos... Espere >>" AT 19,14 ATTRIBUTE (REVERSE,BOLD) PREPARE comando FROM selec1 DECLARE busca3 SCROLL CURSOR FOR comando OPEN busca3 USING p_ano { LET select_bal = "SELECT a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec,ISNULL(sum(a.cantidad_2),0) ", "FROM ", " iptb00034 x LEFT OUTER JOIN iptb00035 x1 ON x.cod_categoria = x1.cod_cat RIGHT OUTER JOIN ", "iptb00006 a ON a.cod_n = x1.cod_n WHERE ", " a.status_t is null and a.fecha <= ? AND ",criterio CLIPPED, " GROUP BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec ORDER BY a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_sec" DISPLAY "<< Estoy Buscando Balances Iniciales >>" AT 19,14 ATTRIBUTE (REVERSE,BOLD) PREPARE busca_balan FROM select_bal DECLARE consu SCROLL CURSOR FOR busca_balan OPEN consu USING fecha2 } # Elige el disenio .4rp segun la opcion del formulario: # D = Detallado (una linea por producto) -> ipprrp013.4rp # R = Resumen (subtotales por CLASE cod_n) -> ipprrp013r.4rp IF tipo_reporte = "R" THEN LET r_filename = "ipprrp013r.4rp" ELSE LET r_filename = "ipprrp013.4rp" END IF LET idx = 1 LET prev_cod_n = -999999 FOREACH accion INTO estadis.* LET estadis.pcodigo = estadis.cod_n USING "&&&&","-", estadis.cod_grupo using "&&&&","-", estadis.cod_tipo using "&&&&","-", estadis.cod_sec using "&&&&&&" IF int_flag THEN LET numero_msg = 2 CALL msg(numero_msg) LET int_flag = FALSE LET estadis.consumo = 0 LET estadis.existe = 0 # Busca el consumo de los materiales LET sale = "N" RETURN END IF IF idx =1 THEN iF fgl_report_loadCurrentSettings(r_filename) THEN -- load the .4rp file CALL seleccionarSalida() RETURNING r_output LET preview=1 CALL fgl_report_selectDevice(r_output) -- changing default CALL fgl_report_selectPreview(preview) -- changing default LET handler = fgl_report_commitCurrentSettings() -- commit changes ELSE EXIT PROGRAM END IF --run the report IF handler IS NOT NULL THEN -- report engine was configured ok IF tipo_reporte = "R" THEN START REPORT resumen TO XML HANDLER HANDLER ELSE START REPORT estadistica TO XML HANDLER HANDLER END IF ELSE EXIT FOREACH END IF END IF {LET sale = "N" WHILE sale != "S" FETCH consu INTO consume.* IF status = notfound THEN LET sale = "S" LET STATUS = 0 EXIT WHILE END IF IF consume.cod_n = estadis.cod_n AND consume.cod_grupo = estadis.cod_grupo AND consume.cod_Tipo = estadis.cod_tipo AND consume.cod_sec = estadis.cod_sec THEN LET estadis.existe = consume.existe LET sale = "S" EXIT WHILE END IF END WHILE } # Busqueda del costo del material # Se multiplica por -1 por que el movimiento 36 es negativo IF estadis.consumo < 0 THEN LET estadis.consumo = estadis.consumo * -1 END IF CALL disponibles(estadis.cod_n,estadis.cod_grupo,estadis.cod_tipo,estadis.cod_sec,fecha2) RETURNING estadis.cantidad_orden,estadis.pcantidadConduce,estadis.transito,estadis.existencia,estadis.reservado, valororden LET estadis.existe = estadis.existencia # ---- COSTO ESTANDAR (movido aqui para que el valor de exceso Y el margen # usen el costo real; antes se calculaba despues y quedaba en cero) ---- LET estadis.costo = 0 SELECT AVG(a.material+a.labor+a.gastos) INTO estadis.costo FROM iptb00004 a WHERE a.ano = YEAR(TODAY) AND a.mes_fin = 12 AND a.cod_n = estadis.cod_n AND a.cod_grupo = estadis.cod_grupo AND a.cod_tipo = estadis.cod_tipo AND a.cod_sec = estadis.cod_sec AND a.status_t IS NULL IF estadis.costo IS NULL THEN LET estadis.costo = 0 END IF # Calculo para los dias de produccion IF estadis.existe > 0 THEN LET estadis.cantidad_orden = estadis.cantidad_orden - estadis.pcantidadConduce LET estadis.disponible=estadis.existe -estadis.cantidad_orden - estadis.reservado LET estadis.dias = (estadis.existe / estadis.consumo) * dias1 ELSE LET estadis.dias =0 END IF IF estadis.disponible <= 0 THEN CONTINUE FOREACH END IF IF estadis.dias < 0 THEN LET estadis.dias = 0 END IF # Calculo para el exedente de la existencia apartir de los dias de exeso # especificado LET estadis.valor = 0 IF estadis.dias >= c_dias THEN IF estadis.dias > 0 THEN LET valor1 = (estadis.existe * c_dias)/estadis.dias LET estadis.valor = (estadis.existe - valor1) * estadis.costo ELSE LET estadis.valor = 0 END IF END IF # ============================================================================ # MARGEN DE BENEFICIO Y ROTACION # ============================================================================ # Precio de venta REAL promedio del periodo, ponderado por cantidad y neto del # descuento de cabecera (porc_desc). Fuente: facturas vetb00002 + detalle # vetb00003 con fecha_factura dentro del rango [fecha1, fecha2]. LET estadis.precio = 0 SELECT SUM(d.cantidad * d.precio * (1 - (ISNULL(h.porc_desc,0)/100.0))) / NULLIF(SUM(d.cantidad),0) INTO estadis.precio FROM vetb00003 d, vetb00002 h WHERE d.factura = h.factura AND d.cod_n = estadis.cod_n AND d.cod_grupo = estadis.cod_grupo AND d.cod_tipo = estadis.cod_tipo AND d.cod_sec = estadis.cod_sec AND h.status_t IS NULL AND d.status_t IS NULL AND h.fecha_factura BETWEEN fecha1 AND fecha2 IF estadis.precio IS NULL THEN LET estadis.precio = 0 END IF # Margen % sobre precio = (precio - costo) / precio * 100 IF estadis.precio > 0 AND estadis.costo > 0 THEN LET estadis.margen = ((estadis.precio - estadis.costo) / estadis.precio) * 100 ELSE LET estadis.margen = 0 END IF # Rotacion (misma formula que ipprrp014): consumo / existencia # anualizada = rotacion * (365 / dias del periodo) -- 365.0 evita div. entera IF estadis.existe > 0 AND estadis.consumo > 0 THEN LET estadis.rotacion = estadis.consumo / estadis.existe LET estadis.rotacion_anual = estadis.rotacion * (365.0 / dias1) ELSE LET estadis.rotacion = 0 LET estadis.rotacion_anual = 0 END IF # Valores para totalizar el margen PONDERADO por CLASE en el .4rp LET estadis.valor_inv = estadis.existe * estadis.costo LET estadis.ventas_valor = estadis.consumo * estadis.precio LET estadis.ganancia = estadis.consumo * (estadis.precio - estadis.costo) # Clasificacion por cuadrante (margen x rotacion) CASE WHEN estadis.costo <= 0 LET estadis.clasificacion = "SIN COSTO" WHEN estadis.margen >= g_margen_min AND estadis.rotacion_anual >= g_rot_min LET estadis.clasificacion = "ESTRELLA" WHEN estadis.margen < g_margen_min AND estadis.rotacion_anual >= g_rot_min LET estadis.clasificacion = "VOLUMEN" WHEN estadis.margen >= g_margen_min AND estadis.rotacion_anual < g_rot_min LET estadis.clasificacion = "NICHO" OTHERWISE LET estadis.clasificacion = "REVISAR" END CASE IF estadis.existe > 0 THEN IF tipo_reporte = "R" THEN # --- Agregacion por CLASE: al cambiar cod_n, emite la clase anterior --- IF prev_cod_n <> estadis.cod_n THEN IF prev_cod_n <> -999999 THEN CALL emite_clase() END IF # Nueva clase: reinicia acumuladores LET prev_cod_n = estadis.cod_n LET rc.cod_n = estadis.cod_n LET rc.categoria = estadis.categoria LET rc.nombre_clase = NULL SELECT a.producto INTO rc.nombre_clase FROM iptb00020 a WHERE a.cod_n = estadis.cod_n IF rc.nombre_clase IS NULL THEN LET rc.nombre_clase = " " END IF LET rc.c_prod = 0 LET rc.c_estrella = 0 LET rc.c_revisar = 0 LET rc.c_valor_inv = 0 LET rc.c_ventas = 0 LET rc.c_ganancia = 0 LET rc_rot_sum = 0 END IF LET rc.c_prod = rc.c_prod + 1 LET rc.c_valor_inv = rc.c_valor_inv + estadis.valor_inv LET rc.c_ventas = rc.c_ventas + estadis.ventas_valor LET rc.c_ganancia = rc.c_ganancia + estadis.ganancia LET rc_rot_sum = rc_rot_sum + estadis.rotacion_anual IF estadis.clasificacion = "REVISAR" THEN LET rc.c_revisar = rc.c_revisar + 1 END IF IF estadis.clasificacion = "ESTRELLA" THEN LET rc.c_estrella = rc.c_estrella + 1 END IF ELSE OUTPUT TO REPORT estadistica(estadis.*,dias1,c_dias) END IF END IF LET idx = idx +1 LET estadis.consumo = 0 LET estadis.existe = 0 LET estadis.precio = 0 LET estadis.margen = 0 LET estadis.rotacion = 0 LET estadis.rotacion_anual = 0 END FOREACH IF idx = 1 THEN CALL fgl_winmessage("INFO","NO EXISTEN INFORMACIONES CON ESTOS PARAMETROS","INFO") ELSE IF tipo_reporte = "R" THEN # Emite la ultima clase acumulada IF prev_cod_n <> -999999 THEN CALL emite_clase() END IF FINISH REPORT resumen ELSE FINISH REPORT estadistica END IF END IF #RUN imprime CLEAR SCREEN END FUNCTION # ------------------------------------------------------------------------------ # Calcula el margen ponderado y la rotacion promedio de la clase acumulada en # 'rc' y la envia al reporte 'resumen'. Usada por ipprrp013() al cambiar de # CLASE y al terminar el FOREACH. # ------------------------------------------------------------------------------ FUNCTION emite_clase() IF rc.c_ventas > 0 THEN LET rc.c_margen = (rc.c_ganancia / rc.c_ventas) * 100 ELSE LET rc.c_margen = 0 END IF IF rc.c_prod > 0 THEN LET rc.c_rot_prom = rc_rot_sum / rc.c_prod ELSE LET rc.c_rot_prom = 0 END IF OUTPUT TO REPORT resumen(rc.*) END FUNCTION REPORT estadistica(x,dias2,c_dias) DEFINE x RECORD cod_n LIKE intb00001.cod_n, cod_grupo LIKE intb00001.cod_grupo, cod_tipo LIKE intb00001.cod_tipo, cod_sec LIKE intb00001.cod_sec, descrip_esp LIKE intb00001.descrip_esp, unidad_med LIKE iptb00002.unidad_med, consumo LIKE iptb00006.cantidad_1, grupo CHAR(30), tipo CHAR(30), categoria CHAR(30), fecha date, existe DEC(12,4), valor DECIMAL(12,3), costo DECIMAL(12,4), dias INTEGER, pcodigo char(25), cantidad_orden,pcantidadConduce,transito,existencia,reservado,disponible DEC(12,2), # --- Analisis margen / rotacion (Agosto 2026) - debe reflejar estadis --- precio DEC(12,4), margen DEC(12,2), rotacion DEC(12,4), rotacion_anual DEC(12,4), valor_inv DEC(14,2), ventas_valor DEC(14,2), ganancia DEC(14,2), clasificacion CHAR(12) END RECORD, cantidad_rec,cantidad_or,tcantidad DEC(12,4), fecha_v,fecha_oc DATE DEFINE c_dias SMALLINT, dias_oc INTEGER DEFINE m_total DECIMAL(10,2) DEFINE dias2 SMALLINT DEFINE hora CHAR(5) DEFINE t_total,t_valor DECIMAL(12,2), chorden STRING, porden INTEGER, fecha DATE, pcosto dec(12,4), total_registros smallint, total_grupo smallint, nombre CHAR(50), xsuplidor VARCHAR(100) FORMAT FIRST PAGE HEADER LET hora = time LET fecha = today LET total_registros = 0 LET tcantidad = 0 LET fecha_v = NULL LET fecha_oc = NULL BEFORE GROUP OF x.cod_grupo let total_grupo = 0 BEFORE GROUP OF x.cod_tipo LET hora = time SELECT a.* INTO p_companias.* FROM companias a WHERE a.cod_comp = 1 LET lj = (120 - LENGTH(p_companias.nombre CLIPPED))/2 ON EVERY ROW LET total_registros = total_registros +1 LET total_grupo = total_grupo +1 LET nombre_ant = nombre # BUSCA ULTIMA FECHA DE COMPRA Y VENTA DEL PRODUCTO LET fecha_v = NULL SELECT convert(char(10),MAX(a.fecha_factura),103) INTO fecha_v FROM vetb00003 d,vetb00002 a WHERE d.factura = a.factura AND d.cod_n=x.cod_n AND d.cod_grupo=x.cod_grupo AND d.cod_tipo = x.cod_tipo AND d.cod_sec = x.cod_sec AND a.status_t is NULL LET fecha_oc = NULL SELECT ISNULL(convert(char(10),MAX(a.fech_oc),103)," ") INTO fecha_oc FROM cotb00015 d,cotb00014 a WHERE d.num_oc = a.num_oc AND d.cod_n=x.cod_n AND d.cod_grupo=x.cod_grupo AND d.cod_tipo = x.cod_tipo AND d.cod_sec = x.cod_sec AND d.status_t is NULL LET tcantidad =0 SELECT SUM(d.cantidad) INTO tcantidad FROM cotb00015 d,cotb00014 a WHERE d.num_oc = a.num_oc AND d.cod_n=x.cod_n AND d.cod_grupo=x.cod_grupo AND d.cod_tipo = x.cod_tipo AND d.cod_sec = x.cod_sec AND a.fech_oc = fecha_oc AND d.status_t is NULL LET xsuplidor =null SELECT MAX(c.nom_sp) INTO xsuplidor FROM cotb00015 d,cotb00014 a,cotb00001 c WHERE d.num_oc = a.num_oc AND d.cod_n=x.cod_n AND d.cod_grupo=x.cod_grupo AND d.cod_tipo = x.cod_tipo AND d.cod_sec = x.cod_sec AND a.fech_oc = fecha_oc AND a.cod_sp = c.cod_sp AND a.cod_sp_sec = c.cod_sp_sec AND d.status_t is NULL LET conmes = 0 IF t_total IS NULL THEN LET t_total = 0 END IF IF t_valor is null THEN LET t_valor = 0 END IF { COLOQUE LA BUSQUEDA DE LA ORDEN PARA SUSTITUIR EL QUERY POR LA ULTIMA CANTIDAD COMPRADA DECLARE busca_oc CURSOR FOR SELECT a.num_oc,a.cantidad FROM cotb00015 a, cotb00014 b WHERE a.num_oc = b.num_oc AND a.cod_n = x.cod_n AND a.cod_grupo = x.cod_grupo AND a.cod_tipo = x.cod_tipo AND a.cod_sec = x.cod_sec AND b.cierre = "N" AND b.status_T IS NULL LET chorden = NULL LET tcantidad = 0 FOREACH busca_oc INTO porden,cantidad_rec IF cantidad_rec IS NULL THEN LET cantidad_rec = 0 END IF LET tcantidad = tcantidad + cantidad_Rec LET chorden = porden using "<<<<<<",", ",chorden CLIPPED END FOREACH } LET m_total = x.existe * x.costo LET cantidad_or = tcantidad + x.existe IF x.consumo > 0 THEN LET dias_oc = (cantidad_or/x.consumo) * dias1 END IF LET conmes = x.consumo / m_meses PRINTX x.*,fecha,hora,fecha1,fecha2,fecha_oc,chorden,tcantidad, p_companias.*,pcosto,total_registros,total_grupo,fecha_v INSERT INTO tmpipprrp013 VALUES (fecha1,fecha2,x.categoria,xsuplidor,x.grupo,x.pcodigo,x.descrip_esp,x.existe,x.disponible,x.cantidad_orden, x.dias,x.consumo,fecha_oc,x.costo,fecha_v) END REPORT # ============================================================================== # REPORTE RESUMEN POR CLASE (cod_n) -- version PLANA (sin grupos) # ------------------------------------------------------------------------------ # Recibe UN registro ya agregado por CLASE (lo arma el FOREACH principal) y emite # una linea por clase via ON EVERY ROW. El gran total se acumula aqui y se # muestra en el pie del disenio ipprrp013r.4rp (patron identico al footer de # 'total_registros' del reporte de detalle, por eso no usa grupos ni triggers). # ============================================================================== REPORT resumen(r) DEFINE r RECORD cod_n INTEGER, nombre_clase CHAR(30), categoria CHAR(30), c_prod INTEGER, c_estrella INTEGER, c_revisar INTEGER, c_valor_inv DECIMAL(16,2), c_ventas DECIMAL(16,2), c_ganancia DECIMAL(16,2), c_margen DECIMAL(12,2), c_rot_prom DECIMAL(12,4) END RECORD DEFINE hora CHAR(5), fecha DATE, g_prod INTEGER, g_valor_inv, g_ventas, g_ganancia DECIMAL(16,2), g_margen DECIMAL(12,2) FORMAT FIRST PAGE HEADER LET hora = TIME LET fecha = TODAY SELECT a.* INTO p_companias.* FROM companias a WHERE a.cod_comp = 1 LET lj = (120 - LENGTH(p_companias.nombre CLIPPED))/2 LET g_prod = 0 LET g_valor_inv = 0 LET g_ventas = 0 LET g_ganancia = 0 ON EVERY ROW LET g_prod = g_prod + r.c_prod LET g_valor_inv = g_valor_inv + r.c_valor_inv LET g_ventas = g_ventas + r.c_ventas LET g_ganancia = g_ganancia + r.c_ganancia IF g_ventas > 0 THEN LET g_margen = (g_ganancia / g_ventas) * 100 ELSE LET g_margen = 0 END IF PRINTX r.*, g_prod, g_valor_inv, g_ventas, g_ganancia, g_margen, p_companias.*, fecha, hora, fecha1, fecha2 END REPORT