Add lot_hist readonly
This commit is contained in:
@@ -24,8 +24,14 @@ class Lot(ModelSQL, ModelView):
|
|||||||
|
|
||||||
lot_name = fields.Char("Lot")
|
lot_name = fields.Char("Lot")
|
||||||
number = fields.Char("Number", readonly=True)
|
number = fields.Char("Number", readonly=True)
|
||||||
lot_qt = fields.Float("Quantity",required=False)
|
lot_qt = fields.Float("Quantity", required=False,
|
||||||
lot_unit = fields.Many2One('product.uom', "Unit",required=False)
|
states={
|
||||||
|
'readonly': Eval('lot_type') == 'virtual',
|
||||||
|
})
|
||||||
|
lot_unit = fields.Many2One('product.uom', "Unit", required=False,
|
||||||
|
states={
|
||||||
|
'readonly': Eval('lot_type') == 'virtual',
|
||||||
|
})
|
||||||
lot_product = fields.Many2One('product.product', "Product")
|
lot_product = fields.Many2One('product.product', "Product")
|
||||||
lot_type = fields.Selection([
|
lot_type = fields.Selection([
|
||||||
('virtual', 'Open'),
|
('virtual', 'Open'),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<notebook colspan="4">
|
<notebook colspan="4">
|
||||||
<page string="General" id="general">
|
<page string="General" id="general">
|
||||||
<field name="lot_childs" colspan="4" mode="tree,form" view_ids="lot.lot_view_tree_sequence2,lot.lot_view_form"/>
|
<field name="lot_childs" colspan="4" mode="tree,form" view_ids="lot.lot_view_tree_sequence2,lot.lot_view_form"/>
|
||||||
<field name="lot_hist" colspan="4"/>
|
<field name="lot_hist" colspan="4" readonly="1"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="Accounting" id="accounting">
|
<page string="Accounting" id="accounting">
|
||||||
<field name="pivot" widget="html_viewer" height="600" colspan="4"/>
|
<field name="pivot" widget="html_viewer" height="600" colspan="4"/>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<form col="4">
|
<form col="4">
|
||||||
<label name="lot"/>
|
<label name="lot"/>
|
||||||
<field name="lot"/>
|
<field name="lot" readonly="1"/>
|
||||||
<label name="quantity_type"/>
|
<label name="quantity_type"/>
|
||||||
<field name="quantity_type"/>
|
<field name="quantity_type" readonly="1"/>
|
||||||
<label name="quantity"/>
|
<label name="quantity"/>
|
||||||
<field name="quantity"/>
|
<field name="quantity" readonly="1"/>
|
||||||
<label name="gross_quantity"/>
|
<label name="gross_quantity"/>
|
||||||
<field name="gross_quantity"/>
|
<field name="gross_quantity" readonly="1"/>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<tree editable="1">
|
<tree>
|
||||||
<field name="lot"/>
|
<field name="lot"/>
|
||||||
<field name="quantity_type"/>
|
<field name="quantity_type"/>
|
||||||
<field name="quantity"/>
|
<field name="quantity"/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<tree editable="1">
|
<tree>
|
||||||
<field name="lot"/>
|
<field name="lot"/>
|
||||||
<field name="quantity_type"/>
|
<field name="quantity_type"/>
|
||||||
<field name="quantity"/>
|
<field name="quantity"/>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Statut: `migration partielle`
|
|||||||
## Comment chercher une regle
|
## Comment chercher une regle
|
||||||
|
|
||||||
- Contrats, dates, lieux, banques: [contracts.md](contracts.md)
|
- Contrats, dates, lieux, banques: [contracts.md](contracts.md)
|
||||||
- Lots virtuels, lots physiques, `lot.qt`, weighing: [lots-and-quantities.md](lots-and-quantities.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)
|
- Matching, Create Contracts, back-to-back: [matching.md](matching.md)
|
||||||
- Shipments, controllers, SLA, weight reports: [shipments-execution.md](shipments-execution.md)
|
- Shipments, controllers, SLA, weight reports: [shipments-execution.md](shipments-execution.md)
|
||||||
- Pricing manuel, basis, premium, linked currency: [pricing.md](pricing.md)
|
- Pricing manuel, basis, premium, linked currency: [pricing.md](pricing.md)
|
||||||
|
|||||||
@@ -1,35 +1,53 @@
|
|||||||
# Guide de lecture des regles business
|
# Guide de lecture des règles business
|
||||||
|
|
||||||
Statut: `migration partielle`
|
Statut: `migration partielle`
|
||||||
Derniere mise a jour: `2026-05-13`
|
Dernière mise à jour: `2026-05-13`
|
||||||
|
|
||||||
Ce dossier devient la source de lecture thematique pour les regles business du
|
Ce dossier devient la source de lecture thématique pour les règles business du
|
||||||
module `purchase_trade`.
|
module `purchase_trade`.
|
||||||
|
|
||||||
Chaque page doit rester lisible par deux publics:
|
Chaque page doit rester lisible par deux publics:
|
||||||
|
|
||||||
- les consultants, qui ont besoin d'une regle fonctionnelle stable sans detail
|
- les consultants, qui ont besoin d'une règle fonctionnelle stable sans détail
|
||||||
de code inutile;
|
de code inutile;
|
||||||
- les developpeurs, qui ont besoin des champs, modeles, fichiers et tests
|
- les développeurs, qui ont besoin des champs, modèles, fichiers et tests
|
||||||
concernes pour appliquer la regle sans l'interpreter.
|
concernés pour appliquer la règle sans l'interpréter.
|
||||||
|
|
||||||
## Convention de redaction
|
## Convention de langues
|
||||||
|
|
||||||
Pour chaque regle durable, utiliser autant que possible ce format:
|
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 de rédaction
|
||||||
|
|
||||||
|
Pour chaque règle durable, utiliser autant que possible ce format:
|
||||||
|
|
||||||
```md
|
```md
|
||||||
### BR-PT-THEME-001 - Titre court
|
### BR-PT-THEME-001 - Titre court
|
||||||
|
|
||||||
Statut: active
|
Statut: active
|
||||||
Source: business-rules.md / note de session / decision projet
|
Source: business-rules.md / note de session / décision projet
|
||||||
|
|
||||||
#### Regle consultant
|
#### Règle consultant
|
||||||
|
|
||||||
Texte fonctionnel, sans nom de champ si ce n'est pas necessaire.
|
Texte fonctionnel, sans nom de champ si ce n'est pas nécessaire.
|
||||||
|
|
||||||
#### Notes developpeur
|
#### Notes développeur
|
||||||
|
|
||||||
- Modeles/champs:
|
- Modèles/champs:
|
||||||
- Fichiers:
|
- Fichiers:
|
||||||
- Tests:
|
- Tests:
|
||||||
- Points de vigilance:
|
- Points de vigilance:
|
||||||
@@ -37,9 +55,9 @@ Texte fonctionnel, sans nom de champ si ce n'est pas necessaire.
|
|||||||
|
|
||||||
## Sources pendant la migration
|
## Sources pendant la migration
|
||||||
|
|
||||||
Les anciennes pages ne sont pas supprimees a cette etape. Elles restent des
|
Les anciennes pages ne sont pas supprimées à cette étape. Elles restent des
|
||||||
sources de verification jusqu'a ce que chaque decision soit promue dans une
|
sources de vérification jusqu'à ce que chaque décision soit promue dans une
|
||||||
page thematique:
|
page thématique:
|
||||||
|
|
||||||
- `modules/purchase_trade/docs/business-rules.md`
|
- `modules/purchase_trade/docs/business-rules.md`
|
||||||
- `modules/purchase_trade/docs/fees.md`
|
- `modules/purchase_trade/docs/fees.md`
|
||||||
@@ -48,4 +66,3 @@ page thematique:
|
|||||||
- `modules/purchase_trade/docs/template-properties.md`
|
- `modules/purchase_trade/docs/template-properties.md`
|
||||||
- `notes/business_rules.md`
|
- `notes/business_rules.md`
|
||||||
- `notes/template_business_rules.md`
|
- `notes/template_business_rules.md`
|
||||||
|
|
||||||
|
|||||||
259
modules/purchase_trade/docs/business/lots-and-quantities.en.md
Normal file
259
modules/purchase_trade/docs/business/lots-and-quantities.en.md
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
# Lots and Quantities
|
||||||
|
|
||||||
|
Language: `en`
|
||||||
|
Mirror page: [lots-and-quantities.md](lots-and-quantities.md)
|
||||||
|
Status: `partial migration`
|
||||||
|
Last code verification: `2026-05-13`
|
||||||
|
|
||||||
|
This page consolidates the former rules `BR-PT-LOT-001`,
|
||||||
|
`BR-PT-LOT-002`, and `BR-PT-LOT-003` around one functional rule: the life
|
||||||
|
cycle of open, forecasted, and physical quantities.
|
||||||
|
|
||||||
|
## Consultant Business Rule
|
||||||
|
|
||||||
|
### BR-PT-LOT-001 - Lot and quantity life cycle
|
||||||
|
|
||||||
|
When a purchase line or sale line is created, the system creates one virtual
|
||||||
|
lot linked to that line. This virtual lot represents the contract quantity that
|
||||||
|
is still open. Its initial quantity is the contractual or theoretical quantity
|
||||||
|
defined on the line.
|
||||||
|
|
||||||
|
At the same time, the system adds one open line in `lot.qt`. This line is the
|
||||||
|
basis for commercial and logistics forecasts: forecast sale, future matching,
|
||||||
|
planned transport, shipment, and so on. `lot.qt` therefore carries the
|
||||||
|
operational forecast, while the virtual lot remains the global representation
|
||||||
|
of the open balance in `lot.lot`.
|
||||||
|
|
||||||
|
Example: an open quantity `P1` can be progressively subdivided in `lot.qt` to
|
||||||
|
forecast several sales or transports:
|
||||||
|
|
||||||
|
- `P1S1T1`
|
||||||
|
- `P1S1T2`
|
||||||
|
- `P1S2T3`
|
||||||
|
- `P1S2T4`
|
||||||
|
|
||||||
|
These subdivisions do not create several virtual lots for `P1`. They only
|
||||||
|
describe the forecast allocation of the open quantity.
|
||||||
|
|
||||||
|
When physical lots are added, they are created from a specific Lots Management
|
||||||
|
line, therefore from a `lot.qt` line. If the user selects `P1S1T1`, the
|
||||||
|
physical lot created consumes that specific forecast. The selected `lot.qt`
|
||||||
|
line is reduced, then the line's virtual lot is recalculated so that it only
|
||||||
|
represents the remaining open balance.
|
||||||
|
|
||||||
|
The immutable quantity consistency rule is:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sum of the line's physical lots + the line's virtual lot
|
||||||
|
= the line's contractual/theoretical quantity
|
||||||
|
```
|
||||||
|
|
||||||
|
This consistency must remain true even if the contractual quantity is adjusted
|
||||||
|
along the way. The contractual/theoretical quantity is the only quantity that
|
||||||
|
the user enters on the line. The standard line quantity is a counter: it
|
||||||
|
follows the contractual quantity as long as there is no physical lot, then it
|
||||||
|
reflects the sum of the executed physical lots.
|
||||||
|
|
||||||
|
Removing a physical lot is allowed only while its stock move is not finalized.
|
||||||
|
If the lot was already matched or linked to a shipment, the user must confirm
|
||||||
|
the action. The removal restores the quantity into the `lot.qt` line that
|
||||||
|
carried the forecast, matching, or transport context used to create the
|
||||||
|
physical lot.
|
||||||
|
|
||||||
|
The quantity history of a lot is never a direct data-entry area. The different
|
||||||
|
quantity states of a lot must be changed only through a dedicated business
|
||||||
|
action, currently `Do weighing`. This rule ensures that open quantity, virtual
|
||||||
|
lot, fee, and stock move recalculations remain synchronized.
|
||||||
|
|
||||||
|
### Tolerance and physical quantities
|
||||||
|
|
||||||
|
A physical lot may have a quantity that differs from the initial forecast,
|
||||||
|
within the contract tolerance limits. Tolerance must be read as a global
|
||||||
|
tolerance on the line or contract, not as an independent tolerance per
|
||||||
|
transport.
|
||||||
|
|
||||||
|
If a physical lot consumes more or less than its forecast, this must
|
||||||
|
dynamically reduce or increase the remaining tolerance for the next physical
|
||||||
|
lots of the same line. No add, weighing, deletion, or contractual adjustment
|
||||||
|
action may break the global quantity consistency rule.
|
||||||
|
|
||||||
|
## Developer Section
|
||||||
|
|
||||||
|
### Main models and fields
|
||||||
|
|
||||||
|
- Purchase line: `purchase.line`.
|
||||||
|
- Sale line: `sale.line`.
|
||||||
|
- Lot: `lot.lot`.
|
||||||
|
- Forecast / open quantity: `lot.qt`.
|
||||||
|
- Lot quantity history: `lot.qt.hist`.
|
||||||
|
- Purchase contractual quantity: `purchase.line.quantity_theorical`
|
||||||
|
(`Contractual Qt`).
|
||||||
|
- Sale contractual quantity: `sale.line.quantity_theorical`
|
||||||
|
(`Th. quantity`).
|
||||||
|
- Purchase/sale quantity counter: `quantity`.
|
||||||
|
- Lot type: `lot.lot.lot_type`, values `virtual` and `physic`.
|
||||||
|
- Purchase link: `lot.lot.line`.
|
||||||
|
- Sale link: `lot.lot.sale_line`.
|
||||||
|
- Shipment links: `lot_shipment_in`, `lot_shipment_internal`,
|
||||||
|
`lot_shipment_out`.
|
||||||
|
- Purchase/sale forecast matching: `lot.qt.lot_p`, `lot.qt.lot_s`.
|
||||||
|
- Forecast quantity: `lot.qt.lot_quantity`.
|
||||||
|
- Contract/line tolerances: `tol_min`, `tol_max`, `tol_min_qt`,
|
||||||
|
`tol_max_qt`, `tol_min_v`, `tol_max_v`.
|
||||||
|
- Quantity state history: `lot.lot.lot_hist` to `lot.qt.hist`.
|
||||||
|
- History fields: `lot.qt.hist.quantity_type`, `lot.qt.hist.quantity`,
|
||||||
|
`lot.qt.hist.gross_quantity`.
|
||||||
|
- Lot packing fields: `lot.lot.lot_qt`, `lot.lot.lot_unit`.
|
||||||
|
|
||||||
|
### Line and virtual lot creation
|
||||||
|
|
||||||
|
- Purchase: `modules/purchase_trade/purchase.py`, `Line.validate`.
|
||||||
|
- Sale: `modules/purchase_trade/sale.py`, `SaleLine.validate`.
|
||||||
|
- If the line is not `created_by_code`, has no lot yet, the product is not a
|
||||||
|
service, and `quantity != 0`, a `virtual` lot is created.
|
||||||
|
- The virtual lot receives its first `lot.qt.hist` entry.
|
||||||
|
- The open `lot.qt` creation is triggered by
|
||||||
|
`modules/purchase_trade/lot.py`, `Lot.validate`, through
|
||||||
|
`createVirtualPart` when no `lot.qt` exists yet for the virtual lot.
|
||||||
|
- On purchase, the virtual lot feeds `lot.qt.lot_p`.
|
||||||
|
- On sale, the virtual lot feeds `lot.qt.lot_s` with `lot_p = None`.
|
||||||
|
|
||||||
|
### Contractual quantity update
|
||||||
|
|
||||||
|
Verified code state:
|
||||||
|
|
||||||
|
- Purchase: `purchase.py`, `Line.write`.
|
||||||
|
- Sale: `sale.py`, `SaleLine.write`.
|
||||||
|
- Updating `quantity_theorical` recalculates a target virtual quantity:
|
||||||
|
|
||||||
|
```text
|
||||||
|
target_quantity = quantity_theorical - sum(converted physical lots)
|
||||||
|
```
|
||||||
|
|
||||||
|
- If this target quantity becomes negative, the code blocks with
|
||||||
|
`Please unlink or unmatch lot`.
|
||||||
|
- The free `lot.qt` is then resynchronized while taking into account `lot.qt`
|
||||||
|
lines that are already allocated, meaning already matched or linked to a
|
||||||
|
shipment:
|
||||||
|
|
||||||
|
```text
|
||||||
|
free_quantity = target_quantity - sum(already matched or shipped lot.qt)
|
||||||
|
```
|
||||||
|
|
||||||
|
- If `free_quantity` becomes negative, the code blocks with
|
||||||
|
`Please unlink or unmatch lot`.
|
||||||
|
- If the virtual lot does not already carry the target quantity, the code calls
|
||||||
|
`vlot.set_current_quantity(target_quantity, target_quantity, 1)`.
|
||||||
|
- If a free `lot.qt` exists, its quantity is replaced with `free_quantity`.
|
||||||
|
- If no free `lot.qt` exists and `free_quantity > 0`, a new free `lot.qt` is
|
||||||
|
created.
|
||||||
|
- The line fees are resynchronized after the update.
|
||||||
|
|
||||||
|
Purchase-specific point:
|
||||||
|
|
||||||
|
- If `quantity_theorical` was empty during initialization, the code uses the
|
||||||
|
current virtual lot quantity as the baseline to avoid doubling the open
|
||||||
|
`lot.qt`.
|
||||||
|
|
||||||
|
Sale-specific point:
|
||||||
|
|
||||||
|
- If the previous `quantity_theorical` is empty, `SaleLine.write` does not yet
|
||||||
|
run this resynchronization.
|
||||||
|
|
||||||
|
### Adding physical lots
|
||||||
|
|
||||||
|
- Wizard: `modules/purchase_trade/lot.py`, `lot.add`.
|
||||||
|
- Main method: `LotQt.add_physical_lots`.
|
||||||
|
- Unit creation method: `LotQt.add_physical_lot`.
|
||||||
|
- Adding starts from a `lot.qt` line selected in Lots Management.
|
||||||
|
- The code refuses direct addition from a physical lot.
|
||||||
|
- The code refuses physical addition on the sale side through this wizard and
|
||||||
|
asks the user to use `Apply matching`.
|
||||||
|
- The new physical lot inherits the context of the `lot.qt` line: purchase
|
||||||
|
line, matched sale if present, shipment, product, unit, quantities, premium,
|
||||||
|
and chunk key.
|
||||||
|
- After creation, the code reduces the source `lot.qt` quantity by the total
|
||||||
|
physical quantity created and never lets the line go below zero.
|
||||||
|
- Saving/validating the physical lot recalculates:
|
||||||
|
- the line's virtual lot through `_recompute_virtual_lot`;
|
||||||
|
- the line quantity counter through `_recalc_line_quantity`;
|
||||||
|
- linked stock moves when needed;
|
||||||
|
- fees linked to the lot, line, or shipment.
|
||||||
|
|
||||||
|
### Removing physical lots
|
||||||
|
|
||||||
|
- Wizard: `modules/purchase_trade/lot.py`, `lot.remove`.
|
||||||
|
- Removing an open lot is forbidden.
|
||||||
|
- If the physical lot has a `stock.move`, that move must be in `draft` state.
|
||||||
|
- If the lot is matched or shipped, a confirmable warning is displayed.
|
||||||
|
- The code first deletes the draft move when present.
|
||||||
|
- The code restores the physical quantity into `lot.qt` while reusing the
|
||||||
|
context:
|
||||||
|
- original shipment through `lot.lot_shipment_origin`;
|
||||||
|
- sale virtual lot through `getVlot_s()` if the lot was matched;
|
||||||
|
- purchase virtual lot through `getVlot_p()` in `updateVirtualPart`.
|
||||||
|
- If a compatible `lot.qt` line already exists, it is incremented.
|
||||||
|
- Otherwise, a new `lot.qt` line is created.
|
||||||
|
- Deleting the physical lot then triggers recalculation of the virtual lot,
|
||||||
|
the line quantity counter, and fees.
|
||||||
|
|
||||||
|
### Quantity history and weighing
|
||||||
|
|
||||||
|
- History is carried by `lot.qt.hist`.
|
||||||
|
- `lot.qt.hist` represents the different quantity states of a lot.
|
||||||
|
- Historical quantities must not be changed directly from the `lot.lot` form.
|
||||||
|
- The `lot.lot` view displays `lot_hist` as read-only.
|
||||||
|
- `lot.qt.hist` views are consultative: no direct editing from tree or form.
|
||||||
|
- The functional change path is the `lot.weighing` wizard, exposed by the
|
||||||
|
`Do weighing` action.
|
||||||
|
- The wizard writes or updates the `lot.qt.hist` entry for the selected
|
||||||
|
`lot_state`, then synchronizes the lot, open quantities, and fees.
|
||||||
|
- A virtual lot must not receive packing data entry from the lot form:
|
||||||
|
`lot_qt` and `lot_unit` are not editable for `lot_type = virtual`.
|
||||||
|
|
||||||
|
### Line quantity counter
|
||||||
|
|
||||||
|
- Method: `lot.py`, `Lot._recalc_line_quantity`.
|
||||||
|
- If the line has only one lot, `quantity` takes the current quantity of that
|
||||||
|
lot.
|
||||||
|
- If the line has several lots, `quantity` sums physical lots only.
|
||||||
|
- This matches the functional rule:
|
||||||
|
- without a physical lot: `quantity` follows the virtual lot;
|
||||||
|
- with physical lots: `quantity` reflects executed physical quantity.
|
||||||
|
|
||||||
|
### Tolerance: current state and point to confirm
|
||||||
|
|
||||||
|
The code already exposes tolerances on contracts and lines:
|
||||||
|
|
||||||
|
- Purchase: `purchase.purchase.tol_min`, `purchase.purchase.tol_max`,
|
||||||
|
`purchase.line.tol_min`, `purchase.line.tol_max`.
|
||||||
|
- Sale: `sale.sale.tol_min`, `sale.sale.tol_max`, `sale.line.tol_min`,
|
||||||
|
`sale.line.tol_max`.
|
||||||
|
- Display functions: `get_tol_min`, `get_tol_max`.
|
||||||
|
- Add wizard: `lot.add.line.tol_min`, `lot.add.line.tol_max`, with defaults
|
||||||
|
from the source contract.
|
||||||
|
|
||||||
|
To confirm / potential gap:
|
||||||
|
|
||||||
|
- In `LotQt.add_physical_lots` and `LotQt.add_physical_lot`, I do not yet see
|
||||||
|
a complete control that computes remaining global tolerance while taking
|
||||||
|
already created physical lots into account.
|
||||||
|
- The consultant rule above about dynamic global tolerance must therefore be
|
||||||
|
considered a target business rule to verify/implement before marking it
|
||||||
|
`active`.
|
||||||
|
|
||||||
|
### Nearby tests
|
||||||
|
|
||||||
|
- `modules/purchase_trade/tests/test_module.py`
|
||||||
|
- `test_sale_line_write_updates_virtual_lot_when_theorical_qty_increases`
|
||||||
|
- `test_sale_line_write_blocks_theorical_qty_decrease_when_no_open_quantity`
|
||||||
|
- `test_purchase_line_write_syncs_open_lot_qt_with_physical_lots`
|
||||||
|
- `test_purchase_line_write_syncs_virtual_fee_quantity`
|
||||||
|
- `test_purchase_line_write_initial_theorical_qty_does_not_double_open_lot`
|
||||||
|
|
||||||
|
To add if this rule becomes regression-sensitive:
|
||||||
|
|
||||||
|
- verify that `lot_hist` is read-only on the `lot.lot` form;
|
||||||
|
- verify that `Do weighing` can still create or update a quantity state;
|
||||||
|
- verify that a virtual lot does not allow direct entry of `lot_qt` and
|
||||||
|
`lot_unit`.
|
||||||
@@ -1,224 +1,254 @@
|
|||||||
# Lots et quantites
|
# Lots et quantités
|
||||||
|
|
||||||
|
Langue: `fr`
|
||||||
|
Page miroir: [lots-and-quantities.en.md](lots-and-quantities.en.md)
|
||||||
Statut: `migration partielle`
|
Statut: `migration partielle`
|
||||||
Derniere verification code: `2026-05-13`
|
Dernière vérification code: `2026-05-13`
|
||||||
|
|
||||||
Cette page consolide les anciennes regles `BR-PT-LOT-001`,
|
Cette page consolide les anciennes règles `BR-PT-LOT-001`,
|
||||||
`BR-PT-LOT-002` et `BR-PT-LOT-003` autour d'une regle fonctionnelle unique:
|
`BR-PT-LOT-002` et `BR-PT-LOT-003` autour d'une règle fonctionnelle unique :
|
||||||
le cycle de vie des quantites ouvertes, forecastees et physiques.
|
le cycle de vie des quantités ouvertes, forecastées et physiques.
|
||||||
|
|
||||||
## Regle business consultant
|
## Règle business consultant
|
||||||
|
|
||||||
### BR-PT-LOT-001 - Cycle de vie des lots et des quantites
|
### BR-PT-LOT-001 - Cycle de vie des lots et des quantités
|
||||||
|
|
||||||
Lors de la creation d'une ligne d'achat ou de vente, le systeme cree un lot
|
Lors de la création d'une ligne d'achat ou de vente, le système crée un lot
|
||||||
virtuel associe a cette ligne. Ce lot virtuel represente la quantite encore
|
virtuel associé à cette ligne. Ce lot virtuel représente la quantité encore
|
||||||
ouverte du contrat. Sa quantite initiale reprend la quantite contractuelle ou
|
ouverte du contrat. Sa quantité initiale reprend la quantité contractuelle ou
|
||||||
theorique de la ligne.
|
théorique de la ligne.
|
||||||
|
|
||||||
En parallele, le systeme ajoute une ligne ouverte dans `lot.qt`. Cette ligne
|
En parallèle, le système ajoute une ligne ouverte dans `lot.qt`. Cette ligne
|
||||||
sert de base aux previsions commerciales et logistiques: vente previsionnelle,
|
sert de base aux prévisions commerciales et logistiques : vente prévisionnelle,
|
||||||
matching futur, transport planifie, shipment, etc. `lot.qt` porte donc le
|
matching futur, transport planifié, shipment, etc. `lot.qt` porte donc le
|
||||||
forecast operationnel, tandis que le lot virtuel reste la representation
|
forecast opérationnel, tandis que le lot virtuel reste la représentation
|
||||||
globale du solde ouvert dans `lot.lot`.
|
globale du solde ouvert dans `lot.lot`.
|
||||||
|
|
||||||
Exemple: une quantite ouverte `P1` peut etre progressivement subdivisee dans
|
Exemple : une quantité ouverte `P1` peut être progressivement subdivisée dans
|
||||||
`lot.qt` pour prevoir plusieurs ventes ou transports:
|
`lot.qt` pour prévoir plusieurs ventes ou transports :
|
||||||
|
|
||||||
- `P1S1T1`
|
- `P1S1T1`
|
||||||
- `P1S1T2`
|
- `P1S1T2`
|
||||||
- `P1S2T3`
|
- `P1S2T3`
|
||||||
- `P1S2T4`
|
- `P1S2T4`
|
||||||
|
|
||||||
Ces subdivisions ne creent pas plusieurs lots virtuels pour `P1`. Elles
|
Ces subdivisions ne créent pas plusieurs lots virtuels pour `P1`. Elles
|
||||||
decrivent seulement la repartition previsionnelle de la quantite ouverte.
|
décrivent seulement la répartition prévisionnelle de la quantité ouverte.
|
||||||
|
|
||||||
Quand des lots physiques sont ajoutes, ils sont crees depuis une ligne precise
|
Quand des lots physiques sont ajoutés, ils sont créés depuis une ligne précise
|
||||||
de Lots Management, donc depuis une ligne `lot.qt`. Si l'utilisateur choisit
|
de Lots Management, donc depuis une ligne `lot.qt`. Si l'utilisateur choisit
|
||||||
`P1S1T1`, le lot physique cree consomme ce forecast particulier. La ligne
|
`P1S1T1`, le lot physique créé consomme ce forecast particulier. La ligne
|
||||||
`lot.qt` choisie est reduite, puis le lot virtuel de la ligne est recalcule
|
`lot.qt` choisie est réduite, puis le lot virtuel de la ligne est recalculé
|
||||||
pour representer seulement le reliquat encore ouvert.
|
pour représenter seulement le reliquat encore ouvert.
|
||||||
|
|
||||||
La regle immuable de coherence est:
|
La règle immuable de cohérence est :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
somme des lots physiques de la ligne + lot virtuel de la ligne
|
somme des lots physiques de la ligne + lot virtuel de la ligne
|
||||||
= quantite contractuelle/theorique de la ligne
|
= quantité contractuelle/théorique de la ligne
|
||||||
```
|
```
|
||||||
|
|
||||||
Cette coherence doit rester vraie meme si la quantite contractuelle est
|
Cette cohérence doit rester vraie même si la quantité contractuelle est
|
||||||
ajustee en cours de route. La quantite contractuelle/theorique est la seule
|
ajustée en cours de route. La quantité contractuelle/théorique est la seule
|
||||||
quantite saisie par l'utilisateur sur la ligne. La quantite standard de la
|
quantité saisie par l'utilisateur sur la ligne. La quantité standard de la
|
||||||
ligne est un compteur: elle reprend la quantite contractuelle tant qu'il n'y a
|
ligne est un compteur : elle reprend la quantité contractuelle tant qu'il n'y a
|
||||||
pas de lot physique, puis elle reflete la somme des lots physiques executes.
|
pas de lot physique, puis elle reflète la somme des lots physiques exécutés.
|
||||||
|
|
||||||
Le retrait d'un lot physique est autorise seulement tant que son mouvement
|
Le retrait d'un lot physique est autorisé seulement tant que son mouvement
|
||||||
stock n'est pas finalise. Si ce lot etait deja matche ou rattache a un
|
stock n'est pas finalisé. Si ce lot était déjà matché ou rattaché à un
|
||||||
shipment, l'utilisateur doit confirmer l'action. Le retrait restaure la
|
shipment, l'utilisateur doit confirmer l'action. Le retrait restaure la
|
||||||
quantite dans la ligne `lot.qt` qui portait le contexte forecast, matching ou
|
quantité dans la ligne `lot.qt` qui portait le contexte forecast, matching ou
|
||||||
transport ayant permis de creer le lot physique.
|
transport ayant permis de créer le lot physique.
|
||||||
|
|
||||||
### Tolerance et quantites physiques
|
L'historique des quantités d'un lot n'est jamais une zone de saisie directe.
|
||||||
|
Les différents états de quantité d'un lot doivent être modifiés uniquement par
|
||||||
|
une action métier dédiée, aujourd'hui `Do weighing`. Cette règle garantit que
|
||||||
|
les recalculs de quantité ouverte, de lot virtuel, de fees et de mouvements
|
||||||
|
stock restent synchronisés.
|
||||||
|
|
||||||
Un lot physique peut avoir une quantite differente de la prevision initiale,
|
### Tolérance et quantités physiques
|
||||||
dans les limites de tolerance du contrat. La tolerance doit se lire comme une
|
|
||||||
tolerance globale sur la ligne ou le contrat, pas comme une tolerance
|
|
||||||
independante par transport.
|
|
||||||
|
|
||||||
Si un lot physique consomme plus ou moins que son forecast, cela doit reduire
|
Un lot physique peut avoir une quantité différente de la prévision initiale,
|
||||||
ou augmenter dynamiquement la tolerance restante pour les prochains lots
|
dans les limites de tolérance du contrat. La tolérance doit se lire comme une
|
||||||
physiques de la meme ligne. Aucune action d'ajout, de weighing, de suppression
|
tolérance globale sur la ligne ou le contrat, pas comme une tolérance
|
||||||
ou d'ajustement contractuel ne doit permettre de sortir de la coherence globale
|
indépendante par transport.
|
||||||
des quantites.
|
|
||||||
|
|
||||||
## Section developpeur
|
Si un lot physique consomme plus ou moins que son forecast, cela doit réduire
|
||||||
|
ou augmenter dynamiquement la tolérance restante pour les prochains lots
|
||||||
|
physiques de la même ligne. Aucune action d'ajout, de weighing, de suppression
|
||||||
|
ou d'ajustement contractuel ne doit permettre de sortir de la cohérence globale
|
||||||
|
des quantités.
|
||||||
|
|
||||||
### Modeles et champs principaux
|
## Section développeur
|
||||||
|
|
||||||
- Ligne achat: `purchase.line`.
|
### Modèles et champs principaux
|
||||||
- Ligne vente: `sale.line`.
|
|
||||||
- Lot: `lot.lot`.
|
- Ligne achat : `purchase.line`.
|
||||||
- Forecast / quantite ouverte: `lot.qt`.
|
- Ligne vente : `sale.line`.
|
||||||
- Historique des quantites de lot: `lot.qt.hist`.
|
- Lot : `lot.lot`.
|
||||||
- Quantite contractuelle achat: `purchase.line.quantity_theorical`
|
- Forecast / quantité ouverte : `lot.qt`.
|
||||||
|
- Historique des quantités de lot : `lot.qt.hist`.
|
||||||
|
- Quantité contractuelle achat : `purchase.line.quantity_theorical`
|
||||||
(`Contractual Qt`).
|
(`Contractual Qt`).
|
||||||
- Quantite contractuelle vente: `sale.line.quantity_theorical`
|
- Quantité contractuelle vente : `sale.line.quantity_theorical`
|
||||||
(`Th. quantity`).
|
(`Th. quantity`).
|
||||||
- Quantite compteur achat/vente: `quantity`.
|
- Quantité compteur achat/vente : `quantity`.
|
||||||
- Type de lot: `lot.lot.lot_type`, valeurs `virtual` et `physic`.
|
- Type de lot : `lot.lot.lot_type`, valeurs `virtual` et `physic`.
|
||||||
- Lien achat: `lot.lot.line`.
|
- Lien achat : `lot.lot.line`.
|
||||||
- Lien vente: `lot.lot.sale_line`.
|
- Lien vente : `lot.lot.sale_line`.
|
||||||
- Liens shipment: `lot_shipment_in`, `lot_shipment_internal`,
|
- Liens shipment : `lot_shipment_in`, `lot_shipment_internal`,
|
||||||
`lot_shipment_out`.
|
`lot_shipment_out`.
|
||||||
- Matching forecast achat/vente: `lot.qt.lot_p`, `lot.qt.lot_s`.
|
- Matching forecast achat/vente : `lot.qt.lot_p`, `lot.qt.lot_s`.
|
||||||
- Quantite forecast: `lot.qt.lot_quantity`.
|
- Quantité forecast : `lot.qt.lot_quantity`.
|
||||||
- Tolerances contrat/ligne: `tol_min`, `tol_max`, `tol_min_qt`,
|
- Tolérances contrat/ligne : `tol_min`, `tol_max`, `tol_min_qt`,
|
||||||
`tol_max_qt`, `tol_min_v`, `tol_max_v`.
|
`tol_max_qt`, `tol_min_v`, `tol_max_v`.
|
||||||
|
- Historique des états de quantité : `lot.lot.lot_hist` vers `lot.qt.hist`.
|
||||||
|
- Champs d'historique : `lot.qt.hist.quantity_type`,
|
||||||
|
`lot.qt.hist.quantity`, `lot.qt.hist.gross_quantity`.
|
||||||
|
- Champs de packing du lot : `lot.lot.lot_qt`, `lot.lot.lot_unit`.
|
||||||
|
|
||||||
### Creation de la ligne et du lot virtuel
|
### Création de la ligne et du lot virtuel
|
||||||
|
|
||||||
- Achat: `modules/purchase_trade/purchase.py`, `Line.validate`.
|
- Achat : `modules/purchase_trade/purchase.py`, `Line.validate`.
|
||||||
- Vente: `modules/purchase_trade/sale.py`, `SaleLine.validate`.
|
- Vente : `modules/purchase_trade/sale.py`, `SaleLine.validate`.
|
||||||
- Si la ligne n'est pas `created_by_code`, qu'elle n'a pas encore de lot, que
|
- Si la ligne n'est pas `created_by_code`, qu'elle n'a pas encore de lot, que
|
||||||
le produit n'est pas un service et que `quantity != 0`, un lot `virtual` est
|
le produit n'est pas un service et que `quantity != 0`, un lot `virtual` est
|
||||||
cree.
|
créé.
|
||||||
- Le lot virtuel recoit une premiere entree `lot.qt.hist`.
|
- Le lot virtuel reçoit une première entrée `lot.qt.hist`.
|
||||||
- La creation du `lot.qt` ouvert est declenchee par
|
- La création du `lot.qt` ouvert est déclenchée par
|
||||||
`modules/purchase_trade/lot.py`, `Lot.validate`, via `createVirtualPart`
|
`modules/purchase_trade/lot.py`, `Lot.validate`, via `createVirtualPart`
|
||||||
quand aucun `lot.qt` n'existe encore pour le lot virtuel.
|
quand aucun `lot.qt` n'existe encore pour le lot virtuel.
|
||||||
- Pour l'achat, le lot virtuel alimente `lot.qt.lot_p`.
|
- Pour l'achat, le lot virtuel alimente `lot.qt.lot_p`.
|
||||||
- Pour la vente, le lot virtuel alimente `lot.qt.lot_s` avec `lot_p = None`.
|
- Pour la vente, le lot virtuel alimente `lot.qt.lot_s` avec `lot_p = None`.
|
||||||
|
|
||||||
### Modification de la quantite contractuelle
|
### Modification de la quantité contractuelle
|
||||||
|
|
||||||
Etat du code verifie:
|
État du code vérifié :
|
||||||
|
|
||||||
- Achat: `purchase.py`, `Line.write`.
|
- Achat : `purchase.py`, `Line.write`.
|
||||||
- Vente: `sale.py`, `SaleLine.write`.
|
- Vente : `sale.py`, `SaleLine.write`.
|
||||||
- La modification de `quantity_theorical` recalcule une quantite virtuelle
|
- La modification de `quantity_theorical` recalcule une quantité virtuelle
|
||||||
cible:
|
cible :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
target_quantity = quantity_theorical - somme(lots physiques convertis)
|
target_quantity = quantity_theorical - somme(lots physiques convertis)
|
||||||
```
|
```
|
||||||
|
|
||||||
- Si cette quantite cible devient negative, le code bloque avec
|
- Si cette quantité cible devient négative, le code bloque avec
|
||||||
`Please unlink or unmatch lot`.
|
`Please unlink or unmatch lot`.
|
||||||
- Le `lot.qt` libre est ensuite resynchronise en tenant compte des lignes
|
- Le `lot.qt` libre est ensuite resynchronisé en tenant compte des lignes
|
||||||
`lot.qt` deja allouees, c'est-a-dire deja matchees ou rattachees a un
|
`lot.qt` déjà allouées, c'est-à-dire déjà matchées ou rattachées à un
|
||||||
shipment:
|
shipment :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
free_quantity = target_quantity - somme(lot.qt deja matches ou shippes)
|
free_quantity = target_quantity - somme(lot.qt déjà matchés ou shippés)
|
||||||
```
|
```
|
||||||
|
|
||||||
- Si `free_quantity` devient negative, le code bloque avec
|
- Si `free_quantity` devient négative, le code bloque avec
|
||||||
`Please unlink or unmatch lot`.
|
`Please unlink or unmatch lot`.
|
||||||
- Si le lot virtuel ne porte pas deja la quantite cible, le code appelle
|
- Si le lot virtuel ne porte pas déjà la quantité cible, le code appelle
|
||||||
`vlot.set_current_quantity(target_quantity, target_quantity, 1)`.
|
`vlot.set_current_quantity(target_quantity, target_quantity, 1)`.
|
||||||
- Si un `lot.qt` libre existe, sa quantite est remplacee par `free_quantity`.
|
- Si un `lot.qt` libre existe, sa quantité est remplacée par `free_quantity`.
|
||||||
- Si aucun `lot.qt` libre n'existe et que `free_quantity > 0`, un nouveau
|
- Si aucun `lot.qt` libre n'existe et que `free_quantity > 0`, un nouveau
|
||||||
`lot.qt` libre est cree.
|
`lot.qt` libre est créé.
|
||||||
- Les fees de la ligne sont resynchronises apres modification.
|
- Les fees de la ligne sont resynchronisés après modification.
|
||||||
|
|
||||||
Point specifique achat:
|
Point spécifique achat :
|
||||||
|
|
||||||
- Si `quantity_theorical` etait vide au moment de l'initialisation, le code
|
- Si `quantity_theorical` était vide au moment de l'initialisation, le code
|
||||||
prend comme baseline la quantite courante du lot virtuel pour eviter de
|
prend comme baseline la quantité courante du lot virtuel pour éviter de
|
||||||
doubler le `lot.qt` ouvert.
|
doubler le `lot.qt` ouvert.
|
||||||
|
|
||||||
Point specifique vente:
|
Point spécifique vente :
|
||||||
|
|
||||||
- Si l'ancienne `quantity_theorical` est vide, `SaleLine.write` ne lance pas
|
- Si l'ancienne `quantity_theorical` est vide, `SaleLine.write` ne lance pas
|
||||||
encore cette resynchronisation.
|
encore cette resynchronisation.
|
||||||
|
|
||||||
### Ajout de lots physiques
|
### Ajout de lots physiques
|
||||||
|
|
||||||
- Wizard: `modules/purchase_trade/lot.py`, `lot.add`.
|
- Wizard : `modules/purchase_trade/lot.py`, `lot.add`.
|
||||||
- Methode principale: `LotQt.add_physical_lots`.
|
- Méthode principale : `LotQt.add_physical_lots`.
|
||||||
- Creation unitaire: `LotQt.add_physical_lot`.
|
- Création unitaire : `LotQt.add_physical_lot`.
|
||||||
- L'ajout part obligatoirement d'une ligne `lot.qt` issue de Lots Management.
|
- L'ajout part obligatoirement d'une ligne `lot.qt` issue de Lots Management.
|
||||||
- Le code refuse l'ajout direct depuis un lot physique.
|
- Le code refuse l'ajout direct depuis un lot physique.
|
||||||
- Le code refuse l'ajout physique cote vente par ce wizard et demande
|
- Le code refuse l'ajout physique côté vente par ce wizard et demande
|
||||||
d'utiliser `Apply matching`.
|
d'utiliser `Apply matching`.
|
||||||
- Le nouveau lot physique reprend le contexte de la ligne `lot.qt`:
|
- Le nouveau lot physique reprend le contexte de la ligne `lot.qt` :
|
||||||
ligne achat, vente matchee si presente, shipment, produit, unite,
|
ligne achat, vente matchée si présente, shipment, produit, unité,
|
||||||
quantites, premium et chunk key.
|
quantités, premium et chunk key.
|
||||||
- Apres creation, le code reduit la quantite de la ligne `lot.qt` source du
|
- Après création, le code réduit la quantité de la ligne `lot.qt` source du
|
||||||
total physique cree et ne laisse pas la ligne descendre sous zero.
|
total physique créé et ne laisse pas la ligne descendre sous zéro.
|
||||||
- La sauvegarde/validation du lot physique recalcule:
|
- La sauvegarde/validation du lot physique recalcule :
|
||||||
- le lot virtuel de la ligne via `_recompute_virtual_lot`;
|
- le lot virtuel de la ligne via `_recompute_virtual_lot` ;
|
||||||
- la quantite compteur de la ligne via `_recalc_line_quantity`;
|
- la quantité compteur de la ligne via `_recalc_line_quantity` ;
|
||||||
- les mouvements stock lies si necessaire;
|
- les mouvements stock liés si nécessaire ;
|
||||||
- les fees rattaches au lot, a la ligne ou au shipment.
|
- les fees rattachés au lot, à la ligne ou au shipment.
|
||||||
|
|
||||||
### Retrait de lots physiques
|
### Retrait de lots physiques
|
||||||
|
|
||||||
- Wizard: `modules/purchase_trade/lot.py`, `lot.remove`.
|
- Wizard : `modules/purchase_trade/lot.py`, `lot.remove`.
|
||||||
- Le retrait d'un lot ouvert est interdit.
|
- Le retrait d'un lot ouvert est interdit.
|
||||||
- Si le lot physique possede un `stock.move`, ce move doit etre en etat
|
- Si le lot physique possède un `stock.move`, ce move doit être en état
|
||||||
`draft`.
|
`draft`.
|
||||||
- Si le lot est matche ou shippe, un warning confirmable est affiche.
|
- Si le lot est matché ou shippé, un warning confirmable est affiché.
|
||||||
- Le code supprime d'abord le move draft si present.
|
- Le code supprime d'abord le move draft si présent.
|
||||||
- Le code restaure la quantite physique dans `lot.qt` en reutilisant le
|
- Le code restaure la quantité physique dans `lot.qt` en réutilisant le
|
||||||
contexte:
|
contexte :
|
||||||
- shipment d'origine via `lot.lot_shipment_origin`;
|
- shipment d'origine via `lot.lot_shipment_origin` ;
|
||||||
- lot virtuel sale via `getVlot_s()` si le lot etait matche;
|
- lot virtuel sale via `getVlot_s()` si le lot était matché ;
|
||||||
- lot virtuel purchase via `getVlot_p()` dans `updateVirtualPart`.
|
- lot virtuel purchase via `getVlot_p()` dans `updateVirtualPart`.
|
||||||
- Si une ligne `lot.qt` compatible existe deja, elle est incrementee.
|
- Si une ligne `lot.qt` compatible existe déjà, elle est incrémentée.
|
||||||
- Sinon une nouvelle ligne `lot.qt` est creee.
|
- Sinon une nouvelle ligne `lot.qt` est créée.
|
||||||
- La suppression du lot physique declenche ensuite le recalcul du lot virtuel,
|
- La suppression du lot physique déclenche ensuite le recalcul du lot virtuel,
|
||||||
de la quantite compteur de ligne et des fees.
|
de la quantité compteur de ligne et des fees.
|
||||||
|
|
||||||
### Quantite compteur de ligne
|
### Historique de quantité et weighing
|
||||||
|
|
||||||
- Methode: `lot.py`, `Lot._recalc_line_quantity`.
|
- L'historique est porté par `lot.qt.hist`.
|
||||||
- Si la ligne n'a qu'un seul lot, `quantity` reprend la quantite courante de ce
|
- `lot.qt.hist` représente les différents états de quantité d'un lot.
|
||||||
|
- Les quantités historiques ne doivent pas être modifiées directement depuis
|
||||||
|
la fiche `lot.lot`.
|
||||||
|
- La vue `lot.lot` affiche `lot_hist` en lecture seule.
|
||||||
|
- Les vues `lot.qt.hist` sont consultatives: pas d'édition directe depuis
|
||||||
|
l'arbre ou le formulaire.
|
||||||
|
- Le chemin fonctionnel de modification est le wizard `lot.weighing`, exposé
|
||||||
|
par l'action `Do weighing`.
|
||||||
|
- Le wizard écrit ou met à jour l'entrée `lot.qt.hist` correspondant au
|
||||||
|
`lot_state` choisi, puis synchronise le lot, les quantités ouvertes et les
|
||||||
|
fees.
|
||||||
|
- Un lot virtuel ne doit pas recevoir de saisie de packing depuis la fiche
|
||||||
|
lot: les champs `lot_qt` et `lot_unit` sont non éditables pour
|
||||||
|
`lot_type = virtual`.
|
||||||
|
|
||||||
|
### Quantité compteur de ligne
|
||||||
|
|
||||||
|
- Méthode : `lot.py`, `Lot._recalc_line_quantity`.
|
||||||
|
- Si la ligne n'a qu'un seul lot, `quantity` reprend la quantité courante de ce
|
||||||
lot.
|
lot.
|
||||||
- Si la ligne a plusieurs lots, `quantity` somme uniquement les lots physiques.
|
- Si la ligne a plusieurs lots, `quantity` somme uniquement les lots physiques.
|
||||||
- Cette logique correspond a la regle fonctionnelle:
|
- Cette logique correspond à la règle fonctionnelle :
|
||||||
- sans physique: `quantity` suit le virtuel;
|
- sans physique : `quantity` suit le virtuel ;
|
||||||
- avec physiques: `quantity` reflete l'execute physique.
|
- avec physiques : `quantity` reflète l'exécuté physique.
|
||||||
|
|
||||||
### Tolerance: etat actuel et point a confirmer
|
### Tolérance : état actuel et point à confirmer
|
||||||
|
|
||||||
Le code expose deja les tolerances sur contrats et lignes:
|
Le code expose déjà les tolérances sur contrats et lignes :
|
||||||
|
|
||||||
- Achat: `purchase.purchase.tol_min`, `purchase.purchase.tol_max`,
|
- Achat : `purchase.purchase.tol_min`, `purchase.purchase.tol_max`,
|
||||||
`purchase.line.tol_min`, `purchase.line.tol_max`.
|
`purchase.line.tol_min`, `purchase.line.tol_max`.
|
||||||
- Vente: `sale.sale.tol_min`, `sale.sale.tol_max`, `sale.line.tol_min`,
|
- Vente : `sale.sale.tol_min`, `sale.sale.tol_max`, `sale.line.tol_min`,
|
||||||
`sale.line.tol_max`.
|
`sale.line.tol_max`.
|
||||||
- Fonctions d'affichage: `get_tol_min`, `get_tol_max`.
|
- Fonctions d'affichage : `get_tol_min`, `get_tol_max`.
|
||||||
- Wizard d'ajout: `lot.add.line.tol_min`, `lot.add.line.tol_max`, avec defauts
|
- Wizard d'ajout : `lot.add.line.tol_min`, `lot.add.line.tol_max`, avec
|
||||||
depuis le contrat source.
|
défauts depuis le contrat source.
|
||||||
|
|
||||||
A confirmer / gap potentiel:
|
À confirmer / gap potentiel :
|
||||||
|
|
||||||
- Dans `LotQt.add_physical_lots` et `LotQt.add_physical_lot`, je ne vois pas
|
- Dans `LotQt.add_physical_lots` et `LotQt.add_physical_lot`, je ne vois pas
|
||||||
encore de controle complet qui calcule une tolerance restante globale en
|
encore de contrôle complet qui calcule une tolérance restante globale en
|
||||||
tenant compte des lots physiques deja crees.
|
tenant compte des lots physiques déjà créés.
|
||||||
- La regle consultant ci-dessus de tolerance globale dynamique doit donc etre
|
- La règle consultant ci-dessus de tolérance globale dynamique doit donc être
|
||||||
consideree comme cible metier a verifier/implementer avant de la marquer
|
considérée comme cible métier à vérifier/implémenter avant de la marquer
|
||||||
`active`.
|
`active`.
|
||||||
|
|
||||||
### Tests proches
|
### Tests proches
|
||||||
@@ -229,3 +259,11 @@ A confirmer / gap potentiel:
|
|||||||
- `test_purchase_line_write_syncs_open_lot_qt_with_physical_lots`
|
- `test_purchase_line_write_syncs_open_lot_qt_with_physical_lots`
|
||||||
- `test_purchase_line_write_syncs_virtual_fee_quantity`
|
- `test_purchase_line_write_syncs_virtual_fee_quantity`
|
||||||
- `test_purchase_line_write_initial_theorical_qty_does_not_double_open_lot`
|
- `test_purchase_line_write_initial_theorical_qty_does_not_double_open_lot`
|
||||||
|
|
||||||
|
À ajouter si cette règle devient sensible côté régression:
|
||||||
|
|
||||||
|
- vérifier que `lot_hist` est en lecture seule sur la fiche `lot.lot`;
|
||||||
|
- vérifier que `Do weighing` reste capable de créer ou mettre à jour un état de
|
||||||
|
quantité;
|
||||||
|
- vérifier qu'un lot virtuel ne permet pas la saisie directe de `lot_qt` et
|
||||||
|
`lot_unit`.
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ regles lisibles par les consultants des notes utiles aux developpeurs.
|
|||||||
## Regles par domaine
|
## Regles par domaine
|
||||||
|
|
||||||
- [Contrats achat / vente](business/contracts.md)
|
- [Contrats achat / vente](business/contracts.md)
|
||||||
- [Lots et quantites](business/lots-and-quantities.md)
|
- [Lots et quantités](business/lots-and-quantities.md) / [Lots and Quantities](business/lots-and-quantities.en.md)
|
||||||
- [Matching achat / vente](business/matching.md)
|
- [Matching achat / vente](business/matching.md)
|
||||||
- [Shipments et execution](business/shipments-execution.md)
|
- [Shipments et execution](business/shipments-execution.md)
|
||||||
- [Pricing, basis, premium](business/pricing.md)
|
- [Pricing, basis, premium](business/pricing.md)
|
||||||
|
|||||||
Reference in New Issue
Block a user