Files
MBS/PROYECTO/otrodir/GeneraEntradaDiario.4gl
T
jsotoandClaude Opus 5.5 d8764b3bda JSOTO Alta y compilacion G6 de programas CG, Cheques, Activos, Tesoreria, Repuestos e Informatica
Merge de main (ipprrp013/014/046/053) con conflictos resueltos:
- mbsERP.4pw: ipprrp014 conserva ambos 4rp y su 4fd.
- bin/ipprrp014.4rp: columnas MARGEN/CLASIF. + titulo IPPRRP014.

Programas agregados a mbsERP.4pw (53 compilan y enlazan con fgl602):
- CONTABILIDAD GENERAL, ACTIVOS FIJOS, REPUESTOS; grupos nuevos TESORERIA,
  CHEQUES e INFORMATICA (segprmt001 = seguridad2.0/segprmt0001.4gl).
- irdir copiado de 3.20 PROYECTOS/irdir a PROYECTO/irdir; helpers de
  PROYECTOS/otrodir en FUNCIONES_IR (departamento -> irdepartamento.4gl).
- Fuentes mas nuevos de 3.20: edprrp118, edprrp080, acprrp010, cgprmt022.
- FUNCIONES: GeneraEntradaDiario.4gl a la version 3.20 + costoLiquidacion.4gl.
- Ajustes G6: existe duplicado en irprgb000, fakeData de 22 campos y
  answer2 en irprmt036/020 (ApiMaintainC), selectOutputSimple en irprcs008,
  schemas de forms a smarmotech, referencia declarada en cgprmt005.
- cgprmt005 sigue sin enlazar: requiere funciones de EXTERIOR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:22:14 -04:00

997 lines
39 KiB
Plaintext

{
FUNCION : GeneraEntradaDiario
OBJETIVO : REcibir las informaciones desde otros modulos con la finalidad
de adicionar los registros necesarios en el mayor de contabilidad
relacionado al documento fuente
DESARROLLADO : JUAN SOTO
FECHA : 7, Noviembre 2025
}
FUNCTION GeneraEntradaDiario(
usuario,
tipoPrograma,
idEntrada,
cuenta_no_banco,
xfecha,
valor_bruto,
monto_desc,
impuesto,
tipoCliente,
secCliente,
moneda,
tasa,
xnumeroDoc,
comision)
DEFINE
tipoPrograma, usuario, xventas VARCHAR(50),
cuenta_no_banco,
xcuenta_no_ingreso,
xcuenta_no_prima_ingresos,
xcuenta_no_ventas,
xcuenta_no_prima,
xcuenta_comision,
xcuenta_no_itbis
VARCHAR(8),
idEntrada,
tipoCliente,
secCliente,
xdepartamento,
xnumeroDoc,
idrow,
deptoAct
INT,
xfecha DATE,
moneda SMALLINT,
valor_bruto, monto_desc, impuesto, tasa, debito, comision, dolares, diferencia DEC(18, 2),
tieneDepto_ing, tieneDepto_prima, tieneDepto_ventas, tieneDepto_comision
CHAR(1),
entra VARCHAR(25),
detalle1 VARCHAR(100)
DEFINE
registroEntrada DYNAMIC ARRAY OF RECORD
referenciaEntrada VARCHAR(25),
fecha DATE,
tipo CHAR(1),
cuenta_no VARCHAR(8),
departamento INT,
detalle VARCHAR(100),
debito, credito DEC(12, 2)
END RECORD,
qcuentas STRING
LET idrow = 1
LET deptoAct = NULL
DISPLAY "comision entr ", comision
CALL registroEntrada.clear()
#QUERYS GENERALES PARA TODOS LOS AUXILIARES
LET qcuentas =
"
SELECT DISTINCT a.cuenta_no_ventas,a.cuenta_no_ingresos,a.cuenta_no_prima,a.cuenta_no_prima_ingresos,a.cuenta_comision
,a.departamento,b.descripcion
FROM marmotech.dbo.vetb00060 a INNER JOIN marmotech.dbo.vetb00061 b ON b.ventas = a.ventas WHERE a.tipo_cliente = ?
"
PREPARE scuentas FROM qcuentas
EXECUTE scuentas
INTO xcuenta_no_ventas, xcuenta_no_ingreso, xcuenta_no_prima, xcuenta_no_prima_ingresos, xcuenta_comision, xdepartamento, xventas USING tipoCliente
LET qcuentas =
"
SELECT ISNULL(a.depto,'N') FROM marmotech.dbo.cgtb00001 a WHERE a.cuenta_no = ?"
PREPARE sdepto FROM qcuentas
EXECUTE sdepto INTO tieneDepto_ing USING xcuenta_no_ingreso
LET qcuentas =
"
SELECT ISNULL(a.depto,'N') FROM marmotech.dbo.cgtb00001 a WHERE a.cuenta_no = ?"
PREPARE cprima FROM qcuentas
EXECUTE cprima INTO tieneDepto_prima USING xcuenta_no_prima_ingresos
LET qcuentas =
"
SELECT ISNULL(a.depto,'N') FROM marmotech.dbo.cgtb00001 a WHERE a.cuenta_no = ?"
PREPARE sventas FROM qcuentas
EXECUTE sventas INTO tieneDepto_ventas USING xcuenta_no_ventas
LET qcuentas =
"
SELECT ISNULL(a.depto,'N') FROM marmotech.dbo.cgtb00001 a WHERE a.cuenta_no = ?"
PREPARE sventas FROM qcuentas
EXECUTE sventas INTO tieneDepto_comision USING xcuenta_comision
#------------------------------------------------------------------------
# RECIBOS INGRESOS
#------------------------------------------------------------------------
IF tipoPrograma = 'RECIBOS INGRESOS' THEN
LET qcuentas =
"SELECT a.tasa-1 FROM marmotech.dbo.cgtb00084 a WHERE a.ano = YEAR(?) AND a.mes = MONTH(?) AND
a.tipo_cliente = ?"
PREPARE stasa FROM qcuentas
EXECUTE stasa INTO tasa USING xfecha, xfecha, tipoCliente
IF STATUS = NOTFOUND THEN
RETURN FALSE, registroEntrada
END IF
LET deptoAct = xdepartamento
IF tieneDepto_ing = 'N' THEN
LET deptoAct = NULL
END IF
LET detalle1 =
'RECIBO INGRESO ', xventas CLIPPED, " ", xnumeroDoc USING "<<<<<<<<"
CALL controlNumericoED(idEntrada, xfecha, usuario) RETURNING entra
LET debito = (valor_bruto - monto_desc)
LET registroEntrada[1].cuenta_no = xcuenta_no_ingreso CLIPPED
LET registroEntrada[1].fecha = xfecha
LET registroEntrada[1].referenciaEntrada = entra
LET registroEntrada[1].tipo = '1'
LET registroEntrada[1].departamento = deptoAct
LET registroEntrada[1].detalle = detalle1 CLIPPED
LET registroEntrada[1].debito = debito
LET registroEntrada[1].credito = 0
IF xcuenta_no_prima_ingresos IS NOT NULL THEN
LET deptoAct = xdepartamento
IF tieneDepto_prima = 'N' THEN
LET deptoAct = NULL
END IF
LET registroEntrada[2].cuenta_no = xcuenta_no_prima_ingresos CLIPPED
LET registroEntrada[2].referenciaEntrada = entra
LET registroEntrada[2].fecha = xfecha
LET registroEntrada[2].tipo = '1'
LET registroEntrada[2].departamento = deptoAct
LET registroEntrada[2].detalle = detalle1 CLIPPED
LET registroEntrada[2].debito = debito * tasa
LET registroEntrada[2].credito = 0
END IF
LET deptoAct = xdepartamento
IF tieneDepto_ventas = 'N' THEN
LET deptoAct = NULL
END IF
LET registroEntrada[3].cuenta_no = xcuenta_no_ventas CLIPPED
LET registroEntrada[3].referenciaEntrada = entra
LET registroEntrada[3].fecha = xfecha
LET registroEntrada[3].tipo = '1'
LET registroEntrada[3].departamento = deptoAct
LET registroEntrada[3].detalle = detalle1 CLIPPED
LET registroEntrada[3].debito = 0
LET registroEntrada[3].credito = debito
IF xcuenta_no_prima IS NOT NULL THEN
LET deptoAct = xdepartamento
IF tieneDepto_prima = 'N' THEN
LET deptoAct = NULL
END IF
LET registroEntrada[4].cuenta_no = xcuenta_no_prima CLIPPED
LET registroEntrada[4].referenciaEntrada = entra
LET registroEntrada[4].fecha = xfecha
LET registroEntrada[4].tipo = '1'
LET registroEntrada[4].departamento = deptoAct
LET registroEntrada[4].detalle = detalle1 CLIPPED
LET registroEntrada[4].debito = 0
LET registroEntrada[4].credito = debito * tasa
END IF
RETURN TRUE, registroEntrada
END IF
#------------------------------------------------------------------------
# DEPOSITOS
#------------------------------------------------------------------------
IF tipoPrograma = 'DEPOSITOS' THEN
LET idrow = 1
LET qcuentas =
"SELECT avg(a.tasa) FROM marmotech.dbo.cgtb00084 a WHERE a.ano = YEAR(?) AND a.mes = MONTH(?) AND
a.ventas = ?"
PREPARE stasa1 FROM qcuentas
EXECUTE stasa1 INTO tasa USING xfecha, xfecha, moneda
IF STATUS = NOTFOUND THEN
RETURN FALSE, registroEntrada
END IF
LET qcuentas =
"
SELECT DISTINCT a.cuenta_no_ventas,a.cuenta_no_ingresos,a.cuenta_no_prima,a.cuenta_no_prima_ingresos,a.cuenta_comision
,a.departamento,b.descripcion,a.cuenta_no_itbis,a.cuenta_comision
FROM marmotech.dbo.vetb00060 a INNER JOIN marmotech.dbo.vetb00061 b ON b.ventas = a.ventas WHERE a.ventas = ?
"
PREPARE scuentasdp FROM qcuentas
EXECUTE scuentasdp
INTO xcuenta_no_ventas, xcuenta_no_ingreso, xcuenta_no_prima, xcuenta_no_prima_ingresos, xcuenta_comision, xdepartamento, xventas, xcuenta_no_itbis, xcuenta_comision USING moneda
LET deptoAct = NULL
LET detalle1 =
'DEPOSITOS ', xventas CLIPPED, " ", xnumeroDoc USING "<<<<<<<<"
LET usuario = NULL
CALL controlNumericoED(idEntrada, xfecha, usuario) RETURNING entra
LET debito = valor_bruto
IF comision > 0 THEN
LET impuesto = (valor_bruto / 1.18) * .02
LET debito = valor_bruto - comision - impuesto
END IF
DISPLAY "en DEPOSITO: ",
detalle1,
" debito ",
debito,
" comision ",
comision,
" valor Bruto :",
valor_bruto,
" tasa ",
tasa
IF tasa = 0 THEN
LET tasa = 1
END IF
LET registroEntrada[idrow].cuenta_no = cuenta_no_banco CLIPPED
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = debito
LET registroEntrada[idrow].credito = 0
IF comision > 0 THEN
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_no_itbis CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = impuesto
LET registroEntrada[idrow].credito = 0
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_comision CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = comision
LET registroEntrada[idrow].credito = 0
LET deptoAct = xdepartamento
# El credito completo al ingreso solo aplica en depositos locales.
# En dolares (moneda > 1) el credito lo arma el bloque de mas abajo (Caja US$ + Prima).
IF moneda = 1 THEN
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_no_ingreso CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = 0
LET registroEntrada[idrow].credito = valor_bruto
END IF
END IF
IF moneda = 1 AND comision = 0 THEN
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_no_ingreso CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = 0
LET registroEntrada[idrow].credito = valor_bruto
END IF
IF moneda > 1 THEN
# DOLARES PAGADOS AL DEPOSITO (guardados en las columnas monto_* de tetb00001)
LET dolares = 0
LET qcuentas =
"SELECT ISNULL(a.monto_efectivo,0)+ISNULL(a.monto_ck,0)+ISNULL(a.monto_link,0)+ISNULL(a.monto_tarjeta,0)
FROM marmotech.dbo.tetb00001 a WHERE a.num_doc = ?"
PREPARE sdolares FROM qcuentas
EXECUTE sdolares INTO dolares USING xnumeroDoc
IF dolares IS NULL THEN
LET dolares = 0
END IF
LET diferencia = valor_bruto - dolares
# 1100-01 CAJA US$ = dolares pagados
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_no_ingreso CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = 0
LET registroEntrada[idrow].credito = dolares
# 1100-02 PRIMA = valor_bruto - dolares (solo si hubo conversion)
IF diferencia <> 0 THEN
LET idrow = idrow + 1
LET registroEntrada[idrow].cuenta_no = xcuenta_no_prima_ingresos CLIPPED
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = xfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].departamento = deptoAct
LET registroEntrada[idrow].detalle = detalle1 CLIPPED
LET registroEntrada[idrow].debito = 0
LET registroEntrada[idrow].credito = diferencia
END IF
END IF
RETURN TRUE, registroEntrada
END IF
#------------------------------------------------------------------------
# VENTAS
#------------------------------------------------------------------------
IF tipoPrograma = 'VENTAS' THEN
END IF
#------------------------------------------------------------------------
# INVENTARIO PRODUCTOS TERMINADOS
# Ver GeneraEntradaInventario('P',...) mas abajo: la entrada de
# inventario necesita las N lineas del documento (cod_mov/bodega),
# que no caben en esta firma de valor unico.
#------------------------------------------------------------------------
IF tipoPrograma = 'INV PRODUCTOS' THEN
END IF
#------------------------------------------------------------------------
# INVENTARIO REPUESTOS -> ver GeneraEntradaInventario('R',...)
#------------------------------------------------------------------------
IF tipoPrograma = 'INV REPUESTOS' THEN
END IF
#------------------------------------------------------------------------
# INVENTARIOS MATERIA PRIMA
#------------------------------------------------------------------------
IF tipoPrograma = 'INV MAT PRIMA' THEN
END IF
#------------------------------------------------------------------------
# ACTIVOS FIJS
#------------------------------------------------------------------------
IF tipoPrograma = 'ACTIVOS' THEN
END IF
END FUNCTION
{
FUNCION : GeneraEntradaInventario
OBJETIVO : Armar las lineas debito/credito del asiento al mayor (cgtb00004)
para UN documento de inventario (productos terminados o repuestos),
valorizado con costoLiquidacion() y con las cuentas contables
definidas por codigo de movimiento, replicando el criterio de
EDPRRP080 (terminados) y EDPRRP118 (repuestos).
PARAMETROS : usuario - usuario que crea el asiento (NOT NULL = consume secuencia)
tipoInv - 'P' productos terminados / 'R' repuestos
pnum_doc - num_doc del documento de inventario
pcod_mov - codigo de movimiento
pbodega - bodega del documento
pfecha - fecha del documento
RETORNA : generaE BOOLEAN (TRUE si armo al menos una linea),
registroEntrada (mismo shape que GeneraEntradaDiario).
NOTA : Solo toma las lineas con referenciaentrada IS NULL (idempotente:
si se llama dos veces no duplica). El llamador inserta el arreglo
en cgtb00004 (agregando numero_documento/cod_mov/bodega/
sistema_auxiliar), y sella <tabla>.referenciaentrada = ED.xxx.
DEBITO/CREDITO (por signo de cantidad_2, igual que los batch):
entrada (cantidad >= 0): inventario DEBITO / contrapartida CREDITO
salida (cantidad < 0): inventario CREDITO / contrapartida DEBITO
CUENTAS : terminados -> iptb00005.cuenta_1/2/3 (material/labor/gasto por
cod_mov) contra iptb00022.cuenta_no (por cod_cia).
repuestos -> irtb00002.cuenta (por articulo, como EDPRRP118)
contra iptb00022.cuenta_no (por cod_n).
COSTEO : produccion (es_produccion=1) -> desglose material/labor/gasto de
iptb00004. Compra/venta y repuestos -> costo unico costoLiquidacion()
aplicado a la cuenta material (cuenta_1).
}
FUNCTION GeneraEntradaInventario(usuario, tipoInv, pnum_doc, pcod_mov, pbodega, pfecha)
DEFINE
usuario STRING,
tipoInv CHAR(1),
pnum_doc, pcod_mov, pbodega INT,
pfecha DATE,
entra VARCHAR(25),
idrow INT,
qsql STRING,
es_prod SMALLINT,
status_mov CHAR(1),
cta_mat, cta_lab, cta_gas, cta_inv VARCHAR(14),
cta_mat_imp, cta_mat_uso VARCHAR(14),
dep_mat, dep_lab, dep_gas, dep_inv CHAR(1),
usarCuentaItem SMALLINT,
matStd, labStd, gasStd DEC(18, 4),
unit, v_mat, v_lab, v_gas, v_total DEC(18, 4),
detalle1 VARCHAR(100),
depto_cia, dep_uso INT,
dep_flag CHAR(1),
nc, k, j, m, encontrado INT
#--- Candidatos de la linea y acumulador por (cuenta, departamento).
#--- Convencion de 'valor': POSITIVO = DEBITO, NEGATIVO = CREDITO.
DEFINE
cand DYNAMIC ARRAY OF RECORD
cuenta_no VARCHAR(14),
valor DEC(18, 4)
END RECORD,
acum DYNAMIC ARRAY OF RECORD
cuenta_no VARCHAR(14),
departamento INT,
valor DEC(18, 4),
detalle VARCHAR(100)
END RECORD
DEFINE lin RECORD
cod_n, cod_grupo, cod_tipo, cod_sec INT,
cantidad DEC(18, 4),
departamento INT,
cod_cia INT,
descrip VARCHAR(180)
END RECORD
DEFINE
lineas DYNAMIC ARRAY OF RECORD
cod_n, cod_grupo, cod_tipo, cod_sec INT,
cantidad DEC(18, 4),
departamento INT,
cod_cia INT,
descrip VARCHAR(180)
END RECORD,
i INT
DEFINE
registroEntrada DYNAMIC ARRAY OF RECORD
referenciaEntrada VARCHAR(25),
fecha DATE,
tipo CHAR(1),
cuenta_no VARCHAR(8),
departamento INT,
detalle VARCHAR(100),
debito, credito DEC(12, 2)
END RECORD
CALL registroEntrada.clear()
LET idrow = 0
#--- Secuencia de la entrada al diario (id 25 = entrada automatica inventario)
CALL controlNumericoED(25, pfecha, usuario) RETURNING entra
#--- Cuentas contables
IF tipoInv = 'P' THEN
#--- Terminados: cuentas por codigo de movimiento (iptb00005), como EDPRRP080
LET qsql =
"SELECT ISNULL(status_mov,'E'), cuenta_1, cuenta_2, cuenta_3,
cuenta_imp_material
FROM marmotech.dbo.iptb00005 WHERE cod_mov = ?"
PREPARE s_cta FROM qsql
EXECUTE s_cta
INTO status_mov, cta_mat, cta_lab, cta_gas, cta_mat_imp
USING pcod_mov
FREE s_cta
LET usarCuentaItem = 0
ELSE
#--- Repuestos: la cuenta se toma del articulo (irtb00002.cuenta), como EDPRRP118.
#--- Compras locales confirmadas; internacionales pendientes de validar con
#--- finanzas (se asume el mismo criterio de EDPRRP118).
LET cta_mat = NULL
LET cta_lab = NULL
LET cta_gas = NULL
LET cta_mat_imp = NULL
LET usarCuentaItem = 1
END IF
#--- Preparados reutilizables dentro del ciclo
LET qsql =
"SELECT ISNULL(a.depto,'N') FROM marmotech.dbo.cgtb00001 a WHERE a.cuenta_no = ?"
PREPARE s_dep FROM qsql
LET qsql =
"SELECT a.cuenta_no, a.departamento FROM marmotech.dbo.iptb00022 a WHERE a.cod_cia = ?"
PREPARE s_inv FROM qsql
IF tipoInv = 'P' THEN
LET qsql =
"SELECT TOP 1 ISNULL(a.es_produccion,0) FROM marmotech.dbo.iptb00002 a
WHERE a.cod_n=? AND a.cod_grupo=? AND a.cod_tipo=? AND a.cod_sec=?"
PREPARE s_esp FROM qsql
LET qsql =
"SELECT ISNULL(AVG(ISNULL(a.material,0)),0), ISNULL(AVG(ISNULL(a.labor,0)),0),
ISNULL(AVG(ISNULL(a.gastos,0)),0)
FROM marmotech.dbo.iptb00004 a
WHERE a.cod_n=? AND a.cod_grupo=? AND a.cod_tipo=? AND a.cod_sec=?
AND a.ano=YEAR(?) AND a.mes_fin=12 AND a.status_t IS NULL"
PREPARE s_std FROM qsql
ELSE
LET qsql =
"SELECT a.cuenta FROM marmotech.dbo.irtb00002 a
WHERE a.cod_n=? AND a.cod_grupo=? AND a.cod_tipo=? AND a.cod_sec=?"
PREPARE s_itemcta FROM qsql
END IF
#--- Lectura de las lineas del documento (solo las no asentadas)
IF tipoInv = 'P' THEN
LET qsql =
"SELECT c.cod_n,c.cod_grupo,c.cod_tipo,c.cod_sec,SUM(c.cantidad_2),
ISNULL(c.departamento,0), MAX(e.cod_cia), MAX(e.descrip_esp)
FROM marmotech.dbo.iptb00006 c
INNER JOIN marmotech.dbo.iptb00002 e
ON c.cod_n=e.cod_n AND c.cod_grupo=e.cod_grupo
AND c.cod_tipo=e.cod_tipo AND c.cod_sec=e.cod_sec
WHERE c.num_doc=? AND c.cod_mov=? AND c.bodega=?
AND c.status_t IS NULL AND c.referenciaentrada IS NULL
GROUP BY c.cod_n,c.cod_grupo,c.cod_tipo,c.cod_sec,c.departamento
HAVING SUM(c.cantidad_2) <> 0"
ELSE
LET qsql =
"SELECT b.cod_n,b.cod_grupo,b.cod_tipo,b.cod_sec,SUM(b.cantidad_2),
ISNULL(b.sec_a,0), b.cod_n, MAX(a.descrip_esp)
FROM marmotech.dbo.irtb00006 b
INNER JOIN marmotech.dbo.irtb00002 a
ON b.cod_n=a.cod_n AND b.cod_grupo=a.cod_grupo
AND b.cod_tipo=a.cod_tipo AND b.cod_sec=a.cod_sec
WHERE b.num_doc=? AND b.cod_mov=? AND b.bodega=?
AND b.status_t IS NULL AND b.referenciaentrada IS NULL
GROUP BY b.cod_n,b.cod_grupo,b.cod_tipo,b.cod_sec,b.sec_a,b.cod_n
HAVING SUM(b.cantidad_2) <> 0"
END IF
PREPARE s_lin FROM qsql
DECLARE c_lin CURSOR FOR s_lin
#--- Cargar las lineas a un arreglo ANTES de procesar, para no mantener el
#--- cursor abierto mientras se hacen consultas anidadas (evita "connection busy")
CALL lineas.clear()
LET i = 0
FOREACH c_lin USING pnum_doc, pcod_mov, pbodega INTO lin.*
LET i = i + 1
LET lineas[i].* = lin.*
END FOREACH
FREE c_lin
FOR i = 1 TO lineas.getLength()
LET lin.* = lineas[i].*
#--- Valuacion segun tipo de producto
LET matStd = 0
LET labStd = 0
LET gasStd = 0
LET es_prod = 0
LET unit = 0
IF tipoInv = 'P' THEN
EXECUTE s_esp INTO es_prod
USING lin.cod_n, lin.cod_grupo, lin.cod_tipo, lin.cod_sec
IF es_prod IS NULL THEN LET es_prod = 0 END IF
END IF
IF tipoInv = 'P' AND es_prod = 1 THEN
#--- Produccion: desglose material/labor/gasto del estandard
EXECUTE s_std INTO matStd, labStd, gasStd
USING lin.cod_n, lin.cod_grupo, lin.cod_tipo, lin.cod_sec, pfecha
LET v_mat = matStd * lin.cantidad
LET v_lab = labStd * lin.cantidad
LET v_gas = gasStd * lin.cantidad
ELSE
#--- Compra/venta y repuestos: costo unico a la cuenta material
LET unit =
costoLiquidacion(
lin.cod_n, lin.cod_grupo, lin.cod_tipo, lin.cod_sec, pfecha, tipoInv)
LET v_mat = unit * lin.cantidad
LET v_lab = 0
LET v_gas = 0
END IF
LET v_total = v_mat + v_lab + v_gas
IF v_total = 0 THEN
CONTINUE FOR
END IF
#--- Cuenta del articulo para repuestos sin cuenta por movimiento
IF usarCuentaItem = 1 THEN
LET cta_mat = NULL
EXECUTE s_itemcta INTO cta_mat
USING lin.cod_n, lin.cod_grupo, lin.cod_tipo, lin.cod_sec
END IF
#--- Cuenta de inventario (contrapartida) y DEPARTAMENTO, por cod_cia.
#--- El departamento contable del item sale de iptb00022 segun el cod_cia
#--- que tenga en iptb00002; se aplica a TODA cuenta marcada depto='S'
#--- en cgtb00001.
LET cta_inv = NULL
LET depto_cia = NULL
EXECUTE s_inv INTO cta_inv, depto_cia USING lin.cod_cia
LET detalle1 =
'INV ', tipoInv, ' DOC ', pnum_doc USING "<<<<<<<<",
' MOV ', pcod_mov USING "<<<<", ' ', lin.descrip CLIPPED
IF LENGTH(detalle1) > 100 THEN
LET detalle1 = detalle1[1, 100]
END IF
#--- Candidatos de esta linea. Convencion: valor POSITIVO = DEBITO,
#--- NEGATIVO = CREDITO. Las contrapartidas aportan el valor invertido y
#--- el inventario el total, por lo que la entrada CUADRA POR CONSTRUCCION.
CALL cand.clear()
LET nc = 0
#--- ORIGEN DEL ARTICULO (iptb00022 via iptb00002.cod_cia):
#--- cod_cia 2 = PTOS. MAT.IMPORTADOS y 3 = PRODUCTOS IMPORTADOS llevan la
#--- cuenta de material IMPORTADO (iptb00005.cuenta_imp_material) en lugar
#--- de la cuenta_1 local. Mismo criterio que EDPRRP080. Labor y gasto NO
#--- se cambian: siguen saliendo de cuenta_2 / cuenta_3.
LET cta_mat_uso = cta_mat
IF tipoInv = 'P' THEN
IF lin.cod_cia = 2 OR lin.cod_cia = 3 THEN
IF cta_mat_imp IS NOT NULL THEN
LET cta_mat_uso = cta_mat_imp
END IF
END IF
END IF
IF cta_mat_uso IS NOT NULL AND v_mat <> 0 THEN
LET nc = nc + 1
LET cand[nc].cuenta_no = cta_mat_uso CLIPPED
LET cand[nc].valor = (0 - v_mat)
END IF
IF cta_lab IS NOT NULL AND v_lab <> 0 THEN
LET nc = nc + 1
LET cand[nc].cuenta_no = cta_lab CLIPPED
LET cand[nc].valor = (0 - v_lab)
END IF
IF cta_gas IS NOT NULL AND v_gas <> 0 THEN
LET nc = nc + 1
LET cand[nc].cuenta_no = cta_gas CLIPPED
LET cand[nc].valor = (0 - v_gas)
END IF
IF cta_inv IS NOT NULL AND v_total <> 0 THEN
LET nc = nc + 1
LET cand[nc].cuenta_no = cta_inv CLIPPED
LET cand[nc].valor = v_total
END IF
#--- Acumular por (cuenta, departamento): los items con el mismo cod_cia
#--- se suman en una sola linea; si hay items con cod_cia distinto, la
#--- misma cuenta se repite en la entrada con otro departamento y valor.
FOR k = 1 TO nc
LET dep_flag = 'N'
EXECUTE s_dep INTO dep_flag USING cand[k].cuenta_no
IF dep_flag = 'S' THEN
LET dep_uso = depto_cia
ELSE
LET dep_uso = NULL
END IF
LET encontrado = 0
FOR j = 1 TO acum.getLength()
IF acum[j].cuenta_no = cand[k].cuenta_no THEN
IF (acum[j].departamento IS NULL AND dep_uso IS NULL)
OR (acum[j].departamento = dep_uso) THEN
LET acum[j].valor = acum[j].valor + cand[k].valor
LET encontrado = 1
EXIT FOR
END IF
END IF
END FOR
IF encontrado = 0 THEN
LET m = acum.getLength() + 1
LET acum[m].cuenta_no = cand[k].cuenta_no
LET acum[m].departamento = dep_uso
LET acum[m].valor = cand[k].valor
LET acum[m].detalle = detalle1 CLIPPED
END IF
END FOR
END FOR
#--- Emitir UNA linea por cada (cuenta, departamento) acumulado
FOR j = 1 TO acum.getLength()
IF acum[j].valor = 0 THEN
CONTINUE FOR
END IF
LET idrow = idrow + 1
LET registroEntrada[idrow].referenciaEntrada = entra
LET registroEntrada[idrow].fecha = pfecha
LET registroEntrada[idrow].tipo = '1'
LET registroEntrada[idrow].cuenta_no = acum[j].cuenta_no
LET registroEntrada[idrow].departamento = acum[j].departamento
LET registroEntrada[idrow].detalle = acum[j].detalle
IF acum[j].valor > 0 THEN
LET registroEntrada[idrow].debito = acum[j].valor
LET registroEntrada[idrow].credito = 0
ELSE
LET registroEntrada[idrow].debito = 0
LET registroEntrada[idrow].credito = (0 - acum[j].valor)
END IF
END FOR
FREE s_lin
FREE s_dep
FREE s_inv
IF tipoInv = 'P' THEN
FREE s_esp
FREE s_std
ELSE
FREE s_itemcta
END IF
IF idrow = 0 THEN
RETURN FALSE, registroEntrada
END IF
RETURN TRUE, registroEntrada
END FUNCTION
{
FUNCION : registraEntradaInventario
OBJETIVO : Registrar en el mayor (cgtb00004) el asiento de UN documento de
inventario y sellar la referencia ED en la tabla de movimientos.
IMPORTANTE : Se ejecuta DENTRO de la transaccion del programa llamador.
NO hace BEGIN WORK ni COMMIT WORK. Si retorna FALSE el llamador
debe hacer ROLLBACK WORK.
PARAMETROS : usuario, tipoInv ('P'/'R'), num_doc, cod_mov, bodega, fecha
RETORNA : ok BOOLEAN, entra VARCHAR(25) con la referencia ED generada
(ok = TRUE y entra = NULL significa que no habia nada pendiente
por asentar, lo cual no es un error).
}
FUNCTION registraEntradaInventario(usuario, tipoInv, pnum_doc, pcod_mov, pbodega, pfecha)
DEFINE
usuario STRING,
tipoInv CHAR(1),
pnum_doc, pcod_mov, pbodega INT,
pfecha DATE,
genera BOOLEAN,
entra VARCHAR(25),
sistema VARCHAR(2),
tipodoc VARCHAR(10),
tabla STRING,
qsql STRING,
idx INT,
t_debito, t_credito DEC(18, 2)
DEFINE
registroEntrada DYNAMIC ARRAY OF RECORD
referenciaEntrada VARCHAR(25),
fecha DATE,
tipo CHAR(1),
cuenta_no VARCHAR(8),
departamento INT,
detalle VARCHAR(100),
debito, credito DEC(12, 2)
END RECORD
LET genera = FALSE
LET entra = NULL
CALL GeneraEntradaInventario(
usuario, tipoInv, pnum_doc, pcod_mov, pbodega, pfecha)
RETURNING genera, registroEntrada
#--- Sin lineas pendientes por asentar: no es error
IF NOT genera THEN
RETURN TRUE, entra
END IF
LET entra = registroEntrada[1].referenciaEntrada
LET tipodoc = 'INV'
#--- Guardian de cuadre (equivalente a verificaCuadre() de los batch).
#--- Si falta una cuenta configurada (iptb00022 / iptb00005 / irtb00002) la
#--- contrapartida no se genera y el asiento quedaria descuadrado: se aborta
#--- para no ensuciar el mayor.
LET t_debito = 0
LET t_credito = 0
FOR idx = 1 TO registroEntrada.getLength()
IF registroEntrada[idx].cuenta_no IS NULL THEN
CONTINUE FOR
END IF
LET t_debito = t_debito + registroEntrada[idx].debito
LET t_credito = t_credito + registroEntrada[idx].credito
END FOR
IF t_debito <> t_credito THEN
DISPLAY "ED FALLO: ASIENTO DESCUADRADO ref=", entra CLIPPED,
" debito=", t_debito, " credito=", t_credito,
" dif=", (t_debito - t_credito)
DISPLAY "ED FALLO: detalle de las lineas armadas ->"
FOR idx = 1 TO registroEntrada.getLength()
DISPLAY " cta=", registroEntrada[idx].cuenta_no,
" depto=", registroEntrada[idx].departamento,
" debito=", registroEntrada[idx].debito,
" credito=", registroEntrada[idx].credito
END FOR
DISPLAY "ED FALLO: revise que el cod_mov tenga cuenta_1/2/3 en ",
"iptb00005/irtb00005 y que el cod_cia del item tenga cuenta_no en iptb00022"
RETURN FALSE, entra
END IF
IF tipoInv = 'P' THEN
LET sistema = 'IP'
LET tabla = 'marmotech.dbo.iptb00006'
ELSE
LET sistema = 'IR'
LET tabla = 'marmotech.dbo.irtb00006'
END IF
#--- Lineas del asiento al mayor
LET qsql =
"INSERT INTO marmotech.dbo.cgtb00004
(fecha,tipo,ref,cuenta_no,departamento,detalle_1,debito,credito,
us_crea,fech_crea,numero_documento,cod_mov,bodega,
sistema_auxiliar,tipo_documento)
VALUES (?,?,?,?,?,?,?,?,?,GETDATE(),?,?,?,?,?)"
PREPARE s_insed FROM qsql
FOR idx = 1 TO registroEntrada.getLength()
IF registroEntrada[idx].cuenta_no IS NULL THEN
CONTINUE FOR
END IF
EXECUTE s_insed
USING registroEntrada[idx].fecha,
registroEntrada[idx].tipo,
registroEntrada[idx].referenciaEntrada,
registroEntrada[idx].cuenta_no,
registroEntrada[idx].departamento,
registroEntrada[idx].detalle,
registroEntrada[idx].debito,
registroEntrada[idx].credito,
usuario,
pnum_doc,
pcod_mov,
pbodega,
sistema,
tipodoc
IF STATUS < 0 THEN
DISPLAY "ED FALLO: INSERT cgtb00004 status=", STATUS,
" ", SQLERRMESSAGE
DISPLAY " ref=", entra CLIPPED,
" cta=", registroEntrada[idx].cuenta_no,
" depto=", registroEntrada[idx].departamento,
" debito=", registroEntrada[idx].debito,
" credito=", registroEntrada[idx].credito
DISPLAY " doc=", pnum_doc, " mov=", pcod_mov, " bodega=", pbodega,
" sistema=", sistema
FREE s_insed
RETURN FALSE, entra
END IF
END FOR
FREE s_insed
#--- Sellar la referencia en las lineas del documento
LET qsql =
"UPDATE ",
tabla,
" SET referenciaentrada = ?
WHERE num_doc = ? AND cod_mov = ? AND bodega = ?
AND status_t IS NULL AND referenciaentrada IS NULL"
PREPARE s_updref FROM qsql
EXECUTE s_updref USING entra, pnum_doc, pcod_mov, pbodega
IF STATUS < 0 THEN
DISPLAY "ED FALLO: UPDATE ", tabla, ".referenciaentrada status=", STATUS,
" ", SQLERRMESSAGE
DISPLAY " ref=", entra CLIPPED, " doc=", pnum_doc,
" mov=", pcod_mov, " bodega=", pbodega
FREE s_updref
RETURN FALSE, entra
END IF
FREE s_updref
RETURN TRUE, entra
END FUNCTION
{
FUNCION : anulaEntradaPorRef
OBJETIVO : Anular en el mayor (cgtb00004) las lineas de UNA entrada ED,
marcandolas status_t = 'E'. Mismo criterio que usa
ccprmt016 para anular los asientos de CxC.
IMPORTANTE : Se ejecuta DENTRO de la transaccion del programa llamador.
NO hace BEGIN WORK ni COMMIT WORK.
RETORNA : TRUE si anulo o si no habia nada que anular; FALSE si fallo.
NOTA : NO se borra la referencia de la tabla de movimientos: el
movimiento queda con status_t='E' y conserva su referencia
como rastro de cual asiento se anulo.
}
FUNCTION anulaEntradaPorRef(usuario, refED)
DEFINE
usuario STRING,
refED VARCHAR(25),
qsql STRING
IF refED IS NULL THEN
RETURN TRUE
END IF
IF LENGTH(refED) = 0 THEN
RETURN TRUE
END IF
LET qsql =
"UPDATE marmotech.dbo.cgtb00004
SET status_t = 'E', us_mod = ?, fech_mod = GETDATE()
WHERE ref = ? AND status_t IS NULL"
PREPARE s_anuED FROM qsql
EXECUTE s_anuED USING usuario, refED
IF STATUS < 0 THEN
DISPLAY "ED FALLO: no se pudo anular el asiento ", refED CLIPPED,
" status=", STATUS, " ", SQLERRMESSAGE
FREE s_anuED
RETURN FALSE
END IF
FREE s_anuED
RETURN TRUE
END FUNCTION
{
FUNCION : anulaEntradaInventario
OBJETIVO : Anular el asiento al mayor de UN documento de inventario.
Busca la referencia ED sellada en la tabla de movimientos y
delega en anulaEntradaPorRef.
PARAMETROS : usuario, tipoInv ('P'/'R'), num_doc, cod_mov,
bodega (puede venir NULL: entonces no filtra por bodega,
que es como anula irprmt066).
IMPORTANTE : Dentro de la transaccion del llamador. Si retorna FALSE el
llamador debe hacer ROLLBACK WORK.
RETORNA : ok BOOLEAN, refED de la entrada anulada (NULL si no habia)
}
FUNCTION anulaEntradaInventario(usuario, tipoInv, pnum_doc, pcod_mov, pbodega)
DEFINE
usuario STRING,
tipoInv CHAR(1),
pnum_doc, pcod_mov, pbodega INT,
refED VARCHAR(25),
tabla STRING,
qsql STRING,
ok BOOLEAN
IF tipoInv = 'P' THEN
LET tabla = 'marmotech.dbo.iptb00006'
ELSE
LET tabla = 'marmotech.dbo.irtb00006'
END IF
#--- La referencia se busca SIN filtrar status_t: al momento de llamarnos
#--- las lineas del movimiento ya pueden estar marcadas 'E'.
LET refED = NULL
LET qsql =
"SELECT MAX(a.referenciaentrada) FROM ",
tabla,
" a WHERE a.num_doc = ? AND a.cod_mov = ? AND (a.bodega = ? OR ? IS NULL)"
PREPARE s_refanu FROM qsql
EXECUTE s_refanu INTO refED USING pnum_doc, pcod_mov, pbodega, pbodega
FREE s_refanu
IF refED IS NULL THEN
#--- Documento sin asiento (anterior al automatico, o costo cero)
RETURN TRUE, refED
END IF
LET ok = anulaEntradaPorRef(usuario, refED)
RETURN ok, refED
END FUNCTION