06_movimientos_uuid_fifo.py
Ruta original: docs/proyectos/consumo-interno-fifo/scripts/06_movimientos_uuid_fifo.py
"""
CLI: genera el CSV de movimientos de salida enlazados a su UUID de compra via FIFO on the
fly. Logica compartida con el reporte interactivo V2 del hub en movimientos_uuid_lib.py --
ver ese modulo y decisions/2026-07-movimientos-uuid-fifo.md para el detalle completo.
Uso: python3 scripts/06_movimientos_uuid_fifo.py 2026-01-01 2026-01-31
"""
import sys
from movimientos_uuid_lib import TOLERANCIA, reporte_completo_uuid_fifo
def main(fecha_ini: str, fecha_fin: str):
print(f"Periodo: {fecha_ini} a {fecha_fin}\n")
resultado, salidas, mov, chequeo, descuadres = reporte_completo_uuid_fifo(fecha_ini, fecha_fin)
print(f"Movimientos efectivos del periodo: {len(mov)} totales, {len(salidas)} de salida")
print(f"Filas de asignacion FIFO: {len(resultado)}")
folios_usados = resultado["Co_Folio_origen"].dropna().nunique()
con_uuid = resultado.loc[resultado["con_uuid"], "Co_Folio_origen"].nunique()
print(f"Folios de compra con UUID resuelto: {con_uuid} de {folios_usados}")
print(f"\nValidando cobertura (tolerancia {TOLERANCIA})...")
print(f" Movimientos con cobertura FIFO != magnitud original: {len(descuadres)} de {len(chequeo)}")
print("\nMovimientos partidos en 2+ registros por cruce de capa...")
partidos = resultado[resultado["total_partes_del_movimiento"] > 1]
n_movimientos_partidos = partidos.groupby(["Pr_Cve_Producto", "Mv_Folio", "Mv_ID"]).ngroups
print(f" {n_movimientos_partidos} movimientos partidos (de {len(salidas)} salidas totales) "
f"-> {len(partidos)} filas resultantes de esos movimientos")
if n_movimientos_partidos:
print("\n Por categoria de movimiento:")
print(partidos.drop_duplicates(["Pr_Cve_Producto", "Mv_Folio", "Mv_ID"])
.groupby("categoria_movimiento").size().sort_values(ascending=False).to_string())
print("\n Por numero de partes (2, 3, 4...):")
partes_por_mov = partidos.groupby(["Pr_Cve_Producto", "Mv_Folio", "Mv_ID"])["total_partes_del_movimiento"].first()
print(partes_por_mov.value_counts().sort_index().to_string())
out_path = f"output/movimientos_uuid_fifo_{fecha_ini}_a_{fecha_fin}.csv"
resultado.to_csv(out_path, index=False)
print(f"\nGuardado: {out_path} ({len(resultado)} filas)")
return resultado, chequeo, descuadres
if __name__ == "__main__":
fecha_ini = sys.argv[1] if len(sys.argv) > 1 else "2026-01-01"
fecha_fin = sys.argv[2] if len(sys.argv) > 2 else "2026-01-31"
main(fecha_ini, fecha_fin)