9b502e67fe
CI / Contraintes NON-NÉGOCIABLES (CLAUDE.md) (push) Has been cancelled
CI / Validation JSON (schémas Faisabilité) (push) Has been cancelled
CI / Qualité documentaire (liens + 4Big) (push) Has been cancelled
CI / Reproductibilité des artefacts out/ (build == commité) (push) Has been cancelled
CI / Fraîcheur matrice de régression (run == commité) (push) Has been cancelled
CI / Intégrité du câblage CI (gate agrège tout · gates statiques verrouillés) (push) Has been cancelled
CI / Intégrité des chiffres du README (valeur == artefact cité · (push) Has been cancelled
CI / Publiciste · parser + schéma + generator (unittest) (push) Has been cancelled
CI / RBAC · 50 rôles + schéma (unittest) (push) Has been cancelled
CI / Faisabilité · générateur 4 volets + round-trip (unittest) (push) Has been cancelled
CI / RBAC · fixtures ERPNext (Role + Custom DocPerm) (push) Has been cancelled
CI / RBAC · plan User Permission (row-level) (push) Has been cancelled
CI / RBAC · Role Profile (bundles par portail) (push) Has been cancelled
CI / RBAC · run-book d'application unifié (agrégat 3 volets) (push) Has been cancelled
CI / Faisabilité · dossier bancable trilingue FR/EN/ES (push) Has been cancelled
CI / CRM · workflow vente ERPNext (lead → CONFOTUR) (push) Has been cancelled
CI / CRM · DocType porteur OTO Dossier Vente (push) Has been cancelled
CI / CRM · barème commissions vendeurs (push) Has been cancelled
CI / CRM · Financement Bancaire (gate hypothécaire RD) (push) Has been cancelled
CI / Fiscal · e-CF DGII (Compupar) (push) Has been cancelled
CI / Frontend · Workspaces 5 portails rôle (push) Has been cancelled
CI / Legal · DocType CONFOTUR Application (push) Has been cancelled
CI / QA · Audit 5D conformité (push) Has been cancelled
CI / SEO · mots-clés trilingues + schema.org + hreflang (push) Has been cancelled
CI / Chat OTOIA · montage par portail (Custom Block) (push) Has been cancelled
CI / QA · Audit 4Big (95+/100 sur 100% deliverables) (push) Has been cancelled
CI / Démo · Scénarios (run-sheet P07 banquier / P05 client) (push) Has been cancelled
CI / QA · Matrice de régression exhaustive (Sprint 8) (push) Has been cancelled
CI / DevOps · Run-book de déploiement VPS unifié (Sprint 8) (push) Has been cancelled
CI / QA · Matrice d'acceptation / traçabilité MVP (Sprint 8) (push) Has been cancelled
CI / Mobile · config app Expo/EAS (navigation par rôle) (push) Has been cancelled
CI / E2E baseline Playwright (manuel) (push) Has been cancelled
CI / Gate qualité (agrégat) (push) Has been cancelled
101 lines
3.9 KiB
Python
101 lines
3.9 KiB
Python
"""Assemblage du bundle d'artefacts Financement Bancaire depuis le contrat.
|
|
|
|
Entrée : `financement_spec.json` + un `RoleResolver` (id → nom Frappe issu de
|
|
rbac_50_roles.json). Sortie : un bundle déterministe (tri stable, aucun
|
|
horodatage) → reproductible bit-à-bit à contrat constant, donc diffable et
|
|
re-générable en CI (`ci/check_artifacts.sh`).
|
|
|
|
Le builder n'invente rien (#6) : banques, documents, autorisations, sections,
|
|
conditions du gate proviennent du contrat ; les noms de rôle proviennent du
|
|
contrat RBAC ; l'exemple de gate-status est CALCULÉ par `finlib.gate` depuis le
|
|
dossier d'exemple du contrat (donc auditable, pas fabriqué).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from . import gate
|
|
from .rbac import RoleResolver
|
|
|
|
|
|
def build_bundle(spec: dict, resolver: RoleResolver) -> dict[str, Any]:
|
|
"""Transforme le contrat en bundle d'artefacts prêts à consommer."""
|
|
cfg = gate.GateConfig.from_spec(spec)
|
|
|
|
# --- rôles résolus (id → nom Frappe) --------------------------------------
|
|
roles_resolved = {
|
|
cle: {"role_id": rid, "erpnext_role_name": resolver.erpnext_name(rid)}
|
|
for cle, rid in sorted(spec["roles"].items())
|
|
}
|
|
|
|
# --- banques (ordre du contrat = ordre d'affichage) -----------------------
|
|
banques = list(spec["banques"])
|
|
|
|
# --- sections triées par `ordre` -----------------------------------------
|
|
sections = sorted(spec["sections"], key=lambda s: s["ordre"])
|
|
|
|
documents = list(spec["documents"])
|
|
autorisations = list(spec["autorisations"])
|
|
|
|
# --- spec du gate (conditions + bannière + endpoints + rôle validation) ---
|
|
gate_spec = {
|
|
"endpoint": spec["gate"]["endpoint"],
|
|
"submit_endpoint": spec["gate"]["submit_endpoint"],
|
|
"condition_keys": list(gate.CONDITION_KEYS),
|
|
"conditions": sorted(spec["gate"]["conditions"], key=lambda c: c["ordre"]),
|
|
"banniere": spec["gate"]["banniere"],
|
|
"role_validation": roles_resolved["validation_dossier"],
|
|
"workflow_suivi_banque": list(spec["workflow_suivi_banque"]),
|
|
}
|
|
|
|
# --- exemple de gate-status CALCULÉ (auditable, pas inventé) ---------------
|
|
exemple = spec["dossier_exemple"]
|
|
can_submit, reasons = gate.can_submit_dossier(exemple, cfg)
|
|
gate_status_example = {
|
|
"dossier_id": exemple["id"],
|
|
"projet": exemple["projet"],
|
|
"unite": exemple["unite"],
|
|
"banque_choisie": exemple["banque_choisie"],
|
|
"gate_status": gate.gate_status(exemple, cfg),
|
|
"can_submit": can_submit,
|
|
"reasons": reasons,
|
|
}
|
|
|
|
# --- comptes des documents requis par type de résidence -------------------
|
|
docs_requis = {
|
|
rt["code"]: len(gate.required_document_ids(rt["code"], cfg))
|
|
for rt in spec["apport"]["residence_types"]
|
|
}
|
|
|
|
manifest = {
|
|
"generated_from": "financement_spec.json",
|
|
"source_directive": spec["source_directive"],
|
|
"rbac_source": "rbac_50_roles.json",
|
|
"source_version": spec["version"],
|
|
"module": spec["module"],
|
|
"titre": spec["titre"],
|
|
"counts": {
|
|
"banques": len(banques),
|
|
"sections": len(sections),
|
|
"documents": len(documents),
|
|
"documents_requis_resident": docs_requis.get("resident_rd", 0),
|
|
"documents_requis_etranger": docs_requis.get("etranger", 0),
|
|
"autorisations": len(autorisations),
|
|
"gate_conditions": len(gate_spec["conditions"]),
|
|
"banniere_lignes": len(gate_spec["banniere"]["lignes"]),
|
|
"workflow_suivi_etapes": len(gate_spec["workflow_suivi_banque"]),
|
|
},
|
|
"roles_rbac_utilises": [roles_resolved[k] for k in sorted(roles_resolved)],
|
|
}
|
|
|
|
return {
|
|
"manifest": manifest,
|
|
"banques": banques,
|
|
"sections": sections,
|
|
"documents": documents,
|
|
"autorisations": autorisations,
|
|
"gate_spec": gate_spec,
|
|
"gate_status_example": gate_status_example,
|
|
}
|