03_reconciliacion_recibo_pago.py
Ruta original: docs/proyectos/poliza-explor/scripts/03_reconciliacion_recibo_pago.py
"""
Reconciliacion Recibo_Pago vs poliza contable (origen Pc_Tabla='RECIBO_PAGO').
A diferencia de Cheque, aqui Poliza_Detalle.Pd_Referencia SI trae el folio
correcto (Rp_Folio = Pc_Documento) de forma directa y confiable -- no hizo
falta el workaround de match por monto de 02_reconciliacion_cheque.py.
Se aisla el Cargo (Pd_Tipo=1, cuenta de banco) por Pd_Referencia = Pc_Documento
y se compara contra Rp_Importe.
Una sola poliza consolida varios recibos del mismo dia (hasta 14 documentos
por poliza en el censo de 01_conteo_polizas_por_origen.py) -- por eso el
join agrupa por (Pl_Folio, Pc_Documento), no solo por Pl_Folio.
Validado: enero 2026 100% (69/69 documentos), Q1 2026 99.66% (293/294) --
la unica excepcion (poliza 0000485755, documento 01-0018207) tiene Cargo
$44,379.31 vs Rp_Importe $39,000.00, diferencia $5,379.31 sin explicar
todavia (pendiente si es comision bancaria, tipo de cambio, u otro cargo
combinado en la misma linea).
Uso:
python3 03_reconciliacion_recibo_pago.py --fecha-ini 2026-01-01 --fecha-fin 2026-02-01
"""
import argparse
from connection_205_trivasadb3 import engine # default de exploracion -- ver skill trivasa-sql-exploracion
import pandas as pd
from sqlalchemy import text
from helpers_output import console, mostrar_tabla, resumen
QUERY = """
SELECT
plc.Pl_Folio, plc.Pc_Documento AS RECIBO_FOLIO, MAX(rp.Rp_Importe) AS RP_IMPORTE,
SUM(CASE WHEN pd.Pd_Tipo = 1 THEN pd.Pd_Importe ELSE 0 END) AS CARGO
FROM Poliza pl
JOIN Poliza_Control plc ON plc.Pl_Folio = pl.Pl_Folio AND plc.Pc_Tabla = 'RECIBO_PAGO'
JOIN Recibo_Pago rp ON rp.Rp_Folio = plc.Pc_Documento
LEFT JOIN Poliza_Detalle pd ON pd.Pl_Folio = plc.Pl_Folio AND pd.Pd_Referencia = plc.Pc_Documento
WHERE pl.Pl_Fecha >= :fecha_ini AND pl.Pl_Fecha < :fecha_fin
AND pl.Es_Cve_Estado <> 'CA'
GROUP BY plc.Pl_Folio, plc.Pc_Documento
"""
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--fecha-ini", required=True)
ap.add_argument("--fecha-fin", required=True)
args = ap.parse_args()
df = pd.read_sql(
text(QUERY), engine,
params={"fecha_ini": args.fecha_ini, "fecha_fin": args.fecha_fin},
)
df["DIFERENCIA"] = (df["CARGO"] - df["RP_IMPORTE"]).abs()
df["CUADRA"] = df["DIFERENCIA"] <= 1
out = f"03_reconciliacion_recibo_pago_{args.fecha_ini}_{args.fecha_fin}.csv"
df.to_csv(out, index=False)
n, c = len(df), int(df["CUADRA"].sum())
resumen(documentos=n, cuadran=c, pct=f"{100 * c / n:.2f}%")
no_cuadra = df[~df["CUADRA"]]
if len(no_cuadra):
console.print(f"\n[bold red]No cuadran:[/bold red] {len(no_cuadra)}")
mostrar_tabla(no_cuadra, "Excepciones", max_filas=30)
else:
console.print("\n[green]100% de los documentos de Recibo_Pago cuadran.[/green]")
console.print(f"\n[green]Guardado: {out}[/green]")
if __name__ == "__main__":
main()