El módulo de Finanzas convierte las filas terminales de validations en agregados mensuales útiles para conciliación contable: KPIs, estados de cuenta (PDF/XLSX/CSV/HTML), cuatro reportes detallados y un archivo ZIP con los XMLs CEP del periodo. Todo se computa al vuelo desde la tabla validations del usuario — no hay job pre-agregador.
Qué cuenta como "verificado"
Una validación es "verificada" únicamente cuando validations.status = 'valid' Y cep_xml quedó persistido (Banxico devolvió el XML del CEP). Cualquier otro veredicto terminal — not_found, cep_unavailable, invalid, failed, error — entra en el agregado de "no verificado" y suma al monto unverified pero NO al verified. La definición es la misma que usa Semántica del CEP.
Esa distinción es la que hace que los KPIs no se muevan cuando un retry tiene éxito: la fila se re-marca como valid y verified_volume crece, mientras que unverified_volume baja en el mismo monto.
El KPI bundle de summary
GET /v1/finance/summary?month=YYYY-MM devuelve, para el periodo solicitado, el bundle que renderiza el panel /finanzas:
counts— total + desglose por veredicto (valid,not_found,cep_unavailable,invalid,failed,error).amounts—total_volume,verified_volume,unverified_volume,avg_ticket,median_ticket,max_ticket,min_ticket.success_rate— porcentaje de filas terminales con veredictovalid.avg_processing_ms— latencia media desde insert hasta cierre terminal.top_counterparties/top_banks_receptor/top_banks_emisor— top 5 cada uno, concount+valid+verified_volume.verdict_distribution— counts por veredicto en formato gráfico.comparison_prev_month— total + verified volume del mes anterior y los deltas porcentuales.
Estado de cuenta y reportes
GET /v1/finance/statement?month=YYYY-MM&format=... emite el estado de cuenta mensual en cuatro formatos:
format=pdf(default) — render via Dompdf con header repetido, paginación "Página X de Y" y logo embebido.format=xlsx— workbook multi-hoja (Resumen / Detalle diario / Top contrapartes / Top bancos / KPIs / Transacciones).format=csv— secciones[HEADER]/[KPIS]/[TRANSACTIONS]/[TOTALS]con BOM UTF-8.format=html— el mismo template que el PDF, útil para imprimir desde el navegador.
Los cuatro reportes detallados (monthly / counterparties / by-bank / accounting) aceptan format=csv|preview y, en accounting, decimal=comma|dot para tooling SAT/contable. El PDF tiene un cap de 1000 filas para evitar OOM en Dompdf.
Archivo de CEPs
GET /v1/finance/ceps?from=YYYY-MM-DD&to=YYYY-MM-DD devuelve un ZIP con todos los cep_xml (y cep_pdf_path si está) del rango, más dos manifiestos paralelos — manifest.csv y manifest.xlsx — con columnas validation_id, fecha, clave_rastreo, archivo. Solo se incluyen filas con cep_xml IS NOT NULL OR cep_pdf_path IS NOT NULL, así que el archivo es exactamente el subconjunto verificado del periodo. Si el rango está vacío la respuesta es 404 no_ceps.
Scope: propio vs cross-user
Por default los siete endpoints operan sobre el user_id del API key. Un admin con permiso finance:generate_all puede pasar ?user_id=<UUID> para apuntar a cualquier usuario; sin ese permiso el parámetro user_id devuelve 403 forbidden o se ignora silenciosamente. No hay endpoint público para listar usuarios — el operador admin necesita el UUID por canal aparte.
Para descargar un XML individual sin pasar por el archivo masivo, GET /v1/validations/{id}/cep responde con el XML directamente cuando la fila es valid.