diff --git a/AGENTS.md b/AGENTS.md index ce99e0e..68d598a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -69,6 +69,10 @@ Guide rapide pour les agents qui codent dans ce repository. - `notes/business_rules.md` - Regles metier locales `purchase_trade`: - `modules/purchase_trade/docs/business-rules.md` + - `modules/purchase_trade/docs_source/business/` pour les sources de verite + des pages business publiees dans le wiki + - `modules/purchase_trade/docs/business/` pour les pages generees lues par le + wiki - Decisions templates / reports: - `notes/template_business_rules.md` - Documentation comptable et reporting: @@ -80,6 +84,7 @@ Guide rapide pour les agents qui codent dans ce repository. - Regles sensibles `purchase_trade` a relire avant de toucher lots, quantites ou fees: - `modules/purchase_trade/AGENTS.md` + - `modules/purchase_trade/docs_source/business/lots-and-quantities.md` - `modules/purchase_trade/docs/business-rules.md` BR-PT-020 / BR-PT-021 (`quantity_theorical`, `lot.qt`, lots physiques, fees et PnL fee). diff --git a/modules/purchase_trade/AGENTS.md b/modules/purchase_trade/AGENTS.md index 91e50fa..acb8c88 100644 --- a/modules/purchase_trade/AGENTS.md +++ b/modules/purchase_trade/AGENTS.md @@ -41,6 +41,10 @@ de negoce physique: - Regles metier: - `modules/purchase_trade/docs/business-rules.md` +- Documentation business publiee dans le wiki: + - `modules/purchase_trade/docs/business/*.md` +- Sources de verite de la documentation business generee: + - `modules/purchase_trade/docs_source/business/*.md` - Regles templates: - `modules/purchase_trade/docs/template-rules.md` - Catalogue des proprietes templates: @@ -179,6 +183,23 @@ de negoce physique: ## 5) Conventions de modification +### Documentation business + +- Ne pas modifier directement une page generee sous + `modules/purchase_trade/docs/business/` si elle contient le commentaire + `Generated from docs_source/business`. +- Toute regle business nouvelle ou modifiee doit etre editee dans + `modules/purchase_trade/docs_source/business/`. +- Apres modification des sources business, regenerer le wiki avec: + `python modules/purchase_trade/docs/tools/render_business_docs.py` +- Avant de rendre une modification documentaire, verifier que le rendu publie + est synchronise avec: + `python modules/purchase_trade/docs/tools/render_business_docs.py --check` +- Les pages francaises et anglaises miroir doivent rester synchronisees. +- Le rendu publie doit rester lisible dans MkDocs meme sans extensions + optionnelles: eviter les marqueurs bruts `!!!` et `:material-...:` dans les + fichiers publies. + 1. Modifier la logique metier dans le fichier pivot le plus proche. 2. Si un template `.fodt` devient complexe, deplacer la logique dans une propriete Python `report_*`. diff --git a/modules/purchase_trade/docs/business/INDEX.md b/modules/purchase_trade/docs/business/INDEX.md index af2d99d..8764737 100644 --- a/modules/purchase_trade/docs/business/INDEX.md +++ b/modules/purchase_trade/docs/business/INDEX.md @@ -1,48 +1,91 @@ + + # Index thematique des regles business Statut: `migration partielle` ## Comment chercher une regle -- Contrats, dates, lieux, banques: [contracts.md](contracts.md) -- Lots virtuels, lots physiques, `lot.qt`, weighing: [FR](lots-and-quantities.md) / [EN](lots-and-quantities.en.md) -- Matching, Create Contracts, back-to-back: [matching.md](matching.md) -- Shipments, controllers, SLA, weight reports: [shipments-execution.md](shipments-execution.md) -- Pricing manuel, basis, premium, linked currency: [pricing.md](pricing.md) -- Fees, freight, lots effectifs, `% rate`: [fees.md](fees.md) -- Valuation, PnL, MTM, derivatives: [valuation-pnl-mtm.md](valuation-pnl-mtm.md) -- Factures provisoires/finales, padding: [invoicing.md](invoicing.md) -- Impacts `account.move`, validate/post: [accounting-bridge.md](accounting-bridge.md) -- Comptes bancaires, payment terms, payment orders: [payments-banking.md](payments-banking.md) -- Relatorio, `.fodt`, proprietes `report_*`: [reports-templates.md](reports-templates.md) -- Risque, credit, forex: [risk-credit-forex.md](risk-credit-forex.md) -- Rapport Lots Management: [lots-management.md](lots-management.md) -- Diagnostics SQL des invariants: [sql/README.md](sql/README.md) + ## Regles migrees dans cette premiere passe -- `BR-PT-CON-001`: texte par defaut de pricing rule. -- `BR-PT-CON-002`: delivery period coherent. -- `BR-PT-CON-003`: lieux stock propages dans Create Contracts. -- `BR-PT-LOT-001`: cycle de vie des lots et des quantites. -- `BR-PT-LOT-002`: quantity contractuelle, execute physique et ligne finie. -- `BR-PT-LOT-003`: garde-fous Python et diagnostics SQL des invariants de - quantite. -- `BR-PT-MAT-001`: Create Contracts multi-lots. -- `BR-PT-SHP-001`: affectation controller. -- `BR-PT-SHP-002`: couts SLA controller. -- `BR-PT-SHP-003`: weight reports distants. -- `BR-PT-PRI-001`: premium dans priced et basis. -- `BR-PT-PRI-002`: linked currency. -- `BR-PT-PRI-003`: pricing manuel. -- `BR-PT-FEE-001`: maritime freight depuis fee shipment. -- `BR-PT-FEE-002`: lots effectifs des fees. -- `BR-PT-FEE-003`: `% rate` via delta de financement. -- `BR-PT-VAL-001`: valuation achat/vente et sale-first. -- `BR-PT-VAL-002`: references de valuation. -- `BR-PT-VAL-003`: MTM hors fees. -- `BR-PT-INV-001`: padding facture provisoire vente. -- `BR-PT-ACC-001`: Validate facture client attribue le numero. -- `BR-PT-PAY-001`: comptes bancaires tiers vs compagnie. -- `BR-PT-RPT-001`: templates trade via proprietes Python. -- `BR-PT-LOTMGT-001`: filtres Lots Management. + diff --git a/modules/purchase_trade/docs/business/README.md b/modules/purchase_trade/docs/business/README.md index 8046a59..499f027 100644 --- a/modules/purchase_trade/docs/business/README.md +++ b/modules/purchase_trade/docs/business/README.md @@ -1,3 +1,5 @@ + + # Guide de lecture des règles business Statut: `migration partielle` @@ -6,32 +8,44 @@ Dernière mise à jour: `2026-05-13` Ce dossier devient la source de lecture thématique publiée dans le wiki pour les règles business du module `purchase_trade`. -Certaines pages peuvent être générées depuis une source de vérité plus sobre, -rangée hors du dossier wiki dans `modules/purchase_trade/docs_source/`. Dans ce -cas, la page publiée dans `modules/purchase_trade/docs/` porte un commentaire -`Generated from ...` en tête de fichier et ne doit pas être modifiée -directement. +Toutes les pages business publiées dans `modules/purchase_trade/docs/business/` +sont générées depuis une source de vérité plus sobre, rangée hors du dossier +wiki dans `modules/purchase_trade/docs_source/business/`. + +Les pages publiées portent un commentaire `Generated from ...` en tête de +fichier et ne doivent pas être modifiées directement. Aucun contenu business ne +doit être ajouté ou modifié sans passer par cette source puis par le script de +génération. Chaque page doit rester lisible par deux publics: -- les consultants, qui ont besoin d'une règle fonctionnelle stable sans détail - de code inutile; -- les développeurs, qui ont besoin des champs, modèles, fichiers et tests - concernés pour appliquer la règle sans l'interpréter. + ## Convention de langues Chaque page thématique durable doit exister en deux versions maintenues ensemble: -- une page française, rédigée en français correct avec accents, typographie et - formulations naturelles pour le wiki consultant; -- une page anglaise miroir, portant le même contenu fonctionnel et technique. + Convention de nommage: -- page française principale: `theme.md`; -- page anglaise miroir: `theme.en.md`. + Toute modification d'une règle business, d'un statut, d'un champ technique ou d'un point de vigilance doit être reportée dans les deux pages au même moment. @@ -39,50 +53,61 @@ Les deux pages doivent indiquer leur page miroir en en-tête. ## Convention source / wiki -Pour les pages qui ont besoin d'une présentation riche dans MkDocs: +Pour toute page business: -- éditer la source de vérité dans `modules/purchase_trade/docs_source/`; -- régénérer la version wiki avec: + -```bash -python modules/purchase_trade/docs/tools/render_business_docs.py -``` +
python modules/purchase_trade/docs/tools/render_business_docs.py
Le rendu wiki privilégie du HTML simple et portable plutôt que des extensions MkDocs optionnelles. Cela évite d'exposer dans le wiki des marqueurs non rendus comme `!!!` ou `:material-...:`. +Les fichiers générés dans `modules/purchase_trade/docs/business/` sont des +artefacts de publication: ils peuvent être relus, mais toute correction doit +être reportée dans `docs_source/business/` avant régénération. + +Avant de livrer une modification documentaire, vérifier que les pages publiées +sont à jour avec: + +
python modules/purchase_trade/docs/tools/render_business_docs.py --check
+ ## Convention de rédaction Pour chaque règle durable, utiliser autant que possible ce format: -```md -### BR-PT-THEME-001 - Titre court +
### BR-PT-THEME-001 - Titre court
 
 Statut: active
 Source: business-rules.md / note de session / décision projet
 
 #### Règle consultant
 
-Texte fonctionnel, sans nom de champ si ce n'est pas nécessaire.
+Texte fonctionnel, sans nom de champ si ce n'est pas nécessaire.
 
 #### Notes développeur
 
 - Modèles/champs:
 - Fichiers:
 - Tests:
-- Points de vigilance:
-```
+- Points de vigilance:
## Convention de validation Quand une règle business devient structurante pour l'intégrité des données, elle doit être accompagnée autant que possible de deux garde-fous: -- un check applicatif bloquant dans le code Python, appelé à la fin des flux qui - modifient les données concernées; -- un diagnostic SQL en lecture seule pour auditer les bases existantes ou les - bases de test. + Les diagnostics SQL du module sont rangés dans `business/sql/`. Ils ne remplacent pas les règles applicatives: ils servent à retrouver et qualifier les @@ -94,10 +119,19 @@ Les anciennes pages ne sont pas supprimées à cette étape. Elles restent des sources de vérification jusqu'à ce que chaque décision soit promue dans une page thématique: -- `modules/purchase_trade/docs/business-rules.md` -- `modules/purchase_trade/docs/fees.md` -- `modules/purchase_trade/docs/padding-invoice-accounting.md` -- `modules/purchase_trade/docs/template-rules.md` -- `modules/purchase_trade/docs/template-properties.md` -- `notes/business_rules.md` -- `notes/template_business_rules.md` + diff --git a/modules/purchase_trade/docs/business/accounting-bridge.md b/modules/purchase_trade/docs/business/accounting-bridge.md index 9ed8d82..ca93606 100644 --- a/modules/purchase_trade/docs/business/accounting-bridge.md +++ b/modules/purchase_trade/docs/business/accounting-bridge.md @@ -1,3 +1,5 @@ + + # Pont comptable Statut: `migration partielle` @@ -13,13 +15,16 @@ validation, comme une facture fournisseur. ### Notes developpeur -- Cible: `account.invoice` avec `type = out`. -- Workflow `Validate`: creer `account.move` et attribuer `number`. -- Workflow `Post`: ne doit pas reintroduire une session fraiche specifique au - flux client. + ## Notes de migration Les notes comptables detaillees restent dans `notes/accounting/` tant qu'elles n'ont pas ete promues ici. - diff --git a/modules/purchase_trade/docs/business/contracts.md b/modules/purchase_trade/docs/business/contracts.md index ad12d06..9c8bfe1 100644 --- a/modules/purchase_trade/docs/business/contracts.md +++ b/modules/purchase_trade/docs/business/contracts.md @@ -1,3 +1,5 @@ + + # Contrats achat / vente Statut: `migration partielle` @@ -13,9 +15,14 @@ repris automatiquement sur les nouvelles lignes achat et vente. ### Notes developpeur -- Configuration: `purchase_trade.configuration.pricing_rule`. -- Cibles: `purchase.line.pricing_rule`, `sale.line.pricing_rule`. -- Les lignes existantes ne sont pas modifiees retroactivement. + ## BR-PT-CON-002 - Delivery period coherent @@ -28,9 +35,12 @@ borne renseignee reste acceptee. ### Notes developpeur -- Champs: `purchase.line.from_del`, `purchase.line.to_del`, - `sale.line.from_del`, `sale.line.to_del`. -- Validation attendue: bloquer si `from_del > to_del`. + ## BR-PT-CON-003 - Propagation des lieux stock dans Create Contracts @@ -43,8 +53,13 @@ logistiques doivent etre proposes selon le flux source pour eviter la ressaisie. ### Notes developpeur -- Champs: `from_location`, `to_location`. -- Flux fournisseur vers client: recopier le couple source. -- Achat vers stock puis vente: `sale.from_location = purchase.to_location`. -- Vente depuis stock puis achat: `purchase.to_location = sale.from_location`. - + diff --git a/modules/purchase_trade/docs/business/fees.md b/modules/purchase_trade/docs/business/fees.md index 47e9cbf..902b5b8 100644 --- a/modules/purchase_trade/docs/business/fees.md +++ b/modules/purchase_trade/docs/business/fees.md @@ -1,3 +1,5 @@ + + # Fees Statut: `migration partielle` @@ -15,10 +17,16 @@ shipment, pas d'un champ direct de la facture. ### Notes developpeur -- Retrouver le lot physique depuis la facture. -- Retrouver son `shipment_in`. -- Chercher le `fee.fee` avec `product.name = 'Maritime freight'`. -- Utiliser `fee.get_amount()`. + ## BR-PT-FEE-002 - Les fees lies aux lots privilegient les physiques @@ -31,12 +39,18 @@ physique est lie, les lots physiques deviennent la base de calcul du fee. ### Notes developpeur -- Ne pas supprimer le lien virtuel: il reste le fallback. -- Quantite `ppack`: somme de `lot.lot_qt` des physiques. -- Modes quantitatifs: quantites courantes converties des physiques. -- La meme selection s'applique au PnL fee. -- Points de synchronisation: creation fee, lien `fee.lots`, changement de - `quantity_theorical`, weighing, suppression de physique. + ## BR-PT-FEE-003 - Fees `% rate` via delta de financement @@ -49,7 +63,11 @@ de la ligne d'estimation `BL date`, pas avec la date du jour. ### Notes developpeur -- Formule: `amount = unit_price * quantity * (price / 100) * fin_int_delta / 360`. -- Source du delta: ligne `Estimated date` avec `trigger = bldate`. -- Si aucune ligne `bldate` n'existe, ne pas calculer de montant `% rate`. - + diff --git a/modules/purchase_trade/docs/business/glossary.md b/modules/purchase_trade/docs/business/glossary.md index 5987986..e4e1dc6 100644 --- a/modules/purchase_trade/docs/business/glossary.md +++ b/modules/purchase_trade/docs/business/glossary.md @@ -1,22 +1,42 @@ + + # Glossaire purchase_trade Statut: `migration partielle` -- `Purchase Line`: ligne d'achat. -- `Sale Line`: ligne de vente. -- `quantity_theorical`: quantite contractuelle theorique d'une ligne. -- `Virtual Lot`: lot de type `virtual`, representant un reliquat ouvert. -- `Physical Lot`: lot de type `physic`, representant une quantite executee. -- `lot.qt`: ligne de quantite ouverte, matchee ou rattachee a un shipment. -- `lot.qt ouvert`: `lot.qt` libre, sans lot oppose et sans shipment. -- `Shipment In`: shipment entrant utilise aussi pour les flux dropship dans ce module. -- `Dropship`: flux fournisseur vers client, sans passage par stock interne. -- `Inbound`: flux entrant classique qui ne correspond pas au dropship. -- `Basis`: mode de prix construit a partir d'un prix de marche et d'un premium. -- `Premium`: prime ou discount commercial ajoute au prix economique. -- `Linked currency`: saisie d'un prix dans une devise/unite liee, par exemple `USC/LB`. -- `Valuation`: lignes de PnL generees pour prix, fees, derivatives et MTM. -- `MTM`: mark-to-market applique aux lignes valorisables au marche. -- `Fee`: frais commercial ou logistique rattache a une ligne, un lot ou un shipment. -- `Report property`: propriete Python exposee pour simplifier un template Relatorio. - + diff --git a/modules/purchase_trade/docs/business/invariants.md b/modules/purchase_trade/docs/business/invariants.md index a38144a..c7c0480 100644 --- a/modules/purchase_trade/docs/business/invariants.md +++ b/modules/purchase_trade/docs/business/invariants.md @@ -1,3 +1,5 @@ + + # Invariants structurants Statut: `migration partielle` @@ -15,11 +17,14 @@ contrats et l'execution logistique. ### Notes developpeur -- Source historique: `BR-PT-002`. -- Voir aussi: [lots-and-quantities.md](lots-and-quantities.md), - [matching.md](matching.md), [reports-templates.md](reports-templates.md). -- Champs frequents: `lot.line`, `lot.sale_line`, `lot_shipment_in`, - `lot_shipment_internal`, `lot_shipment_out`. + ## INV-PT-002 - Le reliquat ouvert ne doit pas doubler les lots physiques @@ -31,19 +36,22 @@ executer. ### Notes developpeur -- Source historique: `BR-PT-020`. -- Le calcul doit tenir compte de la quantite contractuelle, des lots physiques - existants et des `lot.qt` deja matches ou shippes. -- Regle de conservation: - `sum(lots physiques) + lot virtuel = quantity_theorical`. -- Regle du forecast ouvert: - `sum(lot.qt non zero) = max(lot virtuel, 0)`. -- Les lignes `lot.qt` a zero sont ignorees par les checks: elles peuvent servir - de memoire d'une prevision consommee. -- Le check applicatif est centralise dans - `lot.lot.assert_lines_quantity_consistency()`. -- Le diagnostic SQL correspondant est - [sql/quantity_consistency_checks.sql](sql/quantity_consistency_checks.sql). + ## INV-PT-003 - Les fees utilisent leurs lots effectifs @@ -55,10 +63,14 @@ effective de calcul. ### Notes developpeur -- Source historique: `BR-PT-021`. -- Ne pas supprimer le lien virtuel: il reste le fallback si les physiques sont - retires. -- Voir [fees.md](fees.md). + ## INV-PT-004 - Les templates doivent rester simples @@ -69,7 +81,11 @@ chemin technique pour les retrouver est complexe. ### Notes developpeur -- Preferer des proprietes Python `report_*` aux expressions Genshi complexes. -- Ne pas supposer qu'une variable locale comme `shipment` existe partout dans - un `.fodt`. -- Voir [reports-templates.md](reports-templates.md). + diff --git a/modules/purchase_trade/docs/business/invoicing.md b/modules/purchase_trade/docs/business/invoicing.md index ac3c51a..13b1a5b 100644 --- a/modules/purchase_trade/docs/business/invoicing.md +++ b/modules/purchase_trade/docs/business/invoicing.md @@ -1,3 +1,5 @@ + + # Facturation trade Statut: `migration partielle` @@ -13,12 +15,15 @@ constituer une provision, sans modifier la quantite physique du lot. ### Notes developpeur -- Le padding global du wizard `lot.invoice` est reparti entre les lots - selectionnes. -- La ligne facture expose `Inc. padding`. -- Le lot conserve sa part dans `sale_invoice_padding`. -- La facture finale retire le padding de la quantite provisoire avant de - calculer le delta. -- Les ecritures d'extourne doivent relire la provisoire depuis - `lot.sale_invoice_line_prov`. - + diff --git a/modules/purchase_trade/docs/business/lots-and-quantities.en.md b/modules/purchase_trade/docs/business/lots-and-quantities.en.md index 0d8157d..dcf4608 100644 --- a/modules/purchase_trade/docs/business/lots-and-quantities.en.md +++ b/modules/purchase_trade/docs/business/lots-and-quantities.en.md @@ -296,174 +296,379 @@ them with Python guards and SQL diagnostics. ### Key Fields -- Purchase line: `purchase.line` -- Sale line: `sale.line` -- Lot: `lot.lot` -- Forecast: `lot.qt` -- History: `lot.qt.hist` -- Purchase business quantity: `purchase.line.quantity_theorical` -- Sale business quantity: `sale.line.quantity_theorical` -- Technical counter: `quantity` -- Finished line: `purchase.line.finished`, `sale.line.finished` -- Virtual / physical lot: `lot.lot.lot_type = virtual / physic` -- Purchase link: `lot.lot.line` -- Sale link: `lot.lot.sale_line` -- Purchase forecast: `lot.qt.lot_p` -- Sale forecast: `lot.qt.lot_s` -- Forecast quantity: `lot.qt.lot_quantity` -- Weight basis: `purchase.purchase.wb`, `sale.sale.wb` -- Weight basis state: `purchase.weight.basis.qt_type` -- Packing: `lot.lot.lot_qt`, `lot.lot.lot_unit` -- Tolerances: `tol_min`, `tol_max`, `tol_min_qt`, `tol_max_qt`, - `tol_min_v`, `tol_max_v` + ### Line / Virtual Lot Creation -- Purchase: `purchase.py`, `Line.validate` -- Sale: `sale.py`, `SaleLine.validate` -- If `quantity_theorical` is entered and `quantity` is empty or zero: - - `quantity` is initialized from `quantity_theorical`; - - only if no physical lot exists. -- If the line is eligible: - - not `created_by_code`; - - no lot yet; - - non-service product; - - `quantity_theorical != 0`; - - create one `virtual` lot. -- The virtual lot receives a first `lot.qt.hist` entry. -- `Lot.validate` creates the open `lot.qt` through `createVirtualPart`. + ### Updating `quantity_theorical` -- Purchase: `purchase.py`, `Line.write` -- Sale: `sale.py`, `SaleLine.write` -- Virtual lot target: +
target_quantity = quantity_theorical - sum(converted physical lots)
-- If `target_quantity < 0`: - - block with `Please unlink or unmatch lot`. -- Free `lot.qt` target: +
free_quantity = target_quantity - sum(already matched or shipped lot.qt)
-- If `free_quantity < 0`: - - block with `Please unlink or unmatch lot`. -- If a free `lot.qt` exists: - - replace its quantity. -- If no free `lot.qt` exists and `free_quantity > 0`: - - create a new `lot.qt`. -- Line fees are resynchronized. + ### Adding Physical Lots -- Wizard: `lot.add` -- Methods: - - `LotQt.add_physical_lots` - - `LotQt.add_physical_lot` -- Mandatory source: one `lot.qt` line. -- Direct add from a physical lot is refused. -- Physical add on sale side through this wizard is refused: use - `Apply matching`. -- The physical lot inherits: - - purchase line; - - matched sale, if any; - - shipment; - - product; - - unit; - - quantities; - - premium; - - chunk key. -- After creation: - - source `lot.qt` is reduced; - - `lot.qt` cannot become negative; - - virtual lot is recalculated; - - `quantity` is recalculated; - - moves and fees are updated when needed. + ### Removing Physical Lots -- Wizard: `lot.remove` -- Open lot: removal forbidden. -- Lot with `stock.move`: - - move must be `draft`. -- Matched or shipped lot: - - confirmable warning. -- Effects: - - draft move deletion; - - restore quantity into `lot.qt`; - - restore context through shipment, `getVlot_p()`, `getVlot_s()`; - - recalculate virtual lot, `quantity`, fees. + ### Weighing / Quantity States -- Wizard: `lot.weighing` -- UI action: `Do weighing` -- Writes or updates `lot.qt.hist`. -- May update `lot_state`. -- Synchronizes: - - lot; - - open quantities; - - fees. -- `lot.qt.hist` views are consultative. + ### Quantity Counter `quantity` -- Method: `Lot._recalc_line_quantity` -- Without physical lots: - - `quantity` follows the virtual lot. -- With physical lots: - - `quantity` sums physical lots only. -- `quantity` is readonly on trade lines. + ### Line Amount -- Purchase: `purchase.line.on_change_with_amount()` -- Sale: `sale.line.on_change_with_amount()` -- Helpers: - - `_get_amount_quantity()` - - `_get_weight_basis_quantity()` -- Priorities: - - `finished = False`: `quantity_theorical` - - `finished = True` + usable Weight basis: physical sum in that state - - `finished = True` without usable Weight basis: `quantity` - - legacy fallback: `quantity` if `quantity_theorical` is empty + ### Python Guards -- Central check: - - `lot.lot.assert_lines_quantity_consistency()` -- Non-zero orphan `lot.qt` block: - - `lot.qt.validate` -- Called after: - - `quantity_theorical` update; - - physical lot creation / deletion; - - matching / unmatching; - - shipping / unshipping; - - weighing. + ### SQL Diagnostic -- Script: - - [sql/quantity_consistency_checks.sql](sql/quantity_consistency_checks.sql) -- Use: - - test database audit; - - historical data audit; - - qualification before repair. -- The script completely ignores `lot.qt = 0`. + ## Nearby Tests -- `modules/purchase_trade/tests/test_module.py` -- Existing coverage: - - readonly `quantity`; - - initialization from `quantity_theorical`; - - protection when physical lots exist; - - amount on theoretical / physical / Weight basis; - - virtual lot resynchronization; - - blocking when open quantity is not enough. -- Tests to add: - - readonly `lot_hist`; - - `Do weighing` creates or updates a state; - - virtual lot without direct `lot_qt` / `lot_unit` entry; - - SQL checks replayed on inconsistent datasets. + diff --git a/modules/purchase_trade/docs/business/lots-and-quantities.md b/modules/purchase_trade/docs/business/lots-and-quantities.md index f19b83f..50cedf2 100644 --- a/modules/purchase_trade/docs/business/lots-and-quantities.md +++ b/modules/purchase_trade/docs/business/lots-and-quantities.md @@ -295,173 +295,379 @@ puis les sécuriser par des checks Python et des diagnostics SQL. ### Champs clés -- Ligne achat : `purchase.line` -- Ligne vente : `sale.line` -- Lot : `lot.lot` -- Forecast : `lot.qt` -- Historique : `lot.qt.hist` -- Quantité métier achat : `purchase.line.quantity_theorical` -- Quantité métier vente : `sale.line.quantity_theorical` -- Compteur technique : `quantity` -- Ligne finie : `purchase.line.finished`, `sale.line.finished` -- Lot virtuel / physique : `lot.lot.lot_type = virtual / physic` -- Lien achat : `lot.lot.line` -- Lien vente : `lot.lot.sale_line` -- Forecast achat : `lot.qt.lot_p` -- Forecast vente : `lot.qt.lot_s` -- Quantité forecast : `lot.qt.lot_quantity` -- Weight basis : `purchase.purchase.wb`, `sale.sale.wb` -- État Weight basis : `purchase.weight.basis.qt_type` -- Packing : `lot.lot.lot_qt`, `lot.lot.lot_unit` -- Tolerances : `tol_min`, `tol_max`, `tol_min_qt`, `tol_max_qt`, - `tol_min_v`, `tol_max_v` + ### Création ligne / lot virtuel -- Achat : `purchase.py`, `Line.validate` -- Vente : `sale.py`, `SaleLine.validate` -- Si `quantity_theorical` est saisi et que `quantity` est vide ou zéro : - - `quantity` est initialisée depuis `quantity_theorical` ; - - seulement si aucun lot physique n'existe. -- Si la ligne est éligible : - - pas `created_by_code` ; - - pas encore de lot ; - - produit non service ; - - `quantity_theorical != 0` ; - - création d'un lot `virtual`. -- Le lot virtuel reçoit une première entrée `lot.qt.hist`. -- `Lot.validate` crée le `lot.qt` ouvert via `createVirtualPart`. + ### Modification de `quantity_theorical` -- Achat : `purchase.py`, `Line.write` -- Vente : `sale.py`, `SaleLine.write` -- Cible lot virtuel : +
target_quantity = quantity_theorical - somme(lots physiques convertis)
-- Si `target_quantity < 0` : - - blocage : `Please unlink or unmatch lot`. -- Cible `lot.qt` libre : +
free_quantity = target_quantity - somme(lot.qt déjà matchés ou shippés)
-- Si `free_quantity < 0` : - - blocage : `Please unlink or unmatch lot`. -- Si un `lot.qt` libre existe : - - sa quantité est remplacée. -- Si aucun `lot.qt` libre n'existe et `free_quantity > 0` : - - création d'un nouveau `lot.qt`. -- Les fees de ligne sont resynchronisés. + ### Ajout de lots physiques -- Wizard : `lot.add` -- Méthodes : - - `LotQt.add_physical_lots` - - `LotQt.add_physical_lot` -- Source obligatoire : une ligne `lot.qt`. -- Ajout direct depuis un lot physique refusé. -- Ajout physique côté vente par ce wizard refusé : utiliser `Apply matching`. -- Le lot physique reprend : - - ligne achat ; - - vente matchée si présente ; - - shipment ; - - produit ; - - unité ; - - quantités ; - - premium ; - - chunk key. -- Après création : - - réduction de la ligne `lot.qt` source ; - - pas de quantité `lot.qt` négative ; - - recalcul du lot virtuel ; - - recalcul de `quantity` ; - - mise à jour moves et fees si nécessaire. + ### Retrait de lots physiques -- Wizard : `lot.remove` -- Lot ouvert : retrait interdit. -- Lot avec `stock.move` : - - move obligatoire en `draft`. -- Lot matché ou shippé : - - warning confirmable. -- Effets : - - suppression du move draft ; - - restauration de la quantité dans `lot.qt` ; - - contexte restauré via shipment, `getVlot_p()`, `getVlot_s()` ; - - recalcul lot virtuel, `quantity`, fees. + ### Weighing / états de quantité -- Wizard : `lot.weighing` -- Action UI : `Do weighing` -- Écrit ou met à jour `lot.qt.hist`. -- Peut mettre à jour `lot_state`. -- Synchronise : - - lot ; - - quantités ouvertes ; - - fees. -- Les vues `lot.qt.hist` sont consultatives. + ### Quantité compteur `quantity` -- Méthode : `Lot._recalc_line_quantity` -- Sans physique : - - `quantity` suit le lot virtuel. -- Avec physiques : - - `quantity` somme uniquement les lots physiques. -- `quantity` est readonly côté ligne trade. + ### Montant de ligne -- Achat : `purchase.line.on_change_with_amount()` -- Vente : `sale.line.on_change_with_amount()` -- Helper : - - `_get_amount_quantity()` - - `_get_weight_basis_quantity()` -- Priorités : - - `finished = False` : `quantity_theorical` - - `finished = True` + Weight basis disponible : somme physique dans cet état - - `finished = True` sans Weight basis exploitable : `quantity` - - fallback legacy : `quantity` si `quantity_theorical` vide + ### Garde-fous Python -- Check central : - - `lot.lot.assert_lines_quantity_consistency()` -- Blocage `lot.qt` orphelin non zéro : - - `lot.qt.validate` -- Appels après : - - modification `quantity_theorical` ; - - création / suppression de lots physiques ; - - matching / unmatching ; - - shipping / unshipping ; - - weighing. + ### Diagnostic SQL -- Script : - - [sql/quantity_consistency_checks.sql](sql/quantity_consistency_checks.sql) -- Usage : - - audit des bases de test ; - - audit des données historiques ; - - qualification avant correction. -- Le script ignore totalement les `lot.qt = 0`. + ## Tests proches -- `modules/purchase_trade/tests/test_module.py` -- Couverture existante : - - `quantity` readonly ; - - initialisation depuis `quantity_theorical` ; - - protection si lots physiques ; - - amount sur théorique / physique / Weight basis ; - - resynchronisation des lots virtuels ; - - blocages quand l'open ne suffit plus. -- Tests à ajouter : - - `lot_hist` readonly ; - - `Do weighing` crée ou met à jour un état ; - - lot virtuel sans saisie directe `lot_qt` / `lot_unit` ; - - contrôles SQL rejoués sur jeux de données incohérents. + diff --git a/modules/purchase_trade/docs/business/lots-management.md b/modules/purchase_trade/docs/business/lots-management.md index fd89c29..96279d5 100644 --- a/modules/purchase_trade/docs/business/lots-management.md +++ b/modules/purchase_trade/docs/business/lots-management.md @@ -1,3 +1,5 @@ + + # Lots Management Statut: `migration partielle` @@ -13,15 +15,21 @@ commercial, le sens achat/vente et l'avancement logistique. ### Notes developpeur -- Filtres: `Matching status`, `Side`, `Shipping status`, `Dimension`, - `Strategy`. -- Dates `As of` / `To`: `purchase.purchase_date` et `sale.sale_date`. -- `Unshipped`: aucun `shipment_in`. -- `Scheduled`: shipment `draft`. -- `Shipped`: shipment `started`. -- `Received`: shipment `received` ou `done`. -- `Shipment Type = Dropship` si `from_location.type = supplier` et - `to_location.type = customer`, sinon `Inbound`. -- `Mark as finished` masque seulement les reliquats ouverts / virtuels, pas - les lots physiques. - + diff --git a/modules/purchase_trade/docs/business/matching.md b/modules/purchase_trade/docs/business/matching.md index 89c617c..1fc1f77 100644 --- a/modules/purchase_trade/docs/business/matching.md +++ b/modules/purchase_trade/docs/business/matching.md @@ -1,3 +1,5 @@ + + # Matching achat / vente Statut: `migration partielle` @@ -14,14 +16,16 @@ lot source. ### Notes developpeur -- La quantite du wizard doit correspondre a la somme des quantites ouvertes - selectionnees. -- Creer une ligne par `lot.qt` source. -- Conserver `created_by_code = True` pour eviter les creations automatiques - parasites lors des validations. + ## Notes de migration Les regles sur `Apply matching` presentes dans les notes de session du `2026-05-09` doivent encore etre promues ici. - diff --git a/modules/purchase_trade/docs/business/payments-banking.md b/modules/purchase_trade/docs/business/payments-banking.md index 977ff4a..cf318be 100644 --- a/modules/purchase_trade/docs/business/payments-banking.md +++ b/modules/purchase_trade/docs/business/payments-banking.md @@ -1,3 +1,5 @@ + + # Paiements et banques Statut: `migration partielle` @@ -13,9 +15,13 @@ bancaire utilise par la compagnie courante pour encaisser ou payer. ### Notes developpeur -- Contrats: `sale.sale`, `purchase.purchase`. -- `bank_account`: compte de la party du contrat. -- `our_bank_account`: compte de la compagnie courante, selectionnable parmi - les comptes disponibles. -- La devise du contrat est prioritaire pour proposer un compte par defaut. - + diff --git a/modules/purchase_trade/docs/business/pricing.md b/modules/purchase_trade/docs/business/pricing.md index 3ebee56..2b432d3 100644 --- a/modules/purchase_trade/docs/business/pricing.md +++ b/modules/purchase_trade/docs/business/pricing.md @@ -1,3 +1,5 @@ + + # Pricing, basis, premium Statut: `migration partielle` @@ -13,9 +15,14 @@ la ligne soit en prix fixe ou en basis. ### Notes developpeur -- `unit_price` reste le prix de base hors premium. -- Montant economique: `unit_price + premium converti si necessaire`. -- En basis, le premium s'applique aussi aux blocs valorises. + ## BR-PT-PRI-002 - Linked currency @@ -28,11 +35,14 @@ dans ce meme repere puis converti pour les calculs internes. ### Notes developpeur -- Champs obligatoires si active: `linked_price`, `linked_currency`, - `linked_unit`. -- En `basis + linked currency`, `linked_price` represente le basis brut hors - premium. -- `amount` ajoute le premium converti. + ## BR-PT-PRI-003 - Pricing manuel @@ -45,9 +55,13 @@ le prix de marche. Les cumuls et prix moyens sont calcules automatiquement. ### Notes developpeur -- Champs saisis: `quantity`, `settl_price`. -- Champs derives: `fixed_qt`, `fixed_qt_price`, `unfixed_qt`, - `unfixed_qt_price`, `eod_price`, `last`. -- Groupe metier: `line + component` ou `sale_line + component`. -- Le composant choisi doit appartenir a la ligne courante. - + diff --git a/modules/purchase_trade/docs/business/reports-templates.md b/modules/purchase_trade/docs/business/reports-templates.md index c59463a..f150c0a 100644 --- a/modules/purchase_trade/docs/business/reports-templates.md +++ b/modules/purchase_trade/docs/business/reports-templates.md @@ -1,12 +1,19 @@ + + # Reports et templates Statut: `migration partielle` Voir aussi: -- `../template-rules.md` -- `../template-properties.md` -- `../../../../notes/template_business_rules.md` + ## BR-PT-RPT-001 - Templates trade via proprietes Python @@ -19,21 +26,30 @@ d'expressions fragiles dans le fichier bureautique. ### Notes developpeur -- Preferer des proprietes Python simples, souvent prefixees `report_*`. -- Dans les placeholders XML, utiliser `"` et `'` plutot que des - antislashs. -- Pour les factures liees a vente/achat/shipment, privilegier le lot physique - comme pont. -- Verifier le cache `invoice_report_cache` avant de conclure qu'une action - report pointe vers le mauvais `.fodt`. -- Pour les templates shipment, preferer `records[0]...` ou des proprietes sur - `stock.shipment.in` plutot qu'une variable locale supposee. + ## Decisions deja documentees a migrer ensuite -- `insurance.fodt`: compagnie courante, amount insured a 110%, surveyor. -- `packing_list.fodt`: date du jour, unites depuis `purchase.line`. -- `bill.fodt`: maturity date reelle et montant en lettres depuis le total. -- `invoice_ict.fodt` / `invoice_ict_final.fodt`: poids, shipments et lots. -- `sale_ict.fodt`: priorite lots et unite reelle. - + diff --git a/modules/purchase_trade/docs/business/risk-credit-forex.md b/modules/purchase_trade/docs/business/risk-credit-forex.md index 8157c24..4842046 100644 --- a/modules/purchase_trade/docs/business/risk-credit-forex.md +++ b/modules/purchase_trade/docs/business/risk-credit-forex.md @@ -1,3 +1,5 @@ + + # Risque, credit, forex Statut: `placeholder` @@ -9,7 +11,11 @@ Aucune regle canonique `purchase_trade` n'a ete promue ici dans cette premiere passe. Les notes comptables et forex existantes doivent etre relues avant toute migration: -- `notes/accounting/README.md` -- `notes/accounting/business_rules.md` -- `notes/accounting/reporting.md` - + diff --git a/modules/purchase_trade/docs/business/sessions.md b/modules/purchase_trade/docs/business/sessions.md index 5cb8e8a..cde9119 100644 --- a/modules/purchase_trade/docs/business/sessions.md +++ b/modules/purchase_trade/docs/business/sessions.md @@ -1,3 +1,5 @@ + + # Journal de migration et sessions Statut: `non canonique` @@ -7,25 +9,28 @@ canonique seulement quand elle est reprise dans une page thematique. ## Sources historiques -- `modules/purchase_trade/docs/business-rules.md` -- `modules/purchase_trade/docs/business-rules-architecture-proposal.md` -- `notes/business_rules.md` -- `notes/template_business_rules.md` + ## Notes deja partiellement promues -- Session `2026-04-30`: PnL fees ouverts et `% rate`, promue dans - [fees.md](fees.md) et [valuation-pnl-mtm.md](valuation-pnl-mtm.md). -- Session `2026-05-01`: solde ouvert apres lots physiques et lots effectifs - des fees, promue dans [lots-and-quantities.md](lots-and-quantities.md) et - [fees.md](fees.md). -- Session `2026-05-06`: Remove physical lot, promue dans - [lots-and-quantities.md](lots-and-quantities.md). -- Session `2026-05-09`: Lots Management, promue partiellement dans - [lots-management.md](lots-management.md). -- Session `2026-05-13`: cadrage `quantity_theorical` / `quantity`, amount de - ligne, Weight basis, invariants de quantite, checks Python bloquants et - diagnostic SQL. Promue dans - [lots-and-quantities.md](lots-and-quantities.md), - [lots-and-quantities.en.md](lots-and-quantities.en.md), - [invariants.md](invariants.md) et [sql/README.md](sql/README.md). + diff --git a/modules/purchase_trade/docs/business/shipments-execution.md b/modules/purchase_trade/docs/business/shipments-execution.md index b9e9784..f8bfe4d 100644 --- a/modules/purchase_trade/docs/business/shipments-execution.md +++ b/modules/purchase_trade/docs/business/shipments-execution.md @@ -1,3 +1,5 @@ + + # Shipments et execution Statut: `migration partielle` @@ -13,10 +15,16 @@ retard par rapport a son objectif. ### Notes developpeur -- Configuration: onglet `Execution` de `party.party`. -- La zone du shipment vient de `shipment.to_location.country`. -- Une region parente couvre ses sous-regions. -- `% achieved` compte seulement les shipments deja affectes a un controller. + ## BR-PT-SHP-002 - Couts SLA controller par pays et/ou lieu @@ -29,8 +37,12 @@ lieu. Le couple est le cas le plus specifique. ### Notes developpeur -- Matching: `country + location`, puis `location`, puis `country`. -- Le pays vient de `shipment.to_location.country`. + ## BR-PT-SHP-003 - Weight reports distants par lot @@ -43,7 +55,11 @@ sur le shipment. ### Notes developpeur -- Exporter seulement les lots physiques des `incoming_moves`. -- Exiger au minimum `controller` et `returned_id` sur le shipment. -- Conserver les cles distantes et la date d'envoi sur le `weight.report`. - + diff --git a/modules/purchase_trade/docs/business/sql/README.md b/modules/purchase_trade/docs/business/sql/README.md index 426119d..66e02b9 100644 --- a/modules/purchase_trade/docs/business/sql/README.md +++ b/modules/purchase_trade/docs/business/sql/README.md @@ -1,3 +1,5 @@ + + # SQL diagnostics for purchase_trade business rules These scripts are read-only diagnostics for a PostgreSQL test database. @@ -23,24 +25,34 @@ reported as anomalous. Run it on a restored test database: -```sql -\i modules/purchase_trade/docs/business/sql/quantity_consistency_checks.sql -``` +
\i modules/purchase_trade/docs/business/sql/quantity_consistency_checks.sql
The script returns rows only when it finds a potential issue. Main columns: -- `check_name`: invariant or diagnostic that failed. -- `contract_model`: `purchase.purchase` or `sale.sale`. -- `contract_id`: database id of the contract. -- `contract_number`: purchase or sale contract number. -- `line_id`: `purchase.line` or `sale.line` id depending on the check. -- `virtual_lot_id`: virtual lot involved in the inconsistency. -- `observed_value`: value found in the database. -- `expected_value`: value required by the business rule. -- `diff`: observed minus expected. -- `detail`: human-readable explanation. + Cross-category UoM rows are reported as manual-review diagnostics because the Python code may pass explicit conversion factors that cannot be inferred safely diff --git a/modules/purchase_trade/docs/business/valuation-pnl-mtm.md b/modules/purchase_trade/docs/business/valuation-pnl-mtm.md index 073441a..4e9e446 100644 --- a/modules/purchase_trade/docs/business/valuation-pnl-mtm.md +++ b/modules/purchase_trade/docs/business/valuation-pnl-mtm.md @@ -1,3 +1,5 @@ + + # Valuation, PnL, MTM Statut: `migration partielle` @@ -13,12 +15,14 @@ n'est pas encore matchee a un achat. ### Notes developpeur -- Une `sale.line` non matchee doit generer au minimum `sale priced`, `sale fee` - et `derivative` si applicable. -- Une sale basis sans detail de prix doit quand meme produire une ligne a zero - ou au prix economique fallback selon la regle applicable. -- Ne pas attacher arbitrairement une sale unique si plusieurs sales sont - matchees au meme ouvert. + ## BR-PT-VAL-002 - References de valuation @@ -31,9 +35,12 @@ vente, ouverte ou physique. ### Notes developpeur -- References autorisees: `Purchase/Open`, `Purchase/Physic`, `Sale/Open`, - `Sale/Physic`. -- Un lot virtuel ne doit pas sortir avec une reference physique. + ## BR-PT-VAL-003 - MTM hors fees @@ -45,7 +52,11 @@ Le mark-to-market s'applique aux prix et aux derives, pas aux frais. ### Notes developpeur -- MTM autorise pour `pur. priced`, `sale priced`, `derivative`. -- Fees hors MTM: `pur. fee`, `sale fee`, `shipment fee`, `line fee`. -- Pour les fees: `mtm_price`, `mtm`, `strategy` doivent rester vides. - + diff --git a/modules/purchase_trade/docs/tools/render_business_docs.py b/modules/purchase_trade/docs/tools/render_business_docs.py index 0a2574a..bb2dac4 100644 --- a/modules/purchase_trade/docs/tools/render_business_docs.py +++ b/modules/purchase_trade/docs/tools/render_business_docs.py @@ -10,18 +10,13 @@ from __future__ import annotations import argparse import html import re +import sys from pathlib import Path ROOT = Path(__file__).resolve().parents[1] BUSINESS = ROOT / "business" SOURCE = ROOT.parent / "docs_source" / "business" -TARGETS = ( - "lots-and-quantities.md", - "lots-and-quantities.en.md", -) - - MATERIAL_ICON = re.compile(r":material-[a-z0-9-]+:\s*") @@ -190,6 +185,56 @@ def render_callout(lines: list[str]) -> str: ) +def is_bullet_line(line: str) -> bool: + return bool(re.match(r"^\s*-\s+", line)) + + +def bullet_level(line: str) -> int: + return len(re.match(r"^\s*", line).group(0)) // 2 + + +def render_list(lines: list[str]) -> str: + root: list[dict[str, object]] = [] + stack: list[tuple[int, list[dict[str, object]]]] = [(-1, root)] + last_item: dict[str, object] | None = None + + for line in lines: + if is_bullet_line(line): + level = bullet_level(line) + content = re.sub(r"^\s*-\s+", "", line).strip() + while stack[-1][0] >= level: + stack.pop() + item: dict[str, object] = { + "content": content, + "children": [], + } + stack[-1][1].append(item) + stack.append((level, item["children"])) + last_item = item + elif line.strip() and last_item is not None: + last_item["content"] = str(last_item["content"]) + " " + line.strip() + + def render_items(items: list[dict[str, object]], level: int = 0) -> str: + margin = "1.1rem" if level == 0 else "1.35rem" + bullet = "disc" if level == 0 else "circle" + parts = [ + f'") + return "\n".join(parts) + + return render_items(root) + + def render_source(text: str) -> str: lines = text.splitlines() out = [ @@ -244,20 +289,47 @@ def render_source(text: str) -> str: out.extend(table) continue + if is_bullet_line(line): + list_lines = [] + while i < len(lines) and ( + is_bullet_line(lines[i]) + or ( + lines[i].startswith(" ") + and lines[i].strip() + and not lines[i].lstrip().startswith("|") + ) + ): + list_lines.append(lines[i]) + i += 1 + out.append(render_list(list_lines)) + continue + out.append(line) i += 1 return "\n".join(out).strip() + "\n" -def render_all(normalize: bool = False) -> None: +def source_files() -> list[Path]: + return sorted(path for path in SOURCE.rglob("*.md") if path.is_file()) + + +def render_all(normalize: bool = False, check: bool = False) -> bool: SOURCE.mkdir(parents=True, exist_ok=True) - for name in TARGETS: - source = SOURCE / name - target = BUSINESS / name + ok = True + for source in source_files(): + target = BUSINESS / source.relative_to(SOURCE) + target.parent.mkdir(parents=True, exist_ok=True) if normalize: source.write_text(normalize_source(source.read_text(encoding="utf-8")), encoding="utf-8") - target.write_text(render_source(source.read_text(encoding="utf-8")), encoding="utf-8") + rendered = render_source(source.read_text(encoding="utf-8")) + if check: + if not target.exists() or target.read_text(encoding="utf-8") != rendered: + print(f"Outdated generated doc: {target.relative_to(ROOT.parent)}") + ok = False + else: + target.write_text(rendered, encoding="utf-8") + return ok def main() -> None: @@ -267,8 +339,16 @@ def main() -> None: action="store_true", help="Clean existing source files from wiki-only syntax before rendering.", ) + parser.add_argument( + "--check", + action="store_true", + help="Fail if generated wiki files are not up to date.", + ) args = parser.parse_args() - render_all(normalize=args.normalize_source) + if args.normalize_source and args.check: + parser.error("--normalize-source cannot be used with --check") + if not render_all(normalize=args.normalize_source, check=args.check): + sys.exit(1) if __name__ == "__main__": diff --git a/modules/purchase_trade/docs_source/business/INDEX.md b/modules/purchase_trade/docs_source/business/INDEX.md new file mode 100644 index 0000000..af2d99d --- /dev/null +++ b/modules/purchase_trade/docs_source/business/INDEX.md @@ -0,0 +1,48 @@ +# Index thematique des regles business + +Statut: `migration partielle` + +## Comment chercher une regle + +- Contrats, dates, lieux, banques: [contracts.md](contracts.md) +- Lots virtuels, lots physiques, `lot.qt`, weighing: [FR](lots-and-quantities.md) / [EN](lots-and-quantities.en.md) +- Matching, Create Contracts, back-to-back: [matching.md](matching.md) +- Shipments, controllers, SLA, weight reports: [shipments-execution.md](shipments-execution.md) +- Pricing manuel, basis, premium, linked currency: [pricing.md](pricing.md) +- Fees, freight, lots effectifs, `% rate`: [fees.md](fees.md) +- Valuation, PnL, MTM, derivatives: [valuation-pnl-mtm.md](valuation-pnl-mtm.md) +- Factures provisoires/finales, padding: [invoicing.md](invoicing.md) +- Impacts `account.move`, validate/post: [accounting-bridge.md](accounting-bridge.md) +- Comptes bancaires, payment terms, payment orders: [payments-banking.md](payments-banking.md) +- Relatorio, `.fodt`, proprietes `report_*`: [reports-templates.md](reports-templates.md) +- Risque, credit, forex: [risk-credit-forex.md](risk-credit-forex.md) +- Rapport Lots Management: [lots-management.md](lots-management.md) +- Diagnostics SQL des invariants: [sql/README.md](sql/README.md) + +## Regles migrees dans cette premiere passe + +- `BR-PT-CON-001`: texte par defaut de pricing rule. +- `BR-PT-CON-002`: delivery period coherent. +- `BR-PT-CON-003`: lieux stock propages dans Create Contracts. +- `BR-PT-LOT-001`: cycle de vie des lots et des quantites. +- `BR-PT-LOT-002`: quantity contractuelle, execute physique et ligne finie. +- `BR-PT-LOT-003`: garde-fous Python et diagnostics SQL des invariants de + quantite. +- `BR-PT-MAT-001`: Create Contracts multi-lots. +- `BR-PT-SHP-001`: affectation controller. +- `BR-PT-SHP-002`: couts SLA controller. +- `BR-PT-SHP-003`: weight reports distants. +- `BR-PT-PRI-001`: premium dans priced et basis. +- `BR-PT-PRI-002`: linked currency. +- `BR-PT-PRI-003`: pricing manuel. +- `BR-PT-FEE-001`: maritime freight depuis fee shipment. +- `BR-PT-FEE-002`: lots effectifs des fees. +- `BR-PT-FEE-003`: `% rate` via delta de financement. +- `BR-PT-VAL-001`: valuation achat/vente et sale-first. +- `BR-PT-VAL-002`: references de valuation. +- `BR-PT-VAL-003`: MTM hors fees. +- `BR-PT-INV-001`: padding facture provisoire vente. +- `BR-PT-ACC-001`: Validate facture client attribue le numero. +- `BR-PT-PAY-001`: comptes bancaires tiers vs compagnie. +- `BR-PT-RPT-001`: templates trade via proprietes Python. +- `BR-PT-LOTMGT-001`: filtres Lots Management. diff --git a/modules/purchase_trade/docs_source/business/README.md b/modules/purchase_trade/docs_source/business/README.md new file mode 100644 index 0000000..4b736d2 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/README.md @@ -0,0 +1,117 @@ +# Guide de lecture des règles business + +Statut: `migration partielle` +Dernière mise à jour: `2026-05-13` + +Ce dossier devient la source de lecture thématique publiée dans le wiki pour les +règles business du module `purchase_trade`. + +Toutes les pages business publiées dans `modules/purchase_trade/docs/business/` +sont générées depuis une source de vérité plus sobre, rangée hors du dossier +wiki dans `modules/purchase_trade/docs_source/business/`. + +Les pages publiées portent un commentaire `Generated from ...` en tête de +fichier et ne doivent pas être modifiées directement. Aucun contenu business ne +doit être ajouté ou modifié sans passer par cette source puis par le script de +génération. + +Chaque page doit rester lisible par deux publics: + +- les consultants, qui ont besoin d'une règle fonctionnelle stable sans détail + de code inutile; +- les développeurs, qui ont besoin des champs, modèles, fichiers et tests + concernés pour appliquer la règle sans l'interpréter. + +## Convention de langues + +Chaque page thématique durable doit exister en deux versions maintenues +ensemble: + +- une page française, rédigée en français correct avec accents, typographie et + formulations naturelles pour le wiki consultant; +- une page anglaise miroir, portant le même contenu fonctionnel et technique. + +Convention de nommage: + +- page française principale: `theme.md`; +- page anglaise miroir: `theme.en.md`. + +Toute modification d'une règle business, d'un statut, d'un champ technique ou +d'un point de vigilance doit être reportée dans les deux pages au même moment. +Les deux pages doivent indiquer leur page miroir en en-tête. + +## Convention source / wiki + +Pour toute page business: + +- éditer la source de vérité dans `modules/purchase_trade/docs_source/business/`; +- régénérer la version wiki avec: + +```bash +python modules/purchase_trade/docs/tools/render_business_docs.py +``` + +Le rendu wiki privilégie du HTML simple et portable plutôt que des extensions +MkDocs optionnelles. Cela évite d'exposer dans le wiki des marqueurs non rendus +comme `!!!` ou `:material-...:`. + +Les fichiers générés dans `modules/purchase_trade/docs/business/` sont des +artefacts de publication: ils peuvent être relus, mais toute correction doit +être reportée dans `docs_source/business/` avant régénération. + +Avant de livrer une modification documentaire, vérifier que les pages publiées +sont à jour avec: + +```bash +python modules/purchase_trade/docs/tools/render_business_docs.py --check +``` + +## Convention de rédaction + +Pour chaque règle durable, utiliser autant que possible ce format: + +```md +### BR-PT-THEME-001 - Titre court + +Statut: active +Source: business-rules.md / note de session / décision projet + +#### Règle consultant + +Texte fonctionnel, sans nom de champ si ce n'est pas nécessaire. + +#### Notes développeur + +- Modèles/champs: +- Fichiers: +- Tests: +- Points de vigilance: +``` + +## Convention de validation + +Quand une règle business devient structurante pour l'intégrité des données, elle +doit être accompagnée autant que possible de deux garde-fous: + +- un check applicatif bloquant dans le code Python, appelé à la fin des flux qui + modifient les données concernées; +- un diagnostic SQL en lecture seule pour auditer les bases existantes ou les + bases de test. + +Les diagnostics SQL du module sont rangés dans `business/sql/`. Ils ne +remplacent pas les règles applicatives: ils servent à retrouver et qualifier les +écarts déjà présents dans une base. + +## Sources pendant la migration + +Les anciennes pages ne sont pas supprimées à cette étape. Elles restent des +sources de vérification jusqu'à ce que chaque décision soit promue dans une +page thématique: + +- `modules/purchase_trade/docs/business-rules.md` +- `modules/purchase_trade/docs/fees.md` +- `modules/purchase_trade/docs/padding-invoice-accounting.md` +- `modules/purchase_trade/docs/template-rules.md` +- `modules/purchase_trade/docs/template-properties.md` +- `notes/business_rules.md` +- `notes/template_business_rules.md` diff --git a/modules/purchase_trade/docs_source/business/accounting-bridge.md b/modules/purchase_trade/docs_source/business/accounting-bridge.md new file mode 100644 index 0000000..9ed8d82 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/accounting-bridge.md @@ -0,0 +1,25 @@ +# Pont comptable + +Statut: `migration partielle` + +## BR-PT-ACC-001 - Validate facture client attribue aussi le numero + +Source: `BR-PT-017` + +### Regle consultant + +Une facture client doit recevoir son mouvement comptable et son numero des la +validation, comme une facture fournisseur. + +### Notes developpeur + +- Cible: `account.invoice` avec `type = out`. +- Workflow `Validate`: creer `account.move` et attribuer `number`. +- Workflow `Post`: ne doit pas reintroduire une session fraiche specifique au + flux client. + +## Notes de migration + +Les notes comptables detaillees restent dans `notes/accounting/` tant qu'elles +n'ont pas ete promues ici. + diff --git a/modules/purchase_trade/docs_source/business/contracts.md b/modules/purchase_trade/docs_source/business/contracts.md new file mode 100644 index 0000000..ad12d06 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/contracts.md @@ -0,0 +1,50 @@ +# Contrats achat / vente + +Statut: `migration partielle` + +## BR-PT-CON-001 - Texte par defaut de pricing rule + +Source: `BR-PT-013` + +### Regle consultant + +Le texte de regle de pricing recurrent doit etre configure une seule fois et +repris automatiquement sur les nouvelles lignes achat et vente. + +### Notes developpeur + +- Configuration: `purchase_trade.configuration.pricing_rule`. +- Cibles: `purchase.line.pricing_rule`, `sale.line.pricing_rule`. +- Les lignes existantes ne sont pas modifiees retroactivement. + +## BR-PT-CON-002 - Delivery period coherent + +Source: `BR-PT-014` historique, doublon de numerotation a corriger + +### Regle consultant + +Une periode de livraison ne peut pas commencer apres sa date de fin. Une seule +borne renseignee reste acceptee. + +### Notes developpeur + +- Champs: `purchase.line.from_del`, `purchase.line.to_del`, + `sale.line.from_del`, `sale.line.to_del`. +- Validation attendue: bloquer si `from_del > to_del`. + +## BR-PT-CON-003 - Propagation des lieux stock dans Create Contracts + +Source: `BR-PT-024` + +### Regle consultant + +Quand un contrat miroir est cree depuis une quantite ouverte, les lieux +logistiques doivent etre proposes selon le flux source pour eviter la ressaisie. + +### Notes developpeur + +- Champs: `from_location`, `to_location`. +- Flux fournisseur vers client: recopier le couple source. +- Achat vers stock puis vente: `sale.from_location = purchase.to_location`. +- Vente depuis stock puis achat: `purchase.to_location = sale.from_location`. + diff --git a/modules/purchase_trade/docs_source/business/fees.md b/modules/purchase_trade/docs_source/business/fees.md new file mode 100644 index 0000000..47e9cbf --- /dev/null +++ b/modules/purchase_trade/docs_source/business/fees.md @@ -0,0 +1,55 @@ +# Fees + +Statut: `migration partielle` + +Voir aussi la page technique historique: `../fees.md`. + +## BR-PT-FEE-001 - Freight value depuis fee shipment + +Source: `BR-PT-003` + +### Regle consultant + +La valeur de fret affichee sur les documents facture vient du fee maritime du +shipment, pas d'un champ direct de la facture. + +### Notes developpeur + +- Retrouver le lot physique depuis la facture. +- Retrouver son `shipment_in`. +- Chercher le `fee.fee` avec `product.name = 'Maritime freight'`. +- Utiliser `fee.get_amount()`. + +## BR-PT-FEE-002 - Les fees lies aux lots privilegient les physiques + +Source: `BR-PT-021` + +### Regle consultant + +Un fee suit le lot virtuel tant qu'aucun lot physique n'est lie. Des qu'un lot +physique est lie, les lots physiques deviennent la base de calcul du fee. + +### Notes developpeur + +- Ne pas supprimer le lien virtuel: il reste le fallback. +- Quantite `ppack`: somme de `lot.lot_qt` des physiques. +- Modes quantitatifs: quantites courantes converties des physiques. +- La meme selection s'applique au PnL fee. +- Points de synchronisation: creation fee, lien `fee.lots`, changement de + `quantity_theorical`, weighing, suppression de physique. + +## BR-PT-FEE-003 - Fees `% rate` via delta de financement + +Source: `BR-PT-016` historique et notes `2026-04-30` + +### Regle consultant + +Les frais financiers en pourcentage se calculent avec le delta de financement +de la ligne d'estimation `BL date`, pas avec la date du jour. + +### Notes developpeur + +- Formule: `amount = unit_price * quantity * (price / 100) * fin_int_delta / 360`. +- Source du delta: ligne `Estimated date` avec `trigger = bldate`. +- Si aucune ligne `bldate` n'existe, ne pas calculer de montant `% rate`. + diff --git a/modules/purchase_trade/docs_source/business/glossary.md b/modules/purchase_trade/docs_source/business/glossary.md new file mode 100644 index 0000000..5987986 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/glossary.md @@ -0,0 +1,22 @@ +# Glossaire purchase_trade + +Statut: `migration partielle` + +- `Purchase Line`: ligne d'achat. +- `Sale Line`: ligne de vente. +- `quantity_theorical`: quantite contractuelle theorique d'une ligne. +- `Virtual Lot`: lot de type `virtual`, representant un reliquat ouvert. +- `Physical Lot`: lot de type `physic`, representant une quantite executee. +- `lot.qt`: ligne de quantite ouverte, matchee ou rattachee a un shipment. +- `lot.qt ouvert`: `lot.qt` libre, sans lot oppose et sans shipment. +- `Shipment In`: shipment entrant utilise aussi pour les flux dropship dans ce module. +- `Dropship`: flux fournisseur vers client, sans passage par stock interne. +- `Inbound`: flux entrant classique qui ne correspond pas au dropship. +- `Basis`: mode de prix construit a partir d'un prix de marche et d'un premium. +- `Premium`: prime ou discount commercial ajoute au prix economique. +- `Linked currency`: saisie d'un prix dans une devise/unite liee, par exemple `USC/LB`. +- `Valuation`: lignes de PnL generees pour prix, fees, derivatives et MTM. +- `MTM`: mark-to-market applique aux lignes valorisables au marche. +- `Fee`: frais commercial ou logistique rattache a une ligne, un lot ou un shipment. +- `Report property`: propriete Python exposee pour simplifier un template Relatorio. + diff --git a/modules/purchase_trade/docs_source/business/invariants.md b/modules/purchase_trade/docs_source/business/invariants.md new file mode 100644 index 0000000..a38144a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/invariants.md @@ -0,0 +1,75 @@ +# Invariants structurants + +Statut: `migration partielle` + +Ces invariants doivent etre relus avant de modifier des flux `purchase_trade` +touchant lots, quantites, fees, PnL, factures ou templates. + +## INV-PT-001 - Le lot physique est le pont metier stable + +### Regle consultant + +Quand une information doit relier achat, vente, shipment et facture, le chemin +fonctionnel de reference passe par le lot physique. Il porte le lien entre les +contrats et l'execution logistique. + +### Notes developpeur + +- Source historique: `BR-PT-002`. +- Voir aussi: [lots-and-quantities.md](lots-and-quantities.md), + [matching.md](matching.md), [reports-templates.md](reports-templates.md). +- Champs frequents: `lot.line`, `lot.sale_line`, `lot_shipment_in`, + `lot_shipment_internal`, `lot_shipment_out`. + +## INV-PT-002 - Le reliquat ouvert ne doit pas doubler les lots physiques + +### Regle consultant + +Une quantite deja executee physiquement ne doit pas rester disponible comme +quantite ouverte. Le reliquat ouvert represente seulement ce qui reste a +executer. + +### Notes developpeur + +- Source historique: `BR-PT-020`. +- Le calcul doit tenir compte de la quantite contractuelle, des lots physiques + existants et des `lot.qt` deja matches ou shippes. +- Regle de conservation: + `sum(lots physiques) + lot virtuel = quantity_theorical`. +- Regle du forecast ouvert: + `sum(lot.qt non zero) = max(lot virtuel, 0)`. +- Les lignes `lot.qt` a zero sont ignorees par les checks: elles peuvent servir + de memoire d'une prevision consommee. +- Le check applicatif est centralise dans + `lot.lot.assert_lines_quantity_consistency()`. +- Le diagnostic SQL correspondant est + [sql/quantity_consistency_checks.sql](sql/quantity_consistency_checks.sql). + +## INV-PT-003 - Les fees utilisent leurs lots effectifs + +### Regle consultant + +Un fee ouvert suit le lot virtuel tant qu'il n'y a pas de lot physique. Des +qu'un ou plusieurs lots physiques sont lies au fee, ils deviennent la base +effective de calcul. + +### Notes developpeur + +- Source historique: `BR-PT-021`. +- Ne pas supprimer le lien virtuel: il reste le fallback si les physiques sont + retires. +- Voir [fees.md](fees.md). + +## INV-PT-004 - Les templates doivent rester simples + +### Regle consultant + +Les documents doivent afficher des informations metier stables, meme si le +chemin technique pour les retrouver est complexe. + +### Notes developpeur + +- Preferer des proprietes Python `report_*` aux expressions Genshi complexes. +- Ne pas supposer qu'une variable locale comme `shipment` existe partout dans + un `.fodt`. +- Voir [reports-templates.md](reports-templates.md). diff --git a/modules/purchase_trade/docs_source/business/invoicing.md b/modules/purchase_trade/docs_source/business/invoicing.md new file mode 100644 index 0000000..ac3c51a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/invoicing.md @@ -0,0 +1,24 @@ +# Facturation trade + +Statut: `migration partielle` + +## BR-PT-INV-001 - Padding facture provisoire vente + +Source: `BR-PT-019` et `../padding-invoice-accounting.md` + +### Regle consultant + +Le padding d'une facture provisoire vente augmente la quantite facturee pour +constituer une provision, sans modifier la quantite physique du lot. + +### Notes developpeur + +- Le padding global du wizard `lot.invoice` est reparti entre les lots + selectionnes. +- La ligne facture expose `Inc. padding`. +- Le lot conserve sa part dans `sale_invoice_padding`. +- La facture finale retire le padding de la quantite provisoire avant de + calculer le delta. +- Les ecritures d'extourne doivent relire la provisoire depuis + `lot.sale_invoice_line_prov`. + diff --git a/modules/purchase_trade/docs_source/business/lots-management.md b/modules/purchase_trade/docs_source/business/lots-management.md new file mode 100644 index 0000000..fd89c29 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/lots-management.md @@ -0,0 +1,27 @@ +# Lots Management + +Statut: `migration partielle` + +## BR-PT-LOTMGT-001 - Separations matching, side et shipping status + +Source: `BR-PT-023` et notes `2026-05-09` + +### Regle consultant + +Le rapport Lots Management doit permettre de lire separement le matching +commercial, le sens achat/vente et l'avancement logistique. + +### Notes developpeur + +- Filtres: `Matching status`, `Side`, `Shipping status`, `Dimension`, + `Strategy`. +- Dates `As of` / `To`: `purchase.purchase_date` et `sale.sale_date`. +- `Unshipped`: aucun `shipment_in`. +- `Scheduled`: shipment `draft`. +- `Shipped`: shipment `started`. +- `Received`: shipment `received` ou `done`. +- `Shipment Type = Dropship` si `from_location.type = supplier` et + `to_location.type = customer`, sinon `Inbound`. +- `Mark as finished` masque seulement les reliquats ouverts / virtuels, pas + les lots physiques. + diff --git a/modules/purchase_trade/docs_source/business/matching.md b/modules/purchase_trade/docs_source/business/matching.md new file mode 100644 index 0000000..89c617c --- /dev/null +++ b/modules/purchase_trade/docs_source/business/matching.md @@ -0,0 +1,27 @@ +# Matching achat / vente + +Statut: `migration partielle` + +## BR-PT-MAT-001 - Create Contracts multi-lots conserve le matching source + +Source: `BR-PT-012` et doublon historique `BR-PT-013` + +### Regle consultant + +Le wizard `Create contracts` peut creer un seul contrat miroir depuis plusieurs +quantites ouvertes selectionnees. Chaque ligne creee doit rester reliee a son +lot source. + +### Notes developpeur + +- La quantite du wizard doit correspondre a la somme des quantites ouvertes + selectionnees. +- Creer une ligne par `lot.qt` source. +- Conserver `created_by_code = True` pour eviter les creations automatiques + parasites lors des validations. + +## Notes de migration + +Les regles sur `Apply matching` presentes dans les notes de session du +`2026-05-09` doivent encore etre promues ici. + diff --git a/modules/purchase_trade/docs_source/business/payments-banking.md b/modules/purchase_trade/docs_source/business/payments-banking.md new file mode 100644 index 0000000..977ff4a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/payments-banking.md @@ -0,0 +1,21 @@ +# Paiements et banques + +Statut: `migration partielle` + +## BR-PT-PAY-001 - Distinguer banque tiers et banque compagnie + +Source: `BR-PT-018` + +### Regle consultant + +Un contrat distingue le compte bancaire du client ou fournisseur du compte +bancaire utilise par la compagnie courante pour encaisser ou payer. + +### Notes developpeur + +- Contrats: `sale.sale`, `purchase.purchase`. +- `bank_account`: compte de la party du contrat. +- `our_bank_account`: compte de la compagnie courante, selectionnable parmi + les comptes disponibles. +- La devise du contrat est prioritaire pour proposer un compte par defaut. + diff --git a/modules/purchase_trade/docs_source/business/pricing.md b/modules/purchase_trade/docs_source/business/pricing.md new file mode 100644 index 0000000..3ebee56 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/pricing.md @@ -0,0 +1,53 @@ +# Pricing, basis, premium + +Statut: `migration partielle` + +## BR-PT-PRI-001 - Le premium fait partie du prix economique + +Source: `BR-PT-008` + +### Regle consultant + +Le premium ou discount saisi sur une ligne fait partie du prix economique, que +la ligne soit en prix fixe ou en basis. + +### Notes developpeur + +- `unit_price` reste le prix de base hors premium. +- Montant economique: `unit_price + premium converti si necessaire`. +- En basis, le premium s'applique aussi aux blocs valorises. + +## BR-PT-PRI-002 - Linked currency + +Source: `BR-PT-009` et `BR-PT-010` + +### Regle consultant + +Quand le prix est saisi dans une devise ou unite liee, le premium est exprime +dans ce meme repere puis converti pour les calculs internes. + +### Notes developpeur + +- Champs obligatoires si active: `linked_price`, `linked_currency`, + `linked_unit`. +- En `basis + linked currency`, `linked_price` represente le basis brut hors + premium. +- `amount` ajoute le premium converti. + +## BR-PT-PRI-003 - Pricing manuel + +Source: `BR-PT-016` et doublon historique `BR-PT-015` + +### Regle consultant + +En pricing manuel, l'utilisateur saisit uniquement la quantite fixee du jour et +le prix de marche. Les cumuls et prix moyens sont calcules automatiquement. + +### Notes developpeur + +- Champs saisis: `quantity`, `settl_price`. +- Champs derives: `fixed_qt`, `fixed_qt_price`, `unfixed_qt`, + `unfixed_qt_price`, `eod_price`, `last`. +- Groupe metier: `line + component` ou `sale_line + component`. +- Le composant choisi doit appartenir a la ligne courante. + diff --git a/modules/purchase_trade/docs_source/business/reports-templates.md b/modules/purchase_trade/docs_source/business/reports-templates.md new file mode 100644 index 0000000..c59463a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/reports-templates.md @@ -0,0 +1,39 @@ +# Reports et templates + +Statut: `migration partielle` + +Voir aussi: + +- `../template-rules.md` +- `../template-properties.md` +- `../../../../notes/template_business_rules.md` + +## BR-PT-RPT-001 - Templates trade via proprietes Python + +Source: `template-rules.md`, `template-properties.md`, notes AGENTS + +### Regle consultant + +Un document trade doit afficher des informations metier fiables, sans dependre +d'expressions fragiles dans le fichier bureautique. + +### Notes developpeur + +- Preferer des proprietes Python simples, souvent prefixees `report_*`. +- Dans les placeholders XML, utiliser `"` et `'` plutot que des + antislashs. +- Pour les factures liees a vente/achat/shipment, privilegier le lot physique + comme pont. +- Verifier le cache `invoice_report_cache` avant de conclure qu'une action + report pointe vers le mauvais `.fodt`. +- Pour les templates shipment, preferer `records[0]...` ou des proprietes sur + `stock.shipment.in` plutot qu'une variable locale supposee. + +## Decisions deja documentees a migrer ensuite + +- `insurance.fodt`: compagnie courante, amount insured a 110%, surveyor. +- `packing_list.fodt`: date du jour, unites depuis `purchase.line`. +- `bill.fodt`: maturity date reelle et montant en lettres depuis le total. +- `invoice_ict.fodt` / `invoice_ict_final.fodt`: poids, shipments et lots. +- `sale_ict.fodt`: priorite lots et unite reelle. + diff --git a/modules/purchase_trade/docs_source/business/risk-credit-forex.md b/modules/purchase_trade/docs_source/business/risk-credit-forex.md new file mode 100644 index 0000000..8157c24 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/risk-credit-forex.md @@ -0,0 +1,15 @@ +# Risque, credit, forex + +Statut: `placeholder` + +Cette page est reservee aux regles business sur le risque, le credit et les +ecarts de change. + +Aucune regle canonique `purchase_trade` n'a ete promue ici dans cette premiere +passe. Les notes comptables et forex existantes doivent etre relues avant toute +migration: + +- `notes/accounting/README.md` +- `notes/accounting/business_rules.md` +- `notes/accounting/reporting.md` + diff --git a/modules/purchase_trade/docs_source/business/sessions.md b/modules/purchase_trade/docs_source/business/sessions.md new file mode 100644 index 0000000..5cb8e8a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/sessions.md @@ -0,0 +1,31 @@ +# Journal de migration et sessions + +Statut: `non canonique` + +Cette page sert de routeur vers les notes historiques. Une note devient +canonique seulement quand elle est reprise dans une page thematique. + +## Sources historiques + +- `modules/purchase_trade/docs/business-rules.md` +- `modules/purchase_trade/docs/business-rules-architecture-proposal.md` +- `notes/business_rules.md` +- `notes/template_business_rules.md` + +## Notes deja partiellement promues + +- Session `2026-04-30`: PnL fees ouverts et `% rate`, promue dans + [fees.md](fees.md) et [valuation-pnl-mtm.md](valuation-pnl-mtm.md). +- Session `2026-05-01`: solde ouvert apres lots physiques et lots effectifs + des fees, promue dans [lots-and-quantities.md](lots-and-quantities.md) et + [fees.md](fees.md). +- Session `2026-05-06`: Remove physical lot, promue dans + [lots-and-quantities.md](lots-and-quantities.md). +- Session `2026-05-09`: Lots Management, promue partiellement dans + [lots-management.md](lots-management.md). +- Session `2026-05-13`: cadrage `quantity_theorical` / `quantity`, amount de + ligne, Weight basis, invariants de quantite, checks Python bloquants et + diagnostic SQL. Promue dans + [lots-and-quantities.md](lots-and-quantities.md), + [lots-and-quantities.en.md](lots-and-quantities.en.md), + [invariants.md](invariants.md) et [sql/README.md](sql/README.md). diff --git a/modules/purchase_trade/docs_source/business/shipments-execution.md b/modules/purchase_trade/docs_source/business/shipments-execution.md new file mode 100644 index 0000000..b9e9784 --- /dev/null +++ b/modules/purchase_trade/docs_source/business/shipments-execution.md @@ -0,0 +1,49 @@ +# Shipments et execution + +Statut: `migration partielle` + +## BR-PT-SHP-001 - Affectation controller par ecart a l'objectif + +Source: `BR-PT-014` + +### Regle consultant + +Le controller propose automatiquement est celui dont la zone a le plus grand +retard par rapport a son objectif. + +### Notes developpeur + +- Configuration: onglet `Execution` de `party.party`. +- La zone du shipment vient de `shipment.to_location.country`. +- Une region parente couvre ses sous-regions. +- `% achieved` compte seulement les shipments deja affectes a un controller. + +## BR-PT-SHP-002 - Couts SLA controller par pays et/ou lieu + +Source: `BR-PT-014-bis` + +### Regle consultant + +Un cout controller peut etre defini pour un pays, un lieu, ou le couple pays + +lieu. Le couple est le cas le plus specifique. + +### Notes developpeur + +- Matching: `country + location`, puis `location`, puis `country`. +- Le pays vient de `shipment.to_location.country`. + +## BR-PT-SHP-003 - Weight reports distants par lot + +Source: `BR-PT-015` + +### Regle consultant + +L'export distant par lot part du weight report global choisi par l'utilisateur +sur le shipment. + +### Notes developpeur + +- Exporter seulement les lots physiques des `incoming_moves`. +- Exiger au minimum `controller` et `returned_id` sur le shipment. +- Conserver les cles distantes et la date d'envoi sur le `weight.report`. + diff --git a/modules/purchase_trade/docs_source/business/sql/README.md b/modules/purchase_trade/docs_source/business/sql/README.md new file mode 100644 index 0000000..426119d --- /dev/null +++ b/modules/purchase_trade/docs_source/business/sql/README.md @@ -0,0 +1,47 @@ +# SQL diagnostics for purchase_trade business rules + +These scripts are read-only diagnostics for a PostgreSQL test database. + +They exist to support the same business rules enforced by Python guards. The +expected workflow is: + +1. write the consultant/developer rule in the thematic documentation; +2. enforce the invariant in the application code when feasible; +3. provide a read-only SQL diagnostic to audit existing data. + +## quantity_consistency_checks.sql + +Checks the two core lot quantity invariants documented in +`lots-and-quantities.md` and `lots-and-quantities.en.md`. + +Zero `lot_qt` rows are ignored completely. They are treated as legitimate +memory of an open quantity consumed by a physical lot. This is required because +`lot_qt` represents usable open forecast and stops at zero, while the virtual +lot may become negative to compensate the difference between theoretical and +executed quantity. A non-zero `lot_qt` row without both `lot_p` and `lot_s` is +reported as anomalous. + +Run it on a restored test database: + +```sql +\i modules/purchase_trade/docs/business/sql/quantity_consistency_checks.sql +``` + +The script returns rows only when it finds a potential issue. + +Main columns: + +- `check_name`: invariant or diagnostic that failed. +- `contract_model`: `purchase.purchase` or `sale.sale`. +- `contract_id`: database id of the contract. +- `contract_number`: purchase or sale contract number. +- `line_id`: `purchase.line` or `sale.line` id depending on the check. +- `virtual_lot_id`: virtual lot involved in the inconsistency. +- `observed_value`: value found in the database. +- `expected_value`: value required by the business rule. +- `diff`: observed minus expected. +- `detail`: human-readable explanation. + +Cross-category UoM rows are reported as manual-review diagnostics because the +Python code may pass explicit conversion factors that cannot be inferred safely +from SQL alone. diff --git a/modules/purchase_trade/docs_source/business/valuation-pnl-mtm.md b/modules/purchase_trade/docs_source/business/valuation-pnl-mtm.md new file mode 100644 index 0000000..073441a --- /dev/null +++ b/modules/purchase_trade/docs_source/business/valuation-pnl-mtm.md @@ -0,0 +1,51 @@ +# Valuation, PnL, MTM + +Statut: `migration partielle` + +## BR-PT-VAL-001 - La valuation couvre achat, vente et sale-first + +Source: `BR-PT-004`, `BR-PT-006`, `BR-PT-011` + +### Regle consultant + +Le PnL doit exister pour les achats et pour les ventes, meme quand une vente +n'est pas encore matchee a un achat. + +### Notes developpeur + +- Une `sale.line` non matchee doit generer au minimum `sale priced`, `sale fee` + et `derivative` si applicable. +- Une sale basis sans detail de prix doit quand meme produire une ligne a zero + ou au prix economique fallback selon la regle applicable. +- Ne pas attacher arbitrairement une sale unique si plusieurs sales sont + matchees au meme ouvert. + +## BR-PT-VAL-002 - References de valuation + +Source: `BR-PT-005` + +### Regle consultant + +La reference de PnL doit decrire la nature de la ligne valorisee: achat ou +vente, ouverte ou physique. + +### Notes developpeur + +- References autorisees: `Purchase/Open`, `Purchase/Physic`, `Sale/Open`, + `Sale/Physic`. +- Un lot virtuel ne doit pas sortir avec une reference physique. + +## BR-PT-VAL-003 - MTM hors fees + +Source: `BR-PT-007` + +### Regle consultant + +Le mark-to-market s'applique aux prix et aux derives, pas aux frais. + +### Notes developpeur + +- MTM autorise pour `pur. priced`, `sale priced`, `derivative`. +- Fees hors MTM: `pur. fee`, `sale fee`, `shipment fee`, `line fee`. +- Pour les fees: `mtm_price`, `mtm`, `strategy` doivent rester vides. +