This commit is contained in:
Abel López
2026-08-25 16:59:08 -04:00
16 changed files with 864 additions and 85 deletions
+1 -1
View File
@@ -40,7 +40,7 @@
<Label gridHeight="1" gridWidth="8" name="label2" posX="24" posY="1" text="FECHA FINAL"/>
<DateEdit fieldId="16" gridHeight="1" gridWidth="13" name="fech_final" posX="33" posY="1" tabIndex="-1" title="dateedit2" widget="DateEdit"/>
<Label gridHeight="1" gridWidth="6" name="label3" posX="47" posY="1" text="ESTADO "/>
<ComboBox fieldId="17" gridHeight="1" gridWidth="12" items="ABIERTA, CERRADA" name="estado1" posX="54" posY="1" tabIndex="-1" title="combobox1" widget="ComboBox">
<ComboBox fieldId="17" gridHeight="1" gridWidth="12" items="ABIERTA, CERRADA" name="estado1" notNull="true" posX="54" posY="1" tabIndex="-1" title="combobox1" widget="ComboBox">
<Item lstrtext="false" name="ABIERTA" text="ABIERTA"/>
<Item lstrtext="false" name="CERRADA" text="CERRADA"/>
</ComboBox>
+72
View File
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ManagedForm databaseName="smarmotech" fileVersion="40100" gstVersion="60003" name="ManagedForm" uid="{50926d70-025d-4be1-a15f-45acbf1b2888}">
<AGSettings>
<DynamicProperties version="4"/>
</AGSettings>
<Record name="record1" uid="{ae577ed1-a849-40c1-a3a8-3df0bfba35f6}">
<RecordField colName="cotizacion_no" fieldIdRef="5" name="cotizacion_no" sqlTabName="formonly" uid="{34fb79d0-ea3c-45e5-bd43-bd2484db0e24}"/>
<RecordField colName="num_oc" fieldIdRef="12" name="num_oc" sqlTabName="formonly" uid="{1b817c74-fb63-4453-9c9e-580cd0ebe8dd}"/>
<RecordField colName="cerrada" fieldIdRef="10" name="cerrada" sqlTabName="formonly" uid="{a0ade89e-f809-4801-83fc-82267e75339d}"/>
<RecordField colName="sec_vend" fieldIdRef="13" name="sec_vend" sqlTabName="formonly" uid="{532f53e9-4b3f-4c15-8919-c4afedd6e638}"/>
<RecordField colName="historico" defaultValue="N" fieldIdRef="0" name="historico" sqlTabName="formonly" uid="{a297c185-81e7-4ae6-8988-2224946811de}"/>
<RecordField colName="fecha" fieldIdRef="11" name="fecha" sqlTabName="formonly" sqlType="DATE" uid="{62430a14-a00f-413f-b6b1-766e90f9315e}"/>
<RecordField colName="tipo_cliente" fieldIdRef="7" name="tipo_cliente" sqlTabName="formonly" uid="{7cf8df86-dc57-4cd8-9b40-6636785559c9}"/>
<RecordField colName="sec_cliente" fieldIdRef="8" name="sec_cliente" sqlTabName="formonly" uid="{c77b4cbf-8ab9-4072-b566-5ce5401f170b}"/>
<RecordField colName="nombre_cliente" fieldIdRef="6" name="nombre_cliente" sqlTabName="formonly" uid="{b775b626-23dd-4f6c-8fda-b729a1e40605}"/>
<RecordField colName="telefono_r" fieldIdRef="9" name="telefono_r" sqlTabName="formonly" uid="{c545bc0e-23c1-465b-9688-5d5039b27597}"/>
<RecordField colName="cod_n" fieldIdRef="1" name="cod_n" sqlTabName="formonly" uid="{a8bcc1fa-5503-4b65-8249-fdaa1e91c258}"/>
<RecordField colName="cod_grupo" fieldIdRef="2" name="cod_grupo" sqlTabName="formonly" uid="{71e68d6d-8151-44c2-a42c-4e9465dd3c2b}"/>
<RecordField colName="cod_tipo" fieldIdRef="3" name="cod_tipo" sqlTabName="formonly" uid="{a5d7c1ab-90d7-4feb-b86d-6a74f1966b44}"/>
<RecordField colName="cod_sec" fieldIdRef="4" name="cod_sec" sqlTabName="formonly" uid="{0fed854c-cd15-4a85-b593-c3a9f114d277}"/>
<RecordField colName="salida" defaultValue="Detallado" fieldIdRef="14" name="salida" sqlTabName="formonly" uid="{72b478e3-81f8-4d24-ad49-d777be1c0608}"/>
<RecordField colName="visualiza" defaultValue="PANTALLA" fieldIdRef="15" name="visualiza" sqlTabName="formonly" uid="{7c7aa938-7433-4dd6-bcc2-c27d6b3e2e34}"/>
</Record>
<Form gridHeight="10" gridWidth="67" name="prfmrp116" text="STATUS ORDENES PEDIDOS">
<ActionDefaultList name="actiondefaultlist1">
<ActionDefault image="print" name="ejecutar" text="Genera Reporte"/>
</ActionDefaultList>
<Grid gridHeight="10" gridWidth="67" name="grid1" posX="0" posY="0">
<Label gridHeight="1" gridWidth="10" name="label1" posX="3" posY="0" text="Cotizacion"/>
<Edit colName="cotizacion_no" comment="Digite un numero de cotizacion o deje en blanco para todas" fieldId="5" gridHeight="1" gridWidth="10" name="cotizacion_no" posX="19" posY="0" sqlTabName="formonly" tabIndex="1" widget="Edit"/>
<Label gridHeight="1" gridWidth="5" name="label2" posX="3" posY="1" text="Orden"/>
<Edit colName="num_oc" comment="Digite un numero de orden o deje en blanco para todas" fieldId="12" gridHeight="1" gridWidth="10" name="num_oc" posX="19" posY="1" sqlTabName="formonly" tabIndex="2" widget="Edit"/>
<Label gridHeight="1" gridWidth="12" name="label3" posX="34" posY="1" text="Status Orden"/>
<ComboBox colName="cerrada" fieldId="10" gridHeight="1" gridWidth="14" items="Cerrada, Abiertas" name="cerrada" notNull="true" posX="47" posY="1" sqlTabName="formonly" tabIndex="3" widget="ComboBox">
<Item name="S" text="Cerrada"/>
<Item name="N" text="Abiertas"/>
</ComboBox>
<Label gridHeight="1" gridWidth="8" name="label4" posX="3" posY="2" text="Vendedor"/>
<Edit colName="sec_vend" comment="Digite un numero de vendedor o deje en blanco para todos" fieldId="13" gridHeight="1" gridWidth="10" name="sec_vend" posX="19" posY="2" sqlTabName="formonly" tabIndex="4" widget="Edit"/>
<RadioGroup colName="historico" defaultValue="N" fieldId="0" gridHeight="1" gridWidth="26" items="HISTORICO, ACTUAL" name="historico" posX="35" posY="2" sqlTabName="formonly" tabIndex="5" widget="RadioGroup">
<Item name="H" text="HISTORICO"/>
<Item name="N" text="ACTUAL"/>
</RadioGroup>
<Label gridHeight="1" gridWidth="5" name="label5" posX="3" posY="3" text="Fecha"/>
<DateEdit colName="fecha" fieldId="11" format="dd/mm/yyyy" gridHeight="1" gridWidth="10" name="fecha" posX="19" posY="3" sqlTabName="formonly" sqlType="DATE" tabIndex="6" widget="DateEdit"/>
<Label gridHeight="1" gridWidth="15" name="label6" posX="3" posY="4" text="Codigo Cliente"/>
<Edit colName="tipo_cliente" fieldId="7" gridHeight="1" gridWidth="3" name="tipo_cliente" posX="19" posY="4" sqlTabName="formonly" tabIndex="7" widget="Edit"/>
<Label gridHeight="1" gridWidth="1" name="label7" posX="23" posY="4" text="-"/>
<Edit colName="sec_cliente" fieldId="8" gridHeight="1" gridWidth="6" name="sec_cliente" posX="25" posY="4" sqlTabName="formonly" tabIndex="8" widget="Edit"/>
<Label gridHeight="1" gridWidth="15" name="label8" posX="3" posY="5" text="Nombre Cliente"/>
<Edit colName="nombre_cliente" comment="Utilice el simbolo (*) para buscar nombres similares al que desea" fieldId="6" gridHeight="1" gridWidth="47" name="nombre_cliente" posX="19" posY="5" sqlTabName="formonly" tabIndex="9" widget="Edit"/>
<Label gridHeight="1" gridWidth="13" name="label9" posX="3" posY="6" text="Telefono Res."/>
<Edit colName="telefono_r" fieldId="9" gridHeight="1" gridWidth="15" name="telefono_r" posX="19" posY="6" sqlTabName="formonly" tabIndex="10" widget="Edit"/>
<Label gridHeight="1" gridWidth="8" name="label10" posX="3" posY="7" text="Producto"/>
<Edit colName="cod_n" fieldId="1" gridHeight="1" gridWidth="5" name="cod_n" posX="19" posY="7" sqlTabName="formonly" tabIndex="11" widget="Edit"/>
<Edit colName="cod_grupo" fieldId="2" gridHeight="1" gridWidth="6" name="cod_grupo" posX="26" posY="7" sqlTabName="formonly" tabIndex="12" widget="Edit"/>
<Edit colName="cod_tipo" fieldId="3" gridHeight="1" gridWidth="6" name="cod_tipo" posX="34" posY="7" sqlTabName="formonly" tabIndex="13" widget="Edit"/>
<Edit colName="cod_sec" fieldId="4" gridHeight="1" gridWidth="7" name="cod_sec" posX="42" posY="7" sqlTabName="formonly" tabIndex="14" widget="Edit"/>
<Label gridHeight="1" gridWidth="15" name="label11" posX="3" posY="8" text="Salida Reporte"/>
<ComboBox colName="salida" defaultValue="Detallado" fieldId="14" gridHeight="1" gridWidth="15" items="Detallado, Resumido" name="salida" posX="19" posY="8" sqlTabName="formonly" tabIndex="15" widget="ComboBox">
<Item name="prprrp116.4rp" text="Detallado"/>
<Item name="prprrp016a.4rp" text="Resumido"/>
</ComboBox>
<Label gridHeight="1" gridWidth="13" name="label12" posX="3" posY="9" text="Visualizacion"/>
<ComboBox colName="visualiza" defaultValue="PANTALLA" fieldId="15" gridHeight="1" gridWidth="15" items="PANTALLA, ACROBAT READER, EXCEL" name="visualiza" posX="19" posY="9" sqlTabName="formonly" tabIndex="16" widget="ComboBox">
<Item name="SVG" text="PANTALLA"/>
<Item name="PDF" text="ACROBAT READER"/>
<Item name="XLSX" text="EXCEL"/>
</ComboBox>
</Grid>
</Form>
</ManagedForm>
+1 -1
View File
@@ -48,7 +48,7 @@ DATEEDIT f1 = formonly.fecha type date,format = "dd/mm/yyyy";
o1 = formonly.num_oc,comments="Digite un numero de orden o deje en blanco para todas";
v1 = formonly.sec_vend,comments="Digite un numero de vendedor o deje en blanco para todos";
COMBOBOX s=formonly.salida,ITEMS=(("prprrp116.4rp","Detallado"),("prprrp016a.4rp","Resumido")),default="Detallado";
COMBOBOX v=formonly.visualiza,ITEMS=(("SVG","PANTALLA"),("PDF","ACROBAT READER")),default="PANTALLA";
COMBOBOX v=formonly.visualiza,ITEMS=(("SVG","PANTALLA"),("PDF","ACROBAT READER"),("XLSX","EXCEL")),default="PANTALLA";
instructions
delimiters " "
end
+3 -1
View File
@@ -71,7 +71,9 @@ DEFINE hoy DATE
END INPUT
CONSTRUCT BY NAME criterio ON a.tipo_cliente,a.sec_cliente,
a.num_oc,a.fecha
a.num_oc,a.fecha_oc
FROM tipo_cliente,sec_cliente,
num_oc,fecha
AFTER CONSTRUCT
IF tipo_orden = 'N' THEN
+63 -28
View File
@@ -79,6 +79,8 @@ FUNCTION prprrp016()
END RECORD,
salida,visualiza CHAR(20)
DEFINE hay_datos SMALLINT
OPTIONS
PROMPT LINE 23,
FORM LINE 8,
@@ -201,12 +203,46 @@ FUNCTION prprrp016()
"WHERE ",criterio clipped,
" and a.status_t is null and f.status_t is null "
END IF
END IF
PREPARE comando FROM selec
DECLARE busca CURSOR FOR comando
-- Verifica primero si hay registros: si el reporte se inicia sin filas,
-- el motor de reportes falla al no poder resolver p_compania.nombre
-- (variable "look ahead" del encabezado) porque nunca se llega a imprimir nada.
OPEN busca
FETCH busca INTO busqueda.cotizacion_no,busqueda.fecha,busqueda.tipo_cliente,
busqueda.sec_cliente,busqueda.nombre_proyecto,busqueda.direccion_proyecto,
busqueda.telefono_r,busqueda.nombre,busqueda.num_oc,busqueda.fecha_oc,
busqueda.fecha_entrega,busqueda.fecha_cierre,busqueda.cod_n,
busqueda.cod_grupo,busqueda.cod_tipo,busqueda.cod_sec,
busqueda.descrip_esp,busqueda.unidad_med,busqueda.cantidad,
busqueda.precio,busqueda.cantidad_2,busqueda.cod_mov,
busqueda.fecha_doc,busqueda.documento,busqueda.status_mov,
busqueda.simbolo,busqueda.vendedor,busqueda.monto_cotizacion,
busqueda.condicion,busqueda.estado_orden,busqueda.telefono,
busqueda.celular,busqueda.email,busqueda.contacto
IF STATUS = NOTFOUND THEN
CALL fgl_winmessage("WARNING","NO EXISTEN REGISTROS CON ESA CONDICION","SOP")
LET hay_datos = FALSE
ELSE
LET hay_datos = TRUE
END IF
# El formulario solo guarda el texto visible del combo (no el valor interno
# que tenia el .per original), asi que aqui se traduce de vuelta.
CASE salida CLIPPED
WHEN "Detallado" LET salida = "prprrp116.4rp"
WHEN "Resumido" LET salida = "prprrp016a.4rp"
END CASE
CASE visualiza CLIPPED
WHEN "PANTALLA" LET visualiza = "SVG"
WHEN "ACROBAT READER" LET visualiza = "PDF"
WHEN "EXCEL" LET visualiza = "XLSX"
END CASE
LET r_filename = salida CLIPPED
IF fgl_report_loadCurrentSettings(r_filename) THEN -- load the .4rp file
LET r_output=visualiza CLIPPED
LET preview=1
@@ -216,30 +252,13 @@ FUNCTION prprrp016()
END IF
IF handler IS NOT NULL THEN -- report engine was configured ok
IF handler IS NOT NULL AND hay_datos THEN -- report engine was configured ok and there is data to print
START REPORT reporte_16 TO XML HANDLER handler
FOREACH busca INTO busqueda.cotizacion_no,busqueda.fecha,busqueda.tipo_cliente,
busqueda.sec_cliente,busqueda.nombre_proyecto,busqueda.direccion_proyecto,
busqueda.telefono_r,busqueda.nombre,busqueda.num_oc,busqueda.fecha_oc,
busqueda.fecha_entrega,busqueda.fecha_cierre,busqueda.cod_n,
busqueda.cod_grupo,busqueda.cod_tipo,busqueda.cod_sec,
busqueda.descrip_esp,busqueda.unidad_med,busqueda.cantidad,
busqueda.precio,busqueda.cantidad_2,busqueda.cod_mov,
busqueda.fecha_doc,busqueda.documento,busqueda.status_mov,
busqueda.simbolo,busqueda.vendedor,busqueda.monto_cotizacion,
busqueda.condicion,busqueda.estado_orden,busqueda.telefono,
busqueda.celular,busqueda.email,busqueda.contacto
IF STATUS = NOTFOUND THEN
CALL fgl_winmessage("WARNING","NO EXISTEN REGISTROS CON ESA CONDICION","SOP")
EXIT FOREACH
END IF
-- La primera fila ya fue leida arriba (para saber si hay_datos); aqui se
-- procesa esa fila y se sigue con FETCH manual hasta agotar el cursor.
WHILE hay_datos
IF busqueda.cantidad_2 IS NULL THEN
LET busqueda.cantidad_2 = 0
END IF
@@ -247,7 +266,7 @@ IF handler IS NOT NULL THEN -- report engine was configured ok
LET busqueda.fecha_avance= NULL
LET busqueda.monto_avance = NULL
SELECT MAX(a.num_doc),MAX(a.fecha_orig)
SELECT MAX(a.num_doc),MAX(a.fecha_orig)
INTO busqueda.avance,busqueda.fecha_avance,
busqueda.monto_avance
FROM cctb00001 a
@@ -255,7 +274,7 @@ IF handler IS NOT NULL THEN -- report engine was configured ok
a.tipo_Doc = 'AV' and a.tipo_cliente = busqueda.tipo_cliente and
a.sec_cliente = busqueda.sec_cliente and a.status_t is null and
a.fecha_orig > '08/01/2009'
LET busqueda.codigo = busqueda.cod_n using "&&&&","-",
busqueda.cod_grupo USING "&&&&","-",
busqueda.cod_tipo USING "&&&&","-",
@@ -266,11 +285,27 @@ IF handler IS NOT NULL THEN -- report engine was configured ok
IF busqueda.estado_orden = "S" THEN
LET busqueda.estado_orden = "CERRADA"
END IF
OUTPUT TO REPORT reporte_16(busqueda.*)
END FOREACH
FETCH busca INTO busqueda.cotizacion_no,busqueda.fecha,busqueda.tipo_cliente,
busqueda.sec_cliente,busqueda.nombre_proyecto,busqueda.direccion_proyecto,
busqueda.telefono_r,busqueda.nombre,busqueda.num_oc,busqueda.fecha_oc,
busqueda.fecha_entrega,busqueda.fecha_cierre,busqueda.cod_n,
busqueda.cod_grupo,busqueda.cod_tipo,busqueda.cod_sec,
busqueda.descrip_esp,busqueda.unidad_med,busqueda.cantidad,
busqueda.precio,busqueda.cantidad_2,busqueda.cod_mov,
busqueda.fecha_doc,busqueda.documento,busqueda.status_mov,
busqueda.simbolo,busqueda.vendedor,busqueda.monto_cotizacion,
busqueda.condicion,busqueda.estado_orden,busqueda.telefono,
busqueda.celular,busqueda.email,busqueda.contacto
IF STATUS = NOTFOUND THEN
LET hay_datos = FALSE
END IF
END WHILE
FINISH REPORT reporte_16
END IF
CLOSE busca
AFTER DIALOG
@@ -349,7 +384,7 @@ BEFORE GROUP OF x.cotizacion_no
PRINTX x.cotizacion_no,x.direccion_proyecto,x.nombre_proyecto,
x.tipo_cliente,x.sec_cliente,x.telefono_r,x.num_oc,x.fecha,x.fecha_cierre,
x.fecha_entrega,x.fecha_oc
x.fecha_entrega,x.fecha_oc,p_compania.nombre
BEFORE GROUP OF x.codigo
+1 -1
View File
@@ -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)
+21 -1
View File
@@ -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,
+1 -1
View File
@@ -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
+62 -4
View File
@@ -330,8 +330,65 @@
</Library>
</Group>
<Group id="202834315" label="MATERIA PRIMA">
<Library binaryName="FORMULARIOS_IN" id="-863149381" label="FORMULARIOS_IN"/>
<Library binaryName="FUNCIONES_IN" id="-801525068" label="FUNCIONES_IN"/>
<Library binaryName="FORMULARIOS_IN" id="-863149381" label="FORMULARIOS_IN">
<File filePath="../PROYECTOS/indir/infmmt002.per"/>
<File filePath="../PROYECTOS/indir/infmmt005.per"/>
</Library>
<Library binaryName="FUNCIONES_IN" dependencies="-1026233879" id="-801525068" label="FUNCIONES_IN">
<File filePath="../PROYECTOS/indir/inprgb000.4gl"/>
</Library>
<Application binaryName="inprmt002" dependencies="-801525068,-1026233879,-764824792" id="-900000001" label="inprmt002">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000002" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt002.4gl"/>
</Application>
<Application binaryName="inprmt005" dependencies="-801525068,-1026233879,-764824792" id="-900000003" label="inprmt005">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000004" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt005.4gl"/>
</Application>
<Application binaryName="inprmt013" dependencies="-801525068,-1026233879,-764824792" id="-900000005" label="inprmt013">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000006" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt013.4gl"/>
</Application>
<Application binaryName="inprmt046" dependencies="-801525068,-1026233879,-764824792" id="-900000007" label="inprmt046">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000008" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt046.4gl"/>
</Application>
<Application binaryName="inprmt036" dependencies="-801525068,-1026233879,-764824792" id="-900000009" label="inprmt036">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000010" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt036.4gl"/>
</Application>
<Application binaryName="inprmt066" dependencies="-801525068,-1026233879,-764824792" id="-900000011" label="inprmt066">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000012" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprmt066.4gl"/>
</Application>
<Application binaryName="inprcs006" dependencies="-801525068,-1026233879,-764824792" id="-900000013" label="inprcs006">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000014" label="Configuration"/>
<File filePath="../PROYECTOS/indir/inprcs006.4gl"/>
</Application>
<Application binaryName="inprrp003" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000015" label="inprrp003">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000016" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp003.4gl"/>
</Application>
<Application binaryName="inprrp005" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000017" label="inprrp005">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000018" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp005.4gl"/>
</Application>
<Application binaryName="inprrp008" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000019" label="inprrp008">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000020" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp008.4gl"/>
</Application>
<Application binaryName="inprrp009" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000021" label="inprrp009">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000022" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp009.4gl"/>
</Application>
<Application binaryName="inprrp028" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000023" label="inprrp028">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000024" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp028.4gl"/>
</Application>
<Application binaryName="inprrp011" dependencies="-801525068,-1026233879,-764824792" externalDependencies="libgre.42x" id="-900000025" label="inprrp011">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-900000026" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="../PROYECTOS/indir/inprrp011.4gl"/>
</Application>
</Group>
<Group id="1302820616" label="NOMINA">
<Library binaryName="FORMULARIOS_NO" id="-335228674" label="FORMULARIOS_NO"/>
@@ -370,7 +427,7 @@
<Configuration commandLineArguments="jpeguero Peguero2023" id="-974560942" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="PRDIR/prprmt021.4gl"/>
</Application>
<Application binaryName="prprmt020" dependencies="-837156229,-1026233879,-764824792" id="-358374666" label="prprmt020">
<Application binaryName="prprmt020" dependencies="-837156229,-1026233879,-764824792,493047263" id="-358374666" label="prprmt020">
<Configuration commandLineArguments="jpeguero Peguero2023" id="240197034" label="Configuration"/>
<File filePath="PRDIR/prprmt020.4gl"/>
</Application>
@@ -387,7 +444,7 @@
<File compilerOptions="--build-rdd" filePath="PRDIR/prprrp116.4gl"/>
</Application>
<Library binaryName="FORMULARIOS_PR" dependencies="-1026233879" id="-956683955" label="FORMULARIOS_PR">
<File filePath="PRDIR/prfmrp116.per"/>
<File filePath="PRDIR/prfmrp116.4fd"/>
<File filePath="PRDIR/prfmmt008.4fd"/>
<File filePath="vedir/vefmwd002.4fd"/>
<File filePath="ctdir/prfmmt003.per"/>
@@ -420,6 +477,7 @@
<File filePath="PRDIR/pretiquetas.4gl"/>
<File filePath="PRDIR/prempacar.4gl"/>
<File filePath="otrodir/bcode128.4gl"/>
<File filePath="../PROYECTOS/otrodir/codmov.4gl"/>
</Library>
</Group>
<Group id="46006545" label="RECURSOS HUMANOS">
+3
View File
@@ -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>
+2
View File
@@ -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",
+4 -1
View File
@@ -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>
+33
View File
@@ -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
+315 -26
View File
@@ -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
@@ -86,10 +154,28 @@ DEFINE c_dias INTEGER
DISPLAY "Dias de Inventarios" AT 6,33 ATTRIBUTE(BLACK)
LET tipo_papel = 2
CALL msgrp000(tipo_papel)
INPUT BY NAME fecha1,fecha2,c_dias,m_meses
# 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
@@ -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"
LET idx = 1
# 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,10 +361,14 @@ 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
EXIT FOREACH
END IF
START REPORT estadistica TO XML HANDLER HANDLER
END IF
ELSE
EXIT FOREACH
END IF
END IF
{LET sale = "N"
@@ -299,7 +403,18 @@ END WHILE
valororden
LET estadis.existe = estadis.existencia
# Calculo para los dias de produccion
# ---- 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
@@ -328,30 +443,139 @@ 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
END FOREACH
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
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)
@@ -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
View File
@@ -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,
+26 -1
View File
@@ -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,