Todos los proyectosAll projects
Caso de estudio · datos sintéticosCase study · synthetic data

Que ninguna factura mal cargada llegue a la corrida de pagos.

No wrong invoice reaches the payment run.

Un control automático para el área de cuentas a pagar de una empresa argentina ficticia: valida CUIT, cruza factura, orden de compra y recepción, y entrega una lista de excepciones con el motivo de cada una.

An automated control for the payables team of a fictional Argentine company: it validates CUITs, matches invoice, purchase order and goods receipt, and hands over an exception list with the reason for each one.

PythonpandaspytestExcelCUIT / IVA / CAE3-way match
SectorIndustryServicios compartidosShared services
Mi rolMy roleReglas, análisis y QARules, analysis and QA
VolumenVolume1.260 facturas1,260 invoices
ValidaciónValidationTotales de control + 7 testsControl totals + 7 tests
Resumen del control de facturas: estados y reglas

Contexto

Context

Un equipo de servicios compartidos recibe cientos de facturas de proveedores por mes. La mayoría está bien. Las que cuestan plata son pocas: una factura cargada dos veces, más unidades que las recibidas, un precio que se fue por encima de la orden de compra, un CUIT mal tipeado, un IVA que no cierra.

A shared-services team receives hundreds of supplier invoices a month. Most are fine. The costly ones are few: an invoice keyed twice, more units than were received, a price that drifted above the purchase order, a mistyped CUIT, IVA that does not add up.

Encontrarlas a ojo es lento y depende de quién revise. Y casi siempre aparecen cuando el pago ya salió.

Finding them by eye is slow and depends on who is reviewing. And they usually surface after the money has left.

Enfoque

Approach

Escribí doce reglas en lenguaje de negocio, cada una con un código, una acción (bloquear o revisar) y un umbral que finanzas puede cambiar sin tocar la lógica. Después cada factura cae en uno de tres estados: lista para pagar, para revisar o bloqueada.

I wrote twelve rules in business language, each with a code, an action (block or review) and a threshold finance can change without touching the logic. Every invoice then lands in one of three states: ready to pay, needs review or blocked.

Bloquea el pagoBlocks paymentPide revisiónNeeds review
R01CUIT con dígito verificador inválidoInvalid CUIT check digit10
R02Proveedor fuera del maestroSupplier not in master18
R03Duplicado exactoExact duplicate14
R04Posible duplicado (7 días)Possible duplicate (7 days)6
R05IVA mal calculado o alícuota inválidaWrong IVA rate or amount12
R06Total ≠ neto + IVA + otrosTotal ≠ net + IVA + other8
R07Sin orden de compra sobre ARS 250.000No PO above ARS 250,00010
R08Precio > 2 % sobre la OCPrice > 2 % above PO18
R09Cantidad facturada > recibidaQty invoiced > received12
R10Tipo de factura vs condición fiscalInvoice type vs tax status8
R11CAE faltante o vencidoCAE missing or expired9
R12Fechas inconsistentesInconsistent dates6

Las reglas se superponen a propósito: un CUIT mal tipeado (R01) tampoco aparece en el maestro de proveedores (R02). Por eso la suma por regla es mayor que la cantidad de facturas marcadas.

Rules overlap on purpose: a mistyped CUIT (R01) is also missing from the supplier master (R02). That is why the per-rule total is higher than the number of flagged invoices.

# src/apcontrol/rules.py: thresholds finance can edit
IVA_RATES = {0.21, 0.105, 0.27, 0.0}
PRICE_TOLERANCE = 0.02      # 2 % above the purchase order
AMOUNT_TOLERANCE = 0.01     # ARS rounding
NO_PO_THRESHOLD = 250_000   # ARS: above this, a PO is required
POSSIBLE_DUP_DAYS = 7

Cómo sé que está bien

How I know it is right

Un control de pagos que se equivoca es peor que no tenerlo. Por eso el proceso se valida a sí mismo en cada corrida:

A payment control that is wrong is worse than none. So the process checks itself on every run:

Cada factura y cada peso cae en un solo estado (si no, el proceso se detiene)Every invoice and every peso lands in exactly one state (otherwise the run stops)PASS
Las 121 anomalías cargadas a propósito son detectadas por su reglaAll 121 planted issues are caught by their rulePASS
Ninguna factura limpia queda marcadaNo clean invoice is flaggedPASS
Los cruces con proveedores, OC y recepciones no duplican facturasJoins with suppliers, POs and receipts never duplicate an invoicePASS

Resultado

Result

Salida del caso de prueba: 1.260 facturas sintéticas por ARS 500,2 M (marzo a agosto de 2026).

Output of the test case: 1,260 synthetic invoices worth ARS 500.2 M (March to August 2026).

1.1391,139listas para pagarready to payARS 431,3 MARS 431.3 M
4848para revisarneed reviewARS 29,4 MARS 29.4 M
7373bloqueadasblockedARS 39,4 MARS 39.4 M

El equipo deja de revisar todas las facturas: revisa solo las marcadas, y cada una llega con el motivo escrito.

The team stops reviewing every invoice: it reviews only the flagged ones, and each arrives with its reason written down.

Entregables

Deliverables

  • exceptions.csv: una fila por factura con las reglas que activó.
  • ap_review.xlsx: estados, reglas, excepciones y totales de control, listo para el equipo.
  • Catálogo de reglas documentado y 7 tests automáticos.
  • Un dashboard interactivo con filtros por estado y regla.
  • exceptions.csv: one row per invoice with the rules it hit.
  • ap_review.xlsx: states, rules, exceptions and control totals, ready for the team.
  • Documented rule catalogue and 7 automated tests.
  • An interactive dashboard with filters by status and rule.
Siguiente casoNext caseReporte de KPIs con IA verificadoAI KPI report, verified