[DTP-Worker] Sprint 4 · Générateur configuration e-CF DGII (Compupar) (ERPNext Backend · roadmap L51)
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>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# 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/`](../../crm/workflow_vente/README.md),
|
||||
le DocType porteur [`../../crm/dossier_vente/`](../../crm/dossier_vente/README.md)
|
||||
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`](../../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`](../../crm/workflow_vente/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`](../../rbac/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
|
||||
|
||||
```bash
|
||||
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](ecf.schema.json). 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](fixtures/dossier_exemple.json) 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).
|
||||
Reference in New Issue
Block a user