From e6bbf2f1c1c25430d6c8fef01fa66257d94f183c Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Thu, 14 May 2026 10:40:35 +0200 Subject: [PATCH] docs --- .../docs/business/lots-and-quantities.en.md | 179 ++++++++--------- .../docs/business/lots-and-quantities.md | 183 +++++++++--------- 2 files changed, 185 insertions(+), 177 deletions(-) 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 ae27555..e05f08f 100644 --- a/modules/purchase_trade/docs/business/lots-and-quantities.en.md +++ b/modules/purchase_trade/docs/business/lots-and-quantities.en.md @@ -1,4 +1,4 @@ -# Lots and Quantities +# :material-scale-balance: Lots and Quantities Language: `en` Mirror page: [lots-and-quantities.md](lots-and-quantities.md) @@ -10,111 +10,116 @@ This page consolidates `BR-PT-LOT-001`, `BR-PT-LOT-002`, and Goal: drive quantity rules from a readable business definition, then secure them with Python guards and SQL diagnostics. -## Key Points +## :material-bookmark-check: Key Points -- A trade line has exactly one virtual lot. -- The virtual lot represents the global open balance of the line. -- `lot.qt` represents the operational forecast: matching, forecast sale, - transport, shipment. -- Physical lots consume a `lot.qt` line. -- `quantity_theorical` is the business quantity entered by the user. -- `quantity` is a read-only technical counter. -- The line amount uses theoretical quantity while the line is not finished. -- A finished line may switch back to physical execution, possibly using the - Weight basis quantity state. -- Invoicing chooses its own quantity states from `lot.qt.hist`. -- Invariants are enforced by Python and auditable with SQL. +!!! abstract ":material-compass-outline: Operational Summary" + A trade line has exactly one virtual lot. The virtual lot carries the + global open balance, `lot.qt` carries the operational forecast, and + physical lots consume that forecast. -## Consultant Rules +| Marker | Topic | Short Rule | +| --- | --- | +| :material-pencil: | Entered quantity | `quantity_theorical` is the business quantity. | +| :material-counter: | Standard quantity | `quantity` is a read-only technical counter. | +| :material-timeline-clock-outline: | Before physical lots | `quantity` follows `quantity_theorical`. | +| :material-package-variant-closed: | After physical lots | `quantity` reflects physical execution. | +| :material-lock-open-variant-outline: | Open line | Line amount uses `quantity_theorical`. | +| :material-check-circle-outline: | Finished line | Line amount may switch back to physical execution. | +| :material-weight: | Weight basis | Purchase and sale may read two different states of the same lot. | +| :material-file-document-check-outline: | Invoicing | It chooses states from `lot.qt.hist`. | +| :material-shield-check-outline: | Controls | Invariants are blocked in Python and auditable with SQL. | + +```text +quantity_theorical + | + v + virtual lot P1 ---> lot.qt forecast ---> physical lot + ^ | + | v + +------ recalculation after consumption +``` + +## :material-account-tie: Consultant Rules ### BR-PT-LOT-001 - Virtual lot / forecast / physical life cycle -- When a `purchase line` or `sale line` is created: - - one virtual lot is created; - - its initial quantity is the contractual/theoretical quantity; - - one open `lot.qt` line is created. -- Virtual lot = global open balance. -- `lot.qt` = forecast allocation of that balance. -- Example split of an open balance `P1`: - - `P1S1T1` - - `P1S1T2` - - `P1S2T3` - - `P1S2T4` -- These splits do not create several virtual lots. -- A physical lot is created from a specific `lot.qt` line. -- The physical lot consumes that forecast. -- The `lot.qt` line decreases. -- The virtual lot is recalculated. +| Step | Moment | Business Effect | +| --- | --- | +| :material-plus-box-outline: | Line creation | One unique virtual lot is created. | +| :material-play-circle-outline: | Initialization | The virtual lot takes `quantity_theorical`. | +| :material-map-marker-path: | Forecast | One open line is created in `lot.qt`. | +| :material-source-branch: | Planning | `lot.qt` may be split by sale, matching, transport, or shipment. | +| :material-package-variant: | Physical add | The physical lot consumes a precise `lot.qt` line. | +| :material-refresh: | After add | `lot.qt` decreases and the virtual lot is recalculated. | + +!!! example ":material-source-branch: Split of an open P1 balance" + `P1S1T1`, `P1S1T2`, `P1S2T3`, `P1S2T4` + +!!! note ":material-lightbulb-outline: Key Point" + These splits do not create several virtual lots. They only describe the + forecast allocation of the open balance. ### BR-PT-LOT-002 - Contractual quantity, counter quantity, finished line -- `quantity_theorical` is the business quantity. -- `quantity` is not a business input. -- Before any physical lot: - - `quantity` is initialized from `quantity_theorical`. -- After physical lots are added: - - `quantity` reflects physical execution. -- While `finished = False`: - - the line amount uses `quantity_theorical`. -- When `finished = True`: - - the user accepts ignoring the open balance; - - the line amount may switch back to physical execution; - - the initial contract trace remains unchanged; - - physical lots and their PnL remain visible. -- If a Weight basis exists on the contract: - - purchase: state from `purchase.purchase.wb.qt_type`; - - sale: state from `sale.sale.wb.qt_type`; - - the same physical lot may be read as BL on purchase and LR on sale. -- Invoicing remains independent: - - it may select a specific state in `lot.qt.hist`; - - example: BL on purchase, Weight Report or LR on sale. +| Marker | Situation | Reference Quantity | +| --- | --- | +| :material-pencil: | User entry | `quantity_theorical` | +| :material-package-variant-remove: | No physical lot | `quantity = quantity_theorical` | +| :material-package-variant-closed: | Physical lots exist | `quantity = sum of physical lots` | +| :material-lock-open-variant-outline: | `finished = False` | Amount based on `quantity_theorical` | +| :material-check-circle-outline: | `finished = True` | Amount based on physical execution | +| :material-weight: | Weight basis available | Amount based on the contract `wb.qt_type` state | + +!!! warning ":material-alert-outline: What `finished` Does Not Do" + `finished` does not erase the contractual quantity, delete physical lots, + or hide their PnL. It only means that the open balance may be ignored for + execution calculations. + +| Marker | Reading of the Same Physical Lot | Possible State | +| --- | --- | +| :material-cart-arrow-down: | Purchase | BL through `purchase.purchase.wb.qt_type` | +| :material-cart-arrow-up: | Sale | LR or Weight Report through `sale.sale.wb.qt_type` | +| :material-file-document-check-outline: | Invoicing | Independent choice in `lot.qt.hist` | ### BR-PT-LOT-003 - Quantity Invariants -Conservation invariant: +| Marker | Invariant | Formula | +| --- | --- | +| :material-shield-check-outline: | Conservation | `sum(physical lots) + virtual lot = quantity_theorical` | +| :material-chart-timeline-variant: | Open forecast | `sum(non-zero lot.qt) = max(virtual lot, 0)` | -```text -sum(physical lots) + virtual lot quantity = quantity_theorical -``` - -Open forecast invariant: - -```text -sum(non-zero lot.qt of the virtual lot) = max(virtual lot quantity, 0) -``` - -Details: - -- Purchase: sum all `lot.qt` where `lot_p = virtual lot`, with or without - `lot_s`. -- Sale: sum all `lot.qt` where `lot_s = virtual lot`, with or without `lot_p`. -- `lot.qt = 0` rows are ignored: - - they may keep the memory of a consumed forecast; - - `lot.qt` never goes below zero. -- The virtual lot may become negative: - - it compensates the gap between `quantity_theorical` and physical execution; - - in that case expected open forecast remains zero. -- A non-zero `lot.qt` without `lot_p` and without `lot_s` is forbidden. +| Marker | Case | Rule | +| --- | --- | +| :material-cart-arrow-down: | Purchase virtual lot | Sum all `lot.qt` where `lot_p = virtual lot`, with or without `lot_s`. | +| :material-cart-arrow-up: | Sale virtual lot | Sum all `lot.qt` where `lot_s = virtual lot`, with or without `lot_p`. | +| :material-numeric-0-box-outline: | `lot.qt = 0` | Ignored by checks; possible memory of a consumed forecast. | +| :material-minus-circle-outline: | Negative virtual lot | Allowed to compensate theoretical / executed gap; expected forecast = zero. | +| :material-alert-octagon-outline: | Non-zero orphan `lot.qt` | Forbidden if neither `lot_p` nor `lot_s` is set. | ### BR-PT-LOT-004 - Quantity history and weighing -- `lot.qt.hist` carries lot quantity states. -- The `lot.lot` form is not a direct entry area for states. -- Updates are allowed only through `Do weighing`. -- A virtual lot does not receive manual packing: - - `lot_qt` is not editable; - - `lot_unit` is not editable. +| Marker | Element | Rule | +| --- | --- | +| :material-history: | `lot.qt.hist` | Carries lot quantity states. | +| :material-form-textbox: | `lot.lot` form | No direct state entry. | +| :material-scale: | Update | Only through `Do weighing`. | +| :material-cloud-outline: | Virtual lot | No manual packing. | +| :material-lock-outline: | Virtual packing fields | `lot_qt` and `lot_unit` are not editable. | ### Tolerances -- Tolerance is global on the line or contract. -- It is not independent per transport. -- A physical lot may consume more or less than its forecast. -- This over/under execution consumes or restores remaining tolerance. -- Current gap: full remaining-tolerance control in `LotQt.add_physical_lots` / - `LotQt.add_physical_lot` still needs confirmation. +!!! warning ":material-alert-outline: Gap to Confirm" + Full remaining-tolerance control in `LotQt.add_physical_lots` / + `LotQt.add_physical_lot` still needs confirmation. -## Developer Section +| Marker | Point | Target Rule | +| --- | --- | +| :material-target: | Level | Global tolerance on line or contract. | +| :material-truck-outline: | Transport | No independent tolerance per transport. | +| :material-arrow-up-bold-outline: | Over-execution | Consumes remaining tolerance. | +| :material-arrow-down-bold-outline: | Under-execution | Restores remaining tolerance. | + +## :material-code-braces: Developer Section ### Key Fields diff --git a/modules/purchase_trade/docs/business/lots-and-quantities.md b/modules/purchase_trade/docs/business/lots-and-quantities.md index 1311b7d..c771bd8 100644 --- a/modules/purchase_trade/docs/business/lots-and-quantities.md +++ b/modules/purchase_trade/docs/business/lots-and-quantities.md @@ -1,4 +1,4 @@ -# Lots et quantités +# :material-scale-balance: Lots et quantités Langue : `fr` Page miroir : [lots-and-quantities.en.md](lots-and-quantities.en.md) @@ -9,113 +9,116 @@ Cette page consolide `BR-PT-LOT-001`, `BR-PT-LOT-002` et `BR-PT-LOT-003`. Objectif : piloter les règles de quantité depuis une définition métier lisible, puis les sécuriser par des checks Python et des diagnostics SQL. -## À retenir +## :material-bookmark-check: À retenir -- Une ligne trade possède un seul lot virtuel. -- Le lot virtuel représente le solde ouvert global de la ligne. -- `lot.qt` représente le forecast opérationnel : matching, vente prévue, - transport, shipment. -- Les lots physiques consomment une ligne `lot.qt`. -- `quantity_theorical` est la quantité métier saisie. -- `quantity` est un compteur technique non éditable. -- Le montant de ligne utilise la quantité théorique tant que la ligne n'est pas - finie. -- Une ligne finie peut revenir à l'exécuté physique, éventuellement dans l'état - de quantité du Weight basis. -- La facturation choisit ses propres états de quantité dans `lot.qt.hist`. -- Les invariants sont contrôlés par Python et auditables en SQL. +!!! abstract ":material-compass-outline: Résumé opérationnel" + Une ligne trade possède un seul lot virtuel. Le lot virtuel porte le solde + ouvert global, `lot.qt` porte le forecast opérationnel, et les lots + physiques consomment ce forecast. -## Règles consultant +| Repère | Sujet | Règle courte | +| --- | --- | +| :material-pencil: | Quantité saisie | `quantity_theorical` est la quantité métier. | +| :material-counter: | Quantité standard | `quantity` est un compteur technique non éditable. | +| :material-timeline-clock-outline: | Avant physique | `quantity` suit `quantity_theorical`. | +| :material-package-variant-closed: | Après physique | `quantity` reflète l'exécuté physique. | +| :material-lock-open-variant-outline: | Ligne non finie | Le montant de ligne utilise `quantity_theorical`. | +| :material-check-circle-outline: | Ligne finie | Le montant peut revenir à l'exécuté physique. | +| :material-weight: | Weight basis | Achat et vente peuvent lire deux états différents du même lot. | +| :material-file-document-check-outline: | Facturation | Elle choisit ses états dans `lot.qt.hist`. | +| :material-shield-check-outline: | Contrôles | Invariants bloqués en Python et auditables en SQL. | + +```text +quantity_theorical + | + v + lot virtuel P1 ---> lot.qt forecast ---> lot physique + ^ | + | v + +------ recalcul après consommation +``` + +## :material-account-tie: Règles consultant ### BR-PT-LOT-001 - Cycle de vie lot virtuel / forecast / physique -- À la création d'une `purchase line` ou `sale line` : - - un lot virtuel est créé ; - - sa quantité initiale reprend la quantité contractuelle/théorique ; - - une ligne ouverte est créée dans `lot.qt`. -- Le lot virtuel = solde ouvert global. -- `lot.qt` = découpage prévisionnel de ce solde. -- Exemple de découpage d'un solde `P1` : - - `P1S1T1` - - `P1S1T2` - - `P1S2T3` - - `P1S2T4` -- Ces découpages ne créent pas plusieurs lots virtuels. -- Un lot physique est créé depuis une ligne `lot.qt` précise. -- Le lot physique consomme cette prévision. -- La ligne `lot.qt` diminue. -- Le lot virtuel est recalculé. +| Étape | Moment | Effet métier | +| --- | --- | +| :material-plus-box-outline: | Création de ligne | Création d'un lot virtuel unique. | +| :material-play-circle-outline: | Initialisation | Le lot virtuel reprend `quantity_theorical`. | +| :material-map-marker-path: | Forecast | Une ligne ouverte est créée dans `lot.qt`. | +| :material-source-branch: | Planification | `lot.qt` peut être subdivisé par vente, matching, transport ou shipment. | +| :material-package-variant: | Ajout physique | Le lot physique consomme une ligne `lot.qt` précise. | +| :material-refresh: | Après ajout | `lot.qt` diminue et le lot virtuel est recalculé. | -### BR-PT-LOT-002 - Quantité contractuelle, quantité compteur, ligne finie +!!! example ":material-source-branch: Découpage d'un solde P1" + `P1S1T1`, `P1S1T2`, `P1S2T3`, `P1S2T4` -- `quantity_theorical` est la quantité métier. -- `quantity` n'est pas une saisie métier. -- Avant lot physique : - - `quantity` est initialisée depuis `quantity_theorical`. -- Après ajout de lots physiques : - - `quantity` reflète l'exécuté physique. -- Tant que `finished = False` : - - le montant de ligne utilise `quantity_theorical`. -- Quand `finished = True` : - - l'utilisateur accepte d'ignorer le reliquat ouvert ; - - le montant de ligne peut revenir à l'exécuté physique ; - - la trace contractuelle initiale reste intacte ; - - les lots physiques et leur PnL restent visibles. -- Si un Weight basis existe sur le contrat : - - achat : état via `purchase.purchase.wb.qt_type` ; - - vente : état via `sale.sale.wb.qt_type` ; - - le même lot physique peut être lu en BL côté achat et en LR côté vente. -- La facturation reste indépendante : - - elle peut choisir un état précis dans `lot.qt.hist` ; - - exemple : BL à l'achat, Weight Report ou LR à la vente. +!!! note ":material-lightbulb-outline: Point clé" + Ces découpages ne créent pas plusieurs lots virtuels. Ils décrivent + seulement la répartition prévisionnelle du solde ouvert. + +### BR-PT-LOT-002 - Quantité contractuelle, compteur, ligne finie + +| Repère | Situation | Quantité de référence | +| --- | --- | +| :material-pencil: | Saisie utilisateur | `quantity_theorical` | +| :material-package-variant-remove: | Aucun lot physique | `quantity = quantity_theorical` | +| :material-package-variant-closed: | Lots physiques présents | `quantity = somme des lots physiques` | +| :material-lock-open-variant-outline: | `finished = False` | Montant basé sur `quantity_theorical` | +| :material-check-circle-outline: | `finished = True` | Montant basé sur l'exécuté physique | +| :material-weight: | Weight basis disponible | Montant basé sur l'état `wb.qt_type` du contrat | + +!!! warning ":material-alert-outline: Ce que `finished` ne fait pas" + `finished` n'efface pas la quantité contractuelle, ne supprime pas les lots + physiques et ne masque pas leur PnL. Il signifie seulement que le reliquat + ouvert peut être ignoré pour les calculs d'exécution. + +| Repère | Lecture du même lot physique | État possible | +| --- | --- | +| :material-cart-arrow-down: | Achat | BL via `purchase.purchase.wb.qt_type` | +| :material-cart-arrow-up: | Vente | LR ou Weight Report via `sale.sale.wb.qt_type` | +| :material-file-document-check-outline: | Facturation | Choix indépendant dans `lot.qt.hist` | ### BR-PT-LOT-003 - Invariants de quantité -Invariant de conservation : +| Repère | Invariant | Formule | +| --- | --- | +| :material-shield-check-outline: | Conservation | `somme(lots physiques) + lot virtuel = quantity_theorical` | +| :material-chart-timeline-variant: | Forecast ouvert | `somme(lot.qt non zéro) = max(lot virtuel, 0)` | -```text -somme(lots physiques) + quantité du lot virtuel = quantity_theorical -``` - -Invariant du forecast ouvert : - -```text -somme(lot.qt non zéro du lot virtuel) = max(quantité du lot virtuel, 0) -``` - -Précisions : - -- Achat : sommer tous les `lot.qt` où `lot_p = lot virtuel`, avec ou sans - `lot_s`. -- Vente : sommer tous les `lot.qt` où `lot_s = lot virtuel`, avec ou sans - `lot_p`. -- Les `lot.qt = 0` sont ignorés : - - ils peuvent mémoriser une prévision vidée ; - - `lot.qt` ne descend jamais sous zéro. -- Le lot virtuel peut devenir négatif : - - il compense l'écart entre `quantity_theorical` et l'exécuté physique ; - - dans ce cas le forecast ouvert attendu reste zéro. -- Un `lot.qt` non zéro sans `lot_p` ni `lot_s` est interdit. +| Repère | Cas | Règle | +| --- | --- | +| :material-cart-arrow-down: | Lot virtuel achat | Sommer tous les `lot.qt` où `lot_p = lot virtuel`, avec ou sans `lot_s`. | +| :material-cart-arrow-up: | Lot virtuel vente | Sommer tous les `lot.qt` où `lot_s = lot virtuel`, avec ou sans `lot_p`. | +| :material-numeric-0-box-outline: | `lot.qt = 0` | Ignoré par les checks ; mémoire possible d'une prévision vidée. | +| :material-minus-circle-outline: | Lot virtuel négatif | Autorisé pour compenser l'écart théorique / exécuté ; forecast attendu = zéro. | +| :material-alert-octagon-outline: | `lot.qt` non zéro orphelin | Interdit si ni `lot_p` ni `lot_s` n'est renseigné. | ### BR-PT-LOT-004 - Historique de quantité et weighing -- `lot.qt.hist` porte les états de quantité d'un lot. -- La fiche `lot.lot` n'est pas une zone de saisie directe des états. -- Modification autorisée uniquement via `Do weighing`. -- Un lot virtuel ne reçoit pas de packing manuel : - - `lot_qt` non éditable ; - - `lot_unit` non éditable. +| Repère | Élément | Règle | +| --- | --- | +| :material-history: | `lot.qt.hist` | Porte les états de quantité d'un lot. | +| :material-form-textbox: | Fiche `lot.lot` | Pas de saisie directe des états. | +| :material-scale: | Modification | Uniquement via `Do weighing`. | +| :material-cloud-outline: | Lot virtuel | Pas de packing manuel. | +| :material-lock-outline: | Champs packing virtuel | `lot_qt` et `lot_unit` non éditables. | ### Tolérances -- La tolérance est globale sur la ligne ou le contrat. -- Elle n'est pas indépendante par transport. -- Un lot physique peut dépasser ou sous-consommer son forecast. -- Ce dépassement consomme ou restitue de la tolérance restante. -- Gap actuel : le contrôle complet de tolérance restante dans - `LotQt.add_physical_lots` / `LotQt.add_physical_lot` reste à confirmer. +!!! warning ":material-alert-outline: Gap à confirmer" + Le contrôle complet de tolérance restante dans `LotQt.add_physical_lots` / + `LotQt.add_physical_lot` reste à confirmer. -## Section développeur +| Repère | Point | Règle cible | +| --- | --- | +| :material-target: | Niveau | Tolérance globale sur ligne ou contrat. | +| :material-truck-outline: | Transport | Pas de tolérance indépendante par transport. | +| :material-arrow-up-bold-outline: | Surconsommation | Consomme la tolérance restante. | +| :material-arrow-down-bold-outline: | Sous-consommation | Restitue de la tolérance restante. | + +## :material-code-braces: Section développeur ### Champs clés