Skip to content

Flujo de Negocio

El flujo de negocio de GM Fiscal cubre seis fases secuenciales que llevan al contador desde el acceso al sistema hasta la obtención del reporte Excel listo para presentar al SAT. Cada fase es atómica: si falla, el estado de la solicitud refleja el error y el sistema permite reintentar sin pérdida de datos.

Diagrama del flujo completo

flowchart TD
    START([Contador accede al sistema]) --> LOGIN

    subgraph AUTH["FASE 1 — Autenticación"]
        LOGIN["Ingresa usuario, contraseña y RFC"]
        VALIDATE["GM Servicios valida credenciales"]
        TOKEN["Se emiten tokens JWT (24h acceso / 30d renovable)"]
        EMPRESA["Se registra la empresa si es la primera vez"]
    end

    subgraph REQUEST["FASE 2 — Crear solicitud"]
        NEW_SOL["Selecciona empresa, período y tipo de facturas"]
        ESTADO1["Solicitud creada: Listo para conciliar"]
    end

    subgraph FETCH["FASE 3 — Obtener facturas"]
        FETCH_ERP["Consulta ERP: facturas registradas en contabilidad"]
        FETCH_SAT["Consulta SAT vía Prodigia o Hades Bóveda Fiscal"]
        PARSE["Parseo y normalización de XMLs CFDI"]
    end

    subgraph CONCILIA["FASE 4 — Conciliación"]
        MATCH["Cruce ERP vs SAT por UUID (strings.EqualFold)"]
        RESULT_A["AMBOS: presente en ERP y en SAT"]
        RESULT_B["SOLO ERP: en contabilidad, sin timbre SAT"]
        RESULT_C["SOLO SAT: timbrado, no registrado en ERP"]
        RESULT_D["CANCELADO: fecha de cancelación en ERP"]
        ESTADO2["Solicitud: Conciliada (estado final)"]
    end

    subgraph REPORT["FASE 5 — Generar reporte"]
        TRIGGER["Solicitud de reporte R21 / RAMCI"]
        ASYNC["Worker asincrónico procesa en segundo plano"]
        EXCEL["Excel generado con formato SAT"]
        AZURE["Subida a Azure Blob Storage"]
        NOTIF["Notificación en tiempo real vía WebSocket"]
    end

    subgraph DOWNLOAD["FASE 6 — Descarga"]
        DOWNLOAD_REPORT["Contador descarga el Excel para presentar al SAT"]
    end

    LOGIN --> VALIDATE --> TOKEN --> EMPRESA
    EMPRESA --> NEW_SOL --> ESTADO1
    ESTADO1 --> FETCH_ERP
    ESTADO1 --> FETCH_SAT
    FETCH_ERP --> PARSE
    FETCH_SAT --> PARSE
    PARSE --> MATCH
    MATCH --> RESULT_A & RESULT_B & RESULT_C & RESULT_D
    RESULT_A & RESULT_B & RESULT_C & RESULT_D --> ESTADO2
    ESTADO2 --> TRIGGER --> ASYNC
    ASYNC --> EXCEL --> AZURE --> NOTIF --> DOWNLOAD_REPORT

Fase 1 — Autenticación

El login valida las credenciales del usuario contra GM Servicios, el sistema centralizado de autenticación del ecosistema GM Transporte. Si la validación es exitosa, se emiten dos tokens JWT:

  • Access token: vigencia de 24 horas. Se envía en el encabezado Authorization: Bearer <token> en todas las peticiones posteriores.
  • Refresh token: vigencia de 30 días. Se usa para obtener un nuevo access token sin requerir credenciales.

La sesión se persiste en la tabla sesiones_usuario con IP, user-agent y fechas para auditoría. Si la empresa asociada al RFC del usuario no existe en el sistema, EmpresaAutoRegistrationAdapter la registra automáticamente con los datos del token.

Fase 2 — Creación de solicitud

El contador crea una Solicitud especificando el RFC de la empresa, el período fiscal (fecha inicio y fecha fin) y el tipo de facturas a conciliar. La solicitud nace en estado Listo para conciliar y recibe un UUID único que la identifica durante todo el flujo.

POST /api/solicitudes

El tipo de facturas puede incluir emitidas, recibidas, pagos, nómina o una combinación de ellas. Este parámetro determina los filtros aplicados en las consultas posteriores al SAT y al ERP.

Fase 3 — Obtención de facturas

Esta fase es la de mayor complejidad técnica. Las facturas se obtienen de dos fuentes en paralelo:

Desde el ERP. El gateway erp/facturas_client.go consulta el sistema de contabilidad interno de GM Transporte para obtener las facturas registradas en el período. Los datos provienen del QueryGatewayService de Hades (MSSQL multi-empresa) cuando el provider es Hades, o del endpoint HTTP directo del ERP cuando el provider es Prodigia.

Desde el SAT. El gateway activo —Prodigia o Hades— entrega los CFDIs oficiales en formato ZIP. Los XMLs se extraen, se limpian de namespaces con RemoveNamespaces() y se parsean con xml.Unmarshal hacia las estructuras CFDI.

El parseo aplica 50 goroutines concurrentes para procesar los XMLs en paralelo. Los UUIDs se comparan siempre con strings.EqualFold para manejar la insensibilidad a mayúsculas/minúsculas de los UUIDs SAT.

Fase 4 — Conciliación

La conciliación la ejecuta MakeConciliacion, una función pura del dominio. No tiene efectos secundarios, no accede a base de datos ni a HTTP. Recibe las listas de facturas de ambas fuentes y produce un resultado determinístico clasificando cada factura en una de cuatro categorías:

CategoríaCondición
AMBOSUUID presente en ERP y en SAT, estatus vigente
ERPUUID en ERP, ausente en SAT
PRODIGIAUUID en SAT, ausente en ERP
CANCELADOUUID presente en ERP con fecha de cancelación

Al finalizar, la solicitud pasa a estado Conciliada, que es el único estado final e inmutable del sistema.

Fase 5 — Generación de reportes

El endpoint POST /api/reporte persiste el reporte con estado Pendiente y responde 202 Accepted de forma inmediata. El procesamiento real ocurre en el ReporteWorker, que corre con un ticker cada 10 segundos.

El worker toma los reportes pendientes y los procesa con un semáforo de máximo 3 simultáneos. Para cada reporte:

  1. R21Processor clasifica las facturas conciliadas y calcula IVA Causado, IVA Acreditable, IVA Retenido e ISR Retenido con redondeo half-up SAT.
  2. RAMCIProcessor clasifica los comprobantes en categorías R/A/M/C/I para el reporte anual.
  3. excelize genera el archivo Excel con las hojas del R21 y el RAMCI.
  4. El archivo se sube a Azure Blob Storage y se genera una URL SAS con vigencia configurable.
  5. El sistema notifica al cliente mediante WebSocket que el reporte está disponible.

Fase 6 — Descarga

El cliente recibe la notificación WebSocket con la URL del Excel en Azure Blob. La URL incluye un token SAS con vigencia de 1440 minutos (24 horas) por defecto, configurable mediante AZURE_SAS_EXPIRY_MINUTES. Pasado ese tiempo, el cliente puede solicitar una nueva URL sin regenerar el archivo.

Contrato HTTP del flujo principal

Las rutas principales que cubren el flujo de negocio son:

POST /api/auth/login # Autenticación
POST /api/solicitudes # Crear solicitud
GET /api/solicitudes/uuid/{uuid} # Consultar estado
POST /api/conciliacion # Ejecutar conciliación
GET /api/conciliacion/{uuid} # Ver resultado
POST /api/reporte # Solicitar reporte
GET /api/reporte/{uuid} # Consultar estado del reporte
WS /api/ws/notificaciones/{rfc} # Canal WebSocket por RFC

Todas las rutas bajo /api/* requieren el encabezado Authorization: Bearer <token> excepto /api/auth/login y /api/auth/refresh.

Pre-conciliación autónoma (solo con Hades)

Cuando el proveedor activo es Hades, el sistema puede ejecutar un pipeline de pre-conciliación en segundo plano antes de que el contador lo solicite explícitamente. Dos goroutines independientes sincronizadas con sync.WaitGroup procesan simultáneamente:

  • Rama SAT: descarga y caché de todos los CFDIs del período en PostgreSQL 5434 + Azure Blob.
  • Rama ERP: obtención y caché de las facturas del ERP para el mismo período.

El resultado queda almacenado como SolicitudAsset. Cuando el contador inicia la conciliación, el sistema usa los datos precacheados y el proceso es prácticamente instantáneo.

Resumen

  • El flujo completo cubre seis fases: autenticación, creación de solicitud, obtención de facturas, conciliación, generación de reporte y descarga.
  • La conciliación la ejecuta MakeConciliacion, una función pura sin efectos secundarios, completamente testeable sin infraestructura.
  • Los reportes se generan de forma asincrónica con notificación WebSocket en tiempo real; el endpoint responde 202 inmediatamente.
  • La pre-conciliación autónoma con Hades descarga y cachea facturas SAT y ERP en segundo plano para acelerar el proceso cuando el contador lo solicite.
  • El estado Conciliada es el único estado final e inmutable; ninguna transición puede salir de él.