REPORT: Auditoría de Campos — Manual Técnico SIFEN v150 vs Código
Fecha: 2026-03-18 Fuente manual:
camposformatosv150.pdf(Tabla de Formato de Campos, páginas 62-80) Archivos auditados:SifenXmlBuilder.php,app/Domains/Sifen/Enums/
1. Tabla Comparativa — Campos Críticos
Sección A — Campos firmados del DE
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| A002 | Id (atributo DE) | A, 44 chars, CDC | CDC de 44 chars, setIdAttribute('Id', true) | ✅ |
| A003 | dDVId | N, 1 — Módulo 11 | substr($dte->cdc, 43, 1) | ✅ |
| A004 | dFecFirma | F, 19, AAAA-MM-DDThh:mm:ss, anterior a transmisión | now()->setTimezone('America/Asuncion')->format('Y-m-d\TH:i:s') | ✅ |
| A005 | dSisFact | N, 1 — 1=Sistema contribuyente, 2=SIFEN solución gratuita | hardcoded '1' | ✅ |
Sección B — Operación del DE
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| B002 | iTipEmi | N, 1, 1-1 — 1=Normal, 2=Contingencia | hardcoded '1' | ✅ |
| B003 | dDesTipEmi | A, 6-12, 1-1 | match: "Normal" para 1 | ✅ |
| B004 | dCodSeg | N, 9, 1-1, generado aleatoriamente por emisor | $dte->cdc posiciones 34-42 (9 dígitos) | ✅ |
Sección C — Datos del Timbrado
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| C002 | iTiDE | N, 1-2, 1-1 — 1=Factura...8=Comprobante retención | extraído del CDC pos 0-1 | ✅ |
| C003 | dDesTiDE | A, 15-40, 1-1 — texto referente a C002 | match($iTiDE): "Factura electrónica", etc. | ✅ |
| C004 | dNumTim | N, 8, 1-1 | $config['timbrado'] = 80126006 | ✅ |
| C005 | dEst | A, 3, 1-1 — pad con ceros | substr($cdc, 11, 3) = "001" | ✅ |
| C006 | dPunExp | A, 3, 1-1 — pad con ceros | substr($cdc, 14, 3) = "001" | ✅ |
| C007 | dNumDoc | A, 7, 1-1 — pad con ceros, empezar desde 1 | substr($cdc, 17, 7) = 7 dígitos | ✅ |
| C010 | dSerieNum | A, 2, 0-1 — solo cuando numeración agotada | solo emitido si $dte->serie_timbrado no vacío | ✅ |
| C008 | dFeIniT | F, 10, 1-1 — AAAA-MM-DD | $config['fecha_inicio_timbrado'] = "2025-01-01" | ✅ |
| C009 | dFeFInT | F, 10, destacado en rojo = comentado en XSD v150 | NO emitido (comentado en XSD v150) | ✅ |
Sección D1 — Operación Comercial (gOpeCom)
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| D010 | gOpeCom | G, 0-1 — Obligatorio si C002≠7 | siempre emitido para facturas (C002=1) | ✅ |
| D011 | iTipTra | N, 1-2, 0-1 — Obligatorio si C002=1 o 4 | $config['tipo_transaccion'] = 2 ("Prestación de servicios") | ✅ |
| D012 | dDesTipTra | A, 5-36, 0-1 | match($tipTra) — "Prestación de servicios" | ✅ |
| D013 | iTImp | N, 1, 1-1 — 1=IVA | hardcoded '1' | ✅ |
| D014 | dDesTImp | A, 3-11, 1-1 | hardcoded 'IVA' | ✅ |
| D015 | cMoneOpe | A, 3, 1-1 — ISO 4217 | $moneda = 'PYG' | ✅ |
| D016 | dDesMoneOpe | A, 3-20, 1-1 | 'Guarani' para PYG | ✅ |
| D017 | dCondTiCam | N, 0-1 — Obligatorio si D015≠PYG | solo emitido si moneda≠PYG | ✅ |
| D018 | dTiCam | N, 0-1 — No informar si D015=PYG | solo emitido si moneda≠PYG | ✅ |
Sección D2 — Datos del Emisor (gEmis)
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| D101 | dRucEm | A, 3-8, 1-1 | $emitter->ruc = "80126006" | ✅ |
| D102 | dDVEmi | N, 1, 1-1 — Módulo 11 | $emitter->dv = "0" | ✅ |
| D103 | iTipCont | N, 1, 1-1 — 1=Persona Física, 2=Persona Jurídica | substr($dte->cdc, 24, 1) = "2" | ✅ |
| D105 | dNomEmi | A, 4-255 — en TEST: literal obligatorio | $emitter->razon_social | ✅ FIXED |
| D106 | dNomFanEmi | A, 4-255, 0-1 | $emitter->nombre_fantasia ?? $emitter->razon_social | ✅ |
| D107 | dDirEmi | A, 1-255, 1-1 | $config['direccion'] = "BELGICA Y GUIDO SPANO" | ✅ |
| D108 | dNumCas | N, 1-6, 1-1 — 0 si no tiene | $config['numero_casa'] = 0 | ✅ |
| D111 | cDepEmi | N, 1-2, 1-1 — XSD Departamentos | $config['departamento'] = "1" (CAPITAL) | ✅ |
| D112 | dDesDepEmi | A, 6-16, 1-1 | $config['descripcion_departamento'] = "CAPITAL" | ✅ |
| D113 | cDisEmi | N, 1-4, 0-1 | $config['codigo_distrito'] = "1" | ✅ |
| D115 | cCiuEmi | N, 1-5, 1-1 | $config['codigo_ciudad'] = "1" | ✅ |
| D116 | dDesCiuEmi | A, 1-30, 1-1 | $config['descripcion_ciudad'] = "ASUNCION (DISTRITO)" | ✅ |
| D117 | dTelEmi | A, 6-15, 1-1 — incluir prefijo ciudad | $config['telefono'] = "0974111000" (10 chars) | ✅ |
| D118 | dEmailE | A, 3-80, 1-1 | $config['email'] = "INFO@ONNIX.COM.PY" | ✅ |
| D130 | gActEco | G, 1-9 — OBLIGATORIO mínimo 1 | array de actividades en config | ✅ |
| D131 | cActEco | A, 1-8, 1-1 | $actividad['codigo'] | ✅ |
| D132 | dDesActEco | A, 1-300, 1-1 — con tildes | $actividad['descripcion'] (tildes restauradas) | ✅ |
Sección D3 — Datos del Receptor (gDatRec)
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| D201 | iNatRec | N, 1, 1-1 — 1=contribuyente, 2=no contribuyente | desde $dte->tipo_receptor (naturaleza) | ✅ |
| D202 | iTiOpe | N, 1, 1-1 — 1=B2B, 2=B2C, 3=B2G, 4=B2F | $config['tipo_operacion'] = 1 (B2B) | ✅ |
| D203 | cPaisRec | A, 3, 1-1 — XSD Países | hardcoded 'PRY' | ✅ |
| D204 | dDesPaisRe | A, 4-30, 1-1 | hardcoded 'Paraguay' | ✅ |
| D205 | iTiContRec | N, 0-1 — Obligatorio si D201=1 | $dte->cliente_tipo_contribuyente ?? 1 | ✅ |
| D206 | dRucRec | A, 3-8, 0-1 — Obligatorio si D201=1 | extraído de cliente_documento (RUC-DV format) | ✅ |
| D207 | dDVRec | N, 1, 0-1 — Módulo 11 | extraído de cliente_documento | ✅ |
| D211 | dNomRec | A, 4-255, 1-1 | $dte->cliente_nombre | ✅ |
| D213 | dDirRec | A, 0-1 — Obligatorio si C002=1 o D202=4 | OMITIDO (requiere cDepRec+cCiuRec) | ⚠️ Ver nota |
| D218 | dNumCasRec | N, 0-1 — Obligatorio si D213 presente | OMITIDO | ✅ (consistente con D213) |
| D216 | dEmailRec | A, 3-80, 0-1 | $dte->cliente_email | ✅ |
⚠️ Nota D213
dDirRec: El manual dice que es obligatorio cuando C002=1 (Factura). Sin embargo requiere tambiéncDepRec+cCiuRec+dNumCasRec. Nuestro modelo no almacena estos campos del receptor. Impacto potencial pendiente de verificar con SIFEN.
Sección E1 — Campos de la Factura Electrónica (gCamFE)
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| E010 | gCamFE | G, 0-1 — Obligatorio si C002=1 | siempre emitido para facturas | ✅ |
| E011 | iIndPres | N, 1, 1-1 — 2=Operación electrónica | hardcoded '2' | ✅ |
| E012 | dDesIndPres | A, 10-30, 1-1 | hardcoded 'Operación electrónica' | ✅ |
| E013 | dFecEmNR | F, 10, 0-1 — solo nota de remisión (C002=7) | OMITIDO para facturas | ✅ |
Sección E7 — Condición de Pago (gCamCond)
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| E600 | gCamCond | G, 0-1 — Obligatorio si C002=1 o 4 | emitido para facturas | ✅ |
| E601 | iCondOpe | N, 1, 1-1 — 1=Contado, 2=Crédito | $dte->condicion_venta | ✅ |
| E602 | dDCondOpe | A, 7, 1-1 — "Contado" o "Crédito" | match($condicion_venta) | ✅ |
| E605 | gPaConEIni | G, 0-999 — Obligatorio si E601=1 | emitido cuando contado | ✅ |
Sección G — gCamGen
| ID | Campo | Manual | Código | Estado |
|---|---|---|---|---|
| G | gCamGen | G, minOccurs=0 — todos hijos opcionales | ELIMINADO (Regla 5 PDF: no emitir vacíos opcionales) | ✅ FIXED |
2. Discrepancias Detectadas y Fixes Aplicados
🔴 CRÍTICO — Fix aplicado
FIX-AUDIT-01: dNomEmi en ambiente de prueba
- Campo: D105
dNomEmi - Manual: En ambiente TEST, debe contener obligatoriamente el literal
"DE generado en ambiente de prueba - sin valor comercial ni fiscal" - Antes:
$emitter->razon_social="ONNIX TECNOLOGÍA Y SERVICIOS S.A." - Después:
$isTest = ($emitter->ambiente === AmbienteEmision::TEST);
$this->appendText($gEmis, 'dNomEmi',
$isTest
? 'DE generado en ambiente de prueba - sin valor comercial ni fiscal'
: $emitter->razon_social
);
- Impacto: MUY ALTO — SIFEN valida este literal en test y rechaza con 0160 si no coincide.
FIX-AUDIT-02: <gCamGen/> vacío emitido incorrectamente
- Campo:
gCamGen(minOccurs=0 en XSD, todos los hijos también 0) - Manual/Guía: Regla 5 — no emitir tags vacíos de elementos opcionales
- Antes:
$DE->appendChild($this->dom->createElementNS(self::NS, 'gCamGen')); - Después: Removido completamente
- Impacto: ALTO — tag vacío opcional causa 0160 "XML Mal Formado".
3. Puntos Pendientes de Validar
⚠️ dDirRec (D213) — Potencialmente obligatorio para facturas
- Manual D213: "Campo obligatorio cuando C002=1 o cuando D202=4"
- C002=1 = Factura electrónica ← nuestro caso
- Actualmente OMITIDO porque requiere cDepRec+cCiuRec que no tenemos en DB
- Opciones: a. Almacenar departamento/ciudad del receptor en el modelo SifenDte y pasarlos en el request b. Si SIFEN acepta la factura sin dDirRec cuando el receptor es contribuyente con RUC válido
⚠️ Enums — Verificar valores vs manual
| Enum | Campo | Valores manual | Estado |
|---|---|---|---|
TipoDocumentoElectronico | C002 iTiDE | 1-8 (2,3,8 = Futuro) | Verificar que no incluya tipos futuros |
NaturalezaReceptor | D201 iNatRec | 1=contribuyente, 2=no contribuyente | ✅ |
TipoDocumentoReceptor | D208 iTipIDRec | 1,2,3,4,5,6(Futuro),9 | Verificar 6=Tarjeta Diplomática |
CondicionVenta | E601 iCondOpe | 1=Contado, 2=Crédito | ✅ |
4. Estado post-fixes
| Fix | Descripción | Resultado esperado |
|---|---|---|
| FIX-AUDIT-01 | dNomEmi = literal test | SIFEN acepta el nombre del emisor |
| FIX-AUDIT-02 | Remover <gCamGen/> vacío | Elimina tag inválido per Regla 5 |
| Fix previo | Remover dDirRec/dNumCasRec sin cDep/cCiu | Elimina campo invalido |
| Fix previo | Totales desde $dte->items | Consistencia matemática garantizada |
| Fix previo | iTiContRec dinámico | Tipo contribuyente correcto S.R.L.=2 |
| Fix previo | Remover dFecEmNR para facturas | Campo solo para nota de remisión |
| Fix previo | dDVRec con formato RUC-DV | DV receptor correcto |
Tests: 95 pasando ✅