Files
HoruxDespachosNuevo/docs/sessions/2026-05-22-factura-global-contribuyente-fallback.md
Horux Dev 46846200da feat(sat): factura global + fecha_efectiva, fallback tenant-contribuyente, fix anio_global typo
Factura Global & fecha_efectiva:
- Migracion 045_factura_global.sql: periodicidad, meses_global, año_global, fecha_efectiva
- sat-parser.service.ts: extrae InformacionGlobal del XML
- sat.service.ts: calcFechaEfectiva con soporte bimestral (periodicidad 05)
- metricas-compute, dashboard, impuestos, cfdi, export, conciliacion, alertas:
  reemplaza fecha_emision-1h por COALESCE(fecha_efectiva, fecha_emision-1h)
- Script recalc-metricas.ts para recalculo manual

Fallback datos fiscales tenant → contribuyente:
- contribuyente.service.ts: fetchTenantFiscalData + mergeContribuyenteWithTenant
  rellena regimenFiscal, codigoPostal y domicilio cuando el contribuyente
  tiene el mismo RFC que el tenant y sus campos estan vacios
- contribuyente.controller.ts y contribuyente-config.controller.ts:
  pasan req.user!.tenantId al servicio

Fix critico SAT sync:
- sat.service.ts: anio_global → año_global en INSERT/UPDATE de CFDIs
  (la migracion creo 'año_global' con tilde; el codigo usaba 'anio_global',
   causando fallo en 100% de inserciones de CFDI)
- determineChunkMonths: salta sondeo si existe job previo con requestIds
- MAX_POLL_ATTEMPTS: 45 → 500 (~8h) para syncs iniciales grandes

Docs:
- docs/sessions/2026-05-22-factura-global-contribuyente-fallback.md
2026-05-22 15:52:10 +00:00

6.3 KiB

Sesión de cambios: 2026-05-22

Resumen

Tres líneas de trabajo: (1) implementación completa de facturas globales (InformacionGlobal) con fecha_efectiva, (2) fallback robusto de datos fiscales del tenant a contribuyentes con RFC coincidente, y (3) corrección crítica de typo anio_globalaño_global en sincronización SAT.


1. Facturas Globales — InformacionGlobal y fecha_efectiva

Contexto

Las facturas globales del SAT usan el nodo <cfdi:InformacionGlobal> que indica la periodicidad, meses y año al que realmente corresponden los ingresos. Antes del cambio, todos los CFDIs se agrupaban por fecha_emision, lo que desplazaba facturas globales emitidas al cierre de un período (ej. 31 de marzo) al mes equivocado.

Cambios

Base de datos

  • Nueva migración apps/api/src/migrations/tenant/045_factura_global.sql:
    • periodicidad VARCHAR(2)
    • meses_global VARCHAR(10)
    • año_global VARCHAR(4)
    • fecha_efectiva DATE + índice idx_cfdis_fecha_efectiva
  • Aplicada a todos los tenants activos vía script de migración.

Parser SAT

  • apps/api/src/services/sat/sat-parser.service.ts
    • CfdiParsed ahora incluye periodicidad, mesesGlobal, añoGlobal.
    • Extraídos del XML desde comprobante.InformacionGlobal.

Cálculo de fecha_efectiva

  • apps/api/src/services/sat/sat.service.ts
    • calcFechaEfectiva(cfdi): devuelve new Date(año, mes-1, 1) para facturas globales.
    • Soporta periodicidad bimestral (05): códigos 13-18 → meses 2,4,6,8,10,12.

Queries de métricas/reportes Reemplazado fecha_emision - interval '1 hour' por COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') en:

  • metricas-compute.service.ts (counts, min_anio, monthly compute)
  • reportes.service.ts (flujo efectivo, comparativos)
  • dashboard.service.ts (KPIs, neteo PPD/07)
  • impuestos.service.ts (IVA mensual)
  • alertas-auto.service.ts (alertas RESICO y régimen desconocido)
  • cfdi.service.ts (list filters, getResumenCfdis)
  • export.service.ts
  • conciliacion.service.ts
  • alertas.controller.ts

Backfill

  • Ejecutado en todos los tenants activos:
    • horux_hts240708lja: 24 registros
    • horux_roem691011ez4: 2,238 registros
    • horux_auza640701ti9: 6 registros
    • horux_momc8311199va: 14 registros
  • Métricas recalculadas para TORC9611214CA (enero-marzo 2026).

2. Fallback de datos fiscales del tenant al contribuyente

Problema

El tenant HORUX 360 (HTS240708LJA) tiene su régimen fiscal y domicilio en la base central (tenants), pero al existir como contribuyente dentro de su propia BD (contribuyentes), esos campos estaban vacíos. El frontend mostraba "Sin régimen" y "Sin domicilio" al seleccionar ese contribuyente.

Solución robusta

Cuando un contribuyente tiene el mismo RFC que su tenant, el backend ahora mezcla automáticamente los datos faltantes desde la base central.

Archivos

  • apps/api/src/services/contribuyente.service.ts
    • fetchTenantFiscalData(tenantId): consulta tenants + tenant_regimenes_activos para obtener régimen (CSV de claves), CP y domicilio JSON.
    • mergeContribuyenteWithTenant(): rellena regimenFiscal, codigoPostal y domicilio si están vacíos en el contribuyente.
    • listContribuyentes() y getContribuyenteById() aceptan tenantId opcional.
  • apps/api/src/controllers/contribuyente.controller.ts
    • Pasa req.user!.tenantId a listContribuyentes y getContribuyenteById.
  • apps/api/src/controllers/contribuyente-config.controller.ts
    • Pasa req.user!.tenantId a getContribuyenteById en uploadFiel y createOrg.

3. Fix crítico: anio_globalaño_global

Problema

La migración 045_factura_global.sql creó la columna año_global (con tilde), pero sat.service.ts usaba anio_global (sin tilde) en las queries INSERT/UPDATE de saveCfdis. Esto causaba que cada inserción de CFDI fallara con:

column "anio_global" of relation "cfdis" does not exist

Esto explicaba por qué el sync inicial del tenant DESPACHO_MPG95QP7_XZVFF insertó solo 174 de 8,284 CFDIs descargados.

Fix

  • apps/api/src/services/sat/sat.service.ts
    • Líneas 297 y 347: anio_globalaño_global.

Optimización adicional en SAT sync

  • determineChunkMonths(): ahora detecta si existe un job previo completado con satRequestIds y salta el sondeo metadata lento, reutilizando directamente el tamaño de chunk (3 o 6 meses).
  • MAX_POLL_ATTEMPTS: aumentado de 45 a 500 (~8 horas) para syncs iniciales grandes donde el SAT tarda horas en preparar paquetes.

Re-sync validado

Re-lanzado el sync inicial para DESPACHO_MPG95QP7_XZVFF tras el fix:

  • Found: 8,284 | Downloaded: 7,781 | Inserted: 8,266
  • Duración: ~7 minutos (vs. ~3.5 horas del intento anterior con el bug).

Archivos modificados

Archivo Cambio
apps/api/src/migrations/tenant/045_factura_global.sql Nueva migración (untracked → added)
apps/api/src/services/sat/sat-parser.service.ts Extrae periodicidad, mesesGlobal, añoGlobal
apps/api/src/services/sat/sat.service.ts calcFechaEfectiva, fix año_global, determineChunkMonths optimizado, MAX_POLL_ATTEMPTS
apps/api/src/services/metricas-compute.service.ts Usa COALESCE(fecha_efectiva, ...)
apps/api/src/services/dashboard.service.ts Usa fecha_efectiva en KPIs y neteo
apps/api/src/services/impuestos.service.ts Usa fecha_efectiva en IVA mensual
apps/api/src/services/cfdi.service.ts Filtros y resumen por fecha_efectiva
apps/api/src/services/export.service.ts Usa fecha_efectiva
apps/api/src/services/conciliacion.service.ts Usa fecha_efectiva
apps/api/src/services/alertas-auto.service.ts Usa fecha_efectiva en alertas
apps/api/src/controllers/alertas.controller.ts Usa fecha_efectiva en queries de alertas
apps/api/src/services/contribuyente.service.ts Fallback de datos fiscales del tenant
apps/api/src/controllers/contribuyente.controller.ts Pasa tenantId al servicio
apps/api/src/controllers/contribuyente-config.controller.ts Pasa tenantId al servicio
apps/api/src/scripts/recalc-metricas.ts Script de recálculo manual (untracked → added)
apps/web/... Múltiples ajustes frontend relacionados (fechas, alertas, drill-down)