Files
Claude Code DTP Worker ee421add1d [DTP-Worker] Sprint 8 · buffer · Fiscal/ecf_dgii : le JEU DE DEVISES moneda (USD/DOP) ANCRÉ sur CLAUDE.md #10
Le champ que `Encabezado.TipoMoneda` porte dans chaque e-CF DGII —
`moneda.options = ["USD","DOP"]` — vit dans `ecf_spec.json` ET, byte-gaté par
check_artifacts, dans `out/ecf_plan.json`. C'est une valeur CANONIQUE de CLAUDE.md
#10 (« **USD + DOP** devises ») dont le README se réclame « #10 » (README:37/57/77).
Or byte-gater une constante prouve la REPRODUCTIBILITÉ, PAS l'ANCRAGE :
check_artifacts prouve ecf_plan==build depuis le spec, JAMAIS que spec[moneda]==#10.
Les blocs fiscaux amont gatent le FormaPago (Cardnet · #10) + états/champs
émetteurs, AVEUGLES au jeu de devises ; le bloc « Fiches #10 » ancre les fiches
ERPNext/CRM, AVEUGLE au module fiscal.

Piège #6 : RENOMMER/ÉTENDRE les devises dans CLAUDE.md #10 (`USD + DOP`→`USD + EUR`,
ou +`EUR`) ET dans le spec de façon cohérente reste byte-VERT tout en faisant
émettre à l'e-CF un `TipoMoneda` d'une devise qui CONTREDIT le mandat — « vert
trompeur » de la classe de la marque SEO §Entités, la persona Chat OTOIA ou les
tokens branding #4, qu'aucune suite tests/ (FONCTIONS de génération, jamais l'ancre
à CLAUDE.md) n'attrape. L'agent ERPNext Backend câblerait TipoMoneda hors mandat.

Correctif de déclaration : nouveau champ `moneda.options_source` (ecf_spec.json +
requis dans ecf.schema.json) citant « CLAUDE.md #10 — devises **USD + DOP** »,
DISTINCT de `source` (taux TipoCambio, reste null/a_confirmer côté VPS · #8).
Artefact régénéré (byte-gate re-verte · 39 tests module verts).

Gate ajouté (ci/check_readme_claims.sh, bloc « Fiscal · ecf_dgii — le JEU DE
DEVISES `moneda` … ANCRÉ sur CLAUDE.md #10 ») : RÉUTILISE exp["devises"] déjà
recomputé depuis #10 (zéro duplication) ; (a) spec[moneda].options == devises #10
ORDRE exact ; (b) artefact byte-gaté idem ; (c) options_source cite CLAUDE.md #10 +
chaque devise ; (d) prose README qui se réclame de #10 == jeu exact + toute mention
moneda/devise d'une paire concordante (scan ancré sur contexte, évite le faux
positif `RNC / ITBIS`). 7 morsures vérifiées (CLAUDE.md #10 rename = 4 bites en
cascade · spec options régénéré = le vrai silent green · artefact seul · reorder ·
options_source sans ancre · README ligne #10 · README table), restauré vert, 7
gates re-verts.

ci/README.md (clause récap + paragraphe « 4e surface du MÊME README ») mis à jour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-01 07:43:29 +00:00
..

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_cambio et les endpoints Compupar portent null + source: null + a_confirmer: true.
  • Un invariant refuse toute de ces valeurs fixée sans source.
  • Le composeur d'e-NCF reste None tant 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_value doit exister dans workflow_vente_spec.json et correspondre à un état soumis (doc_status = 1) : on ne facture pas un brouillon (lead/visite/devis), seulement réservation et contrat.
  • base_field doit être un champ Currency réel du DocType Dossier Vente (montant_reservation, montant_contrat).
  • role_id doit être résolu depuis rbac_50_roles.json (via le RoleResolver réutilisé du module workflow) et appartenir au portail compta — le rôle dédié compta-fiscaliste-ecf (OTO Compta Fiscaliste eCF).
  • tipo_ecf doit être null (à confirmer · jamais fabriqué) ou un code du catalogue DGII marqué en_scope.
  • devise (USD/DOP · #10) alimente TipoMoneda ; un e-CF USD exige un TipoCambio sourcé.
  • 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)

  1. 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_id du portail compta + erpnext_role_name cohérent RBAC. 6. tipo_ecf null (à 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 = devise USD/DOP alignée sur le DocType ; TipoCambio null ou sourcé. 10. Anti-invention : RNC / ITBIS jamais sans source. 11. field_map : chaque dossier_field réel. 12. Unicité des évènements + comptes du manifeste + tipos_en_scope aligné 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)

  1. 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.
  2. 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 la secuencia depuis 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).