JSOTO adicione los 4rp del ipprrp014

This commit is contained in:
2026-10-14 18:30:22 -04:00
parent 9366fc90e4
commit 659e690af3
13 changed files with 4313 additions and 284 deletions
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<report:Report xmlns:rtl="http://www.4js.com/2004/RTL" xmlns:report="http://www.4js.com/2007/REPORT" xmlns="http://www.4js.com/2004/PXML" gstVersion="3140a" version="6.00">
<report:Settings RWPageWidth="letterlength" RWPageLength="letterwidth" RWLeftMargin="0.5cm" RWTopMargin="0.5cm" RWRightMargin="0.5cm" RWBottomMargin="0.5cm">
<report:FormatList>
<report:Format-SVG/>
<report:Format-PDF/>
<report:Format-image/>
</report:FormatList>
</report:Settings>
<report:Data RWDataLocation="../ipdir/ipprrp014.rdd" RWFglReportName="estadistica"/>
<report:Conflicts/>
<rtl:stylesheet>
<PXML>
<rtl:match name="Report" nameConstraint="Report">
<MINIPAGE name="Page Root" width="max" length="max" alignment="center">
<LAYOUTNODE name="Page Header" width="max" length="min" port="anyPageHeader">
<MINIPAGE name="StripeLayouter3" width="min" length="max" layoutDirection="leftToRight">
<PAGENOBOX name="PageNoBox" x="1.23857" y="max" anchorX="0" anchorY="1" alignment="baseline" baselineType="leftleft" floatingBehavior="enclosed" textAlignment="right"/>
<WORDBOX name="WordBox4" floatingBehavior="enclosed" text="IPPRRP013"/>
<WORDBOX name="WordBox5" x="1.2386" y="453.061" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="PAGINA"/>
<rtl:input-variable name="p_companias.nombre" type="FGLString" expectedLocation="expectedWayAhead"/>
<WORDWRAPBOX name="p_companias.nombre Value" x="1.2386" y="184.611" width="width(&quot;M&quot;)*20" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{p_companias.nombre}}"/>
</MINIPAGE>
<MINIPAGE name="MiniPage7" width="1.5cm" length="max" fontBold="true" layoutDirection="leftToRight">
<WORDBOX name="WordBox9" x="5.539" y="40.8204" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="SISTEMA DE INVENTARIO DE PRODUCTOS TERMINADOS"/>
<WORDBOX name="WordBox11" x="22.5047" y="143.465" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="DIAS DE INVENTARIO"/>
<rtl:input-variable name="fecha" type="FGLString" expectedLocation="expectedWayAhead"/>
<WORDBOX name="WordBox23" x="5.539" y="437.976" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{&quot;FECHA: &quot;+fecha.value}}"/>
<rtl:input-variable name="hora" type="FGLString" expectedLocation="expectedWayAhead"/>
<WORDBOX name="WordBox24" x="27.0497" y="437.976" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{&quot;HORA: &quot;+hora.value}}"/>
</MINIPAGE>
<MINIPAGE name="Table Header" width="min" length="max" alignment="near" fontBold="true" layoutDirection="leftToRight">
<WORDBOX name="Spacer" alignment="baseline" baselineType="leftleft" port="itemSeparator" text=" "/>
<rtl:input-variable name="fecha1" type="FGLString" expectedLocation="expectedWayAhead"/>
<WORDBOX name="WordBox" width="6cm" floatingBehavior="enclosed" text="{{&quot;Fecha Inicial: &quot;+fecha1.value}}"/>
<rtl:input-variable name="fecha2" type="FGLString" expectedLocation="expectedWayAhead"/>
<WORDBOX name="WordBox40" width="4cm" floatingBehavior="enclosed" textAlignment="right" text="{{&quot;Fecha Final: &quot;+fecha2.value}}"/>
<MINIPAGE name="Separator1" width="1" length="max" bgColor="#000000" layoutDirection="leftToRight"/>
<rtl:input-variable name="dias1" type="FGLNumeric" expectedLocation="expectedAhead"/>
<WORDBOX name="WordBox45" alignment="near" floatingBehavior="enclosed" text="{{&quot;DIAS PERIODO: &quot;+dias1}}"/>
<LAYOUTNODE name="LayoutNode3" width="min" length="max" alignment="near" fontSize="8" fontBold="true" layoutDirection="leftToRight" floatingBehavior="free">
<WORDBOX name="WordBox13" floatingBehavior="enclosed" text="CODIGO"/>
<WORDBOX name="WordBox14" width="1cm" floatingBehavior="enclosed" text=""/>
<WORDBOX name="WordBox15" floatingBehavior="enclosed" text="DESCRIPCION"/>
<WORDBOX name="WordBox16" width="3cm" alignment="center" floatingBehavior="enclosed" text=""/>
<WORDBOX name="WordBox17" alignment="baseline" floatingBehavior="enclosed" text="VENTAS DEL PERIODO"/>
<WORDBOX name="WordBox18" width="0.6cm" floatingBehavior="enclosed" text=""/>
<WORDBOX name="WordBox19" floatingBehavior="enclosed" text="EXISTENCIA"/>
<WORDBOX name="WordBox33_2" width="0.5cm" alignment="center" floatingBehavior="enclosed" text=""/>
<WORDBOX name="WordBox34" floatingBehavior="enclosed" text="DIAS INV"/>
<WORDBOX name="WordBox36" width="0.5cm" floatingBehavior="enclosed" text=""/>
<WORDBOX name="WordBox37" floatingBehavior="enclosed" text="FECHA VENTA"/>
<WORDBOX name="WordBox42" width="2cm" floatingBehavior="enclosed" textAlignment="right" text="FECHA C"/>
<WORDBOX name="WordBox43" width="2cm" floatingBehavior="enclosed" textAlignment="right" text="CANTIDAD C."/>
<WORDBOX name="WordBox44" width="2cm" floatingBehavior="enclosed" textAlignment="right" text="ROTACION"/>
<WORDBOX name="WordBoxMargenH" width="2cm" floatingBehavior="enclosed" textAlignment="right" text="MARGEN %"/>
<WORDBOX name="WordBoxClasifH" width="2.2cm" floatingBehavior="enclosed" text="CLASIF."/>
</LAYOUTNODE>
<MINIPAGE name="Separator" width="1" length="max" bgColor="#000000" layoutDirection="leftToRight"/>
</MINIPAGE>
</LAYOUTNODE>
<rtl:match name="FirstPageHeader" nameConstraint="FirstPageHeader" minOccurs="0" maxOccurs="1"/>
<rtl:match name="Group cod_grupo" nameConstraint="Group" minOccurs="0" maxOccurs="unbounded">
<rtl:match name="OnEveryRow" nameConstraint="OnEveryRow" minOccurs="0" maxOccurs="unbounded">
<LAYOUTNODE name="DETALLE" width="min" length="max" alignment="near" fontSize="7" layoutDirection="leftToRight" floatingBehavior="enclosed">
<rtl:input-variable name="x.cod_n" type="FGLNumeric" expectedLocation="expectedHere"/>
<rtl:input-variable name="x.cod_grupo" type="FGLNumeric" expectedLocation="expectedHere"/>
<rtl:input-variable name="x.cod_tipo" type="FGLNumeric" expectedLocation="expectedHere"/>
<rtl:input-variable name="x.cod_sec" type="FGLNumeric" expectedLocation="expectedHere"/>
<WORDBOX name="WordBox18_1" alignment="baseline" baselineType="leftleft" text="{{x.cod_n.format(&quot;&amp;&amp;&amp;&amp;&quot;)+&quot;-&quot;+x.cod_grupo.format(&quot;&amp;&amp;&amp;&amp;&amp;&quot;)+&quot;-&quot;+x.cod_tipo.format(&quot;&amp;&amp;&amp;&amp;&amp;&amp;&quot;)+&quot;-&quot;+x.cod_sec.format(&quot;&amp;&amp;&amp;&amp;&amp;&amp;&quot;)}}"/>
<WORDBOX name="WordBox19_1" width=".3cm" alignment="baseline" baselineType="leftleft"/>
<rtl:input-variable name="x.descrip_esp" type="FGLString" expectedLocation="expectedHere"/>
<rtl:input-variable name="x.unidad_med" type="FGLString" expectedLocation="expectedHere"/>
<WORDWRAPBOX name="WordWrapBox" width="width(&quot;M&quot;)*25" alignment="baseline" floatingBehavior="enclosed" text="{{x.descrip_esp.trim()+&quot; &quot;+x.unidad_med.trim()}}"/>
<WORDBOX name="WordBox41" width="1cm" alignment="baseline" floatingBehavior="enclosed" text=""/>
<rtl:input-variable name="x.consumo" type="FGLNumeric" expectedLocation="expectedHere"/>
<WORDBOX name="WordBox29" width="1.5cm" alignment="baseline" floatingBehavior="enclosed" text="{{x.consumo.format(&quot;####.####&quot;)}}"/>
<rtl:input-variable name="x.existe" type="FGLNumeric" expectedLocation="expectedHere"/>
<WORDBOX name="WordBox31_1" width="2cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{x.existe.format(&quot;###,###.####&quot;)}}"/>
<WORDBOX name="WordBox31_2" width="1cm" floatingBehavior="enclosed" text=""/>
<rtl:input-variable name="x.dias" type="FGLNumeric" expectedLocation="expectedHere"/>
<WORDBOX name="WordBox32" width="1cm" color="{{x.dias&gt;200?Color.RED:Color.BLACK}}" floatingBehavior="enclosed" text="{{x.dias.format(&quot;###,###&quot;)}}"/>
<WORDBOX name="WordBox38" width="1cm" floatingBehavior="enclosed" text=""/>
<rtl:input-variable name="x.fecha_v" type="FGLString" expectedLocation="expectedHere"/>
<WORDBOX name="WordBox39" width="1.5cm" floatingBehavior="enclosed" text="{{x.fecha_v}}"/>
<rtl:input-variable name="x.fecha_oc" type="FGLString" expectedLocation="expectedHere"/>
<WORDBOX name="fecha_oc Value" width="1.5cm" floatingBehavior="enclosed" textAlignment="right" text="{{x.fecha_oc}}"/>
<rtl:input-variable name="x.tcantidad" type="FGLNumeric" expectedLocation="expectedHere"/>
<DECIMALFORMATBOX name="tcantidad Value" width="1.5cm" anchorX="1" floatingBehavior="enclosed" textAlignment="right" format="----------#.####" value="{{x.tcantidad}}"/>
<rtl:input-variable name="rot_anual" type="FGLNumeric" expectedLocation="expectedHere"/>
<DECIMALFORMATBOX name="rot_anual Value" class="grwNumericValue" width="3cm" anchorX="1" floatingBehavior="enclosed" textAlignment="right" format="{{&quot;--,--&amp;.&amp;&amp;&quot;}}" value="{{rot_anual}}"/>
<rtl:input-variable name="x.margen" type="FGLNumeric" expectedLocation="expectedHere"/>
<DECIMALFORMATBOX name="margen Value" class="grwNumericValue" width="2cm" anchorX="1" floatingBehavior="enclosed" textAlignment="right" format="{{&quot;--&amp;.&amp;&amp;&quot;}}" value="{{x.margen}}"/>
<rtl:input-variable name="x.clasificacion" type="FGLString" expectedLocation="expectedHere"/>
<WORDBOX name="clasif Value" width="2.2cm" floatingBehavior="enclosed" color="{{x.clasificacion.trim()==&quot;REVISAR&quot;?Color.RED:(x.clasificacion.trim()==&quot;ESTRELLA&quot;?Color.GREEN:Color.BLACK)}}" text="{{x.clasificacion.trim()}}"/>
</LAYOUTNODE>
</rtl:match>
</rtl:match>
<MINIPAGE name="TOTALES" width="min" length="min">
<rtl:input-variable name="total_registros" type="FGLNumeric" expectedLocation="expectedBefore"/>
<WORDBOX name="WordBox33_1" floatingBehavior="enclosed" text="{{&quot;TOTAL ARTICULOS IMPRESOS: &quot;+total_registros.format(&quot;&gt;&gt;&gt;&gt;&quot;)}}"/>
</MINIPAGE>
</MINIPAGE>
</rtl:match>
</PXML>
</rtl:stylesheet>
</report:Report>
+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<report:Report xmlns:rtl="http://www.4js.com/2004/RTL" xmlns:report="http://www.4js.com/2007/REPORT" xmlns="http://www.4js.com/2004/PXML" version="2.00">
<report:Settings RWPageWidth="letterlength" RWPageLength="letterwidth" RWLeftMargin="0.5cm" RWTopMargin="0.5cm" RWRightMargin="0.5cm" RWBottomMargin="0.5cm">
<report:FormatList>
<report:Format-SVG/>
<report:Format-PDF/>
<report:Format-image/>
</report:FormatList>
</report:Settings>
<report:Data RWDataLocation="../ipdir/ipprrp014.rdd" RWFglReportName="resumen"/>
<rtl:stylesheet>
<rtl:match nameConstraint="Report">
<PXML name="Pxml1">
<MINIPAGE name="Page Root" width="max" length="max" alignment="near">
<LAYOUTNODE name="Page Header" width="max" length="min" port="anyPageHeader">
<MINIPAGE name="StripeLayouter3" width="min" length="max" layoutDirection="leftToRight">
<PAGENOBOX name="PageNoBox" x="1.23857" y="max" anchorX="0" anchorY="1" alignment="baseline" baselineType="leftleft" floatingBehavior="enclosed" textAlignment="right"/>
<WORDBOX name="WordBox4" floatingBehavior="enclosed" text="IPPRRP014"/>
<WORDBOX name="WordBox5" x="1.2386" y="453.061" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="PAGINA"/>
<WORDWRAPBOX name="p_companias.nombre Value" x="1.2386" y="184.611" width="width(&quot;M&quot;)*25" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{p_companias.nombre}}"/>
</MINIPAGE>
<MINIPAGE name="MiniPage7" width="1.5cm" length="max" fontBold="true" layoutDirection="leftToRight">
<WORDBOX name="WordBox9" x="5.539" y="40.8204" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="SISTEMA DE INVENTARIO DE PRODUCTOS TERMINADOS"/>
<WORDBOX name="WordBox11" x="22.5047" y="143.465" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="RESUMEN MARGEN Y ROTACION POR CLASE - GERENTE DE MARCAS"/>
<WORDBOX name="WordBox23" x="5.539" y="437.976" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{&quot;FECHA: &quot;+fecha}}"/>
<WORDBOX name="WordBox24" x="27.0497" y="437.976" anchorX="0" anchorY="0" floatingBehavior="enclosed" text="{{&quot;HORA: &quot;+hora}}"/>
</MINIPAGE>
<MINIPAGE name="PeriodoLine" width="min" length="max" layoutDirection="leftToRight">
<WORDBOX name="WordBoxP1" floatingBehavior="enclosed" text="{{&quot;PERIODO: &quot;+fecha1+&quot; a &quot;+fecha2}}"/>
</MINIPAGE>
<MINIPAGE name="Table Header" width="min" length="max" alignment="near" layoutDirection="leftToRight">
<WORDBOX name="Spacer" alignment="baseline" baselineType="leftleft" port="itemSeparator" text=" "/>
<LAYOUTNODE name="LayoutNodeHdr" width="min" length="max" alignment="near" fontSize="8" fontBold="true" layoutDirection="leftToRight" floatingBehavior="free">
<WORDBOX name="H_clase" width="5cm" floatingBehavior="enclosed" text="CLASE"/>
<WORDBOX name="H_cat" width="3.5cm" floatingBehavior="enclosed" text="CATEGORIA"/>
<WORDBOX name="H_prod" width="1.4cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="#PROD"/>
<WORDBOX name="H_vinv" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="VALOR INV"/>
<WORDBOX name="H_vta" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="CONSUMO VAL"/>
<WORDBOX name="H_gan" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="GANANCIA"/>
<WORDBOX name="H_mg" width="1.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="MARGEN %"/>
<WORDBOX name="H_rot" width="1.8cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="ROT.PROM"/>
<WORDBOX name="H_est" width="1.2cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="#EST"/>
<WORDBOX name="H_rev" width="1.2cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="#REV"/>
</LAYOUTNODE>
<MINIPAGE name="Separator" width="1" length="max" bgColor="#000000" layoutDirection="leftToRight"/>
</MINIPAGE>
</LAYOUTNODE>
<rtl:match nameConstraint="OnEveryRow" minOccurs="0" maxOccurs="unbounded">
<LAYOUTNODE name="ClaseLine" width="min" length="max" alignment="near" fontSize="8" layoutDirection="leftToRight" floatingBehavior="enclosed">
<WORDBOX name="V_clase" width="5cm" alignment="baseline" baselineType="leftleft" text="{{r.cod_n.format(&quot;####&quot;).trim()+&quot; &quot;+r.nombre_clase.trim()}}"/>
<WORDBOX name="V_cat" width="3.5cm" alignment="baseline" baselineType="leftleft" text="{{r.categoria.trim()}}"/>
<WORDBOX name="V_prod" width="1.4cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_prod.format(&quot;###,##&amp;&quot;)}}"/>
<WORDBOX name="V_vinv" width="2.6cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_valor_inv.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="V_vta" width="2.6cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_ventas.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="V_gan" width="2.6cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_ganancia.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="V_mg" width="1.6cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_margen.format(&quot;##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="V_rot" width="1.8cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_rot_prom.format(&quot;###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="V_est" width="1.2cm" alignment="baseline" baselineType="leftleft" textAlignment="right" text="{{r.c_estrella.format(&quot;###,##&amp;&quot;)}}"/>
<WORDBOX name="V_rev" width="1.2cm" alignment="baseline" baselineType="leftleft" textAlignment="right" color="{{r.c_revisar&gt;0?Color.RED:Color.BLACK}}" text="{{r.c_revisar.format(&quot;###,##&amp;&quot;)}}"/>
</LAYOUTNODE>
</rtl:match>
<MINIPAGE name="TotalSep" width="1" length="max" bgColor="#000000" layoutDirection="leftToRight"/>
<MINIPAGE name="TotalLine" width="min" length="max" fontBold="true" alignment="near" fontSize="8" layoutDirection="leftToRight">
<WORDBOX name="T_lbl" width="8.5cm" floatingBehavior="enclosed" text="{{&quot;TOTAL GENERAL (productos: &quot;+g_prod.format(&quot;###,##&amp;&quot;).trim()+&quot;)&quot;}}"/>
<WORDBOX name="T_vinv" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="{{g_valor_inv.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="T_vta" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="{{g_ventas.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="T_gan" width="2.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="{{g_ganancia.format(&quot;###,###,###,##&amp;.&amp;&amp;&quot;)}}"/>
<WORDBOX name="T_mg" width="1.6cm" alignment="baseline" textAlignment="right" floatingBehavior="enclosed" text="{{g_margen.format(&quot;##&amp;.&amp;&amp;&quot;)}}"/>
</MINIPAGE>
</MINIPAGE>
</PXML>
</rtl:match>
</rtl:stylesheet>
</report:Report>
+2 -2
View File
@@ -121,7 +121,7 @@ REPORT entrada14(
fecha1, fecha2 DATE, #### Almacena las fecha del rango de busqueda
hora CHAR(5),
entrada CHAR(14),
entrada VARCHAR(25), -- ref. completa ED.nn-nnnnn/mmaa (CHAR(14) cortaba el anio)
actual VARCHAR(20),
afecta CHAR(3),
p_companias, desc_cuenta CHAR(30)
@@ -274,7 +274,7 @@ REPORT entrada14(
entrada,
y.cuenta_inv,
detalle1,
invcredito,
invdebito,
0,
usuarios,
GETDATE())
+299
View File
@@ -0,0 +1,299 @@
GLOBALS "cgprgb000.4gl"
FUNCTION edprrp118(
fecha1, fecha2, detalle, entra, afecta, p_companias, acumulado_arr, usuario)
DEFINE
handler
om
.SaxDocumentHandler, -- return value from fgl_report_commitCurrentSettings()
r_filename
STRING, -- filename of Report Design Document including .4rp extension
r_output STRING, -- output format option
preview INTEGER
DEFINE
acumulado_arr DYNAMIC ARRAY OF RECORD
cod_mov LIKE irtb00006.cod_mov,
descrip_mov LIKE intb00005.descrip_mov,
departamento SMALLINT,
nombre CHAR(30),
consumo DECIMAL(12, 2),
cuenta CHAR(10),
gasto_ind LIKE irtb00013.costo_st,
descripcion CHAR(50),
consumo_cuenta DECIMAL(12, 2),
cuenta_inv CHAR(10)
END RECORD,
ordenar CHAR(30)
DEFINE
afecta CHAR(3),
fecha1, fecha2 DATE,
p_cctb01 RECORD LIKE cctb00001.*,
entra CHAR(14),
detalle CHAR(100),
p_companias CHAR(30),
idz INT,
###### Variables para almacenar los datos selecionados
usuario, clave CHAR(80),
impresor SMALLINT
LET r_filename = "edprrp118b.4rp"
LET idz = 1
FOR idx = 1 TO acumulado_arr.getLength()
IF idx = 1 THEN
IF fgl_report_loadCurrentSettings(r_filename) THEN
LET preview = 1
CALL seleccionarsalida()
RETURNING r_output -- load the .4rp file
CALL fgl_report_selectDevice(r_output) -- changing default
CALL fgl_report_selectPreview(preview) -- changing default
LET handler =
fgl_report_commitCurrentSettings() -- commit changes
END IF
START REPORT entrada14 TO XML HANDLER HANDLER
END IF
LET ordenar =
acumulado_arr[idz].cuenta CLIPPED,
"-",
acumulado_arr[idz].departamento USING "&&&&&"
OUTPUT TO REPORT entrada14(
p_cctb01.*,
fecha1,
fecha2,
detalle,
entra,
afecta,
p_companias,
acumulado_arr[idz].*,
ordenar, usuario)
LET idz = idz + 1
END FOR
IF idx > 1 THEN
FINISH REPORT entrada14
ELSE
CALL fgl_winmessage(
"INFO",
"NO HAY REGISTROS EN ESTE RANGO DE FECHA Y CON LOS PARAMETROS INDICADOS",
"INFO")
END IF
--RUN imprime
END FUNCTION
REPORT entrada14(
x, fecha1, fecha2, detalle1, entrada, afecta, p_companias, y, xordenar, usuario)
DEFINE x RECORD LIKE cctb00001.*
DEFINE usuario VARCHAR(50)
DEFINE
y RECORD
cod_mov LIKE irtb00006.cod_mov,
descrip_mov LIKE intb00005.descrip_mov,
departamento SMALLINT,
nombre CHAR(30),
consumo DECIMAL(12, 2),
cuenta CHAR(10),
gasto_ind LIKE irtb00013.costo_st,
descripcion CHAR(30),
consumo_cuenta DECIMAL(12, 2),
cuenta_inv CHAR(10)
END RECORD,
xordenar VARCHAR(30)
### Acumula los valores de las diferentes cuentas para entrada diario de nomina
DEFINE
invdebito,
invcredito,
debito,
credito,
total_departamento,
total_haber,
total_deber
DECIMAL(12, 2),
detalle1, nombre_cta, rango_fecha CHAR(100),
fecha1, fecha2 DATE, #### Almacena las fecha del rango de busqueda
hora CHAR(5),
entrada CHAR(14),
actual VARCHAR(20),
afecta CHAR(3),
p_companias, desc_cuenta CHAR(30)
ORDER BY xordenar
FORMAT
FIRST PAGE HEADER
LET hora = TIME
LET actual = TODAY USING "dd/mm/yyyy"
LET rango_fecha =
"Del ",
fecha1 USING "dd/mm/yyyy",
" Al ",
fecha2 USING "dd/mm/yyyy"
LET total_deber = 0
LET total_haber = 0
BEFORE GROUP OF y.departamento
LET total_departamento = 0
AFTER GROUP OF xordenar
IF y.consumo < 0 THEN
LET debito = GROUP SUM(y.consumo_cuenta) * -1
LET credito = 0
ELSE
LET debito = 0
LET credito = GROUP SUM(y.consumo_cuenta)
END IF
PRINTX entrada,
hora,
actual,
rango_fecha,
p_companias,
y.cod_mov,
y.consumo,
y.cuenta,
y.departamento,
y.descrip_mov,
y.gasto_ind,
y.nombre,
y.consumo_cuenta,
y.descripcion,
debito,
credito,
detalle1
IF afecta = "S" THEN
BEGIN WORK
IF y.consumo < 0 THEN
INSERT INTO cgtb00004(
fecha,
tipo,
ref,
cuenta_no,
departamento,
detalle_1,
debito,
credito,
us_crea,
fech_crea)
VALUES(fecha2,
1,
entrada,
y.cuenta,
y.departamento,
detalle1,
debito,
0,
usuarios,
GETDATE())
ELSE
INSERT INTO cgtb00004(
fecha,
tipo,
ref,
cuenta_no,
departamento,
detalle_1,
debito,
credito,
us_crea,
fech_crea)
VALUES(fecha2,
1,
entrada,
y.cuenta,
y.departamento,
detalle1,
0,
credito,
usuarios,
GETDATE())
END IF
COMMIT WORK
END IF
LET total_deber = debito + total_deber
LET total_haber = credito + total_haber
ON LAST ROW
SELECT a.descripcion
INTO nombre_cta
FROM cgtb00001 a
WHERE a.cuenta_no = y.cuenta_inv
IF nombre_cta IS NULL THEN
LET nombre_cta = "CUENTA SIN DESCRIPCION"
END IF
IF y.consumo < 0 THEN
LET invcredito = SUM(y.consumo_cuenta * -1)
LET invdebito = 0
LET total_haber = invcredito + total_haber
ELSE
LET invdebito = SUM(y.consumo_cuenta)
LET invcredito = 0
LET total_deber = invdebito + total_deber
END IF
IF afecta = "S" THEN
BEGIN WORK
IF y.consumo < 0 THEN
INSERT INTO cgtb00004(
fecha,
tipo,
ref,
cuenta_no,
detalle_1,
debito,
credito,
us_crea,
fech_crea)
VALUES(fecha2,
1,
entrada,
y.cuenta_inv,
detalle1,
0,
invcredito,
usuarios,
GETDATE())
ELSE
INSERT INTO cgtb00004(
fecha,
tipo,
ref,
cuenta_no,
detalle_1,
debito,
credito,
us_crea,
fech_crea)
VALUES(fecha2,
1,
entrada,
y.cuenta_inv,
detalle1,
invcredito,
0,
usuarios,
GETDATE())
END IF
{UPDATE cgtb00011
SET referencia = referencia + 1,
us_mod = usuario,
fech_mod = getdate()
WHERE entrada_no = 5}
COMMIT WORK
END IF
PRINTX y.cuenta_inv,
total_haber,
nombre_cta,
desc_cuenta,
total_deber,
invdebito,
invcredito
END REPORT
+2 -2
View File
@@ -29,7 +29,7 @@ DEFINE t_variacion DECIMAL(12,2)
###### Variables que la almacenan la informacion enviada al reporte
DEFINE diario1 RECORD
cuenta_no CHAR(8),
debito DECIMAL(10,2)
debito DECIMAL(14,2) # 14: el SUM del periodo excedia 10,2 (-1226)
END RECORD
DEFINE i SMALLINT
@@ -820,7 +820,7 @@ END FUNCTION
DEFINE x RECORD
cuenta_no CHAR(8),
debito DECIMAL(10,2)
debito DECIMAL(14,2) # 14: el SUM del periodo excedia 10,2 (-1226)
END RECORD
### Acumula los valores de las diferentes cuentas para entrada diario de nomina
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2
View File
@@ -773,6 +773,8 @@
<Application binaryName="ipprrp014" dependencies="1763548104,-1026233879,-764824792" externalDependencies="libgre.42x" id="-960000028" label="ipprrp014">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-961000028" label="Configuration"/>
<File compilerOptions="--build-rdd" filePath="ipdir/ipprrp014.4gl"/>
<File filePath="bin/ipprrp014.4rp"/>
<File filePath="bin/ipprrp014r.4rp"/>
</Application>
<Application binaryName="ipprrp046" dependencies="1763548104,-1026233879,-764824792" externalDependencies="libgre.42x" id="-960000029" label="ipprrp046">
<Configuration commandLineArguments="jpeguero Peguero2023" id="-961000029" label="Configuration"/>
+273 -100
View File
@@ -60,6 +60,9 @@ FUNCTION apiclient(pemail)
DEFINE estado,purl,cmd,res, msg,s,pemail,tiposervice STRING,
ret INT
DEFINE dominio, detalle, api_url, api_key STRING,
dns_estado SMALLINT,
hunter_ok BOOLEAN
# LA API PARA VERIFICAR ESTA OFFLINE 29/05/2025
@@ -68,115 +71,115 @@ FUNCTION apiclient(pemail)
RETURN estado,ret
}
# SE DEVUELVE SI EL EMAIL ESTA EN BLANCO
IF pemail IS NULL THEN
LET pemail = pemail.trim()
IF pemail IS NULL OR pemail.getLength() = 0 THEN
LET ret = 400
LET estado = 'DEBES DIGITAR EL EMAIL POR FAVOR'
RETURN estado,ret
END IF
END IF
DISPLAY "llego: ",pemail
# VALIDACION PROPIA 14/10/2026: FORMATO + DOMINIO EN DNS (NO DEPENDE DE LA API)
IF NOT email_formato_valido(pemail) THEN
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,'formato_invalido',getdate(),'mt101_local',suser_Sname(),0)
LET ret = 400
LET estado = 'EL FORMATO DEL EMAIL NO ES VALIDO'
RETURN estado,ret
END IF
LET dominio = pemail.subString(pemail.getIndexOf("@",1) + 1, pemail.getLength())
LET dns_estado = email_dominio_dns(dominio)
DISPLAY "dominio: ",dominio," dns: ",dns_estado
IF dns_estado = 0 THEN
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,'dominio_inexistente',getdate(),'mt101_dns',suser_Sname(),0)
LET ret = 400
LET estado = 'EL DOMINIO DEL EMAIL NO EXISTE O NO RECIBE CORREO'
RETURN estado,ret
END IF
# ELECCION DE SERVICIOS, POR EL MOMENTO ES IPQUALITY
SELECT a.IDENTIFICACION INTO tiposervice FROM APIS a
# URL Y API KEY SE LEEN DE LA TABLA APIS (YA NO VAN EN EL FUENTE)
SELECT a.IDENTIFICACION, a.url, a.apikey INTO tiposervice, api_url, api_key FROM APIS a
WHERE a.estado = 'ONLINE'
IF STATUS = NOTFOUND THEN
RETURN estado,ret
END IF
# LET tiposervice = 'ipq1'
LET tiposervice = tiposervice.trim()
LET api_url = api_url.trim()
LET api_key = api_key.trim()
# LET tiposervice = 'ipq1'
IF tiposervice = 'HUNTER' THEN
LET purl = "https://api.hunter.io/v2/email-verifier?email=",pemail CLIPPED,"&api_key=2a50343f3a2842b082ee2c4b3ecccaf4ae5a7766"
CALL ipquality_send_command(purl) RETURNING ret,res
LET purl = api_url,"?email=",pemail CLIPPED,"&api_key=",api_key
CALL ipquality_send_command(purl, NULL) RETURNING ret,res
DISPLAY "response api: ",res," longitud: ",res.getLength()
IF res.getLength() =0 THEN
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,data.data.status,getdate(),'mt101_hunter',suser_Sname(),data.data.score)
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
RETURN estado,ret
END IF
TRY
# HUNTER PUEDE NO RESPONDER (CAIDO, 202 EN PROCESO, 222/451 SMTP):
# EN ESE CASO DECIDE LA VALIDACION DNS PROPIA
LET hunter_ok = FALSE
IF ret == 0 AND res.getLength() > 0 THEN
TRY
CALL util.JSON.parse(res,data)
CATCH
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET hunter_ok = TRUE
CATCH
LET hunter_ok = FALSE
END TRY
END IF
IF NOT hunter_ok THEN
INSERT INTO envia_email_log (email,display_name,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,SFMT('hunter http=%1',ret),'hunter_sin_respuesta',getdate(),'mt101_dns',suser_Sname(),0)
CALL email_resultado_dns(dns_estado) RETURNING estado,ret
RETURN estado,ret
END TRY
END IF
# INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
# VALUES (pemail,data.data.status,getdate(),'forzado',suser_Sname(),data.data.score)
# LET estado = 'VALIDO'
# LET ret = 200
# RETURN estado,ret
DISPLAY "DATA EMAIL: ",pemail CLIPPED, " score: ",data.data.score
LET detalle = SFMT('mx=%1 smtp=%2 check=%3 regexp=%4 disp=%5 dns=%6',
data.data.mx_records, data.data.smtp_server, data.data.smtp_check,
data.data.regexp, data.data.disposable, dns_estado)
INSERT INTO envia_email_log (email,display_name,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,detalle,data.data.status,getdate(),'mt101_hunter',suser_Sname(),data.data.score)
LET s = util.JSON.stringify(res)
DISPLAY "DATA EMAIL: ",pemail CLIPPED, " score: ",data.data.score
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,data.data.status,getdate(),'mt101_hunter',suser_Sname(),data.data.score)
IF ret ==0 THEN
# DESECHABLES (MAILINATOR, ETC.) SE RECHAZAN SIEMPRE
IF data.data.disposable THEN
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF data.data.mx_records = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF (data.data.status = 'valid' OR data.data.status = 'accept_all' OR
data.data.status = 'unknown') AND data.data.score > 29 THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
END IF
IF data.data.smtp_server = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
# HUNTER LO RECHAZA: SOLO SE RESPETA SI LLEGO AL SERVIDOR DE CORREO
# Y ESTE RECHAZO EL BUZON (EL BUZON NO EXISTE)
IF data.data.mx_records AND data.data.smtp_server AND NOT data.data.smtp_check THEN
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF data.data.regexp = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
# HUNTER NO VE EL DOMINIO O NO PUDO CONECTAR (DOMINIOS .DO PEQUENOS):
# SI EL DNS CONFIRMA QUE EL DOMINIO RECIBE CORREO, SE ACEPTA
CALL email_resultado_dns(dns_estado) RETURNING estado,ret
IF ret = 200 THEN
INSERT INTO envia_email_log (email,display_name,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,detalle,'valid_dns',getdate(),'mt101_dns',suser_Sname(),0)
END IF
RETURN estado,ret
IF data.data.disposable = TRUE THEN
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
ELSE
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
END IF
IF (data.data.status = 'valid' OR data.data.status = 'accept_all' OR
data.data.status = 'unknown') AND data.data.score > 29 THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
RETURN estado,ret
END IF
END IF
END IF
IF tiposervice = 'IPQUALITY' THEN
LET purl = 'https://ipqualityscore.com/api/json/email/cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3/',pemail CLIPPED
CALL ipquality_send_command(purl) RETURNING ret,res
# EN APIS LA URL DE IPQUALITY YA TRAE LA KEY: .../email/<key>/
LET purl = api_url,pemail CLIPPED
CALL ipquality_send_command(purl, api_key) RETURNING ret,res
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
@@ -195,8 +198,8 @@ DISPLAY "response api: ",res," longitud: ",res.getLength()
END IF
IF tiposervice = 'APILAYER' THEN
# DISPLAY " ESTOY EN APILAYER"
LET purl= "https://api.apilayer.com/email_verification/",pemail CLIPPED
CALL apilayer_send_command(purl, cmd) RETURNING ret, res
LET purl= api_url,pemail CLIPPED
CALL apilayer_send_command(purl, api_key) RETURNING ret, res
# DISPLAY "res ",res," ",ret
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
@@ -233,9 +236,9 @@ END FUNCTION
## Communications library using com (http or https)
#
FUNCTION apilayer_send_command(url, cmd)
FUNCTION apilayer_send_command(url, papikey)
DEFINE url, cmd STRING
DEFINE url, papikey STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
@@ -247,7 +250,7 @@ FUNCTION apilayer_send_command(url, cmd)
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("api_key","2a50343f3a2842b082ee2c4b3ecccaf4ae5a7766")
CALL http_req.setHeader("apikey",papikey)
CALL http_req.doRequest()
@@ -270,21 +273,22 @@ FUNCTION apilayer_send_command(url, cmd)
END FUNCTION
FUNCTION ipquality_send_command(url)
FUNCTION ipquality_send_command(url, papikey)
DEFINE url, cmd STRING
DEFINE url, papikey STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
DISPLAY "url", url
# NO SE MUESTRA LA URL: LLEVA LA API KEY
TRY
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("apikey","cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3")
IF papikey IS NOT NULL THEN
CALL http_req.setHeader("apikey",papikey)
END IF
CALL http_req.doRequest()
LET http_resp=http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
@@ -298,8 +302,177 @@ FUNCTION ipquality_send_command(url)
CATCH
RETURN -2, SFMT("HTTP request error: STATUS=%1 (%2)",STATUS,SQLCA.sqlerrd[2])
END TRY
RETURN 0, result
END FUNCTION
#
## VALIDACION PROPIA DEL EMAIL (14/10/2026)
## Formato basico + el dominio debe existir y recibir correo (registro MX, o A
## como MX implicito segun RFC 5321). Se consulta el DNS por HTTPS (dns.google)
## porque BDL no tiene resolvedor DNS.
#
FUNCTION email_formato_valido(pemail)
DEFINE pemail, usuario, dominio, etiqueta, c, permitidos STRING
DEFINE i, arroba, inicio INT
LET permitidos = "._%+-!#$&'*/=?^`{|}~"
IF pemail IS NULL OR pemail.getLength() > 254 THEN
RETURN FALSE
END IF
# UNA SOLA ARROBA, CON USUARIO Y DOMINIO
LET arroba = pemail.getIndexOf("@",1)
IF arroba <= 1 OR arroba = pemail.getLength() THEN
RETURN FALSE
END IF
IF pemail.getIndexOf("@",arroba + 1) > 0 THEN
RETURN FALSE
END IF
LET usuario = pemail.subString(1, arroba - 1)
LET dominio = pemail.subString(arroba + 1, pemail.getLength())
# USUARIO: MAX 64, SIN PUNTO AL INICIO/FINAL NI DOBLE PUNTO
IF usuario.getLength() > 64 THEN
RETURN FALSE
END IF
IF usuario.getCharAt(1) = "." OR usuario.getCharAt(usuario.getLength()) = "."
OR usuario.getIndexOf("..",1) > 0 THEN
RETURN FALSE
END IF
FOR i = 1 TO usuario.getLength()
LET c = usuario.getCharAt(i)
IF NOT (c MATCHES "[a-zA-Z0-9]" OR permitidos.getIndexOf(c,1) > 0) THEN
RETURN FALSE
END IF
END FOR
# DOMINIO: AL MENOS UN PUNTO, ETIQUETAS DE LETRAS/NUMEROS/GUION,
# SIN GUION AL INICIO/FINAL, Y EXTENSION (TLD) DE 2+ LETRAS
IF dominio.getLength() > 253 OR dominio.getIndexOf(".",1) = 0 THEN
RETURN FALSE
END IF
LET inicio = 1
FOR i = 1 TO dominio.getLength() + 1
IF i > dominio.getLength() OR dominio.getCharAt(i) = "." THEN
LET etiqueta = dominio.subString(inicio, i - 1)
IF etiqueta.getLength() = 0 OR etiqueta.getLength() > 63 THEN
RETURN FALSE
END IF
IF etiqueta.getCharAt(1) = "-" OR etiqueta.getCharAt(etiqueta.getLength()) = "-" THEN
RETURN FALSE
END IF
LET inicio = i + 1
ELSE
LET c = dominio.getCharAt(i)
IF NOT (c MATCHES "[a-zA-Z0-9]" OR c = "-") THEN
RETURN FALSE
END IF
END IF
END FOR
# ETIQUETA FINAL = TLD
IF etiqueta.getLength() < 2 THEN
RETURN FALSE
END IF
FOR i = 1 TO etiqueta.getLength()
IF NOT (etiqueta.getCharAt(i) MATCHES "[a-zA-Z]") THEN
RETURN FALSE
END IF
END FOR
RETURN TRUE
END FUNCTION
# 1 = EL DOMINIO RECIBE CORREO, 0 = NO EXISTE / SIN MX NI A, -1 = NO SE PUDO CONSULTAR
FUNCTION email_dominio_dns(pdominio)
DEFINE pdominio STRING
DEFINE r SMALLINT
LET r = email_dns_consulta(pdominio, "MX")
IF r <> 0 THEN
RETURN r
END IF
# SIN MX: EL REGISTRO A FUNCIONA COMO MX IMPLICITO
RETURN email_dns_consulta(pdominio, "A")
END FUNCTION
FUNCTION email_dns_consulta(pdominio, ptipo)
DEFINE pdominio, ptipo, res, dato STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
DEFINE obj, rr util.JSONObject
DEFINE answers util.JSONArray
DEFINE i, dns_status, tipo_rr, tipo_buscado INT
IF ptipo = "MX" THEN
LET tipo_buscado = 15
ELSE
LET tipo_buscado = 1
END IF
TRY
LET http_req = com.HTTPRequest.Create(
SFMT("https://dns.google/resolve?name=%1&type=%2", pdominio.toLowerCase(), ptipo))
CALL http_req.setTimeOut(10)
CALL http_req.setHeader("Accept","application/dns-json")
CALL http_req.doRequest()
LET http_resp = http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
RETURN -1
END IF
LET res = http_resp.getTextResponse()
LET obj = util.JSONObject.parse(res)
LET dns_status = obj.get("Status")
CATCH
DISPLAY "email_dns_consulta error: ",STATUS
RETURN -1
END TRY
# 3 = NXDOMAIN (EL DOMINIO NO EXISTE); OTRO <> 0 = FALLA DEL DNS
IF dns_status = 3 THEN
RETURN 0
END IF
IF dns_status <> 0 THEN
RETURN -1
END IF
IF NOT obj.has("Answer") THEN
RETURN 0
END IF
IF obj.getType("Answer") <> "ARRAY" THEN
RETURN 0
END IF
LET answers = obj.get("Answer")
FOR i = 1 TO answers.getLength()
LET rr = answers.get(i)
LET tipo_rr = rr.get("type")
LET dato = rr.get("data")
IF tipo_rr = tipo_buscado THEN
# "0 ." ES UN NULL MX (RFC 7505): EL DOMINIO DECLARA QUE NO RECIBE CORREO
IF tipo_buscado = 15 AND dato.trim() MATCHES "* ." THEN
CONTINUE FOR
END IF
RETURN 1
END IF
END FOR
RETURN 0
END FUNCTION
FUNCTION email_resultado_dns(dns_estado)
DEFINE dns_estado SMALLINT
CASE dns_estado
WHEN 1
RETURN 'VALIDO', 200
WHEN 0
RETURN 'EL DOMINIO DEL EMAIL NO EXISTE O NO RECIBE CORREO', 400
OTHERWISE
RETURN 'NO FUE POSIBLE VERIFICAR EL EMAIL, INTENTE DE NUEVO', 400
END CASE
END FUNCTION
+305
View File
@@ -0,0 +1,305 @@
OPTIONS SHORT CIRCUIT
IMPORT util
IMPORT com
FUNCTION apiclient(pemail)
DEFINE data_apilayer RECORD
email,did_you_mean,USER,domain,syntax_valid STRING,
is_disposable,is_role_account,is_catch_all,is_deliverable,can_connect_smtp,
is_inbox_full,is_disabled,mx_records,FREE,score BOOLEAN
END RECORD
DEFINE data RECORD
data RECORD
status ,
result,
deprecation_notice string,
score smallint,
email string,
regexp,
gibberish,
disposable,
webmail,
mx_records,
smtp_server,
smtp_check,
accept_all,
block BOOLEAN
END RECORD,
source DYNAMIC ARRAY OF STRING,
meta RECORD
param STRING
END RECORD
END RECORD
DEFINE data_ipq RECORD
MESSAGE STRING,
success,
valid,
disposable BOOLEAN,
smtp_score ,
overall_score DEC(10,2),
first_name string,
generic,
common,
dns_valid,
honeypot BOOLEAN,
deliverability STRING,
frequent_complainer BOOLEAN,
spam_trap_score STRING,
catch_all,
timed_out,
suspect,
recent_abuse BOOLEAN,
fraud_score DEC(10,2),
suggested_domain string,
leaked BOOLEAN
END RECORD
DEFINE estado,purl,cmd,res, msg,s,pemail,tiposervice STRING,
ret INT
# LA API PARA VERIFICAR ESTA OFFLINE 29/05/2025
{ LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
}
# SE DEVUELVE SI EL EMAIL ESTA EN BLANCO
IF pemail IS NULL THEN
LET ret = 400
LET estado = 'DEBES DIGITAR EL EMAIL POR FAVOR'
RETURN estado,ret
END IF
DISPLAY "llego: ",pemail
# ELECCION DE SERVICIOS, POR EL MOMENTO ES IPQUALITY
SELECT a.IDENTIFICACION INTO tiposervice FROM APIS a
WHERE a.estado = 'ONLINE'
IF STATUS = NOTFOUND THEN
RETURN estado,ret
END IF
# LET tiposervice = 'ipq1'
IF tiposervice = 'HUNTER' THEN
LET purl = "https://api.hunter.io/v2/email-verifier?email=",pemail CLIPPED,"&api_key=2a50343f3a2842b082ee2c4b3ecccaf4ae5a7766"
CALL ipquality_send_command(purl) RETURNING ret,res
DISPLAY "response api: ",res," longitud: ",res.getLength()
IF res.getLength() =0 THEN
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,data.data.status,getdate(),'mt101_hunter',suser_Sname(),data.data.score)
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
RETURN estado,ret
END IF
TRY
CALL util.JSON.parse(res,data)
CATCH
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
RETURN estado,ret
END TRY
# INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
# VALUES (pemail,data.data.status,getdate(),'forzado',suser_Sname(),data.data.score)
# LET estado = 'VALIDO'
# LET ret = 200
# RETURN estado,ret
LET s = util.JSON.stringify(res)
DISPLAY "DATA EMAIL: ",pemail CLIPPED, " score: ",data.data.score
INSERT INTO envia_email_log (email,estado,fecha,programa_envio,us_crea,score)
VALUES (pemail,data.data.status,getdate(),'mt101_hunter',suser_Sname(),data.data.score)
IF ret ==0 THEN
IF data.data.mx_records = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF data.data.smtp_server = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF data.data.regexp = TRUE THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
END IF
IF data.data.disposable = TRUE THEN
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
LET ret = 400
RETURN estado,ret
ELSE
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
END IF
IF (data.data.status = 'valid' OR data.data.status = 'accept_all' OR
data.data.status = 'unknown') AND data.data.score > 29 THEN
LET estado = 'VALIDO'
LET ret = 200
RETURN estado,ret
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
RETURN estado,ret
END IF
END IF
END IF
IF tiposervice = 'IPQUALITY' THEN
LET purl = 'https://ipqualityscore.com/api/json/email/cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3/',pemail CLIPPED
CALL ipquality_send_command(purl) RETURNING ret,res
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
CALL util.JSON.parse(res,data_ipq)
IF data_ipq.valid THEN
LET estado = 'VALIDO'
LET ret = 200
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
END IF
END IF
END IF
IF tiposervice = 'APILAYER' THEN
# DISPLAY " ESTOY EN APILAYER"
LET purl= "https://api.apilayer.com/email_verification/",pemail CLIPPED
CALL apilayer_send_command(purl, cmd) RETURNING ret, res
# DISPLAY "res ",res," ",ret
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
CALL util.JSON.parse(res,data_apilayer)
IF data_apilayer.can_connect_smtp THEN
LET estado = 'VALIDO'
LET ret = 200
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
END IF
# DISPLAY "sintax ",data.syntax_valid," deliv ",data.is_deliverable
ELSE
IF ret = 429 THEN
LET ret = 200
LET estado ='VALIDO POR EXESO DE REQUEST'
ELSE
LET ret = 400
LET estado = 'NO FUE POSIBLE LA CONEXION, '
END IF
END IF
END IF
# LET ret = 200
DISPLAY "en return ",estado," ",ret
RETURN estado,ret
END FUNCTION
#
## Communications library using com (http or https)
#
FUNCTION apilayer_send_command(url, cmd)
DEFINE url, cmd STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
TRY
UPDATE apis SET cuenta = cuenta + 1 WHERE estado = 'ONLINE'
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("api_key","2a50343f3a2842b082ee2c4b3ecccaf4ae5a7766")
CALL http_req.doRequest()
LET http_resp=http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
RETURN http_resp.getStatusCode(), http_resp.getStatusDescription()
END IF
LET tmp = http_resp.getStatusDescription()
IF (tmp == "OK" || tmp == "no error" ) THEN
RETURN -1, SFMT("HTTP request status description: %1 ",tmp)
END IF
LET result = http_resp.getTextResponse()
CATCH
RETURN -2, SFMT("HTTP request error: STATUS=%1 (%2)",STATUS,SQLCA.sqlerrd[2])
END TRY
RETURN 0, result
END FUNCTION
FUNCTION ipquality_send_command(url)
DEFINE url, cmd STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
DISPLAY "url", url
TRY
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("apikey","cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3")
CALL http_req.doRequest()
LET http_resp=http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
RETURN http_resp.getStatusCode(), http_resp.getStatusDescription()
END IF
LET tmp = http_resp.getStatusDescription()
IF (tmp == "OK" || tmp == "no error" ) THEN
RETURN -1, SFMT("HTTP request status description: %1 ",tmp)
END IF
LET result = http_resp.getTextResponse()
CATCH
RETURN -2, SFMT("HTTP request error: STATUS=%1 (%2)",STATUS,SQLCA.sqlerrd[2])
END TRY
RETURN 0, result
END FUNCTION
-172
View File
@@ -1,172 +0,0 @@
OPTIONS SHORT CIRCUIT
IMPORT util
IMPORT com
FUNCTION apiclient(pemail)
DEFINE data_apilayer RECORD
email,did_you_mean,USER,domain,syntax_valid STRING,
is_disposable,is_role_account,is_catch_all,is_deliverable,can_connect_smtp,
is_inbox_full,is_disabled,mx_records,FREE,score BOOLEAN
END RECORD
DEFINE data_ipq RECORD
MESSAGE STRING,
success,
valid,
disposable BOOLEAN,
smtp_score ,
overall_score DEC(10,2),
first_name string,
generic,
common,
dns_valid,
honeypot BOOLEAN,
deliverability STRING,
frequent_complainer BOOLEAN,
spam_trap_score STRING,
catch_all,
timed_out,
suspect,
recent_abuse BOOLEAN,
fraud_score DEC(10,2),
suggested_domain string,
leaked BOOLEAN
END RECORD
DEFINE estado,purl,cmd,res, msg,s,pemail,tiposervice STRING,
ret INT
# ELECCION DE SERVICIOS, POR EL MOMENTO ES IPQUALITY
LET tiposervice = 'ipq1'
IF tiposervice = 'ipq' THEN
LET purl = 'https://ipqualityscore.com/api/json/email/cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3/',pemail CLIPPED
CALL ipquality_send_command(purl) RETURNING ret,res
DISPLAY "estoy a qui"
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
CALL util.JSON.parse(res,data_ipq)
IF data_ipq.valid THEN
LET estado = 'VALIDO'
LET ret = 200
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
END IF
ELSE
CALL apilayer_send_command(purl, cmd) RETURNING ret, res
# DISPLAY "res ",res," ",ret
IF ret ==0 THEN
LET s = util.JSON.stringify(res)
CALL util.JSON.parse(res,data_apilayer)
IF data_apilayer.can_connect_smtp THEN
LET estado = 'VALIDO'
LET ret = 200
ELSE
LET ret = 400
LET estado = 'NO SE PUEDE ENTREGAR MENSAJE A ESTA DIRECCION EMAIL'
END IF
# DISPLAY "sintax ",data.syntax_valid," deliv ",data.is_deliverable
ELSE
IF ret = 429 THEN
LET ret = 200
LET estado ='VALIDO POR EXESO DE REQUEST'
ELSE
LET ret = 400
LET estado = 'NO FUE POSIBLE LA CONEXION, '
END IF
END IF
END IF
END IF
DISPLAY "en return ",estado," ",ret
RETURN estado,ret
END FUNCTION
#
## Communications library using com (http or https)
#
FUNCTION apilayer_send_command(url, cmd)
DEFINE url, cmd STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
TRY
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("apikey","gPWg6pDyOt3k2RL2ElbghaMqs6dNMAwm")
CALL http_req.doRequest()
LET http_resp=http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
RETURN http_resp.getStatusCode(), http_resp.getStatusDescription()
END IF
LET tmp = http_resp.getStatusDescription()
IF (tmp == "OK" || tmp == "no error" ) THEN
RETURN -1, SFMT("HTTP request status description: %1 ",tmp)
END IF
LET result = http_resp.getTextResponse()
CATCH
RETURN -2, SFMT("HTTP request error: STATUS=%1 (%2)",STATUS,SQLCA.sqlerrd[2])
END TRY
RETURN 0, result
END FUNCTION
FUNCTION ipquality_send_command(url)
DEFINE url, cmd STRING
DEFINE result, tmp STRING
DEFINE http_req com.HTTPRequest
DEFINE http_resp com.HTTPResponse
TRY
LET http_req = com.HTTPRequest.Create(url)
CALL http_req.setHeader("apikey","cHZNnfXkbJDtx43YcrQqHSjXzBrndwT3")
CALL http_req.doRequest()
LET http_resp=http_req.getResponse()
IF http_resp.getStatusCode() != 200 THEN
RETURN http_resp.getStatusCode(), http_resp.getStatusDescription()
END IF
LET tmp = http_resp.getStatusDescription()
IF (tmp == "OK" || tmp == "no error" ) THEN
RETURN -1, SFMT("HTTP request status description: %1 ",tmp)
END IF
LET result = http_resp.getTextResponse()
CATCH
RETURN -2, SFMT("HTTP request error: STATUS=%1 (%2)",STATUS,SQLCA.sqlerrd[2])
END TRY
RETURN 0, result
END FUNCTION
FUNCTION show_sync_err(msg)
DEFINE msg STRING
CALL fgl_winmessage(%"ERROR", msg, "exclamation")
END FUNCTION
+27 -8
View File
@@ -97,16 +97,25 @@ FUNCTION productosconteo(pdata)
IF STATUS < 0 THEN
LET p.mensajes.cod_msg=STATUS
LET p.mensajes.descripcion = 'ERROR EN CONEXION ',SQLCA.sqlerrm
DISCONNECT CURRENT
# sin DISCONNECT: no hay conexion abierta y el error tumbaba el server
RETURN util.JSON.stringify(p)
END IF
LET fecha = TODAY
END IF
LET fecha = TODAY
LET fecha_ini = fecha - 90
IF p.credenciales.tipo_inventario IS NULL OR p.credenciales.tipo_inventario <> "productos" THEN
# solo productos tiene consulta; antes PREPARE de NULL tumbaba el server
LET p.mensajes.cod_msg = -1
LET p.mensajes.descripcion = 'TIPO DE INVENTARIO NO DISPONIBLE PARA CONTEO: ',
p.credenciales.tipo_inventario
DISCONNECT CURRENT
RETURN util.JSON.stringify(p)
END IF
IF p.credenciales.tipo_inventario = "productos" THEN
SELECT a.fecha_conteo INTO xfecha_conteo FROM intb00044 a
WHERE a.tipo_inventario = tipo_inventario AND a.disponible = "SI"
SELECT a.fecha_conteo INTO xfecha_conteo FROM intb00044 a
WHERE a.tipo_inventario = 'PRODUCTOS TERMINADOS' AND a.disponible = "SI"
DISPLAY "ESTOY PRODUCTOS",p.credenciales.codn
LET selec =
@@ -127,7 +136,9 @@ FUNCTION productosconteo(pdata)
"SELECT a.codid,b.bodega,c.descripcion,0"{ISNULL(SUM(b.cantidad_2),0)},",d.cod_seccion,d.cod_tramo,d.cod_fila,d.cod_pos
FROM iptb00006 b,iptb00002 a INNER JOIN intb00015 e ON e.cod_n = a.cod_n and
e.cod_grupo = a.cod_grupo and e.cod_tipo = a.cod_tipo and e.cod_sec = a.cod_sec and
e.estado='Pendiente' ,intb00009 c,iptb00062 d
e.estado='Pendiente' AND
e.semana_del = (SELECT MIN (x.semana_del) FROM intb00015 x WHERE x.semana_del >= GETDATE())
,intb00009 c,iptb00062 d
WHERE (a.cod_n = b.cod_n and ",
" a.cod_grupo = b.cod_grupo and a.cod_tipo = b.cod_tipo and a.cod_sec = b.cod_sec) and b.status_t is null ",
@@ -189,6 +200,14 @@ FUNCTION productosconteo(pdata)
END FOREACH
DISPLAY "NUMERO DE PRODUCTOS ",i
IF p.productos.getLength() = 0 THEN
# sin semana programada en intb00015 no hay nada que contar; evita la
# consulta de existencias (iptb00006) que tardaba >5 min y bloqueaba el WS
LET p.mensajes.cod_msg = 100
LET p.mensajes.descripcion = 'NO HAY PRODUCTOS PROGRAMADOS PARA CONTEO (intb00015)'
DISCONNECT CURRENT
RETURN util.JSON.stringify(p)
END IF
LET i = 1
PREPARE comando2 FROM s1
@@ -0,0 +1,213 @@
IMPORT util
IMPORT os
FUNCTION productosconteo(pdata)
DEFINE xfecha_conteo DATE
DEFINE pdata STRING
DEFINE producto RECORD
codid INT,
cod_n SMALLINT,
cod_grupo SMALLINT,
cod_tipo SMALLINT,
cod_sec SMALLINT,
descripcion VARCHAR(100),
unidad_med VARCHAR(4),
factor_conv FLOAT,
despiece STRING,
existencia DEC(12,5),
consumo DEC(12,5),
costo DEC(12,5),
precio DEC(12,2),
ordenes DEC(12,5),
despachado DEC(12,5),
desglose VARCHAR(1),
reservada DEC(12,5),
disponible DEC(12,5),
transito DEC(12,5),
dias SMALLINT,
fecha CHAR(10),
fecha_conteo CHAR(10)
END RECORD
DEFINE existencia RECORD
codid INT,
bodega SMALLINT,
descripcion_bodega VARCHAR(100),
cantidad FLOAT,
cod_seccion INT,cod_tramo INT,cod_fila INT,cod_pos,
fecha DATE
END RECORD
DEFINE p RECORD
credenciales RECORD
usuario,clave,tipo_inventario VARCHAR(50),
codn INT
END RECORD,
productos DYNAMIC ARRAY OF RECORD
codid INT,
cod_n SMALLINT,
cod_grupo SMALLINT,
cod_tipo SMALLINT,
cod_sec SMALLINT,
descripcion VARCHAR(100),
unidad_med VARCHAR(4),
factor_conv FLOAT,
despiece STRING,
existencia DEC(12,5),
consumo DEC(12,5),
costo DEC(12,5),
precio DEC(12,2),
ordenes DEC(12,5),
despachado DEC(12,5),
desglose VARCHAR(1),
reservada DEC(12,5),
disponible DEC(12,5),
transito DEC(12,5),
dias SMALLINT,
fecha CHAR(10),
fecha_conteo CHAR(10)
END RECORD ,
existencia DYNAMIC ARRAY OF RECORD
codid INT,
bodega SMALLINT,
descripcion_bodega VARCHAR(100),
cantidad FLOAT,
cod_seccion INT,cod_tramo INT,cod_fila INT,cod_pos,
fecha DATE
END RECORD,
mensajes RECORD
cod_msg INT,
descripcion STRING
END RECORD
END RECORD,
i int,
selec,s1 STRING,
fecha,fecha_ini DATE
CALL util.JSON.parse(pdata,p)
IF STATUS < 0 THEN
LET p.mensajes.cod_msg=STATUS
LET p.mensajes.descripcion = 'ERROR EN CONEXION ',SQLCA.sqlerrm
RETURN util.JSON.stringify(p)
END IF
# DISPLAY "productos ",p.credenciales.usuario," ",p.credenciales.clave," ",p.credenciales.tipo_inventario
CONNECT TO "smarmotech" USER p.credenciales.usuario USING p.credenciales.clave
IF STATUS < 0 THEN
LET p.mensajes.cod_msg=STATUS
LET p.mensajes.descripcion = 'ERROR EN CONEXION ',SQLCA.sqlerrm
DISCONNECT CURRENT
RETURN util.JSON.stringify(p)
END IF
LET fecha = TODAY
LET fecha_ini = fecha - 90
IF p.credenciales.tipo_inventario = "productos" THEN
SELECT a.fecha_conteo INTO xfecha_conteo FROM intb00044 a
WHERE a.tipo_inventario = tipo_inventario AND a.disponible = "SI"
DISPLAY "ESTOY PRODUCTOS",p.credenciales.codn
LET selec =
"SELECT a.codid,a.cod_n,a.cod_grupo,a.cod_tipo,a.cod_Sec,a.descrip_esp,a.unidad_med,ISNULL(d.factor_conv,1),b.cod_n,
'0','0', '0','0','0','0',a.desglose ",
" FROM iptb00002 a,iptb00001 d INNER JOIN intb00015 e ON e.cod_n = d.cod_n and
e.cod_grupo = d.cod_grupo and e.cod_tipo = d.cod_tipo and e.cod_sec = d.cod_sec and
e.estado = 'Pendiente'
LEFT OUTER JOIN iptb00027 b ON d.cod_n = b.cod_n and
d.cod_grupo = b.cod_grupo and d.cod_tipo = b.cod_tipo and d.cod_sec = b.cod_sec
where ",
" (a.cod_n = d.cod_n and a.cod_grupo = d.cod_grupo and a.cod_tipo = d.cod_tipo and ",
" a.cod_sec = d.cod_sec) AND a.status_t IS NULL AND ",
"a.control_existencia='SI' AND e.semana_del = (SELECT MIN (a.semana_del) FROM intb00015 a WHERE semana_del >= GETDATE())",
" ORDER BY a.codid "
LET s1 =
"SELECT a.codid,b.bodega,c.descripcion,0"{ISNULL(SUM(b.cantidad_2),0)},",d.cod_seccion,d.cod_tramo,d.cod_fila,d.cod_pos
FROM iptb00006 b,iptb00002 a INNER JOIN intb00015 e ON e.cod_n = a.cod_n and
e.cod_grupo = a.cod_grupo and e.cod_tipo = a.cod_tipo and e.cod_sec = a.cod_sec and
e.estado='Pendiente' ,intb00009 c,iptb00062 d
WHERE (a.cod_n = b.cod_n and ",
" a.cod_grupo = b.cod_grupo and a.cod_tipo = b.cod_tipo and a.cod_sec = b.cod_sec) and b.status_t is null ",
" and (d.cod_n = a.cod_n and d.cod_grupo = a.cod_grupo and d.cod_tipo = a.cod_tipo and d.cod_Sec = a.cod_sec) ",
" and ",
"a.control_existencia='SI' AND a.dispositivo_movil='SI' and b.bodega = c.cod_bodega ",
" group by a.codid,b.bodega,c.descripcion,d.cod_seccion,d.cod_tramo,d.cod_fila,d.cod_pos ",
" having SUM(b.cantidad_2) > 0 "
END IF
PREPARE comando FROM selec
DECLARE c2 CURSOR FOR comando
LET i = 1
FOREACH c2 INTO producto.*
IF producto.cod_n IS NOT null THEN
IF p.credenciales.tipo_inventario = 'productos' THEN
LET producto.costo=0
# CALL disponibles(producto.cod_n,producto.cod_grupo,producto.cod_tipo,producto.cod_sec,TODAY)
# RETURNING producto.ordenes,producto.despachado,producto.transito,producto.existencia,
# producto.reservada
LET producto.disponible = producto.existencia - (producto.ordenes+producto.despachado+producto.reservada)
IF producto.disponible IS NULL THEN
LET producto.disponible=0
END IF
# DESPIECE
IF producto.despiece IS NULL THEN
LET producto.despiece = 'NO'
ELSE
LET producto.despiece = 'SI'
END IF
END IF
IF producto.consumo < 0 THEN
LET producto.consumo = producto.consumo * -1
END IF
IF producto.consumo > 0 THEN
LET producto.dias =(producto.disponible/ producto.consumo) * 90
ELSE
LET producto.dias=0
END IF
IF producto.descripcion IS NULL THEN
LET producto.descripcion = "NO TIENE"
END IF
IF producto.unidad_med IS NULL THEN
LET producto.unidad_med='UD'
END IF
LET producto.fecha=TODAY USING "dd/mm/yyyy"
LET producto.fecha_conteo = xfecha_conteo
LET p.productos[i].* = producto.*
LET i = i + 1
END IF
END FOREACH
DISPLAY "NUMERO DE PRODUCTOS ",i
LET i = 1
PREPARE comando2 FROM s1
DECLARE c3 CURSOR FOR comando2
FOREACH c3 INTO existencia.*
IF existencia.cantidad IS NOT NULL THEN
IF existencia.codid > 0 THEN
LET existencia.fecha = today
LET p.existencia[i].* = existencia.*
IF p.existencia[i].cantidad IS NULL THEN
LET p.existencia[i].cantidad=0
END IF
LET i = i+1
END IF
END IF
END FOREACH
DISPLAY "NUMERO DE PRODUCTOS EXISTENCIA ",i
DISCONNECT CURRENT
RETURN util.JSON.stringify(p)
END FUNCTION