OnnixConnect OC — Especificación Técnica
Documento base del proyecto — convertido desde
docs/docx/OnnixConnect_OC_Especificacion_Tecnica.docx.Esta es la especificación original que dio origen al proyecto OnnixConnect. Define la arquitectura, flujos, modelo de datos, eventos, observabilidad y roadmap completo del sistema.
Manual de Integración — Sistema SIFEN Paraguay
| Nombre en Clave | OnnixConnect OC (OC) |
| Versión del Documento | 1.0 — Revisión Inicial |
| Estado | En Desarrollo Activo |
| Tecnología Principal | PHP 8.5 / Laravel 12 / PostgreSQL |
| Interfaz de Usuario | AdminLTE 2024 + Livewire v3 + Alpine.js |
| Panel Administrativo | Filament v3 |
| Área de Monitoreo | Redis + Laravel Horizon + Sentry |
| Responsable Técnico | Onnix Tecnología y Servicios SA |
| Clasificación | CONFIDENCIAL — Uso Interno |
Onnix Tecnología y Servicios SA — RUC: 80126006-0
https://onnix.com.py | Asunción, Paraguay
1. Introducción y Propósito
El presente documento constituye la especificación técnica oficial del proyecto OnnixConnect OC, un sistema de integración nativo para el Sistema Integrado de Facturación Electrónica Nacional (SIFEN) de la República del Paraguay, administrado por la Dirección Nacional de Ingresos Tributarios (DNIT). OnnixConnect OC reemplaza las implementaciones legadas en Java proyecto (SIFEN) por un ecosistema moderno construido sobre PHP 8.5 y Laravel 12, manteniendo compatibilidad total con los protocolos SOAP y las especificaciones técnicas del Manual Técnico de la DNIT.
#################### 1.1 Alcance del Sistema
-
Generación, firmado digital y envío de Documentos Electrónicos (DE) a la DNIT.
-
Gestión completa del ciclo de vida de comprobantes: creación, aprobación, rechazo, cancelación e inutilización.
-
Procesamiento de lotes masivos de hasta 4.500 comprobantes simultáneos (Tarjetas de Crédito Procard y Bancard).
-
Sincronización automática de estados entre el sistema interno y SIFEN, eliminando la conciliación manual.
-
Panel de monitoreo y control operativo integrado en AdminLTE 2024 con componentes reactivos Livewire v3.
-
Panel administrativo en Filament v3 para gestión de empresas, certificados digitales y configuración del sistema.
#################### 1.2 Definiciones y Acrónimos
| Término | Definición |
| SIFEN | Sistema Integrado de Facturación Electrónica Nacional — plataforma oficial de la DNIT |
| DNIT | Dirección Nacional de Ingresos Tributarios - autoridad tributaria de Paraguay |
| DE / KuDE | Documento Electrónico / Representación gráfica imprimible del DE |
| CDC | Código de Control del DE. Identificador único de 44 dígitos asignado por el emisor |
| Timbrado | Número de autorización de impresión otorgado por la SET para un período fiscal |
| CSC | Código de Seguridad del Contribuyente — usado para generar el código QR del KuDE |
| NCR | Nota de Crédito Electrónica — tipo 5 en la nomenclatura SIFEN |
| WS / SOAP | Web Service — protocolo de comunicación con los servicios oficiales de la SET |
| OC | OnnixConnect — nombre en clave del presente proyecto |
| Horizon | Panel de administración de colas Redis para Laravel |
| Livewire v3 | Framework para componentes reactivos server-side en PHP/Laravel |
| Filament v3 | Framework de panel de administración basado en Livewire para Laravel |
2. Arquitectura de Integración
OnnixConnect OC implementa una arquitectura de capas desacopladas donde cada capa tiene responsabilidades bien definidas. La comunicación entre el sistema interno y la DNIT fluye a través de servicios PHP especializados que replican y mejoran la funcionalidad de las librerías Java legadas.
#################### 2.1 Capas del Sistema
| Capa | Componentes | Responsabilidad |
| Presentación | Livewire v3 + Alpine.js + AdminLTE 2024 | Interfaces operativas: monitor de lotes, control SIFEN, gestión de errores |
| Administración | Filament v3 | Configuración de empresas, certificados, usuarios y parámetros del sistema |
| Controladores | Laravel Controllers (MVC) | Enrutamiento HTTP, validación de requests, orquestación de flujos |
| Servicios | PHP Service Classes | Lógica de negocio: generación XML, firmado digital, comunicación SOAP |
| Colas / Jobs | Laravel Horizon + Redis | Procesamiento asíncrono de lotes masivos y sincronización de estados |
| Persistencia | PostgreSQL 18 + Eloquent ORM | Almacenamiento de comprobantes, eventos, logs y configuraciones |
| Caché | Redis + Cache Tags | Estados de comprobantes con TTL de 30 minutos; progreso de lotes |
| Observabilidad | Sentry + Prometheus + Grafana | Trazabilidad de errores y métricas de rendimiento del WS de la DNIT |
#################### 2.2 Componentes Técnicos del Core Criptográfico
El firmado digital, operación crítica y legalmente mandatoria, migra de la implementación Java (javax.xml.crypto.dsig + KeyStore) a PHP puro mediante las siguientes librerías:
| Función Java Legacy | Equivalente PHP en OC | Paquete |
| KeyStore.load(.p12) | openssl_pkcs12_read() | PHP nativo — ext-openssl |
| XML-DSig / RSA-SHA256 | XMLSecurityDSig + XMLSecurityKey | robrichards/xmlseclibs 3.x |
| JAXB Marshalling XML | DOMDocument nativo + spatie/array-to-xml | PHP nativo + Composer |
| SAAJ SoapClient | SoapClient nativo PHP | PHP nativo — ext-soap |
| SifenException hierarchy | Jerarquía propia + Sentry context | sentry/sentry-laravel |
| JPA @Entity | Eloquent Model + Migration | Laravel 12 ORM |
| Spring Scheduler | Laravel Scheduler (cron único) | Laravel 12 nativo |
| ExecutorService (threads) | Laravel Horizon + Redis Queues | laravel/horizon |
#################### 2.3 Stack Tecnológico Justificado
La elección del stack no es arbitraria. Cada componente fue seleccionado con base en tres criterios: compatibilidad con el ecosistema PHP de Onnix, capacidad de manejo de concurrencia a largo plazo, y facilidad de mantenimiento por equipos Junior o Solo Dev.
| Tecnología | Versión | Justificación Técnica |
| PHP | 8.5 | Fibers nativos para concurrencia, JIT mejorado, tipos de intersección y async implícito |
| Laravel | 12.x | Ecosystem maduro: Horizon, Scheduler, Eloquent, Sanctum. Menor curva de aprendizaje vs Spring Boot |
| PostgreSQL | 18 | ACID compliance, JSONB para almacenar respuestas SOAP, particionado por fecha en tablas de alto volumen |
| Redis | 7.x | Driver de colas de Horizon, caché de estados con TTL, pub/sub para actualizaciones en tiempo real |
| Livewire v3 | 3.x | Componentes reactivos sin JavaScript complejo. Polling automático para monitor de lotes |
| Filament v3 | 3.x | Panel administrativo con CRUD, subida de certificados .p12 y gestión de roles sin código extra |
| AdminLTE | 2024 | Plantilla Bootstrap estándar compatible con Blade/Livewire. Familiar para operadores de caja |
| Sentry | Self-hosted | Captura de errores de firmado digital con contexto. Los datos no salen del perímetro de la entidad |
| Prometheus+Grafana | Estable | Métricas de latencia del WS de la DNIT, tasa de aprobación y tamaño de colas de Horizon |
3. Flujos de Datos
#################### 3.1 Envío Individual — Operaciones Diarias
El envío individual es el flujo estándar para comprobantes generados en tiempo real: facturación de caja, cobro de cuotas de préstamos y facturación manual. El ciclo es sincrónico desde la perspectiva del operador, pero asíncrono internamente gracias a Horizon.
Flujo Técnico — Envío Individual Usuario inicia comprobante → Controller valida datos → DocumentoElectronicoDTO → XmlGeneradorService genera XML → Validación XSD → XmlFirmadorService firma (RSA-SHA256) → EnviarComprobanteDLJob despachado a cola 'critica' → SifenSoapService llama recepcionDE() → Respuesta almacenada (IdDocumento, CDC, XML, Respuesta) → Estado actualizado en PostgreSQL → Cache tag invalidado → UI Livewire refleja estado en tiempo real. |
############################## 3.1.1 Estructura JSON de la Cabecera (Factura Electrónica)
El siguiente mapeo define la estructura del JSON de entrada al sistema OC, derivado del formato real analizado (Factura_Json.json):
| Campo JSON | Tipo | Descripción | Ejemplo Real |
| IDFACTURA | string | Identificador único interno del comprobante | "24050738" |
| FECHA | date | Fecha de emisión (YYYY-MM-DD) | "2025-11-07" |
| NRO1 | int | Número de establecimiento (3 dígitos) | 1 |
| NRO2 | int | Número de punto de expedición (3 dígitos) | 1 |
| NRO3 | string | Número correlativo del comprobante | "1427697" |
| IDCOMPROBANTE | int | Tipo: 1=Fact.Contado, 2=Fact.Crédito, 3=NCR, 5=NCR Elect. | 1 |
| NROTIMBRADO | string | Número de timbrado DNIT vigente | "16014181" |
| HORA_EMISION | time | Hora de emisión (HH:MM:SS) | "16:08:17" |
| RUC | string | RUC del receptor con dígito verificador | "80067095-7" |
| NOMBRE | string | Razón social o nombre del receptor | "CATHAY SAE" |
| DIRECCION | string | Dirección del receptor | "SIN DIRECCION" |
| string | Correo electrónico del receptor para KuDE | "jorge.ortiz@timbo.com.py" | |
| CODPAIS | string | Código de país ISO-3166 (PRY por defecto) | "PRY" |
| TOTALGRAL | decimal | Total general del comprobante en guaraníes | "90393" |
| IDMEDIOPAGO | int | 1=Efectivo, 2=Cheque, 3=Tarjeta, 4=Transferencia | "2" |
| TC | decimal | Tipo de cambio (relevante para moneda extranjera) | "7710.7" |
| EXTRANJERO | bool | Indicador de receptor extranjero (0/1) | 0 |
| NOCONTRIBUYENTE | bool | Receptor no contribuyente (0/1) | 0 |
| ITIPDOCASO | int|null | Tipo de doc. asociado (para NCR: tipo de factura) | null |
| NRO1R/NRO2R/NRO3R | int|null | Número de comprobante referenciado (en NCR) | null |
| NROTIMBRADOR | string|null | Timbrado del documento referenciado (en NCR) | null |
| IMOTEMI | int|null | Motivo de emisión de NCR (1-8 según normativa DNIT) | null |
| INDINUTILIZADO | int | Indicador de inutilización previa (0/1) | 0 |
| INDENVIADO | string | Estado de envío: 0=No enviado, 1=Enviado | "0" |
############################## 3.1.2 Estructura del Detalle (Ítems del Comprobante)
| Campo JSON | Tipo | Descripción | Ejemplo Real |
| IDDETALLEFACTURA | int | Número de línea del ítem (secuencial desde 1) | 1 |
| IDFACTURA | int | FK — referencia al comprobante padre | 24050738 |
| CANTIDAD | int | Cantidad de unidades del ítem | 1 |
| DESCRIPCION | string | Descripción del bien o servicio (aparece en KuDE) | "Intereses Cuota Prest. 1661008, cuota 13" |
| PRECIO | decimal | Precio unitario en guaraníes | 90393 |
| EXENTA | decimal | Monto exento de IVA (operaciones exentas) | 0 |
| IVA5 | decimal | Monto gravado a tasa del 5% | 0 |
| IVA10 | decimal | Monto gravado a tasa del 10% | 90393 |
| IDTASAIVA | int | 1=Exenta, 2=IVA 10%, 3=IVA 5% | 2 |
| IDUNIDADMEDIDA | int | Código de unidad de medida (77=UNI estándar DNIT) | 77 |
| DESCUENTO | decimal | Descuento aplicado al ítem | 0 |
| CODIGO | string|null | Código interno del producto/servicio | null |
| CODBARRA | string|null | Código de barras EAN/UPC (opcional) | null |
############################## 3.1.3 Respuesta del Sistema tras el Envío
Tras la transmisión exitosa, OC registra en la tabla documentos_electronicos los siguientes campos retornados por la DNIT vía el WS de DL Informática:
| Campo Respuesta | Fuente | Descripción |
| IDDOCUMENTO | WS DL / DNIT | Identificador numérico asignado por el sistema DL |
| CDC (44 dígitos) | Generado por emisor | Código de Control único del DE. Formato: RUC(8)+DV(1)+TIPO(2)+ESTAB(3)+PUNEXP(3)+NRODOC(7)+FECHA(8)+CODSEG(9)+DV(1)+TIPOEMISION(1)+DVID(1) |
| DCODRES | DNIT | Código de resultado SIFEN (0260=Aprobado, 0422=Rechazado) |
| DMSGRES | DNIT | Mensaje descriptivo del resultado |
| XML (completo) | Generado por OC+DL | XML firmado digitalmente. Incluye firma RSA-SHA256 y namespace http://ekuatia.set.gov.py/sifen/xsd |
| ESTADO | DNIT | Aprobado / Rechazado / En Proceso |
#################### 3.2 Envío Masivo por Lotes — Tarjetas de Crédito
El proceso masivo de Tarjetas de Crédito (Procard y Bancard) involucra aproximadamente 4.500 comprobantes simultáneos. Su arquitectura es radicalmente diferente al envío individual: debe evitar la saturación del WS externo, proveer visibilidad en tiempo real al operador y garantizar que ningún comprobante quede sin procesar ante fallos parciales.
############################## 3.2.1 Diferencias Fundamentales entre Modos de Envío
| Criterio | Envío Individual | Envío por Lotes (TC) |
| Volumen típico | 1 comprobante por operación | ~4.500 comprobantes por proceso |
| Origen del proceso | Acción del operador en tiempo real | Archivo de cierre Procard (E003050T) o período Bancard |
| Modo de ejecución | Sincrónico (UI espera respuesta) | 100% asíncrono (Horizon + Redis) |
| Chunking aplicado | No aplica | Chunks de 50 DEs por job (límite recepcionLoteDE) |
| Jobs de Horizon | 1 job por comprobante (cola 'critica') | 90 jobs de 50 DEs c/u (cola 'lotes') |
| Monitor en UI | Estado actualizado post-respuesta | Livewire polling cada 3 segundos (barra de progreso) |
| Validación duplicados | Por IDFACTURA único | Por tarjeta + período + documento ('YA EXISTE REGISTRO') |
| Respuesta al operador | Inmediata (< 30 seg) | Progresiva (10-15 minutos para 4.500 DEs) |
| Reintentos ante fallo | 3 intentos con backoff (30s, 120s, 480s) | 3 intentos por chunk; chunks fallidos marcados individualmente |
############################## 3.2.2 Flujo Técnico del Proceso Masivo
-
El operador sube el archivo de Procard (E003050T) o selecciona el período de Bancard en la interfaz Livewire.
-
LoteFacturacionService valida duplicados (tarjeta + período + documento), crea el registro LoteSifen en PostgreSQL y emite el evento de inicio.
-
Se generan chunks de 50 comprobantes cada uno y se despachan como EnviarChunkSifenJob a la cola de Horizon 'lotes' con 5 workers paralelos.
-
Cada job procesa su chunk: genera XML → valida XSD → firma RSA-SHA256 → llama recepcionLoteDE() → actualiza estado en PostgreSQL → incrementa progreso en Redis.
-
El componente MonitorLoteTarjetas de Livewire hace polling cada 3 segundos al hash Redis lote:{id}:progreso y actualiza la barra de progreso sin recargar la página.
-
Al completarse todos los chunks, el lote pasa a estado COMPLETADO. Los chunks fallidos (después de 3 reintentos) quedan como ERROR_ENVIO y son accesibles desde el panel de Comprobantes Rechazados para reenvío manual.
Nota Técnica — Límite de la DNIT El WS oficial recepcionLoteDE() de SIFEN acepta un máximo de 50 Documentos Electrónicos por llamada. Por ello, el chunking de 4.500 ÷ 50 = 90 jobs es mandatorio y no configurable. Aumentar el tamaño del chunk por encima de 50 resultará en el error 'Lote no encolado para procesamiento. Se rechazaron todos los DE del lote', error documentado en el sistema actual. |
4. Gestión de Eventos — Inutilización y Cancelación
La gestión de eventos es la operación más delicada del sistema desde el punto de vista legal y tributario. Un error en la elección del tipo de evento (Inutilización vs Cancelación) puede resultar en infracciones tributarias ante la DNIT. OnnixConnect OC implementa validaciones estrictas para garantizar que el tipo correcto de evento sea aplicado según el estado actual del DE.
#################### 4.1 Regla de Negocio Fundamental
REGLA CRÍTICA — Distinción entre Inutilización y Cancelación INUTILIZACIÓN (I): Se aplica EXCLUSIVAMENTE a números de comprobantes que fueron generados localmente pero que NUNCA fueron aprobados por la DNIT. El DE no tiene CDC definitivo de la DNIT. Ejemplo: rangos de números reservados que no se utilizaron. CANCELACIÓN (C): Se aplica EXCLUSIVAMENTE a DEs que YA FUERON APROBADOS por la DNIT (estado APROBADO con CDC completo de 44 dígitos). El motivo es obligatorio y queda registrado en el protocolo de auditoría de la DNIT. |
#################### 4.2 Parámetros Técnicos del WS de Eventos
Los eventos se envían al WS de DL Informática mediante la siguiente estructura de URL (Datasnap REST):
http://{servidor}:{puerto}/datasnap/rest/TServerMetodos/eventoDE/{TIPO}/{CDC}/{TIMBRADO}/{ESTAB}/{PEXPEDICION}/{NRODESDE}/{NROHASTA}/{TIPODOC}/{MOTIVO}
############################## 4.2.1 Tabla de Parámetros por Tipo de Evento
| Parámetro | Posición | Inutilización (I) | Cancelación (C) | Obligatorio |
| tipo | 1 | I (literal) | C (literal) | Sí en ambos |
| cdc | 2 | Vacío (//) | CDC de 44 dígitos del DE aprobado | Solo en C |
| timbrado | 3 | Ej: 12559938 (número de timbrado) | Vacío (//) | Solo en I |
| establecimiento | 4 | Ej: 1 (número de establecimiento) | Vacío (//) | Solo en I |
| p. expedición | 5 | Ej: 3 (punto de expedición) | Vacío (//) | Solo en I |
| nrodesde | 6 | 1005 (número inicial del rango a inutilizar) | Vacío (//) | Solo en I |
| nrohasta | 7 | 1005 (número final del rango a inutilizar) | Vacío (//) | Solo en I |
| tipodoc | 8 | 1=Factura, 4=Autofact, 5=NCR, 6=NDéb, 7=N.Rem. | 1=Factura, 5=NCR, etc. | Sí en ambos |
| motivo | 9 | Texto libre. Mínimo 5 caracteres. Obligatorio. | Texto libre. Mínimo 5 caracteres. Obligatorio. | Sí en ambos |
############################## 4.2.2 Ejemplos de URLs — Ambiente de Pruebas
Inutilización (rango 1005 a 1005, timbrado 12559938, establecimiento 1, punto exp. 3, tipo Factura):
http://10.0.0.242:10000/datasnap/rest/TServerMetodos/eventoDE/I//12559938/1/3/1005/1005/1/PRUEBA DE INUTILIZACION WS
Cancelación (CDC completo del DE aprobado, tipo Factura, motivo de anulación):
#################### 4.3 Validaciones Implementadas en OC
| Validación | Regla | Error si no cumple |
| Motivo obligatorio | El campo motivo NUNCA puede estar vacío o tener menos de 5 caracteres | Error de validación antes de llamar al WS. Equivalente al ORA-20000 del sistema legado |
| CDC para cancelación | Si tipo=C, el CDC debe tener exactamente 44 caracteres alfanuméricos | Rechazo inmediato sin llamar al WS |
| Estado del DE para C | Solo DEs en estado APROBADO pueden cancelarse | Error de negocio: 'El documento no está aprobado por SIFEN' |
| Estado del DE para I | Solo DEs en estado GENERADO, ERROR o RECHAZADO pueden inutilizarse | Error de negocio: 'El documento ya fue aprobado. Use Cancelación' |
| Un evento por tipo | Un DE ya cancelado no puede cancelarse nuevamente (código 0360 de DNIT) | Verificación previa en tabla eventos antes de llamar al WS |
| Plazo de cancelación | La SET rechaza cancelaciones fuera del plazo legal (código 0380) | El sistema advierte si el DE tiene más de 72 horas de emitido |
#################### 4.4 Estructura de Respuesta del WS de Eventos
Respuesta exitosa de cancelación (código 0260 = Aprobado):
{
"success": true,
"payload": {
"dCodRes": "0260",
"dMsgRes": "Aprobado",
"gResProcEVe": [{
"id": "01800262778001001..._001",
"dEstRes": "Aprobado",
"dProtAut": "CAN01800262778001001...",
"gResProc": [{ "dCodRes": "0260", "dMsgRes": "Evento de cancelación procesado correctamente" }]
}]
}
}
5. Gestión de Errores y Sincronización de Estados
#################### 5.1 El Problema de Desfase de Estados
El problema central que motivó el diseño de la arquitectura de sincronización de OC es el siguiente: el WS de DL Informática responde inicialmente con el estado 'Registrado con éxito para su envío', pero no actualiza automáticamente el estado local cuando la DNIT finalmente aprueba o rechaza el DE. Esto genera un desfase donde documentos legalmente aprobados permanecen indefinidamente en estado intermedio en la base de datos interna.
Problema Documentado Estado actual: 'Registrado con éxito para su envío' → Estado correcto: 'APROBADO'. El sistema legado resolvía este desfase descargando manualmente un archivo .txt desde el portal de DL Informática y cargándolo a la base de datos. Este proceso es propenso a errores humanos, introduce latencia de horas o días, y no es escalable para volúmenes de 4.500+ comprobantes mensuales. |
#################### 5.2 Solución: Sincronización Automatizada con Laravel Scheduler
OnnixConnect OC elimina completamente el proceso manual mediante un sistema de sincronización automatizada que consume la API de DL Informática cada 30 minutos y actualiza los estados en PostgreSQL, invalidando simultáneamente el caché de Redis para que la UI de Livewire refleje el estado real.
############################## 5.2.1 Tareas Programadas del Scheduler
| Tarea (artisan command) | Frecuencia | Función |
| sifen:sync-estados | Cada 30 minutos | Consulta estados en DL, actualiza PostgreSQL, invalida Cache Tags Redis |
| sifen:verificar-pendientes | Cada hora | Detecta DEs con más de 60 min en estado 'Registrado' y reencola para verificación |
| sifen:reporte-diario | Diariamente 23:30 | Genera resumen: aprobados, rechazados, pendientes y errores por tipo |
| sifen:limpiar-cache-expirado | Semanal (domingo 02:00) | Limpia entradas Redis huérfanas y logs de auditoría con más de 90 días |
Configuración en Servidor Plesk Solo se requiere un cron de un minuto en Plesk: '* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1'. El Scheduler de Laravel gestiona internamente la frecuencia de cada tarea. No se requieren múltiples crons. |
#################### 5.3 Catálogo de Códigos de Error de la DNIT
| Código DNIT | Descripción | Acción en OC | Pantalla de Control |
| 0260 | Aprobado — DE aceptado por la DNIT | Estado → APROBADO. Cache actualizado. | No aparece en listas de error |
| 0422 | Rechazado — Error en el contenido del DE | Estado → RECHAZADO. Log en Sentry. | Comprobantes Rechazados |
| 0301 | Fallo de schema XML del rea de datos | Estado → RECHAZADO. Detalle en log de error. | Errores SIFEN (41 ocurrencias registradas) |
| 0360 | Documento electrónico duplicado | Validación previa evita el reenvío. | Errores SIFEN (4 ocurrencias) |
| 0350 | El tipo de operación no es compatible con la naturaleza del receptor | Verificar IDCOMPROBANTE vs tipo de receptor. | Errores SIFEN (13 ocurrencias) |
| 0420 | No existe DTE consultado | Verificar CDC en base local. | Errores SIFEN |
| Error PKI | Error Inesperado PKI — fallo de firma digital | Captura automática en Sentry con stack trace. | Errores SIFEN (4 ocurrencias) |
| 0380 | Plazo vencido para envío del evento | Bloquear cancelación. Notificar al operador. | Anulaciones — Estado |
| 0370 | Evento no permitido para el estado actual | Validación previa por estado del DE. | Anulaciones — Estado |
| HTTP 503 | WS de la DNIT no disponible | Reintento con backoff exponencial (Horizon). | Monitor Horizon |
#################### 5.4 Ciclo de Vida de Estados del DE en OC
| Estado OC | Descripción | Transiciones Posibles | Equivalente Legado |
| GENERADO | DE creado en OC, aún no firmado ni enviado | → FIRMADO | → ERROR_FIRMA | No enviado |
| FIRMADO | XML firmado digitalmente. Listo para envío. | → ENVIADO | → ERROR_ENVIO | — |
| ENVIADO | Enviado al WS de DL. Respuesta 'Registrado'. | → APROBADO | → RECHAZADO | → PENDIENTE | Registrado con éxito |
| APROBADO | Aprobado por la DNIT. CDC definitivo asignado. | → CANCELADO (vía evento C) | Migrado SIFEN / Aprobado |
| RECHAZADO | Rechazado por la DNIT con código de error. | → ENVIADO (reenvío tras corrección) | Comprobante Rechazado |
| CANCELADO | Cancelado mediante evento C aprobado por DNIT. | Estado final — no reversible | Anulado SIFEN |
| INUTILIZADO | Inutilizado mediante evento I aprobado por DNIT. | Estado final — no reversible | Inutilizado SIFEN |
| ERROR_FIRMA | Fallo en el firmado digital (PKI/certificado) | → GENERADO (tras corregir certificado) | Error Inesperado PKI |
| ERROR_ENVIO | Fallo de comunicación con el WS tras 3 reintentos | → ENVIADO (reenvío manual) | No Enviado |
6. Estructura de Datos — Modelo Relacional
#################### 6.1 Tablas Principales del Sistema OC
El modelo de datos de OnnixConnect OC extiende el schema original del sistema legado (sifen_db.sql), agregando las tablas necesarias para el ciclo de vida completo de los DEs y la gestión de lotes masivos.
############################## 6.1.1 Tabla: empresas
| Columna | Tipo PostgreSQL | Descripción | Origen |
| id | BIGINT PK | Identificador autonumérico | Nuevo (era INT en legado) |
| ruc | VARCHAR(30) UNIQUE | RUC del emisor sin dígito verificador | empresa.ruc |
| digito_verificador | VARCHAR(2) | Dígito verificador del RUC | empresa.digito_verificador |
| razon_social | TEXT | Razón social completa del emisor | empresa.razon_social |
| csc_sifen | TEXT | Código de Seguridad del Contribuyente (32 chars) | empresa.csc_sifen |
| id_csc_sifen | VARCHAR(4) | Identificador del CSC (ej: '0001') | empresa.id_csc_sifen |
| estado | CHAR(1) | 'A'=Activo, 'I'=Inactivo | empresa.estado |
| ambiente | VARCHAR(20) | 'desarrollo' | 'produccion' | Nuevo |
| nro_timbrado | BIGINT | Número de timbrado DNIT vigente (ej: 16014181) | Nuevo (antes en config) |
| fecha_inicio_timbrado | DATE | Fecha de inicio de vigencia del timbrado | Nuevo |
| establecimiento | VARCHAR(3) | Número de establecimiento (ej: '001') | Nuevo |
| punto_expedicion | VARCHAR(3) | Punto de expedición (ej: '001') | Nuevo |
| created_at / updated_at | TIMESTAMP | Auditoría automática Laravel | fecha_insercion / fecha_ultima_actualizacion |
############################## 6.1.2 Tabla: certificados
| Columna | Tipo PostgreSQL | Descripción |
| id | BIGINT PK | Identificador autonumérico |
| empresa_id | BIGINT FK | Referencia a empresas.id (relación 1:1) |
| alias_entrada | VARCHAR(100) | Alias del certificado dentro del keystore .p12 |
| clave_alias | VARCHAR(100) CIFRADO | Contraseña del alias — cifrada con encrypt() de Laravel |
| clave_certificado | VARCHAR(100) CIFRADO | Contraseña del archivo .p12 — cifrada con encrypt() |
| contenido | TEXT | Contenido del .p12 en Base64 — NUNCA exponer en logs |
| tipo_certificado | VARCHAR(10) | 'P12' | 'PEM' |
############################## 6.1.3 Tabla: documentos_electronicos (tabla central del sistema)
| Columna | Tipo PostgreSQL | Descripción |
| id | BIGINT PK | Identificador autonumérico |
| empresa_id | BIGINT FK | Empresa emisora |
| lote_id | BIGINT FK NULL | Lote masivo al que pertenece (NULL si es envío individual) |
| cdc | VARCHAR(44) UNIQUE NULL | Código de Control de 44 dígitos (NULL hasta ser asignado) |
| id_sifen | BIGINT NULL | ID numérico retornado por DL/DNIT |
| nro_factura | VARCHAR(30) NULL | Número formateado (ej: '001-001-1427697') |
| tipo_documento | SMALLINT | 1=Factura, 3=NCR, 5=NCR Electrónica, etc. |
| estado | ENUM | Ver Sección 5.4 — Ciclo de vida completo |
| receptor_ruc | VARCHAR(20) NULL | RUC del receptor |
| receptor_nombre | TEXT NULL | Nombre o razón social del receptor |
| receptor_email | TEXT NULL | Email para envío del KuDE |
| moneda | CHAR(3) | Código ISO: 'PYG', 'USD', 'BRL', etc. |
| total_general | DECIMAL(18,2) | Monto total del comprobante |
| total_iva_5 | DECIMAL(18,2) | Total IVA al 5% |
| total_iva_10 | DECIMAL(18,2) | Total IVA al 10% |
| total_exenta | DECIMAL(18,2) | Total exento de IVA |
| xml_sin_firmar | LONGTEXT NULL | XML generado antes del firmado (solo para debug) |
| xml_firmado | LONGTEXT NULL | XML con firma RSA-SHA256 — resultado final enviado a DNIT |
| respuesta_dnit | TEXT NULL | Respuesta JSON/XML completa del WS |
| codigo_respuesta | VARCHAR(10) NULL | Código de resultado DNIT (0260, 0422, etc.) |
| mensaje_respuesta | TEXT NULL | Mensaje descriptivo del resultado |
| fecha_emision | TIMESTAMP | Fecha y hora de emisión del DE |
| created_at / updated_at | TIMESTAMP | Auditoría automática Laravel |
############################## 6.1.4 Tabla: eventos
| Columna | Tipo PostgreSQL | Descripción |
| id | BIGINT PK | Identificador autonumérico |
| documento_electronico_id | BIGINT FK | DE sobre el que se aplica el evento |
| empresa_id | BIGINT FK | Empresa emisora del evento |
| tipo_evento | ENUM | 'CANC'=Cancelación, 'INUT'=Inutilización, 'CONF'=Conformidad, 'DISC'=Disconformidad |
| motivo | TEXT | Motivo del evento — OBLIGATORIO para CANC e INUT (mínimo 5 caracteres) |
| cdc | VARCHAR(44) NULL | CDC del DE a cancelar (solo para CANC) |
| nro_timbrado | VARCHAR(8) NULL | Número de timbrado (solo para INUT) |
| nro_desde | VARCHAR(7) NULL | Número inicial del rango a inutilizar |
| nro_hasta | VARCHAR(7) NULL | Número final del rango a inutilizar |
| estado | ENUM | 'PENDIENTE' | 'APROBADO' | 'RECHAZADO' |
| xml_evento | TEXT NULL | XML del evento firmado enviado a la DNIT |
| respuesta_dnit | TEXT NULL | Respuesta completa del WS de eventos |
| codigo_respuesta | VARCHAR(10) NULL | 0260=Aprobado, 0301=Error formato, etc. |
7. Interfaz de Usuario
#################### 7.1 Módulos Operativos — AdminLTE + Livewire v3
| Módulo (ruta Laravel) | Componente Livewire | Función Principal |
| /operaciones/comprobantes/rechazados | ComprobantesRechazados | Listado filtrable. Selección múltiple. Reenvío masivo a SIFEN. |
| /operaciones/comprobantes/no-enviados | ComprobantesNoEnviados | DEs sin CDC o ID SIFEN. Diagnóstico de fallos de comunicación. |
| /operaciones/comprobantes/anulados | ComprobantesAnulados | Vista cruzada: Anulado en ERP vs Inutilizado/Anulado en SIFEN. |
| /operaciones/lotes/monitor/{id} | MonitorLoteTarjetas | Barra de progreso en tiempo real. Polling 3 seg. Contadores live. |
| /operaciones/lotes/nueva-tc | GeneracionLoteTC | Carga archivo Procard (E003050T) o selección período Bancard. |
| /operaciones/control-sifen | ControlIngresoSifen | Cruce Finansys vs SIFEN. Filtros fecha/RUC. 50.000+ registros paginados. |
| /operaciones/eventos/cancelacion | AnulacionComprobante | Modal con CDC + Motivo obligatorio. Validación previa de estado. |
| /operaciones/eventos/inutilizacion | InutilizacionComprobante | Formulario con Timbrado + Establecimiento + Rango + Motivo. |
| /operaciones/errores-sifen | ErroresSifen | Tipificación de errores agrupados. Drill-down a comprobantes afectados. |
#################### 7.2 Módulos Administrativos — Filament v3
| Resource Filament | Tabla gestionada | Función Principal |
| EmpresaResource | empresas | CRUD de empresas emisoras. Configuración de timbrado, CSC y ambiente. |
| CertificadoResource | certificados | Carga segura de .p12. Campos de clave cifrados. Vista previa del alias. |
| UsuarioResource | usuarios | Gestión de operadores y administradores. Asignación de roles. |
| RolResource | roles | Definición de permisos granulares por módulo operativo. |
| LoteSifenResource | lotes_sifen | Historial de lotes masivos. Estado y métricas de cada proceso de TC. |
| ConfiguracionResource | configuraciones | Parámetros globales: URLs de WS, timeouts, thresholds de alertas. |
8. Observabilidad y Monitoreo
#################### 8.1 Sentry Self-Hosted — Trazabilidad de Errores
Sentry captura automáticamente todas las excepciones no manejadas con contexto enriquecido. Para OnnixConnect OC, los eventos más críticos son los fallos de firmado digital (Error PKI) y los rechazos inesperados del WS de la DNIT.
| Tipo de Error | Tag Sentry | Contexto Capturado | Alerta |
| Fallo firmado .p12 | sifen.operacion=firmado_digital | empresa_id, alias (SIN clave ni contenido) | Email inmediato al equipo |
| Error schema XML (0301) | sifen.tipo_error=schema_xml | Campos inválidos, tipo de documento | Agrupación automática |
| SoapFault del WS DNIT | sifen.operacion=soap_dnit | faultcode, faultstring, ambiente | Si >5 en 10 min: alerta |
| Chunk de lote fallido | sifen.operacion=lote_chunk | lote_id, chunk_size, intentos | Log en Horizon |
| Certificado expirado | sifen.tipo_error=cert_expirado | empresa_id, fecha_expiracion | Alerta 30 días antes |
#################### 8.2 Prometheus + Grafana — Métricas de Infraestructura
| Métrica Prometheus | Tipo | Query Grafana sugerido | Alerta si |
| sifen_soap_duration_seconds | Histogram | histogram_quantile(0.95, rate(...)) | p95 > 10 segundos |
| sifen_documentos_total{estado} | Counter | rate(...)[5m] por estado | Tasa rechazo > 5% |
| sifen_horizon_queue_size{cola} | Gauge | sifen_horizon_queue_size{cola='lotes'} | Cola lotes > 500 jobs |
| sifen_cert_expiry_days | Gauge | sifen_cert_expiry_days < 30 | Días para expiración < 30 |
| sifen_lote_duracion_minutos | Histogram | Duración promedio de lotes de TC | Lote > 25 minutos |
9. Hoja de Ruta de Desarrollo (Roadmap)
El roadmap está organizado en cinco fases que priorizan primero la automatización de los procesos manuales más críticos, luego la interfaz operativa completa, y finalmente la infraestructura de observabilidad y escalabilidad.
#################### Fase 1 — Fundación del Core (Semanas )
| Tarea | Responsable | Entregable | Criterio de Éxito |
| Scaffolding Laravel 12 + PostgreSQL + Redis | Backend Dev | Proyecto base funcional | Health check OK en /api/ping |
| Migración del schema sifen_db.sql a Eloquent Migrations | Backend Dev | 5 migraciones ejecutadas | php artisan migrate sin errores |
| Implementar CertificadoService (openssl_pkcs12_read) | Backend Dev | Carga segura de .p12 | Test unitario con cert real |
| Implementar XmlGeneradorService (DOM + XSD validation) | Backend Dev | XML válido contra siRecepDE_v150.xsd | Validación XSD pasa |
| Implementar XmlFirmadorService (xmlseclibs RSA-SHA256) | Backend Dev | XML firmado correctamente | validarFirmaDE() retorna true |
| Configurar Horizon con 3 colas (critica, lotes, sync) | Backend Dev | Workers corriendo en servidor | Dashboard Horizon accesible |
#################### Fase 2 — Automatización de Sincronización (Semanas )
| Tarea | Responsable | Entregable | Criterio de Éxito |
| Implementar SifenSoapService (recepcionDE, recepcionLoteDE, consultaDE) | Backend Dev | WS funcional en ambiente TEST | Respuesta 0260 desde DNIT test |
| Implementar SincronizarEstadosSifenJob (reemplaza .txt manual) | Backend Dev | Job corriendo en Scheduler | Estados actualizados sin intervención |
| Configurar Laravel Scheduler + cron en servidor | DevOps | Scheduler activo en Plesk/VPS | php artisan schedule:list muestra tareas |
| Actualizar WS de anulación a nueva versión de DL Informática | Backend Dev + DL | Nuevo endpoint de eventos activo | Cancelación e inutilización funcionales |
| Implementar Redis Cache Tags para estados de comprobantes | Backend Dev | TTL 30 min configurado | Cache hit >80% en consultas repetidas |
#################### Fase 3 — Interfaces Operativas Livewire (Semanas )
| Tarea | Responsable | Entregable | Criterio de Éxito |
| Componente MonitorLoteTarjetas con polling 3 seg | Frontend Dev | Barra de progreso en tiempo real | UI refleja progreso del lote sin recarga |
| Componente ComprobantesRechazados con reenvío masivo | Frontend Dev | Tabla filtrable + acción masiva | Reenvío de 100 DEs sin timeout de UI |
| Componente ControlIngresoSifen (50.000+ registros paginados) | Frontend Dev | Cruce Finansys vs SIFEN funcional | Carga de página < 2 segundos |
| Componentes de Cancelación e Inutilización con validaciones | Frontend Dev | Modales con validación previa | Motivo obligatorio bloqueante |
| Panel Filament v3: Empresa, Certificado, Usuario, Rol | Frontend Dev | Admin panel funcional | CRUD completo sin errores |
#################### Fase 4 — Monitoreo y Pruebas de Estrés (Semanas )
| Tarea | Responsable | Entregable | Criterio de Éxito |
| Instalar y configurar Sentry Self-Hosted | DevOps | Servidor Sentry operativo | Primer error capturado correctamente |
| Instrumentar código con context tags de Sentry | Backend Dev | Tags: operacion, tipo_error, ambiente | Error PKI visible en Sentry con contexto |
| Configurar Prometheus + exporters (php-fpm, redis, postgres) | DevOps | Métricas scrapeadas cada 15s | Dashboard Grafana con 5 paneles activos |
| Prueba de estrés: 4.500 comprobantes en ambiente TEST | QA + Backend | Informe de resultados | < 20 min total, 0 pérdidas de datos |
| Prueba de resiliencia: fallo de Redis a mitad del lote | QA | Jobs recuperados tras reinicio | 0 duplicados, 0 pérdidas tras recovery |
| Deploy en Plesk con Supervisor para Horizon | DevOps | Sistema en producción | Primer lote TC real procesado correctamente |
#################### Fase 5 — Escalabilidad a Futuro (A definir con dirección)
-
Containerización con Docker + Docker Compose: paridad total entre entornos dev y producción, eliminación de rutas de montaje manuales.
-
Kubernetes Gestionado (EKS/GKE/AKS): auto-scaling de workers Horizon durante picos de proceso masivo. Condición de adopción: >100.000 comprobantes/mes o equipo de 3+ devs.
-
Multi-empresa: soporte de múltiples RUCs y timbrados desde una única instancia de OC, con aislamiento por empresa_id.
-
API REST pública: exposición de endpoints autenticados (Laravel Sanctum) para integración de sistemas ERP de terceros.
-
Generación nativa de KuDE (PDF): eliminación de dependencia del portal de DL para descarga del comprobante imprimible.
10. Consideraciones de Seguridad
Por operar con documentos tributarios legales y certificados digitales, OnnixConnect OC aplica las siguientes medidas de seguridad de forma mandatoria:
| Aspecto | Medida Implementada | Justificación |
| Almacenamiento del .p12 | Base64 en columna TEXT cifrada. Nunca en filesystem público ni en repositorio. | Exposición del .p12 compromete la firma de todos los DEs emitidos |
| Claves del certificado | Cast 'encrypted' en Eloquent (AES-256-CBC con APP_KEY) | Cumplimiento con normativas de protección de datos |
| Variables de entorno | APP_KEY, DB_PASSWORD, REDIS_PASSWORD en .env del servidor — nunca en git | Estándar de la industria para secretos de aplicación |
| Endpoint /metrics | Restringido por IP whitelist (solo servidor Prometheus) | Las métricas pueden revelar patrones de uso del sistema |
| Laravel Telescope | Deshabilitado en producción o restringido a IPs del equipo dev | Telescope almacena payloads completos incluyendo datos de contribuyentes |
| Logs de Sentry | Nunca incluir contenido del .p12, claves o datos personales en el contexto | GDPR/Ley de protección de datos de Paraguay |
| Autenticación admin | Filament con autenticación Laravel + 2FA recomendado | Panel administrativo accede a configuración de certificados reales |
| Comunicación con WS | HTTPS obligatorio para ambiente de producción (sifen.set.gov.py) | Requerimiento técnico de la DNIT para producción |
Documento preparado por el Área de Arquitectura Técnica — Onnix Tecnología y Servicios SA
Versión 1.0 — OnnixConnect OC (Nombre en clave) — CONFIDENCIAL