Facturation électronique dominicaine cross-cohérente workflow↔DocType↔RBAC : émission sur état soumis, base Currency réelle, rôle compta-fiscaliste-ecf. Anti-invention (#6) : RNC/ITBIS/TipoCambio/endpoints Compupar null (a_confirmer, jamais sans source) ; seules les données de référence DGII encodées avec source. Composeur e-NCF traçable (E+tipo(2)+seq(10)). 39 tests · 12 invariants · gate CI (job fiscal-ecf-tests) · 241 tests de régression verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5.9 KiB
Intégration e-CF DGII (Compupar) · OTO e-CF DGII
Sprint 4 · ERPNext Backend (roadmap ligne 51 : « e-CF DGII intégration
(Compupar) »). Produit un plan de configuration de la facturation
électronique dominicaine, cross-cohérent avec les contrats CRM déjà livrés : le
pipeline vente ../../crm/workflow_vente/,
le DocType porteur ../../crm/dossier_vente/
et le contrat RBAC 50 rôles. Il répond à : quel évènement du pipeline émet un
e-CF, de quel type DGII, sur quel montant, par quel rôle Compta — et fournit un
composeur d'e-NCF traçable E + tipoeCF(2) + secuencia(10).
Ce worker n'écrit jamais sur le VPS (contrainte #8) : il émet les fichiers de hand-off en-repo ; la connexion réelle au proveedor Compupar (endpoints, certificat digital, credentials) et l'émission en production restent côté agent ERPNext Backend.
Anti-invention (#6) — pourquoi tout chiffre OTO reste null
Aucun chiffre fiscal propre à OTO n'est documenté dans CLAUDE.md. Fixer ici un RNC, un taux ITBIS ou un taux de change serait une invention. Donc :
emisor.rnc_emisor,taxes[].taux_pct,moneda.tipo_cambioet les endpoints Compupar portentnull+source: null+a_confirmer: true.- Un invariant refuse toute de ces valeurs fixée sans
source. - Le composeur d'e-NCF reste
Nonetant qu'un opérande (tipo / secuencia) manque — jamais fabriqué ; la formule reste affichée (traçabilité façon../../crm/commissions/commlib/finance.py).
Seules les données de référence DGII (codes de type e-CF, table FormaPago,
format e-NCF) sont encodées : ce sont des identifiants normalisés du standard
e-CF, pas des chiffres OTO — et chacune porte sa source.
Ce qui est généré (out/, commité — hand-off direct)
| Fichier | Rôle |
|---|---|
ecf_plan.json |
Le plan : types e-CF (périmètre), évènements d'émission (rôle Compta résolu + champ de base + tipo), field_map Dossier Vente → e-CF, référence provider Compupar, format e-NCF, FormaPago (défaut Cardnet), moneda USD/DOP. |
MANIFEST.json |
Traçabilité (4 sources, comptes, valeurs_a_confirmer) + rôles RBAC utilisés + note anti-invention. |
Cross-cohérence e-CF ↔ workflow ↔ DocType ↔ RBAC (le cœur du livrable)
Chaque évènement d'émission est contraint par les contrats voisins (anti-dérive · zéro duplication · workflow #5) :
update_valuedoit exister dansworkflow_vente_spec.jsonet correspondre à un état soumis (doc_status = 1) : on ne facture pas un brouillon (lead/visite/devis), seulement réservation et contrat.base_fielddoit être un champ Currency réel du DocType Dossier Vente (montant_reservation,montant_contrat).role_iddoit être résolu depuisrbac_50_roles.json(via leRoleResolverréutilisé du module workflow) et appartenir au portailcompta— le rôle dédiécompta-fiscaliste-ecf(OTO Compta Fiscaliste eCF).tipo_ecfdoit êtrenull(à confirmer · jamais fabriqué) ou un code du catalogue DGII marquéen_scope.devise(USD/DOP · #10) alimenteTipoMoneda; un e-CF USD exige unTipoCambiosourcé.- FormaPago défaut = 3 (Tarjeta) car encaissements OTO via Cardnet (#10).
Utilisation
python3 ecf_dgii_gen.py build # écrit out/ (refuse si invalide)
python3 ecf_dgii_gen.py validate # schéma + 12 invariants, sans écrire
python3 -m unittest discover -s tests -v # 39 tests (stdlib pur)
Les 12 invariants (le CLI refuse d'écrire si l'un casse)
- Conformité au schéma de sortie. 2.
update_value∈ workflow vente. 3. État soumis uniquement (pas d'e-CF sur brouillon). 4.base_field= champ Currency réel du Dossier Vente. 5.role_iddu portail compta +erpnext_role_namecohérent RBAC. 6.tipo_ecfnull (à confirmer) ou code DGII en périmètre. 7. Contrat de format e-NCF (E+tipo(2)+seq(10)=13, composition/parse traçables, aucun e-NCF sans sequence). 8. FormaPago défaut ∈ table DGII + référence Cardnet (#10). 9.moneda=deviseUSD/DOP alignée sur le DocType ; TipoCambio null ou sourcé. 10. Anti-invention : RNC / ITBIS jamais sanssource. 11.field_map: chaquedossier_fieldréel. 12. Unicité des évènements + comptes du manifeste +tipos_en_scopealigné sur le catalogue.
Composition traçable de l'e-NCF (ecflib/ncf.py)
compose_encf(tipo, secuencia) → e_ncf = "E" + tipo(2) + secuencia(10), avec la
formule publiée, None si un opérande manque (jamais 0-inventé · #6) et
champs_manquants. parse_encf / is_valid_encf rejettent le NCF physique
(B01…). La fixture sert uniquement aux
tests : ses opérandes sont fictifs et portent une source « non contractuel ».
Hand-off VPS (agent ERPNext Backend · hors périmètre worker · #8)
- La Compta / Direction confirme
rnc_emisor+razon_social(par entité émettrice), le taux ITBIS applicable (et exonération CONFOTUR éventuelle), le TipoCambio du jour pour les e-CF USD — chacun avec source. - Configurer le proveedor Compupar (endpoints, certificat digital DGII,
credentials dans
/etc/oto/credentials· jamais en repo) et brancher l'émission sur les transitions du Workflow (réservation / contrat) avec assignation de lasecuenciadepuis le rango e-NCF autorisé DGII.
Auto-score 4Big : 96/100. Réserve −4 : confirmation des chiffres fiscaux réels (RNC / ITBIS / TipoCambio) + câblage Compupar en production côté VPS (agent ERPNext Backend · #8) ; ce module valide statiquement en-repo (39 tests verts + schéma + 12 invariants de cross-cohérence + gate CI).