488 lines
19 KiB
Plaintext
488 lines
19 KiB
Plaintext
{
|
|
-----------------------------------------------------------------------------
|
|
MODULO : prtraza
|
|
OBJETIVO : Trazabilidad del Bloque. Dado un codigo_bloque, arma el recorrido
|
|
completo desde cttb00003 (inventario inicial, produccion, salidas y
|
|
recepciones entre departamentos, hasta almacen) y lo presenta como
|
|
una pagina HTML que se abre en el navegador del cliente.
|
|
USADO POR: prprmt003 (boton "Trazabilidad")
|
|
NOTA : Requiere el template 'prtraza.html' desplegado junto al programa
|
|
(misma carpeta bin donde corre el .42m).
|
|
-----------------------------------------------------------------------------
|
|
}
|
|
IMPORT os
|
|
|
|
SCHEMA smarmotech
|
|
|
|
# guard one-time del PREPARE/DECLARE (evita -404 al re-trazar en la misma sesion)
|
|
DEFINE m_traza_prep SMALLINT
|
|
DEFINE m_rango_prep SMALLINT
|
|
|
|
FUNCTION trazabilidad_bloque(p_bloque)
|
|
DEFINE p_bloque STRING
|
|
|
|
DEFINE eventos DYNAMIC ARRAY OF RECORD
|
|
num_doc INTEGER,
|
|
fecha CHAR(10),
|
|
dep_no SMALLINT,
|
|
dep_nom CHAR(30),
|
|
cod_mov SMALLINT,
|
|
mov_desc CHAR(30),
|
|
estado_mov SMALLINT,
|
|
cod_prod INTEGER,
|
|
prod_desc CHAR(60),
|
|
unidad CHAR(6),
|
|
cantidad DECIMAL(18,5),
|
|
medida DECIMAL(18,5),
|
|
emp_no INTEGER,
|
|
emp_nom CHAR(60),
|
|
recep_no SMALLINT,
|
|
recep_nom CHAR(30),
|
|
ref_no INTEGER,
|
|
estatus CHAR(1)
|
|
END RECORD
|
|
|
|
DEFINE i, j, found, ndeptos INT
|
|
DEFINE q, cls, mvlabel, prodtxt, qtytxt, s_cant, s_med, line STRING
|
|
DEFINE origen, medida_ini, desc_hero, estado_hero, aprovcls, descbloque STRING
|
|
DEFINE sbflow, sbtl, sbbal, sbfull base.StringBuffer
|
|
DEFINE cin base.Channel
|
|
DEFINE nl CHAR(1)
|
|
DEFINE med_abs, v_balance, v_aprov DECIMAL(18,5)
|
|
DEFINE bal DYNAMIC ARRAY OF RECORD
|
|
uni CHAR(6),
|
|
entro DECIMAL(18,5),
|
|
salio DECIMAL(18,5)
|
|
END RECORD
|
|
|
|
LET nl = ASCII 10
|
|
|
|
IF p_bloque IS NULL OR LENGTH(p_bloque CLIPPED) = 0 THEN
|
|
RETURN
|
|
END IF
|
|
|
|
# ---------------- 1. Consultar el recorrido ----------------
|
|
LET q =
|
|
"SELECT a.num_doc, CONVERT(VARCHAR(10),a.fecha,103), a.departamento, ISNULL(d.nom_dpto,''),",
|
|
" ISNULL(a.cod_mov,0), ISNULL(m.descrip_mov,''), ISNULL(m.estado_mov,0),",
|
|
" ISNULL(a.cod_prod,0), ISNULL(p.descripcion,''), ISNULL(p.unidad_med,''),",
|
|
" ISNULL(a.cantidad,0), ISNULL(a.medida,0),",
|
|
" ISNULL(a.emp_no,0), ISNULL(RTRIM(e.nom1_emp)+' '+RTRIM(e.apell1_emp),''),",
|
|
" ISNULL(a.depto_receptor,0), ISNULL(dr.nom_dpto,''), ISNULL(a.ref,0),",
|
|
" ISNULL(a.status_t,'')",
|
|
" FROM cttb00003 a",
|
|
" LEFT JOIN adtb00001 d ON d.departamento = a.departamento",
|
|
" LEFT JOIN cttb00005 m ON m.cod_mov = a.cod_mov",
|
|
" LEFT JOIN cttb00001 p ON p.cod_prod = a.cod_prod",
|
|
" LEFT JOIN adtb00003 e ON e.num_emp = a.emp_no",
|
|
" LEFT JOIN adtb00001 dr ON dr.departamento = a.depto_receptor",
|
|
" WHERE a.codigo_bloque = ? AND a.status_t IS NULL",
|
|
" ORDER BY a.fecha, a.num_doc, a.cod_mov"
|
|
|
|
IF m_traza_prep = 0 THEN
|
|
PREPARE s_traza FROM q
|
|
DECLARE c_traza CURSOR FOR s_traza
|
|
LET m_traza_prep = 1
|
|
END IF
|
|
|
|
LET i = 1
|
|
FOREACH c_traza USING p_bloque INTO eventos[i].*
|
|
LET i = i + 1
|
|
END FOREACH
|
|
|
|
IF eventos.getLength() = 0 THEN
|
|
CALL fgl_winmessage("Trazabilidad",
|
|
"No se encontraron movimientos activos para el bloque: " || p_bloque CLIPPED,
|
|
"information")
|
|
RETURN
|
|
END IF
|
|
|
|
# ---------------- 2. Armar secciones HTML ----------------
|
|
LET sbflow = base.StringBuffer.create()
|
|
LET sbtl = base.StringBuffer.create()
|
|
LET ndeptos = 0
|
|
|
|
FOR i = 1 TO eventos.getLength()
|
|
|
|
# -- Clasificar el movimiento (color + etiqueta) --
|
|
CASE
|
|
WHEN eventos[i].cod_mov = 1
|
|
LET cls = "inicial" LET mvlabel = "Inventario inicial"
|
|
WHEN eventos[i].cod_mov = 3
|
|
IF UPSHIFT(eventos[i].recep_nom) MATCHES "*ALMAC*" THEN
|
|
LET cls = "almacen"
|
|
ELSE
|
|
LET cls = "salida"
|
|
END IF
|
|
LET mvlabel = "Salida"
|
|
WHEN eventos[i].cod_mov = 2 AND eventos[i].ref_no > 0
|
|
LET cls = "entrada" LET mvlabel = "Recepcion"
|
|
OTHERWISE
|
|
LET cls = "produccion" LET mvlabel = "Produccion"
|
|
END CASE
|
|
|
|
# -- Texto del producto / destino --
|
|
CASE
|
|
WHEN eventos[i].cod_mov = 3
|
|
LET prodtxt = "→ ", eventos[i].recep_nom CLIPPED
|
|
WHEN eventos[i].cod_mov = 1
|
|
IF LENGTH(eventos[i].prod_desc CLIPPED) > 0 THEN
|
|
LET prodtxt = eventos[i].prod_desc CLIPPED
|
|
ELSE
|
|
LET prodtxt = "Bloque recibido"
|
|
END IF
|
|
OTHERWISE
|
|
IF LENGTH(eventos[i].prod_desc CLIPPED) > 0 THEN
|
|
LET prodtxt = eventos[i].prod_desc CLIPPED
|
|
ELSE
|
|
LET prodtxt = "—"
|
|
END IF
|
|
END CASE
|
|
|
|
# -- Cantidad / medida formateadas --
|
|
LET s_cant = eventos[i].cantidad USING "<<<<<<<<<&.#"
|
|
LET s_med = eventos[i].medida USING "<<<<<<<<<&.##"
|
|
LET qtytxt = s_cant CLIPPED, " ", eventos[i].unidad CLIPPED,
|
|
" · ", s_med CLIPPED
|
|
|
|
# -- Contar departamentos distintos (secuencia) --
|
|
# (OR de Genero NO hace short-circuit; se separa para no tocar eventos[0])
|
|
IF i = 1 THEN
|
|
LET ndeptos = ndeptos + 1
|
|
ELSE
|
|
IF eventos[i].dep_no <> eventos[i-1].dep_no THEN
|
|
LET ndeptos = ndeptos + 1
|
|
END IF
|
|
END IF
|
|
|
|
# -- Paso del recorrido horizontal --
|
|
IF i > 1 THEN
|
|
CALL sbflow.append(' <div class="arrow">→</div>' || nl)
|
|
END IF
|
|
LET line =
|
|
' <div class="step" style="--c:var(--', cls CLIPPED, ')">',
|
|
'<div class="dep">', eventos[i].dep_nom CLIPPED,
|
|
' <span class="depno">(', eventos[i].dep_no USING "<<<<<", ')</span></div>',
|
|
'<span class="mv">', mvlabel CLIPPED, '</span>',
|
|
'<div class="prod">', prodtxt CLIPPED, '</div>',
|
|
'<div class="qty">', qtytxt CLIPPED, '</div>',
|
|
'<div class="foot"><span>', eventos[i].fecha[1,5],
|
|
'</span><span>#', eventos[i].num_doc USING "<<<<<<<<", '</span></div></div>'
|
|
CALL sbflow.append(line)
|
|
CALL sbflow.append(nl)
|
|
|
|
# -- Evento de la linea de tiempo --
|
|
LET line =
|
|
' <div class="ev" style="--c:var(--', cls CLIPPED, ')"><div class="row">',
|
|
'<div class="date">', eventos[i].fecha CLIPPED, '</div>',
|
|
'<div class="main"><div class="mv">', mvlabel CLIPPED,
|
|
' · ', eventos[i].dep_nom CLIPPED, '</div>',
|
|
'<div class="ttl">', prodtxt CLIPPED, '</div>',
|
|
'<div class="meta">'
|
|
CALL sbtl.append(line)
|
|
# meta: empleado / referencia
|
|
IF LENGTH(eventos[i].emp_nom CLIPPED) > 0 THEN
|
|
CALL sbtl.append('<span class="k">Empleado:</span> ' || eventos[i].emp_nom CLIPPED || ' ')
|
|
END IF
|
|
IF eventos[i].cod_mov = 3 AND LENGTH(eventos[i].recep_nom CLIPPED) > 0 THEN
|
|
CALL sbtl.append('<span class="k">Receptor:</span> ' || eventos[i].recep_nom CLIPPED)
|
|
END IF
|
|
IF eventos[i].cod_mov = 2 AND eventos[i].ref_no > 0 THEN
|
|
CALL sbtl.append('<span class="k">Ref. salida:</span> #' || (eventos[i].ref_no USING "<<<<<<<<"))
|
|
END IF
|
|
LET line =
|
|
'</div></div>',
|
|
'<div class="amt"><div class="big">', s_cant CLIPPED, ' ', eventos[i].unidad CLIPPED, '</div>',
|
|
'<div class="doc">', s_med CLIPPED, ' · #', eventos[i].num_doc USING "<<<<<<<<",
|
|
'</div></div></div></div>'
|
|
CALL sbtl.append(line)
|
|
CALL sbtl.append(nl)
|
|
|
|
END FOR
|
|
|
|
# ---------------- 3. Campos del encabezado ----------------
|
|
# Descripcion del bloque: intb00018 (por codigo_bloque) -> intb00001 (descrip_esp)
|
|
LET descbloque = ""
|
|
SELECT MAX(i1.descrip_esp)
|
|
INTO descbloque
|
|
FROM intb00018 i18
|
|
LEFT JOIN intb00001 i1
|
|
ON i1.cod_n = i18.cod_n
|
|
AND i1.cod_grupo = i18.cod_grupo
|
|
AND i1.cod_tipo = i18.cod_tipo
|
|
AND i1.cod_sec = i18.cod_sec
|
|
WHERE i18.codigo_bloque = p_bloque
|
|
IF descbloque IS NULL THEN
|
|
LET descbloque = ""
|
|
END IF
|
|
|
|
LET origen = eventos[1].dep_nom CLIPPED
|
|
LET s_med = eventos[1].medida USING "<<<<<<<<<&.##"
|
|
LET medida_ini = s_med CLIPPED, " ", eventos[1].unidad CLIPPED
|
|
LET desc_hero = "Ingreso a produccion el ", eventos[1].fecha CLIPPED,
|
|
" y recorrio ", ndeptos USING "<<", " departamento(s)."
|
|
|
|
# estado por el ultimo movimiento
|
|
IF eventos[eventos.getLength()].cod_mov = 3
|
|
AND UPSHIFT(eventos[eventos.getLength()].recep_nom) MATCHES "*ALMAC*" THEN
|
|
LET estado_hero = "Enviado a almacen"
|
|
ELSE
|
|
LET estado_hero = "En proceso · " || (eventos[eventos.getLength()].dep_nom CLIPPED)
|
|
END IF
|
|
|
|
# ---------------- 4. Aprovechamiento por unidad (desde eventos) ----------------
|
|
# Entro/Produjo = entradas (estado_mov <> 2); Salio = salidas (estado_mov = 2).
|
|
# Se usa el valor absoluto de la medida y se agrupa por unidad de medida.
|
|
CALL bal.clear()
|
|
FOR i = 1 TO eventos.getLength()
|
|
IF eventos[i].cod_prod = 0 OR LENGTH(eventos[i].unidad CLIPPED) = 0 THEN
|
|
CONTINUE FOR
|
|
END IF
|
|
LET med_abs = eventos[i].medida
|
|
IF med_abs < 0 THEN LET med_abs = med_abs * -1 END IF
|
|
|
|
LET found = 0
|
|
FOR j = 1 TO bal.getLength()
|
|
IF bal[j].uni = eventos[i].unidad THEN
|
|
LET found = j
|
|
EXIT FOR
|
|
END IF
|
|
END FOR
|
|
IF found = 0 THEN
|
|
LET found = bal.getLength() + 1
|
|
LET bal[found].uni = eventos[i].unidad
|
|
LET bal[found].entro = 0
|
|
LET bal[found].salio = 0
|
|
END IF
|
|
|
|
IF eventos[i].estado_mov = 2 THEN
|
|
LET bal[found].salio = bal[found].salio + med_abs
|
|
ELSE
|
|
LET bal[found].entro = bal[found].entro + med_abs
|
|
END IF
|
|
END FOR
|
|
|
|
LET sbbal = base.StringBuffer.create()
|
|
IF bal.getLength() = 0 THEN
|
|
CALL sbbal.append(' <tr><td colspan="5" style="text-align:center;color:#9AA1AA">Sin datos de medida.</td></tr>')
|
|
ELSE
|
|
FOR j = 1 TO bal.getLength()
|
|
LET v_balance = bal[j].entro - bal[j].salio
|
|
LET v_aprov = 0
|
|
IF bal[j].entro > 0 THEN
|
|
LET v_aprov = bal[j].salio / bal[j].entro * 100
|
|
END IF
|
|
IF v_aprov >= 85 THEN
|
|
LET aprovcls = "hi"
|
|
ELSE
|
|
IF v_aprov >= 50 THEN
|
|
LET aprovcls = "mid"
|
|
ELSE
|
|
LET aprovcls = "lo"
|
|
END IF
|
|
END IF
|
|
LET line =
|
|
' <tr><td class="uni">', bal[j].uni CLIPPED, '</td>',
|
|
'<td class="num">', bal[j].entro USING "<<<<<<<&.##", '</td>',
|
|
'<td class="num">', bal[j].salio USING "<<<<<<<&.##", '</td>',
|
|
'<td class="num">', v_balance USING "<<<<<<<&.##", '</td>',
|
|
'<td class="num"><span class="aprov ', aprovcls, '">',
|
|
v_aprov USING "<<<&.#", '%</span></td></tr>'
|
|
CALL sbbal.append(line)
|
|
CALL sbbal.append(nl)
|
|
END FOR
|
|
END IF
|
|
|
|
# ---------------- 5. Leer template, sustituir, escribir ----------------
|
|
IF NOT os.Path.exists("prtraza.html") THEN
|
|
CALL fgl_winmessage("Trazabilidad",
|
|
"No se encontro la plantilla 'prtraza.html' en la carpeta del programa (bin).",
|
|
"stop")
|
|
RETURN
|
|
END IF
|
|
|
|
LET sbfull = base.StringBuffer.create()
|
|
LET cin = base.Channel.create()
|
|
CALL cin.openFile("prtraza.html", "r")
|
|
WHILE NOT cin.isEof()
|
|
CALL sbfull.append(cin.readLine())
|
|
CALL sbfull.append(nl)
|
|
END WHILE
|
|
CALL cin.close()
|
|
|
|
CALL sbfull.replace("{{FLOW}}", sbflow.toString(), 0)
|
|
CALL sbfull.replace("{{TIMELINE}}", sbtl.toString(), 0)
|
|
CALL sbfull.replace("{{BALANCE}}", sbbal.toString(), 0)
|
|
CALL sbfull.replace("{{BLOQUE}}", p_bloque CLIPPED, 0)
|
|
CALL sbfull.replace("{{DESCBLOQUE}}", descbloque, 0)
|
|
CALL sbfull.replace("{{DESC}}", desc_hero, 0)
|
|
CALL sbfull.replace("{{ESTADO}}", estado_hero, 0)
|
|
CALL sbfull.replace("{{ORIGEN}}", origen, 0)
|
|
CALL sbfull.replace("{{MEDIDA_INI}}", medida_ini, 0)
|
|
CALL sbfull.replace("{{NMOV}}", eventos.getLength() USING "<<<", 0)
|
|
CALL sbfull.replace("{{NDEPTOS}}", ndeptos USING "<<", 0)
|
|
|
|
# ---------------- 6. Escribir, transferir al cliente y abrir ----------------
|
|
CALL presenta_html(sbfull.toString(), "trazabilidad_bloque.html")
|
|
|
|
END FUNCTION
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Escribe el HTML en el server, lo transfiere al TEMP del cliente y lo abre
|
|
# en el navegador por defecto.
|
|
# ---------------------------------------------------------------------------
|
|
FUNCTION presenta_html(p_full, p_nombre)
|
|
DEFINE p_full, p_nombre STRING
|
|
DEFINE cout base.Channel
|
|
DEFINE server_file, client_dir, client_file, res STRING
|
|
|
|
LET server_file = "traza_salida.html"
|
|
LET cout = base.Channel.create()
|
|
CALL cout.openFile(server_file, "w")
|
|
CALL cout.writeLine(p_full)
|
|
CALL cout.close()
|
|
|
|
CALL ui.Interface.frontCall("standard", "getenv", ["TEMP"], [client_dir])
|
|
LET client_file = client_dir CLIPPED, "\\", p_nombre CLIPPED
|
|
CALL fgl_putfile(server_file, client_file)
|
|
CALL ui.Interface.frontCall("standard", "shellexec", [client_file], [res])
|
|
|
|
END FUNCTION
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Reporte por RANGO DE FECHAS: lista los bloques con movimiento en el periodo.
|
|
# Recibe las fechas como texto DD/MM/YYYY (se convierten en SQL Server).
|
|
# ---------------------------------------------------------------------------
|
|
FUNCTION trazabilidad_rango(f1, f2)
|
|
DEFINE f1, f2 STRING
|
|
|
|
DEFINE bloques DYNAMIC ARRAY OF RECORD
|
|
cod_bloque CHAR(25),
|
|
origen CHAR(30),
|
|
f_desde CHAR(10),
|
|
f_hasta CHAR(10),
|
|
nmov INTEGER,
|
|
ndeptos INTEGER,
|
|
en_almacen SMALLINT,
|
|
entro DECIMAL(18,5),
|
|
salio DECIMAL(18,5),
|
|
descbloque CHAR(60)
|
|
END RECORD
|
|
DEFINE v_aprov DECIMAL(18,5)
|
|
|
|
DEFINE i INT
|
|
DEFINE q, line, estcls, esttxt, f1_disp, f2_disp STRING
|
|
DEFINE sbrows, sbfull base.StringBuffer
|
|
DEFINE cin base.Channel
|
|
DEFINE nl CHAR(1)
|
|
|
|
LET nl = ASCII 10
|
|
|
|
# Fechas opcionales: en blanco = sin limite (todos los bloques)
|
|
IF f1 IS NULL OR LENGTH(f1 CLIPPED) = 0 THEN
|
|
LET f1 = "01/01/1900"
|
|
LET f1_disp = "inicio"
|
|
ELSE
|
|
LET f1_disp = f1 CLIPPED
|
|
END IF
|
|
IF f2 IS NULL OR LENGTH(f2 CLIPPED) = 0 THEN
|
|
LET f2 = "31/12/2999"
|
|
LET f2_disp = "hoy"
|
|
ELSE
|
|
LET f2_disp = f2 CLIPPED
|
|
END IF
|
|
|
|
LET q =
|
|
"SELECT a.codigo_bloque,",
|
|
" ISNULL((SELECT TOP 1 d.nom_dpto FROM cttb00003 b",
|
|
" LEFT JOIN adtb00001 d ON d.departamento = b.departamento",
|
|
" WHERE b.codigo_bloque = a.codigo_bloque AND b.status_t IS NULL",
|
|
" ORDER BY b.fecha, b.num_doc),''),",
|
|
" CONVERT(VARCHAR(10),MIN(a.fecha),103), CONVERT(VARCHAR(10),MAX(a.fecha),103),",
|
|
" COUNT(*), COUNT(DISTINCT a.departamento),",
|
|
" MAX(CASE WHEN a.cod_mov = 3 AND UPPER(ISNULL(dr.nom_dpto,'')) LIKE '%ALMAC%'",
|
|
" THEN 1 ELSE 0 END),",
|
|
" SUM(CASE WHEN ISNULL(m.estado_mov,1) = 2 THEN 0 ELSE ABS(a.medida) END),",
|
|
" SUM(CASE WHEN m.estado_mov = 2 THEN ABS(a.medida) ELSE 0 END),",
|
|
" ISNULL((SELECT MAX(i1.descrip_esp) FROM intb00018 i18",
|
|
" LEFT JOIN intb00001 i1 ON i1.cod_n = i18.cod_n AND i1.cod_grupo = i18.cod_grupo",
|
|
" AND i1.cod_tipo = i18.cod_tipo AND i1.cod_sec = i18.cod_sec",
|
|
" WHERE i18.codigo_bloque = a.codigo_bloque),'')",
|
|
" FROM cttb00003 a",
|
|
" LEFT JOIN adtb00001 dr ON dr.departamento = a.depto_receptor",
|
|
" LEFT JOIN cttb00005 m ON m.cod_mov = a.cod_mov",
|
|
" WHERE a.codigo_bloque IS NOT NULL AND a.status_t IS NULL",
|
|
" AND a.fecha BETWEEN CONVERT(DATE,?,103) AND CONVERT(DATE,?,103)",
|
|
" GROUP BY a.codigo_bloque",
|
|
" ORDER BY MIN(a.fecha), a.codigo_bloque"
|
|
|
|
IF m_rango_prep = 0 THEN
|
|
PREPARE s_rango FROM q
|
|
DECLARE c_rango CURSOR FOR s_rango
|
|
LET m_rango_prep = 1
|
|
END IF
|
|
|
|
CALL bloques.clear()
|
|
LET i = 1
|
|
FOREACH c_rango USING f1, f2 INTO bloques[i].*
|
|
LET i = i + 1
|
|
END FOREACH
|
|
|
|
# -- Armar filas de la tabla --
|
|
LET sbrows = base.StringBuffer.create()
|
|
IF bloques.getLength() = 0 THEN
|
|
CALL sbrows.append(' <tr><td colspan="11" class="empty">No hay bloques con movimiento en ese rango.</td></tr>')
|
|
ELSE
|
|
FOR i = 1 TO bloques.getLength()
|
|
IF bloques[i].en_almacen = 1 THEN
|
|
LET estcls = "alm" LET esttxt = "En almacen"
|
|
ELSE
|
|
LET estcls = "pro" LET esttxt = "En proceso"
|
|
END IF
|
|
LET v_aprov = 0
|
|
IF bloques[i].entro > 0 THEN
|
|
LET v_aprov = bloques[i].salio / bloques[i].entro * 100
|
|
END IF
|
|
LET line =
|
|
' <tr><td class="bq">', bloques[i].cod_bloque CLIPPED, '</td>',
|
|
'<td>', bloques[i].descbloque CLIPPED, '</td>',
|
|
'<td>', bloques[i].origen CLIPPED, '</td>',
|
|
'<td>', bloques[i].f_desde CLIPPED, '</td>',
|
|
'<td>', bloques[i].f_hasta CLIPPED, '</td>',
|
|
'<td class="num">', bloques[i].nmov USING "<<<<", '</td>',
|
|
'<td class="num">', bloques[i].ndeptos USING "<<<", '</td>',
|
|
'<td class="num">', bloques[i].entro USING "<<<<<<<&.##", '</td>',
|
|
'<td class="num">', bloques[i].salio USING "<<<<<<<&.##", '</td>',
|
|
'<td class="num">', v_aprov USING "<<<&.#", '%</td>',
|
|
'<td><span class="est ', estcls, '">', esttxt, '</span></td></tr>'
|
|
CALL sbrows.append(line)
|
|
CALL sbrows.append(nl)
|
|
END FOR
|
|
END IF
|
|
|
|
# -- Leer template y sustituir --
|
|
IF NOT os.Path.exists("prtraza_rango.html") THEN
|
|
CALL fgl_winmessage("Trazabilidad",
|
|
"No se encontro la plantilla 'prtraza_rango.html' en la carpeta del programa (bin).",
|
|
"stop")
|
|
RETURN
|
|
END IF
|
|
|
|
LET sbfull = base.StringBuffer.create()
|
|
LET cin = base.Channel.create()
|
|
CALL cin.openFile("prtraza_rango.html", "r")
|
|
WHILE NOT cin.isEof()
|
|
CALL sbfull.append(cin.readLine())
|
|
CALL sbfull.append(nl)
|
|
END WHILE
|
|
CALL cin.close()
|
|
|
|
CALL sbfull.replace("{{ROWS}}", sbrows.toString(), 0)
|
|
CALL sbfull.replace("{{DESDE}}", f1_disp, 0)
|
|
CALL sbfull.replace("{{HASTA}}", f2_disp, 0)
|
|
CALL sbfull.replace("{{NBLOQUES}}", bloques.getLength() USING "<<<<", 0)
|
|
|
|
CALL presenta_html(sbfull.toString(), "trazabilidad_rango.html")
|
|
|
|
END FUNCTION
|