4. Instalación del módulo e-CF¶
4.1. Estructura del módulo¶
accounting/
├── models.py # SaleInvoice, ECFSequence, EInvoiceReceived, etc.
├── ecf/
│ ├── __init__.py
│ ├── signing.py # firmar_ecf (XAdES-BES)
│ ├── validation.py # validar XSD oficial DGII
│ ├── dgii_client.py # token, envío, consulta TrackID
│ ├── qr.py # generar QR timbre fiscal
│ ├── receiver.py # parsear e-CF entrante + ACR
│ └── _xml.py # safe parser (XXE-safe)
├── services/
│ ├── sequence_service.py # asignar e-NCF transaccional
│ ├── tracking_service.py # poll TrackID
│ ├── receptor_validator.py # validar RNC contra Padrón
│ ├── error_classifier.py
│ └── dgii_versioning.py
└── ecf_dgii_endpoints.py # endpoints públicos que DGII llama
Modelos críticos (accounting/models.py):
SaleInvoicecon campos:ecf_tipo(E31/E32/E33/E34/E41/E43/E44/E45/E46/E47)ecf_ambiente(CERT/PROD)ecf_estado(BORRADOR → GENERADO → VALIDADO → FIRMADO → EN_COLA → ENVIADO → EN_PROCESO → ACEPTADO/RECHAZADO)ecf_encf(string E + 12 dígitos)ecf_trackid(UUID devuelto por DGII)ecf_xml_hash,ecf_intentos,ecf_fecha_envioECFSequence: rango DGII (numero_desde/numero_hasta),fecha_autorizacion/fecha_vencimiento,ambiente,activoECFEnvioDGII: bitácora inmutable (triggers SQL en migración0028_ecfenvio_immutable_triggers)EInvoiceReceived,ECFValidationError,ECFTrackingLog
4.2. Certificado digital DGII¶
DGII RD emite certificados a través de Cámara de Comercio de Santo Domingo (CCPSD) o Camara TC. Se entrega un archivo .p12 con clave privada + certificado público + cadena de confianza.
mkdir -p /opt/tienda/secrets
chown tienda:tienda /opt/tienda/secrets
chmod 700 /opt/tienda/secrets
# Subir el .p12 vía SCP:
scp ccpsd_130768021.p12 root@76.13.100.236:/opt/tienda/secrets/
# Permisos restrictivos
chown tienda:tienda /opt/tienda/secrets/ccpsd_130768021.p12
chmod 400 /opt/tienda/secrets/ccpsd_130768021.p12
Descargar cadena CCPSD (autoridad emisora):
cd /opt/tienda/secrets
wget https://digi.camarasantodomingo.do/CCPSD_cadena.crt
chmod 444 CCPSD_cadena.crt
Verificar contenido y vigencia:
openssl pkcs12 -in /opt/tienda/secrets/ccpsd_*.p12 -nokeys -info -passin pass:<PASSWORD>
# Buscar: "notAfter" — debe ser futura.
Buena práctica: rotar el certificado 30 días antes del vencimiento. Configurar un monitor (accounting/services/cert_monitor.py o cron) que alerte si quedan <60 días.
4.3. Variables .env DGII¶
Ya descritas en sección 3.3. Validación rápida:
cd /opt/tienda && set -a && . .env && set +a && source .venv/bin/activate && \
python manage.py ecf_validate_config
Este comando verifica:
- .p12 legible y con password correcto
- Vigencia certificado
- Cadena CCPSD presente
- ALLOWED_HOSTS incluye el FQDN
- SECRET_KEY no es de DEBUG
- Conectividad TCP a DGII
4.4. Carga de secuencias e-CF¶
DGII autoriza rangos numéricos para cada tipo de e-CF (ej. E31 desde 1 hasta 50000). Se cargan con:
from accounting.models import ECFSequence
from django.utils import timezone
from datetime import date
ECFSequence.objects.create(
tipo_encf="E31",
numero_desde=1,
numero_hasta=50000,
siguiente=1,
ambiente="CERT",
fecha_autorizacion=date(2026, 5, 7),
fecha_vencimiento=date(2027, 5, 7),
activo=True,
)
# Repetir para E32, E33, E34, E41, E43, E44, E45, E46, E47
Al pasar a PROD: crear nuevas filas con
ambiente="PROD"y los rangos PROD autorizados por DGII, y desactivar (activo=False) las de CERT.
4.5. Firma XAdES-BES con signxml¶
El módulo accounting/ecf/signing.py ya implementa la firma. Comprobaciones del estándar DGII:
- Algoritmo:
RSA-SHA256 - Canonicalización:
c14n exclusivo - Transformación:
enveloped-signature+c14n - KeyInfo: incluye certificado completo + cadena CCPSD
- Política: ETSI TS 101 903 v1.3.2 (XAdES-BES)
Test de firma manual:
from accounting.ecf.signing import firmar_ecf, cargar_certificado
cert = cargar_certificado()
xml_firmado = firmar_ecf("<ECF>...</ECF>", cert)
# Verificar con: xmlsec1 verify --pubkey-cert-pem <cert> <archivo.xml>
4.6. Generación XML conforme a XSD oficial¶
mkdir -p /opt/tienda/dgii_schemas
cd /opt/tienda/dgii_schemas
wget https://dgii.gov.do/.../eCF_v1.0.xsd # URL oficial DGII actual
Pipeline en el ERP:
generar_ecf_xml_oficial_base(invoice)
→ estructura conforme a XSD
validar_completo(xml)
→ lxml.etree validate contra XSD
firmar_ecf(xml, cert)
→ XAdES-BES
Validación CLI: