Skill rapprochement-bancaire
Moteur d'état. Travaille uniquement sur l'arborescence
clients/<slug>/...produite parorganisation-documents. Le travail réel est fait parscripts/main.py(qui appellescripts/extract.pypour toute l'extraction de texte). Ce skill = quand le lancer + comment rendre compte.
⚠️ Règle absolue — EXÉCUTION DU SCRIPT (non négociable)
Pour chaque invocation, la SEULE action correcte est d'exécuter la commande :
python3 scripts/main.py <racine_clients>
puis de lire les followup.json / relances.json / anomalies.json par client + le compta_batch_report_<date>.json consolidé, et de relayer au comptable.
❌ INTERDIT
- Réimplémenter le rapprochement en Python inline / pseudo-code. La logique (Pass 1 par référence, Pass 2 fuzzy, validation TVA, détection des anomalies, statuts overdue/partial, génération des relances) est dans
scripts/main.py. La refaire à la main est garanti de diverger. - Écrire
followup.json/relances.json/anomalies.jsonà la main. C'est le script qui le fait, dans son format exact (liste d'objets avec les champsinvoice_id,type,amount,status,bank_matched,matched_tx, …). Toute autre forme (dict keyé, champspayments/amount_paidad hoc) casse les lectures ultérieures. - Modifier le format des fichiers de sortie. Le format est contractuel entre ce skill et d'éventuels skills aval (
relances, dashboards).
✅ OBLIGATOIRE
- Exécuter la commande shell ci-dessus.
- Lire les fichiers produits.
- Relayer au comptable un tableau lisible par client (factures payées / en attente / partielles / overdue, anomalies — en mettant en avant les bloquantes).
Si le script échoue
Signale l'erreur exacte (stderr). Ne rejoue PAS le batch à la main.
Pourquoi : on a déjà eu un run où l'agent a produit un
followup.jsonau mauvais format (dict avec clés"in/N", champspayments/amount_paid/amount_remainingau lieu debank_matched/status). Conséquence : aucun outil ni skill aval ne pouvait l'exploiter. Le script génère le bon format à tous les coups.
Exécution
python3 scripts/main.py [<racine_clients>]
# racine_clients par défaut : ~/.openclaw/workspace/clients
À lancer :
- une fois par jour (idéalement la nuit), sur tous les clients ;
- ou immédiatement après un trigger
rapprochement-bancaireémis parorganisation-documents.
Le script :
- Parcourt
clients/*en ignorant les dossiers techniques_*(_a-identifier,_incomplet,_non-attribue,_cabinet). - Périodes traitées : mois courant + mois précédent, plus tout mois ancien non verrouillé (
batch.lock.jsonabsent). Un mois verrouillé n'est pas retraité. - Factures : nom de fichier conventionnel (
AAAA-MM-JJ_N°Facture_Contrepartie_MontantTTC.pdf) →invoice_id+ montant. Si le nom n'est pas exploitable, lecture du contenu viaextract.py. Si toujours rien → anomaliefacture_illisible. - Relevés bancaires : transactions extraites ligne par ligne via
extract.py(DATE | LIBELLÉ | MONTANT | CR/DB), avec la référence facture si le libellé contientREF <id>ouFACT <id>. Aucune transaction extractible → anomaliereleve_non_parseable. - Rapprochement (montant comparé en valeur absolue : une facture
outest encaissée par un crédit, uneinréglée par un débit) :- Pass 1 — réf facture : transaction dont
invoice_ref == facture.invoice_id. Montant exact (±1 €) →paid; montant inférieur →partial(conserveamount_paid,amount_remaining) ; supérieur →paid+overpaid_by. - Pass 2 — fuzzy :
|montant| ±1 €ET similarité libellé / contrepartie ≥ 0.6. - aucun match + échéance dépassée →
overdue.
- Pass 1 — réf facture : transaction dont
- Validation TVA de chaque facture : si
|TVA déclarée − TVA attendue| / TVA attendue > 5 %(TVA attendue =TOTAL HT × taux) → anomalietva_incorrecte(TVA 0 % / exonération ignorée). - Anomalies : voir tableau ci-dessous.
- Relances :
overdue/partial/unpaidhors délai → step selon ancienneté. - Écrit
clients/<slug>/followup.json,relances.json,anomalies.json, et un rapport consolidécompta_batch_report_<date>.json.
Après l'exécution, lire le rapport et relayer au comptable un tableau lisible par client (factures payées / en attente, relances, anomalies — en mettant en avant les anomalies bloquantes). Jamais de chemins techniques.
Statuts de facture (followup.json)
| Statut | Sens |
|--------|------|
| unpaid | non échue, aucun paiement |
| paid | paiement confirmé (rapprochement réussi) |
| partial | paiement partiel — amount_paid + amount_remaining conservés |
| overdue | échéance dépassée, aucun paiement |
Anomalies (anomalies.json)
Bloquantes (empêchent la clôture de la période) :
| Type | Condition |
|------|-----------|
| doublon_paiement | même date + montant + libellé |
| tva_incorrecte | écart TVA calculée / déclarée > 5 % |
| facture_manquante | une ligne du relevé cite un n° de facture (REF/FACT) absent du dossier, montant > 1 000 € |
| paiement_orphelin | crédit > 1 000 € sans aucune référence ni facture |
Non bloquantes (signalées, clôture possible) :
| Type | Condition |
|------|-----------|
| facture_manquante | n° de facture cité au relevé mais absent, montant ≤ 1 000 € |
| paiement_orphelin | crédit ≤ 1 000 € sans référence |
| releve_non_parseable | aucune transaction extractible d'un relevé |
| facture_illisible | facture dont ni le nom ni le contenu ne donnent n° + montant |
| invoice_overdue | facture non payée, échéance dépassée |
facture_manquante≠paiement_orphelin: le premier = paiement qui cite un n° de facture qu'on n'a pas reçu (le client a oublié de transmettre la pièce) ; le second = encaissement sans aucune référence.
Relances (relances.json)
| Ancienneté du retard | Step | |----------------------|------| | ≤ 30 j | 1 | | ≤ 60 j | 2 | | ≤ 90 j | 3 | | > 90 j | escalation |
Pour partial : mention explicite "Solde restant dû : X,XX €".
Clôture de période
Le script crée clients/<slug>/<AAAA>/<MM>/batch.lock.json quand : aucune anomalie bloquante sur la période, hash des fichiers stable depuis 7 jours, aucun statut unpaid/overdue non justifié. Les périodes verrouillées ne sont jamais retraitées sauf changement de hash.
Règles critiques
- Ne jamais supprimer de données. Ne jamais retraiter un mois verrouillé.
followup.jsonest un cache reconstructible : les PDFs classés restent la vérité. Le batch peut tout recalculer depuis zéro.clients.jsonest lu seulement (maintenu parorganisation-documents), jamais écrit ici.- Toute l'extraction de texte passe par
scripts/extract.py— source unique, pas de logique de parsing dupliquée ici.
Philosophie
organisation-documents → classe les pièces, déduit clients.json
rapprochement-bancaire → rapproche, valide, reconstruit l'état comptable (scripts/main.py)
relances → décision différée
Le système doit pouvoir être recalculé intégralement à partir des documents classés.
Scan to join WeChat group