Saltar al contenido principal

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

IDCampoManualCódigoEstado
A002Id (atributo DE)A, 44 chars, CDCCDC de 44 chars, setIdAttribute('Id', true)
A003dDVIdN, 1 — Módulo 11substr($dte->cdc, 43, 1)
A004dFecFirmaF, 19, AAAA-MM-DDThh:mm:ss, anterior a transmisiónnow()->setTimezone('America/Asuncion')->format('Y-m-d\TH:i:s')
A005dSisFactN, 1 — 1=Sistema contribuyente, 2=SIFEN solución gratuitahardcoded '1'

Sección B — Operación del DE

IDCampoManualCódigoEstado
B002iTipEmiN, 1, 1-1 — 1=Normal, 2=Contingenciahardcoded '1'
B003dDesTipEmiA, 6-12, 1-1match: "Normal" para 1
B004dCodSegN, 9, 1-1, generado aleatoriamente por emisor$dte->cdc posiciones 34-42 (9 dígitos)

Sección C — Datos del Timbrado

IDCampoManualCódigoEstado
C002iTiDEN, 1-2, 1-1 — 1=Factura...8=Comprobante retenciónextraído del CDC pos 0-1
C003dDesTiDEA, 15-40, 1-1 — texto referente a C002match($iTiDE): "Factura electrónica", etc.
C004dNumTimN, 8, 1-1$config['timbrado'] = 80126006
C005dEstA, 3, 1-1 — pad con cerossubstr($cdc, 11, 3) = "001"
C006dPunExpA, 3, 1-1 — pad con cerossubstr($cdc, 14, 3) = "001"
C007dNumDocA, 7, 1-1 — pad con ceros, empezar desde 1substr($cdc, 17, 7) = 7 dígitos
C010dSerieNumA, 2, 0-1 — solo cuando numeración agotadasolo emitido si $dte->serie_timbrado no vacío
C008dFeIniTF, 10, 1-1 — AAAA-MM-DD$config['fecha_inicio_timbrado'] = "2025-01-01"
C009dFeFInTF, 10, destacado en rojo = comentado en XSD v150NO emitido (comentado en XSD v150)

Sección D1 — Operación Comercial (gOpeCom)

IDCampoManualCódigoEstado
D010gOpeComG, 0-1 — Obligatorio si C002≠7siempre emitido para facturas (C002=1)
D011iTipTraN, 1-2, 0-1 — Obligatorio si C002=1 o 4$config['tipo_transaccion'] = 2 ("Prestación de servicios")
D012dDesTipTraA, 5-36, 0-1match($tipTra) — "Prestación de servicios"
D013iTImpN, 1, 1-1 — 1=IVAhardcoded '1'
D014dDesTImpA, 3-11, 1-1hardcoded 'IVA'
D015cMoneOpeA, 3, 1-1 — ISO 4217$moneda = 'PYG'
D016dDesMoneOpeA, 3-20, 1-1'Guarani' para PYG
D017dCondTiCamN, 0-1 — Obligatorio si D015≠PYGsolo emitido si moneda≠PYG
D018dTiCamN, 0-1 — No informar si D015=PYGsolo emitido si moneda≠PYG

Sección D2 — Datos del Emisor (gEmis)

IDCampoManualCódigoEstado
D101dRucEmA, 3-8, 1-1$emitter->ruc = "80126006"
D102dDVEmiN, 1, 1-1 — Módulo 11$emitter->dv = "0"
D103iTipContN, 1, 1-1 — 1=Persona Física, 2=Persona Jurídicasubstr($dte->cdc, 24, 1) = "2"
D105dNomEmiA, 4-255 — en TEST: literal obligatorio$emitter->razon_socialCORREGIDO✅ FIXED
D106dNomFanEmiA, 4-255, 0-1$emitter->nombre_fantasia ?? $emitter->razon_social
D107dDirEmiA, 1-255, 1-1$config['direccion'] = "BELGICA Y GUIDO SPANO"
D108dNumCasN, 1-6, 1-1 — 0 si no tiene$config['numero_casa'] = 0
D111cDepEmiN, 1-2, 1-1 — XSD Departamentos$config['departamento'] = "1" (CAPITAL)
D112dDesDepEmiA, 6-16, 1-1$config['descripcion_departamento'] = "CAPITAL"
D113cDisEmiN, 1-4, 0-1$config['codigo_distrito'] = "1"
D115cCiuEmiN, 1-5, 1-1$config['codigo_ciudad'] = "1"
D116dDesCiuEmiA, 1-30, 1-1$config['descripcion_ciudad'] = "ASUNCION (DISTRITO)"
D117dTelEmiA, 6-15, 1-1 — incluir prefijo ciudad$config['telefono'] = "0974111000" (10 chars)
D118dEmailEA, 3-80, 1-1$config['email'] = "INFO@ONNIX.COM.PY"
D130gActEcoG, 1-9 — OBLIGATORIO mínimo 1array de actividades en config
D131cActEcoA, 1-8, 1-1$actividad['codigo']
D132dDesActEcoA, 1-300, 1-1 — con tildes$actividad['descripcion'] (tildes restauradas)

Sección D3 — Datos del Receptor (gDatRec)

IDCampoManualCódigoEstado
D201iNatRecN, 1, 1-1 — 1=contribuyente, 2=no contribuyentedesde $dte->tipo_receptor (naturaleza)
D202iTiOpeN, 1, 1-1 — 1=B2B, 2=B2C, 3=B2G, 4=B2F$config['tipo_operacion'] = 1 (B2B)
D203cPaisRecA, 3, 1-1 — XSD Paíseshardcoded 'PRY'
D204dDesPaisReA, 4-30, 1-1hardcoded 'Paraguay'
D205iTiContRecN, 0-1 — Obligatorio si D201=1$dte->cliente_tipo_contribuyente ?? 1
D206dRucRecA, 3-8, 0-1 — Obligatorio si D201=1extraído de cliente_documento (RUC-DV format)
D207dDVRecN, 1, 0-1 — Módulo 11extraído de cliente_documento
D211dNomRecA, 4-255, 1-1$dte->cliente_nombre
D213dDirRecA, 0-1 — Obligatorio si C002=1 o D202=4OMITIDO (requiere cDepRec+cCiuRec)⚠️ Ver nota
D218dNumCasRecN, 0-1 — Obligatorio si D213 presenteOMITIDO✅ (consistente con D213)
D216dEmailRecA, 3-80, 0-1$dte->cliente_email

⚠️ Nota D213 dDirRec: El manual dice que es obligatorio cuando C002=1 (Factura). Sin embargo requiere también cDepRec + 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)

IDCampoManualCódigoEstado
E010gCamFEG, 0-1 — Obligatorio si C002=1siempre emitido para facturas
E011iIndPresN, 1, 1-1 — 2=Operación electrónicahardcoded '2'
E012dDesIndPresA, 10-30, 1-1hardcoded 'Operación electrónica'
E013dFecEmNRF, 10, 0-1 — solo nota de remisión (C002=7)OMITIDO para facturas

Sección E7 — Condición de Pago (gCamCond)

IDCampoManualCódigoEstado
E600gCamCondG, 0-1 — Obligatorio si C002=1 o 4emitido para facturas
E601iCondOpeN, 1, 1-1 — 1=Contado, 2=Crédito$dte->condicion_venta
E602dDCondOpeA, 7, 1-1 — "Contado" o "Crédito"match($condicion_venta)
E605gPaConEIniG, 0-999 — Obligatorio si E601=1emitido cuando contado

Sección G — gCamGen

IDCampoManualCódigoEstado
GgCamGenG, minOccurs=0 — todos hijos opcionalesELIMINADO (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

EnumCampoValores manualEstado
TipoDocumentoElectronicoC002 iTiDE1-8 (2,3,8 = Futuro)Verificar que no incluya tipos futuros
NaturalezaReceptorD201 iNatRec1=contribuyente, 2=no contribuyente
TipoDocumentoReceptorD208 iTipIDRec1,2,3,4,5,6(Futuro),9Verificar 6=Tarjeta Diplomática
CondicionVentaE601 iCondOpe1=Contado, 2=Crédito

4. Estado post-fixes

FixDescripciónResultado esperado
FIX-AUDIT-01dNomEmi = literal testSIFEN acepta el nombre del emisor
FIX-AUDIT-02Remover <gCamGen/> vacíoElimina tag inválido per Regla 5
Fix previoRemover dDirRec/dNumCasRec sin cDep/cCiuElimina campo invalido
Fix previoTotales desde $dte->itemsConsistencia matemática garantizada
Fix previoiTiContRec dinámicoTipo contribuyente correcto S.R.L.=2
Fix previoRemover dFecEmNR para facturasCampo solo para nota de remisión
Fix previodDVRec con formato RUC-DVDV receptor correcto

Tests: 95 pasando ✅