Compare commits
2
Commits
4bb2df1630
...
5fa61ead23
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fa61ead23 | ||
|
|
ca75ed204c |
@@ -20,7 +20,7 @@ DEFINE
|
||||
DEFINE
|
||||
dias, registros, pcod_sp, numero_entrada SMALLINT,
|
||||
secuencia_entrada INT,
|
||||
xentrada VARCHAR(14),
|
||||
xentrada VARCHAR(25),
|
||||
nom1_emp, nom2_Emp, apell1_Emp, apell2_emp VARCHAR(30),
|
||||
num_doccxp, num_doccxc VARCHAR(25)
|
||||
|
||||
|
||||
@@ -35,7 +35,27 @@ DEFINE xusername,xsmtphost,xsmtpport,xpassword STRING,
|
||||
|
||||
toEmail, orden_trabajo, answer_workorder, descrip_depto STRING, depto INT
|
||||
|
||||
DEFINE data RECORD LIKE cotb00001.*
|
||||
DEFINE data RECORD
|
||||
area_sp VARCHAR(10),
|
||||
ciu_sp VARCHAR(30),
|
||||
cod_pais VARCHAR(3),
|
||||
cod_sp SMALLINT,
|
||||
cod_sp_sec SMALLINT,
|
||||
cont_sp VARCHAR(30),
|
||||
contactID INTEGER,
|
||||
dir_sp VARCHAR(60),
|
||||
email VARCHAR(60),
|
||||
fax_sp VARCHAR(25),
|
||||
fech_crea DATETIME YEAR TO FRACTION,
|
||||
fech_mod DATETIME YEAR TO FRACTION,
|
||||
id_maintainx INTEGER,
|
||||
nom_sp VARCHAR(41),
|
||||
status_t VARCHAR(1),
|
||||
tel_sp VARCHAR(25),
|
||||
term_sp SMALLINT,
|
||||
us_crea VARCHAR(50),
|
||||
us_mod VARCHAR(50)
|
||||
END RECORD
|
||||
|
||||
DEFINE container RECORD
|
||||
tipo_inv STRING,
|
||||
|
||||
@@ -1596,7 +1596,7 @@ FUNCTION cppcmd000()
|
||||
END IF
|
||||
END FOR
|
||||
|
||||
IF entradas_atadas[0].entrada IS NOT NULL THEN
|
||||
IF entradas_atadas[1].entrada IS NOT NULL THEN
|
||||
DELETE FROM cptb00010
|
||||
WHERE num_doc = factura.num_doc
|
||||
AND cod_sp = factura.cod_sp
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<RecordField colName="m_meses" fieldIdRef="0" name="m_meses" sqlTabName="formonly" uid="{a86d2184-b2b8-4d43-9290-5734a571188e}"/>
|
||||
<RecordField colName="dias1" fieldIdRef="1" name="dias1" sqlTabName="formonly" uid="{941f7da0-4442-4cef-a4f2-b5e701ef9adb}"/>
|
||||
<RecordField colName="cod_cat" fieldIdRef="2" name="cod_cat" sqlTabName="formonly" uid="{e66efc0a-8770-4d48-8f6e-35122ee73b09}"/>
|
||||
<RecordField colName="tipo_reporte" fieldIdRef="10" name="tipo_reporte" sqlTabName="formonly" uid="{b1c2d3e4-1013-4a10-9a10-000000000010}"/>
|
||||
<RecordField colName="cod_n" fieldIdRef="6" fieldType="TABLE_COLUMN" name="intb00001.cod_n" sqlTabName="intb00001" uid="{cd27b48c-6a61-412e-99b5-7c46aa76c481}"/>
|
||||
<RecordField colName="cod_grupo" fieldIdRef="7" fieldType="TABLE_COLUMN" name="intb00001.cod_grupo" sqlTabName="intb00001" uid="{494ef5de-3185-48f2-8cc3-b8bd0d5250cf}"/>
|
||||
<RecordField colName="cod_tipo" fieldIdRef="8" fieldType="TABLE_COLUMN" name="intb00001.cod_tipo" sqlTabName="intb00001" uid="{e8caebc6-7e5e-400a-b9b2-6431d073a46f}"/>
|
||||
@@ -37,6 +38,8 @@
|
||||
<Edit colName="cod_tipo" comment="Digite el TIPO" fieldId="8" fieldType="TABLE_COLUMN" gridHeight="1" gridWidth="4" name="intb00001.cod_tipo" posX="52" posY="5" sqlTabName="intb00001" tabIndex="9" widget="Edit"/>
|
||||
<Label gridHeight="1" gridWidth="1" name="label10" posX="57" posY="5" text="-"/>
|
||||
<Edit colName="cod_sec" comment="Digite la SECUENCIA" fieldId="9" fieldType="TABLE_COLUMN" gridHeight="1" gridWidth="4" name="intb00001.cod_sec" posX="59" posY="5" sqlTabName="intb00001" tabIndex="10" widget="Edit"/>
|
||||
<Label gridHeight="1" gridWidth="12" name="label11" posX="10" posY="7" text="Tipo Reporte"/>
|
||||
<ComboBox colName="tipo_reporte" comment="Detallado (por producto) o Resumen (por clase)" fieldId="10" gridHeight="1" gridWidth="25" items="" name="tipo_reporte" posX="25" posY="7" sqlTabName="formonly" tabIndex="11" widget="ComboBox"/>
|
||||
</Grid>
|
||||
</Form>
|
||||
<DiagramLayout>
|
||||
|
||||
@@ -7,6 +7,7 @@ screen size 24 by 80
|
||||
Dias consumo [p1 ]
|
||||
Categorias [ca1 ]
|
||||
Codigo del Prod. Terminado [a ]-[b ]-[c ]-[d ]
|
||||
Tipo Reporte [tr ]
|
||||
}
|
||||
end
|
||||
tables
|
||||
@@ -15,6 +16,7 @@ attributes
|
||||
ll = formonly.m_meses;
|
||||
p1 = formonly.dias1;
|
||||
COMBOBOX ca1=formonly.cod_cat;
|
||||
COMBOBOX tr=formonly.tipo_reporte;
|
||||
DATEEDIT k1 = formonly.fecha1 type date,format = "dd/mm/yy",
|
||||
comments = "Digite la fecha inicial. Utilice el formato 'DDMMAA'";
|
||||
DATEEDIT k2 = formonly.fecha2 type date,format = "dd/mm/yy",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<RecordField fieldIdRef="10" name="representa" uid="{a33da8bb-5056-4822-9800-277a3e3aff34}"/>
|
||||
<RecordField defaultValue="NO" fieldIdRef="11" name="chexistencia" uid="{de68d342-97e5-4a64-af4d-c31664950aaa}"/>
|
||||
<RecordField fieldIdRef="12" name="progreso" uid="{97aa7412-688e-4594-93e6-9c2366fdee1d}"/>
|
||||
<RecordField colName="tipo_reporte" fieldIdRef="13" name="tipo_reporte" sqlTabName="formonly" uid="{b1c2d3e4-1014-4a14-9a14-000000000014}"/>
|
||||
</Record>
|
||||
<Form gridHeight="24" gridWidth="80" name="ipfmrp013">
|
||||
<Grid gridHeight="24" gridWidth="80" name="grid1" posX="0" posY="0">
|
||||
@@ -44,7 +45,9 @@
|
||||
<Edit colName="cod_grupo" comment="Digite el GRUPO" fieldId="7" fieldType="TABLE_COLUMN" gridHeight="1" gridWidth="4" name="intb00001.cod_grupo" posX="45" posY="7" sqlTabName="intb00001" tabIndex="8" widget="Edit"/>
|
||||
<Edit colName="cod_tipo" comment="Digite el TIPO" fieldId="8" fieldType="TABLE_COLUMN" gridHeight="1" gridWidth="4" name="intb00001.cod_tipo" posX="52" posY="7" sqlTabName="intb00001" tabIndex="9" widget="Edit"/>
|
||||
<Edit colName="cod_sec" comment="Digite la SECUENCIA" fieldId="9" fieldType="TABLE_COLUMN" gridHeight="1" gridWidth="4" name="intb00001.cod_sec" posX="59" posY="7" sqlTabName="intb00001" tabIndex="10" widget="Edit"/>
|
||||
<ProgressBar fieldId="12" gridHeight="1" gridWidth="27" name="progreso" posX="10" posY="9" title="progressbar1" valueMin="10" widget="ProgressBar"/>
|
||||
<Label gridHeight="1" gridWidth="12" name="label11" posX="10" posY="8" text="Tipo Reporte"/>
|
||||
<ComboBox colName="tipo_reporte" comment="Detallado (por producto) o Resumen (por clase)" fieldId="13" gridHeight="1" gridWidth="25" items="" name="tipo_reporte" posX="25" posY="8" sqlTabName="formonly" tabIndex="11" widget="ComboBox"/>
|
||||
<ProgressBar fieldId="12" gridHeight="1" gridWidth="27" name="progreso" posX="10" posY="10" title="progressbar1" valueMin="10" widget="ProgressBar"/>
|
||||
</Grid>
|
||||
</Form>
|
||||
<DiagramLayout>
|
||||
|
||||
@@ -3319,6 +3319,12 @@ FUNCTION ipprad44()
|
||||
|
||||
PREPARE smt FROM procedimiento
|
||||
|
||||
# Guardia sobre el SP: por defecto WHENEVER ERROR STOP
|
||||
# detiene el programa si el SP lanza un error SQL (p.ej.
|
||||
# -3998 "transaccion no-confirmable"), sin llegar a la
|
||||
# validacion limpia de out_result. Lo capturamos para
|
||||
# revertir y avisar en vez de crashear.
|
||||
WHENEVER ERROR CONTINUE
|
||||
EXECUTE smt
|
||||
USING ordenx IN,
|
||||
--idx IN,
|
||||
@@ -3367,6 +3373,27 @@ FUNCTION ipprad44()
|
||||
out_cantidad_item OUT,
|
||||
out_cantidad_ubicacion OUT,
|
||||
out_msg OUT
|
||||
WHENEVER ERROR STOP
|
||||
|
||||
# Si el EXEC del SP fallo a nivel SQL (STATUS < 0), como el
|
||||
# -3998 que deja la transaccion doomed, revertir y avisar
|
||||
# limpiamente en vez de detener el programa.
|
||||
IF STATUS < 0 THEN
|
||||
DISPLAY "ERROR SQL sp_insert_inventario: ",
|
||||
STATUS, " ", SQLERRMESSAGE
|
||||
DISPLAY "ITEM: ",
|
||||
movi2[idx].cod_n, "-",
|
||||
movi2[idx].cod_grupo, "-",
|
||||
movi2[idx].cod_tipo, "-",
|
||||
movi2[idx].cod_sec
|
||||
DISPLAY "DOCUMENTO: ", otros_mov.num_doc,
|
||||
" MOV: ", otros_mov.cod_mov,
|
||||
" BODEGA: ", otros_mov.bodega
|
||||
ROLLBACK WORK
|
||||
LET numero_msg = 1679
|
||||
CALL msg(numero_msg)
|
||||
NEXT FIELD cod_n
|
||||
END IF
|
||||
|
||||
IF out_result <> 0 THEN
|
||||
|
||||
@@ -3396,7 +3423,13 @@ FUNCTION ipprad44()
|
||||
|
||||
DISPLAY "============================================"
|
||||
|
||||
# El SP pudo haber revertido ya la transaccion si
|
||||
# quedo condenada (CATCH con XACT_STATE = -1). Hacemos
|
||||
# este ROLLBACK tolerante para no crashear si ya no
|
||||
# hay transaccion activa.
|
||||
WHENEVER ERROR CONTINUE
|
||||
ROLLBACK WORK
|
||||
WHENEVER ERROR STOP
|
||||
|
||||
IF out_msg IS NOT NULL THEN
|
||||
ERROR out_msg
|
||||
|
||||
+305
-16
@@ -5,9 +5,40 @@ OBJETIVO : REPORTE DIAS DE INVENTARIOS
|
||||
PROGRAMADOR : Ing. Juan Francisco Soto
|
||||
FECHA REALIZACION : Agosto 19, 1992
|
||||
MODIFICADO POR : Ing. Juan Fco. Soto
|
||||
FECHA ULT. MODIFICA : Julio 19, 1993.
|
||||
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"
|
||||
@@ -19,6 +50,31 @@ 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
|
||||
@@ -33,6 +89,9 @@ 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
|
||||
@@ -66,7 +125,16 @@ DEFINE c_dias INTEGER
|
||||
costo DECIMAL(12,4),
|
||||
dias INTEGER,
|
||||
pcodigo char(25),
|
||||
cantidad_orden,pcantidadConduce,transito,existencia,reservado,disponible DEC(12,2)
|
||||
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
|
||||
@@ -87,8 +155,26 @@ DEFINE c_dias INTEGER
|
||||
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
|
||||
|
||||
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
|
||||
@@ -117,6 +203,12 @@ DEFINE c_dias INTEGER
|
||||
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
|
||||
@@ -229,9 +321,17 @@ DEFINE c_dias INTEGER
|
||||
DECLARE consu SCROLL CURSOR FOR busca_balan
|
||||
OPEN consu USING fecha2
|
||||
}
|
||||
LET r_filename = "ipprrp013.4rp"
|
||||
# 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 "&&&&","-",
|
||||
@@ -261,7 +361,11 @@ DEFINE c_dias INTEGER
|
||||
END IF
|
||||
--run the report
|
||||
IF handler IS NOT NULL THEN -- report engine was configured ok
|
||||
START REPORT estadistica TO XML HANDLER HANDLER
|
||||
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
|
||||
@@ -299,6 +403,17 @@ END WHILE
|
||||
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
|
||||
@@ -328,25 +443,115 @@ IF estadis.dias >= c_dias THEN
|
||||
LET estadis.valor = 0
|
||||
END IF
|
||||
END IF
|
||||
# Costo STD
|
||||
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
|
||||
DISPLAY "DATA DESPUES ",estadis.existe
|
||||
|
||||
# ============================================================================
|
||||
# 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
|
||||
OUTPUT TO REPORT estadistica(estadis.*,dias1,c_dias)
|
||||
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
|
||||
FINISH REPORT estadistica
|
||||
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
|
||||
|
||||
@@ -354,6 +559,25 @@ END FOREACH
|
||||
|
||||
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,
|
||||
@@ -372,7 +596,16 @@ REPORT estadistica(x,dias2,c_dias)
|
||||
costo DECIMAL(12,4),
|
||||
dias INTEGER,
|
||||
pcodigo char(25),
|
||||
cantidad_orden,pcantidadConduce,transito,existencia,reservado,disponible DEC(12,2)
|
||||
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
|
||||
@@ -500,3 +733,59 @@ REPORT estadistica(x,dias2,c_dias)
|
||||
|
||||
|
||||
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
|
||||
|
||||
+256
-19
@@ -23,6 +23,23 @@ DESCRIPCION : OPTIMIZACION DE RENDIMIENTO:
|
||||
inventario rota en el periodo). Se agrega ademas
|
||||
la rotacion anualizada = rotacion * (365/dias).
|
||||
DIAS INV se mantiene igual (formula correcta).
|
||||
|
||||
AGOSTO 20, 2026 - MARGEN + DETALLADO/RESUMEN:
|
||||
5. 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
|
||||
COSTO estandar (iptb00004, antes quedaba en 0). Margen %
|
||||
sobre precio = (precio-costo)/precio*100. Clasificacion
|
||||
por cuadrante margen x rotacion (ESTRELLA/VOLUMEN/NICHO/
|
||||
REVISAR/SIN COSTO), umbrales g_margen_min / g_rot_min.
|
||||
6. El formulario permite elegir DETALLADO (una linea por
|
||||
producto -> ipprrp014.4rp) o RESUMEN por CLASE cod_n
|
||||
(subtotales -> ipprrp014r.4rp). La agregacion por clase
|
||||
se hace en el FOREACH (emite_clase) y el reporte
|
||||
'resumen' es PLANO (una fila por clase, total al pie).
|
||||
NOTA: el consumo del 014 es de PRODUCCION
|
||||
(pcantidadConduce); el margen ponderado de la clase pesa
|
||||
por ese consumo.
|
||||
-------------------------------------------------------------------------------
|
||||
}
|
||||
GLOBALS "ipprgb000.4gl"
|
||||
@@ -39,6 +56,29 @@ DEFINE
|
||||
chexistencia CHAR(2),
|
||||
progreso, cuenta_reg, cuenta INT
|
||||
|
||||
# Umbrales de clasificacion margen/rotacion (ajustables aqui)
|
||||
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 la funcion principal 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)
|
||||
DEFINE prev_cod_n INTEGER
|
||||
DEFINE cbtipo ui.ComboBox
|
||||
|
||||
MAIN
|
||||
DEFER INTERRUPT
|
||||
CALL ARG_VAL(1) RETURNING usuarios
|
||||
@@ -95,7 +135,14 @@ FUNCTION ipprrp013()
|
||||
disponible,
|
||||
precio,
|
||||
rotacion
|
||||
DEC(12, 2)
|
||||
DEC(12, 2),
|
||||
# --- Analisis margen (Agosto 2026) ---
|
||||
rotacion_anual DEC(12,4),
|
||||
margen DEC(12,2),
|
||||
valor_inv DEC(14,2),
|
||||
ventas_valor DEC(14,2),
|
||||
ganancia DEC(14,2),
|
||||
clasificacion CHAR(12)
|
||||
END RECORD
|
||||
|
||||
DEFINE
|
||||
@@ -111,11 +158,24 @@ FUNCTION ipprrp013()
|
||||
DISPLAY "ipprrp014" AT 4, 3 ATTRIBUTE(RED)
|
||||
DISPLAY "Dias de Inventarios Gerente Marcas" AT 6, 33 ATTRIBUTE(BLACK)
|
||||
|
||||
INPUT BY NAME fecha1, fecha2, c_dias, m_meses, chexistencia
|
||||
INPUT BY NAME fecha1, fecha2, c_dias, m_meses, chexistencia, tipo_reporte
|
||||
BEFORE INPUT
|
||||
LET progreso = 10
|
||||
LET c_dias = 0
|
||||
DISPLAY BY NAME c_dias, progreso
|
||||
# Umbrales de clasificacion margen/rotacion
|
||||
LET g_margen_min = 25.00
|
||||
LET g_rot_min = 2.00
|
||||
# Combo Detallado / Resumen (llenado por codigo)
|
||||
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
|
||||
IF tipo_reporte IS NULL OR tipo_reporte = " " THEN
|
||||
LET tipo_reporte = "D"
|
||||
END IF
|
||||
DISPLAY BY NAME c_dias, progreso, tipo_reporte
|
||||
SELECT DISTINCT RTRIM(a.nom1_emp) + ' ' + RTRIM(a.apell1_emp),
|
||||
a.num_emp
|
||||
INTO representa, num_representa
|
||||
@@ -159,6 +219,11 @@ FUNCTION ipprrp013()
|
||||
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
|
||||
AFTER INPUT
|
||||
|
||||
IF int_flag THEN
|
||||
@@ -252,9 +317,15 @@ FUNCTION ipprrp013()
|
||||
PREPARE comando2 FROM select_bal
|
||||
DECLARE accion CURSOR FOR comando2
|
||||
|
||||
LET r_filename = "ipprrp014.4rp"
|
||||
# Detallado (D) -> ipprrp014.4rp ; Resumen por clase (R) -> ipprrp014r.4rp
|
||||
IF tipo_reporte = "R" THEN
|
||||
LET r_filename = "ipprrp014r.4rp"
|
||||
ELSE
|
||||
LET r_filename = "ipprrp014.4rp"
|
||||
END IF
|
||||
|
||||
LET idx = 1
|
||||
LET prev_cod_n = -999999
|
||||
DISPLAY progreso TO progreso
|
||||
CALL ui.Interface.refresh()
|
||||
|
||||
@@ -290,7 +361,11 @@ FUNCTION ipprrp013()
|
||||
EXIT PROGRAM
|
||||
END IF
|
||||
IF handler IS NOT NULL THEN
|
||||
START REPORT estadistica TO XML HANDLER handler
|
||||
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
|
||||
@@ -321,6 +396,31 @@ FUNCTION ipprrp013()
|
||||
END IF
|
||||
|
||||
LET estadis.existe = estadis.existencia
|
||||
|
||||
# ---- COSTO ESTANDAR (iptb00004). Antes quedaba en 0; ahora se calcula
|
||||
# para poder obtener el margen y el valor de exceso reales. ----
|
||||
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
|
||||
|
||||
# ---- PRECIO de venta REAL promedio del periodo (ponderado por cantidad,
|
||||
# neto del descuento de cabecera). Fuente vetb00002 + vetb00003. ----
|
||||
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
|
||||
|
||||
# Calculo para los dias de produccion
|
||||
IF estadis.existe > 0 THEN
|
||||
LET estadis.cantidad_orden =
|
||||
@@ -329,25 +429,21 @@ FUNCTION ipprrp013()
|
||||
estadis.existe - estadis.cantidad_orden - estadis.reservado
|
||||
IF estadis.consumo > 0 THEN
|
||||
LET estadis.dias = (estadis.existe / estadis.consumo) * dias1
|
||||
# ==============================================================
|
||||
# FORMULA CORREGIDA: indice de rotacion = consumo / existencia
|
||||
# (veces que rota el inventario en el periodo).
|
||||
# La formula anterior (existe/consumo) era la COBERTURA.
|
||||
# Nota: idealmente usar existencia PROMEDIO del periodo:
|
||||
# (existencia a fecha1 + existencia a fecha2) / 2
|
||||
# ==============================================================
|
||||
# indice de rotacion = consumo / existencia (veces en el periodo)
|
||||
LET estadis.rotacion = estadis.consumo / estadis.existe
|
||||
LET rotacion_anual = estadis.rotacion * (365 / dias1)
|
||||
# anualizada: 365.0 (decimal) evita la division entera
|
||||
LET estadis.rotacion_anual = estadis.rotacion * (365.0 / dias1)
|
||||
ELSE
|
||||
LET estadis.rotacion = 0
|
||||
LET rotacion_anual = 0
|
||||
LET estadis.rotacion_anual = 0
|
||||
END IF
|
||||
|
||||
ELSE
|
||||
LET estadis.dias = 0
|
||||
LET estadis.rotacion = 0
|
||||
LET rotacion_anual = 0
|
||||
LET estadis.rotacion_anual = 0
|
||||
END IF
|
||||
LET rotacion_anual = estadis.rotacion_anual
|
||||
|
||||
LET estadis.valor = 0
|
||||
IF estadis.dias >= c_dias THEN
|
||||
@@ -358,15 +454,69 @@ FUNCTION ipprrp013()
|
||||
LET estadis.valor = 0
|
||||
END IF
|
||||
END IF
|
||||
LET estadis.costo = 0
|
||||
|
||||
OUTPUT TO REPORT estadistica(estadis.*, dias1, c_dias, rotacion_anual)
|
||||
# ---- Margen % sobre precio, valores y clasificacion por cuadrante ----
|
||||
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
|
||||
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)
|
||||
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 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
|
||||
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, estadis.rotacion_anual)
|
||||
END IF
|
||||
|
||||
LET idx = idx + 1
|
||||
LET estadis.consumo = 0
|
||||
LET estadis.existe = 0
|
||||
LET estadis.dias = 0
|
||||
LET estadis.rotacion = 0
|
||||
LET estadis.rotacion_anual = 0
|
||||
LET estadis.precio = 0
|
||||
LET estadis.margen = 0
|
||||
|
||||
# Refrescar progreso solo cada 50 filas: cada refresh es un
|
||||
# round-trip al GDC y hacerlo por fila cuesta minutos.
|
||||
@@ -380,13 +530,91 @@ FUNCTION ipprrp013()
|
||||
CALL fgl_winmessage(
|
||||
"INFO", "NO EXISTEN INFORMACIONES CON ESTOS PARAMETROS", "INFO")
|
||||
ELSE
|
||||
# Emite la ultima clase acumulada (modo Resumen)
|
||||
IF tipo_reporte = "R" AND prev_cod_n <> -999999 THEN
|
||||
CALL emite_clase()
|
||||
END IF
|
||||
LET progreso = 100
|
||||
DISPLAY progreso TO progreso
|
||||
FINISH REPORT estadistica
|
||||
IF tipo_reporte = "R" THEN
|
||||
FINISH REPORT resumen
|
||||
ELSE
|
||||
FINISH REPORT estadistica
|
||||
END IF
|
||||
END IF
|
||||
|
||||
END FUNCTION
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Calcula margen ponderado y rotacion promedio de la clase acumulada en 'rc' y la
|
||||
# envia al reporte 'resumen'. Usada 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
|
||||
|
||||
# ==============================================================================
|
||||
# REPORTE RESUMEN POR CLASE (cod_n) -- version PLANA (una fila por clase).
|
||||
# La agregacion la hace el FOREACH (emite_clase); aqui solo se imprime y se
|
||||
# acumula el gran total para el pie. Alimenta ipprrp014r.4rp.
|
||||
# ==============================================================================
|
||||
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
|
||||
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
|
||||
|
||||
REPORT estadistica(x, dias2, c_dias, rot_anual)
|
||||
DEFINE
|
||||
x RECORD
|
||||
@@ -416,7 +644,14 @@ REPORT estadistica(x, dias2, c_dias, rot_anual)
|
||||
disponible,
|
||||
precio,
|
||||
rotacion
|
||||
DEC(12, 2)
|
||||
DEC(12, 2),
|
||||
# --- Analisis margen (Agosto 2026) - debe reflejar estadis ---
|
||||
rotacion_anual DEC(12,4),
|
||||
margen DEC(12,2),
|
||||
valor_inv DEC(14,2),
|
||||
ventas_valor DEC(14,2),
|
||||
ganancia DEC(14,2),
|
||||
clasificacion CHAR(12)
|
||||
END RECORD,
|
||||
tcantidad DEC(12, 4),
|
||||
|
||||
@@ -491,6 +726,8 @@ REPORT estadistica(x, dias2, c_dias, rot_anual)
|
||||
x.dias,
|
||||
x.rotacion,
|
||||
rot_anual,
|
||||
x.margen,
|
||||
x.clasificacion,
|
||||
x.unidad_med,
|
||||
fecha,
|
||||
hora,
|
||||
|
||||
@@ -38,7 +38,32 @@ DEFINE CheckApi RECORD
|
||||
checkRep BOOLEAN
|
||||
END RECORD
|
||||
|
||||
DEFINE fakeData RECORD LIKE cotb00001.*
|
||||
# fakeData se pasa POR POSICION (fakeData.*) al parametro Data de
|
||||
# ApiMaintainC en api_test.4gl, por lo que su estructura (orden y tipos)
|
||||
# debe ser IDENTICA a ese record. No usar RECORD LIKE cotb00001.* porque
|
||||
# el orden fisico de las columnas de cotb00001 no coincide con ese record
|
||||
# y provoca el error -1260 al convertir los tipos.
|
||||
DEFINE fakeData RECORD
|
||||
area_sp VARCHAR(10),
|
||||
ciu_sp VARCHAR(30),
|
||||
cod_pais VARCHAR(3),
|
||||
cod_sp SMALLINT,
|
||||
cod_sp_sec SMALLINT,
|
||||
cont_sp VARCHAR(30),
|
||||
contactID INTEGER,
|
||||
dir_sp VARCHAR(60),
|
||||
email VARCHAR(60),
|
||||
fax_sp VARCHAR(25),
|
||||
fech_crea DATETIME YEAR TO FRACTION,
|
||||
fech_mod DATETIME YEAR TO FRACTION,
|
||||
id_maintainx INTEGER,
|
||||
nom_sp VARCHAR(41),
|
||||
status_t VARCHAR(1),
|
||||
tel_sp VARCHAR(25),
|
||||
term_sp SMALLINT,
|
||||
us_crea VARCHAR(50),
|
||||
us_mod VARCHAR(50)
|
||||
END RECORD
|
||||
|
||||
DEFINE data RECORD
|
||||
rnumeroDoc,rcodMov,rtipo_cliente,num_oc,tipo_cliente,sec_cliente,bodega,bodega_destino INT,
|
||||
|
||||
Reference in New Issue
Block a user