08_baseline_existencias.py
Ruta original: docs/proyectos/consumo-interno-fifo/scripts/08_baseline_existencias.py
"""
Extiende el baseline de 07_baseline_rpmv008co.py agregando, por producto,
existencia_inicial y existencia_final del periodo -- Metodo C (el mismo de
movimientos_lib.existencia_a_fecha_metodo_c, reimplementado aqui sin la
columna Mv_Cantidad_Control_2 porque el baseline nativo solo necesita
Control_1).
existencia_inicial = existencia al dia anterior a fecha_ini
existencia_final = existencia al ultimo dia del periodo (fecha_fin)
Uso:
python3 08_baseline_existencias.py --fecha-ini 2026-03-01 --fecha-fin 2026-03-31 \
--baseline output/baseline_rpmv008co_2026-03-01_2026-03-31.csv
"""
import argparse
import sys
import pandas as pd
from rich.console import Console
sys.path.append(".")
import connection_205_trivasadb3 as c
console = Console()
PR_CVE_LEN = 10
def existencia_a_fecha_metodo_c(fecha: str) -> pd.DataFrame:
"""Metodo C, validado 100% contra 3 exports reales de MPRO. fecha inclusive."""
df = c.q(f"""
SELECT Producto.Pr_Cve_Producto,
SUM(Movimiento.Mv_Cantidad_Control_1) AS Mv_Cantidad_Control_1
FROM Movimiento
INNER JOIN Producto ON Movimiento.Pr_Cve_Producto = Producto.Pr_Cve_Producto
INNER JOIN Sucursal ON Movimiento.Sc_Cve_Sucursal = Sucursal.Sc_Cve_Sucursal
WHERE Sucursal.Em_Cve_Empresa = '0001' AND Movimiento.Mv_Fecha <= '{fecha}'
GROUP BY Producto.Pr_Cve_Producto
HAVING (SUM(Movimiento.Mv_Cantidad_Control_1) <> 0)
""")
df["Pr_Cve_Producto"] = df["Pr_Cve_Producto"].astype(str).str.strip().str.zfill(PR_CVE_LEN)
return df.groupby("Pr_Cve_Producto", as_index=False)["Mv_Cantidad_Control_1"].sum()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--fecha-ini", required=True)
ap.add_argument("--fecha-fin", required=True)
ap.add_argument("--baseline", required=True, help="CSV de 07_baseline_rpmv008co.py a extender")
args = ap.parse_args()
base = pd.read_csv(args.baseline, dtype={"Pr_Cve_Producto": str})
base["Pr_Cve_Producto"] = base["Pr_Cve_Producto"].str.strip().str.zfill(PR_CVE_LEN)
fecha_inicial_existencia = (pd.Timestamp(args.fecha_ini) - pd.Timedelta(days=1)).strftime("%Y-%m-%d")
console.print(f"Consultando existencia inicial ({fecha_inicial_existencia})...")
ini = existencia_a_fecha_metodo_c(fecha_inicial_existencia).rename(
columns={"Mv_Cantidad_Control_1": "existencia_inicial"}
)
console.print(f"Consultando existencia final ({args.fecha_fin})...")
fin = existencia_a_fecha_metodo_c(args.fecha_fin).rename(
columns={"Mv_Cantidad_Control_1": "existencia_final"}
)
out = base.merge(ini, on="Pr_Cve_Producto", how="left").merge(fin, on="Pr_Cve_Producto", how="left")
out["existencia_inicial"] = out["existencia_inicial"].fillna(0)
out["existencia_final"] = out["existencia_final"].fillna(0)
out_path = args.baseline.replace(".csv", "_con_existencias.csv")
out.to_csv(out_path, index=False)
productos = out["Pr_Cve_Producto"].nunique()
console.print(f"[bold]Baseline con existencias[/bold] {args.fecha_ini} a {args.fecha_fin}")
console.print(f"Filas: {len(out):,} | Productos distintos: {productos:,}")
console.print(f"Guardado en: {out_path}")
if __name__ == "__main__":
main()