21 KiB
21 KiB
Lots et quantités
Langue : fr
Page miroir : lots-and-quantities.en.md
Statut : migration partielle
Dernière vérification code : 2026-05-13
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
Résumé opérationnelUne 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.| Sujet | Règle courte |
|---|---|
| Quantité saisie | quantity_theorical est la quantité métier. |
| Quantité standard | quantity est un compteur technique non éditable. |
| Avant physique | quantity suit quantity_theorical. |
| Après physique | quantity reflète l'exécuté physique. |
| Ligne non finie | Le montant de ligne utilise quantity_theorical. |
| Ligne finie | Le montant peut revenir à l'exécuté physique. |
| Weight basis | Achat et vente peuvent lire deux états différents du même lot. |
| Facturation | Elle choisit ses états dans lot.qt.hist. |
| Contrôles | Invariants bloqués en Python et auditables en SQL. |
quantity_theorical
|
v
lot virtuel P1 ---> lot.qt forecast ---> lot physique
^ |
| v
+------ recalcul après consommation
Règles consultant
BR-PT-LOT-001 - Cycle de vie lot virtuel / forecast / physique
| Moment | Effet métier |
|---|---|
| Création de ligne | Création d'un lot virtuel unique. |
| Initialisation | Le lot virtuel reprend quantity_theorical. |
| Forecast | Une ligne ouverte est créée dans lot.qt. |
| Planification | lot.qt peut être subdivisé par vente, matching, transport ou shipment. |
| Ajout physique | Le lot physique consomme une ligne lot.qt précise. |
| Après ajout | lot.qt diminue et le lot virtuel est recalculé. |
Découpage d'un solde P1
P1S1T1, P1S1T2, P1S2T3, P1S2T4Point 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
| Situation | Quantité de référence |
|---|---|
| Saisie utilisateur | quantity_theorical |
| Aucun lot physique | quantity = quantity_theorical |
| Lots physiques présents | quantity = somme des lots physiques |
finished = False |
Montant basé sur quantity_theorical |
finished = True |
Montant basé sur l'exécuté physique |
| Weight basis disponible | Montant basé sur l'état wb.qt_type du contrat |
Ce que
finished ne fait pasfinished 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.| Lecture du même lot physique | État possible |
|---|---|
| Achat | BL via purchase.purchase.wb.qt_type |
| Vente | LR ou Weight Report via sale.sale.wb.qt_type |
| Facturation | Choix indépendant dans lot.qt.hist |
BR-PT-LOT-003 - Invariants de quantité
| Invariant | Formule |
|---|---|
| Conservation | somme(lots physiques) + lot virtuel = quantity_theorical |
| Forecast ouvert | somme(lot.qt non zéro) = max(lot virtuel, 0) |
| Cas | Règle |
|---|---|
| Lot virtuel achat | Sommer tous les lot.qt où lot_p = lot virtuel, avec ou sans lot_s. |
| Lot virtuel vente | Sommer tous les lot.qt où lot_s = lot virtuel, avec ou sans lot_p. |
lot.qt = 0 |
Ignoré par les checks ; mémoire possible d'une prévision vidée. |
| Lot virtuel négatif | Autorisé pour compenser l'écart théorique / exécuté ; forecast attendu = zéro. |
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
| Élément | Règle |
|---|---|
lot.qt.hist |
Porte les états de quantité d'un lot. |
Fiche lot.lot |
Pas de saisie directe des états. |
| Modification | Uniquement via Do weighing. |
| Lot virtuel | Pas de packing manuel. |
| Champs packing virtuel | lot_qt et lot_unit non éditables. |
Tolérances
Gap à confirmerLe contrôle complet de tolérance restante dans
LotQt.add_physical_lots / LotQt.add_physical_lot reste à confirmer.| Point | Règle cible |
|---|---|
| Niveau | Tolérance globale sur ligne ou contrat. |
| Transport | Pas de tolérance indépendante par transport. |
| Surconsommation | Consomme la tolérance restante. |
| Sous-consommation | Restitue de la tolérance restante. |
Section développeur
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_theoricalest saisi et quequantityest vide ou zéro :quantityest initialisée depuisquantity_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.
- pas
- Le lot virtuel reçoit une première entrée
lot.qt.hist. Lot.validatecrée lelot.qtouvert viacreateVirtualPart.
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.
- blocage :
- Cible
lot.qtlibre :
free_quantity = target_quantity - somme(lot.qt déjà matchés ou shippés)
- Si
free_quantity < 0:- blocage :
Please unlink or unmatch lot.
- blocage :
- Si un
lot.qtlibre existe :- sa quantité est remplacée.
- Si aucun
lot.qtlibre n'existe etfree_quantity > 0:- création d'un nouveau
lot.qt.
- création d'un nouveau
- Les fees de ligne sont resynchronisés.
Ajout de lots physiques
- Wizard :
lot.add - Méthodes :
LotQt.add_physical_lotsLotQt.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.qtsource ; - pas de quantité
lot.qtnégative ; - recalcul du lot virtuel ;
- recalcul de
quantity; - mise à jour moves et fees si nécessaire.
- réduction de la ligne
Retrait de lots physiques
- Wizard :
lot.remove - Lot ouvert : retrait interdit.
- Lot avec
stock.move:- move obligatoire en
draft.
- move obligatoire en
- 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.histsont consultatives.
Quantité compteur quantity
- Méthode :
Lot._recalc_line_quantity - Sans physique :
quantitysuit le lot virtuel.
- Avec physiques :
quantitysomme uniquement les lots physiques.
quantityest 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_theoricalfinished = True+ Weight basis disponible : somme physique dans cet étatfinished = Truesans Weight basis exploitable :quantity- fallback legacy :
quantitysiquantity_theoricalvide
Garde-fous Python
- Check central :
lot.lot.assert_lines_quantity_consistency()
- Blocage
lot.qtorphelin non zéro :lot.qt.validate
- Appels après :
- modification
quantity_theorical; - création / suppression de lots physiques ;
- matching / unmatching ;
- shipping / unshipping ;
- weighing.
- modification
Diagnostic SQL
- Script :
- 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 :
quantityreadonly ;- 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_histreadonly ;Do weighingcré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.