Files
..

Financement Bancaire · parcours hypothécaire immobilier RD

Sprint 4 · CRM natif ERPNext · roadmap L52 (workflow vente end-to-end · volet financement). Matérialise la DIRECTIVE_FINANCEMENT_BANCAIRE_COMPLET_20260803.md (Michel, 2026-08-03) : un module complet de financement bancaire pour un vrai parcours hypothécaire dominicain, à la place du module « trop simpliste » antérieur. Livrable Phase 1 (P0 · MVP) : le contrat de données + le cœur métier du gate check + la structure des 7 sections + la bannière critique.

Ce worker n'écrit jamais sur le VPS (contrainte #8). Il produit le contrat et les artefacts en-repo ; le backend /api/hypotheque/* et le frontend renderHypotheque réels sont appliqués côté serveur (agents ERPNext Backend / Frontend Console). La Phase 2 (vrais formulaires PDF des 6 banques) attend les démarches relationship-manager de Michel — hors périmètre worker.

Le cœur du livrable · le gate check 4 conditions

L'exigence non-négociable de Michel : aucun document n'est transmis à la banque tant que les 4 conditions ne sont pas remplies. La logique vit dans finlib/gate.py — fonctions pures, testées, sans I/O :

# Condition (key) Règle vérifiée
1 apport_initial_complet Σ paiements ≥ prix × taux20 % résident RD · 30 % étranger (amendement Michel · aussi exigence des banques RD · Ley 189-11).
2 documents_exiges Tous les documents is_required de la banque choisie au statut « Validé WAG » ou « Envoyé banque ».
3 autorisations_signees Toutes les autorisations signées (signature_date non nulle).
4 validation_wag Un conseiller WAG référent a validé (wag_validated_by).
from finlib import gate
cfg = gate.GateConfig.from_spec(spec)
ok, reasons = gate.can_submit_dossier(dossier, cfg)   # (False, ["Apport initial incomplet : …", …])
status = gate.gate_status(dossier, cfg)               # forme de l'endpoint gate-status (barres 0-100 %)

Si une condition manque, can_submit est False et reasons liste chaque blocage (ordre canonique). Le backend POST /…/submit doit renvoyer 403 + ces raisons ; le frontend grise le bouton « Envoyer à la banque » et affiche une barre de progression par condition. Tant que l'apport initial est incomplet, toutes les sections aval sont grisées (section apport_initial = seule section gating, en position 1).

Ce qui est généré (out/, commité — hand-off direct)

Fichier Contenu
banques.json Profils des banques partenaires (type, taux/LTV/durée, spécialités, devises).
sections.json Structure accordéon (apport → info achat → choix banque → formulaires → exigences → autorisations → envoi).
documents.json Catalogue des documents exigés par catégorie (client / immobilier / étrangers).
autorisations.json Autorisations à signer (OTO Sign) + base légale.
gate_spec.json Les 4 conditions + bannière critique + endpoints + rôle validation résolu + workflow suivi banque.
gate_status_example.json Exemple calculé (dossier P07 volontairement bloqué) — auditable, jamais fabriqué.
MANIFEST.json Traçabilité (sources, comptes dérivés, rôles RBAC utilisés).

Comptes courants (source de vérité = MANIFEST.json) : 6 banques, 7 sections, 15 documents (requis 9 résident · 13 étranger), 4 autorisations, 4 conditions de gate.

Anti-invention (#6)

  • Aucun taux d'apport codé en dur : 20/30 viennent du contrat (apport.residence_types), sourcés de la DIRECTIVE. Changer le contrat change le gate, sans toucher au code.
  • Aucun taux/LTV bancaire fabriqué : les fourchettes non données par la DIRECTIVE restent null (a_confirmer · démarche relationship manager). Seules les valeurs que la DIRECTIVE énonce (ex. Scotiabank LTV 70 %, BHD León 30 ans) sont encodées.
  • Aucun nom de rôle Frappe en dur : les rôles (ventes-conseiller pour la validation WAG, etc.) sont résolus depuis rbac_50_roles.json via finlib/rbac.py (source unique · zéro duplication · #5).

Validation · schéma + 12 invariants

validate re-génère le bundle en mémoire et vérifie le schéma de sortie (financement.schema.json) plus 12 invariants métier (unicité des ids ; 0 < résident < étranger ≤ 100 ; fourchettes banque min ≤ max ; rôles résolus dans RBAC ; sections contiguës + section gating en tête ; gate = 4 conditions alignées sur la bannière ; documents étrangers strictement additionnels ; statuts recevables ⊆ statuts ; exemple de gate recalculé cohérent ; comptes du manifeste cohérents). Un invariant qui casse refuse le build (anti-régression).

Utilisation

cd 05_deliverables_mvp/crm/financement_bancaire
python3 financement_bancaire_gen.py validate      # schéma + 12 invariants
python3 financement_bancaire_gen.py build          # écrit les 7 artefacts out/
python3 -m unittest discover -s tests -v           # suite (gate + générateur)

Sortie déterministe (tri stable, aucun horodatage) → l'artefact commité est reproductible bit-à-bit et vérifié par ci/check_artifacts.sh.

Endpoints backend visés (Phase 1 · à implémenter côté serveur)

Contrat exposé par gate_spec.json :

  • GET /api/hypotheque/banques · profils banques (⇐ banques.json)
  • GET /api/hypotheque/dossier/{id}/gate-status · état des 4 conditions (forme de gate_status_example.json)
  • POST /api/hypotheque/dossier/{id}/submit · 403 + raisons tant que le gate n'est pas vert
  • GET /api/hypotheque/dossier/{id}/journal · historique horodaté

Périmètre

  • Phase 1 (ce module) : contrat, gate check, sections, bannière, exemple calculé.
  • Phase 2 (hors worker) : vrais formulaires PDF officiels des 6 banques (démarche relationship-manager Michel) + implémentation runtime des endpoints / du renderHypotheque côté VPS.