padding doc

This commit is contained in:
2026-04-26 19:19:41 +02:00
parent 7965b22954
commit 308252215f
4 changed files with 216 additions and 238 deletions

View File

@@ -142,10 +142,15 @@ de negoce physique:
de facture inclut deja le montant padding de facture inclut deja le montant padding
- les comptes de padding viennent de `account.configuration`: - les comptes de padding viennent de `account.configuration`:
`Default Sale Padding` et `Default Accrual Padding` `Default Sale Padding` et `Default Accrual Padding`
- la provisoire doit passer le couple sale/accrual, et la finale doit passer - la section `Padding` doit rester avant la section `Invoice` dans
l'inverse pour le montant exact comptabilise en provisoire `Financial / Configuration`
- preferer stocker ce montant au moment de la provisoire plutot que le - la provisoire cree un `additional_move` debit `Default Sale Padding` /
recalculer depuis la finale credit `Default Accrual Padding`
- la finale cree l'inverse en reprenant le montant depuis
`lot.sale_invoice_line_prov`, donc avec le prix, la devise, la date et le
taux de la provisoire
- le wizard final doit calculer son delta depuis la quantite provisoire hors
padding: `sale_invoice_line_prov.quantity - sale_invoice_padding`
## 5) Conventions de modification ## 5) Conventions de modification

View File

@@ -431,10 +431,17 @@ Owner technique: `a completer`
- Validation comptable: - Validation comptable:
- au `Validate`, le move principal de facture inclut deja le padding car il - au `Validate`, le move principal de facture inclut deja le padding car il
est integre a `account.invoice.line.quantity` est integre a `account.invoice.line.quantity`
- la provisoire doit utiliser le couple de comptes configure - la provisoire cree un `additional_move` avec le couple de comptes configure
`Default Sale Padding` / `Default Accrual Padding` `Default Sale Padding` / `Default Accrual Padding`
- la finale doit passer l'ecriture inverse pour exactement le montant padding - montant provisoire:
`lot.sale_invoice_padding * account.invoice.line.unit_price`
- la finale cree l'ecriture inverse pour exactement le montant padding
comptabilise lors de la provisoire comptabilise lors de la provisoire
- le montant d'extourne finale doit etre relu depuis
`lot.sale_invoice_line_prov`, afin de reprendre le prix, la devise, la date
et le taux de la provisoire
- le calcul de quantite finale doit retirer le padding de la quantite
provisoire avant de calculer le delta
- voir `modules/purchase_trade/docs/padding-invoice-accounting.md` - voir `modules/purchase_trade/docs/padding-invoice-accounting.md`
- Priorite: - Priorite:
- `importante` - `importante`

View File

@@ -1,294 +1,249 @@
# Padding facture provisoire vente - notes comptables # Padding facture provisoire vente - notes de session
Statut: `draft` Statut: `implemente - a valider comptablement`
Derniere mise a jour: `2026-04-26` Derniere mise a jour: `2026-04-26`
Scope: `lot.invoice` -> `account.invoice` -> validation comptable. Scope: `lot.invoice` -> `account.invoice.line` -> `account.move`
## 1) Objectif metier ## 1) Objectif metier
Le padding sert a augmenter temporairement la quantite facturee sur une facture Le padding sert a augmenter temporairement la quantite facturee sur une facture
provisoire cote vente, afin de constituer une provision avant la facture finale. provisoire cote vente, afin de constituer une provision avant la facture finale.
Le padding ne change jamais la quantite physique du lot. Il represente seulement
la part incluse en plus dans la facture provisoire.
Exemple: Exemple:
- 2 lots factures ensemble - 2 lots factures ensemble
- padding global saisi dans le wizard: `1000` - padding global saisi dans le wizard: `1000`
- repartition actuelle: `500` par lot - repartition actuelle: `500` par lot
- chaque ligne facture affiche: - chaque ligne facture affiche:
- `quantity = quantite reelle du lot + padding du lot` - `Quantity = quantite reelle du lot + padding du lot`
- `Inc. padding = padding du lot` - `Inc. padding = padding du lot`
Le padding ne modifie pas la quantite physique du lot. Il doit rester visible et ## 2) Saisie et stockage
traçable comme ecart entre la facture provisoire et le lot.
## 2) Donnees creees ou utilisees ### Wizard `lot.invoice`
- Champ: `sale_padding`
- Label UI: `Global padding`
- Visible uniquement pour:
- `type = sale`
- `action = prov`
Au clic `Invoice`, le wizard:
1. prend le padding global saisi
2. le repartit egalement entre les lots selectionnes
3. ecrit la part de chaque lot dans `lot.sale_invoice_padding`
4. lance la creation de la facture provisoire vente
### `lot.lot` ### `lot.lot`
- Champ: `sale_invoice_padding` - Champ: `sale_invoice_padding`
- Role: memoire de la part de padding appliquee au lot pour la facture - Label UI: `Sale invoice padding`
provisoire vente. - Mode UI: readonly
- UI: readonly sur le lot. - Role: memoire durable de la part de padding appliquee au lot.
Ce champ est la source de verite fonctionnelle pour:
- afficher le padding sur la facture
- exclure le padding du calcul de delta de la facture finale
- calculer les ecritures comptables specifiques au padding
### `account.invoice.line` ### `account.invoice.line`
- Champ fonctionnel: `included_padding` - Champ fonctionnel: `included_padding`
- Label UI: `Inc. padding` - Label UI: `Inc. padding`
- Role: affichage de `line.lot.sale_invoice_padding` sur la ligne facture. - Unite affichee: meme unite que `Quantity`
- La valeur n'est pas stockee sur la ligne; elle lit le padding du lot. - Role: afficher `line.lot.sale_invoice_padding` sur la ligne facture.
### Wizard `lot.invoice` La valeur n'est pas stockee sur la ligne facture. Elle lit le padding depuis le
lot pour eviter une deuxieme source de verite.
- Champ: `sale_padding` (`Global padding`) ## 3) Impact sur la facture provisoire
- Visible seulement pour:
- `type = sale`
- `action = prov`
- Repartition actuelle:
- padding global / nombre de lots selectionnes
## 3) Flux de creation de facture avec padding Lors de la creation des lignes de facture vente provisoire:
1. L'utilisateur ouvre le wizard `lot.invoice` depuis les lots physiques. - seules les lignes positives `out` / `Pro forma` sont impactees
2. Le wizard prepare deux listes: - `invoice_line.quantity` est augmente de `lot.sale_invoice_padding`
- `lot_p` pour achat - le montant de ligne augmente naturellement car Tryton calcule:
- `lot_s` pour vente - `quantity * unit_price`
3. En mode vente provisoire, l'utilisateur saisit `Global padding`.
4. Au clic `Invoice`, le wizard:
- calcule la part de padding par lot
- ecrit cette part dans `lot.sale_invoice_padding`
- appelle `sale.sale._process_invoice(..., action='prov')`
5. `sale.line.get_invoice_line(lots, action)` cree une ligne facture par lot
physique.
6. Pour chaque ligne positive `out` / `Pro forma`, le module ajoute le padding
du lot a `invoice_line.quantity`.
7. L'amount de la ligne augmente naturellement via:
- `quantity * unit_price`
## 4) Ce qui se passe actuellement lors de `Validate` d'une facture Consequence:
Bouton UI: `Validate` sur `account.invoice`. - le move principal de facture contient deja le chiffre d'affaires augmente par
le padding
- `Inc. padding` rend visible la part artificielle incluse dans la quantite
- le lot garde sa quantite physique reelle
Code principal: ## 4) Impact sur la facture finale
- `modules/account_invoice/invoice.py` La facture finale doit comparer la quantite physique finale avec la quantite
- `Invoice.validate_invoice` reelle deja facturee en provisoire, pas avec la quantite provisoire augmentee du
- `Invoice.get_move` padding.
- `InvoiceLine.get_move_lines`
- `Invoice.do_lot_invoicing`
- `Invoice.cleanMoves`
### Etapes de `validate_invoice` Regle:
1. Verifie les taxes avec `_check_taxes`. - quantite provisoire reelle =
2. Attribue le numero via `set_number`. `lot.sale_invoice_line_prov.quantity - lot.sale_invoice_padding`
3. Stocke les caches de montants via `_store_cache`. - delta final =
4. Pour chaque facture: `lot.quantite_physique_courante - quantite_provisoire_reelle`
- appelle `invoice.get_move()`
- affecte le move a `invoice.move` s'il est nouveau
- appelle `invoice.do_lot_invoicing()`
5. Sauvegarde les moves crees.
6. Nettoie certaines lignes de move via `cleanMoves`.
7. Sauvegarde les factures.
Note importante deja actee dans le projet: Exemple:
- `Validate` cree deja le `account.move` et attribue le `number` aussi pour les - lot initial: `993`
factures client (`type = out`). - padding provisoire: `100`
- `Post` ne doit plus etre le premier moment ou ces donnees apparaissent cote - facture provisoire: `1093`
client. - apres weighing: `1080`
- delta final attendu: `1080 - 993 = 87`
### `get_move()` Sans cette correction, le wizard comparerait `1080` a `1093` et proposerait
`-13`, ce qui est faux car le padding ne doit pas etre considere comme une
quantite physique deja facturee.
`get_move()` construit le move comptable principal de la facture: ## 5) Configuration comptable
- appelle `update_taxes(exception=True)` Deux comptes par defaut sont ajoutes dans `Financial / Configuration`, dans une
- parcourt `invoice.lines` section dediee `Padding` placee avant la section `Invoice`.
- pour chaque ligne, appelle `line.get_move_lines()`
- ajoute les lignes de taxes via `tax.get_move_lines()`
- ajoute la ligne tiers / receivable-payable via `_get_move_line`
- ajoute eventuellement une ligne de change via `_get_exchange_move_line`
- cree un `account.move` avec:
- `journal = invoice.journal`
- `period` trouve depuis la date comptable
- `origin = invoice`
- `lines = move_lines`
### `account.invoice.line.get_move_lines()` Champs:
Pour une ligne facture `type = line`: - `Default Sale Padding`
- champ technique: `default_sale_padding_account`
- compte metier attendu: `80021`
- nature attendue: revenu
- `Default Accrual Padding`
- champ technique: `default_accrual_padding_account`
- compte metier attendu: `42021`
- nature attendue: bilan / accrual
- cree une ligne `account.move.line` Les champs suivent le pattern Tryton de `account.configuration`:
- rattache `line.lot = self.invoice.lines[0].lot`
- attention: comportement existant, pas forcement la ligne courante
- convertit le montant si devise differente
- pour une facture client (`type = out`):
- montant positif => credit du compte de revenu de la ligne
- montant negatif => debit
- met `line.account = self.account`
- met `line.origin = self`
- calcule les lignes de taxe
Pour le padding actuel, comme il augmente `invoice_line.quantity`, il est deja - champ `MultiValue` sur `account.configuration`
inclus dans le montant de revenu du move principal. - stockage dans `account.configuration.default_account`
- domaine par compagnie via le contexte `company`
### `do_lot_invoicing()` ## 6) Ecriture padding a la validation d'une provisoire
`do_lot_invoicing()` traite des ajustements lies aux lots: Point d'entree:
- groupe les lignes facture par `i.lot` - `account.invoice.validate_invoice`
- calcule: - puis `invoice.do_lot_invoicing()`
- `var_price` - surcharge `purchase_trade.invoice.Invoice.do_lot_invoicing`
- `var_qt`
- retrouve le mouvement stock:
- fournisseur pour `type = in`
- client pour `type = out`
- declenche des actions stock / shipment si necessaire
- calcule le COG du lot
- prepare des lignes d'ajustement via `_get_move_lines`
- actuellement, le move d'ajustement n'est cree/poste que si:
- `adjust_move_lines` existe
- `self.type == 'in'`
Consequence importante pour le padding: Condition:
- les ajustements de quantite/prix existants sont principalement effectifs cote - facture client: `invoice.type = out`
achat (`type = in`) - reference facture: `Provisional`
- une facture client provisoire avec padding augmente deja le move principal de - ligne facture: `description = Pro forma`
vente, mais ne genere pas encore d'ecritures specifiques padding separees - ligne rattachee a un lot
- `lot.sale_invoice_padding > 0`
### `_get_move_lines(gl, amount, drop, IsUsd=False, stock_move=None)` Montant:
Helper existant pour creer des paires de lignes de move liees au stock/COG: - `padding_amount = lot.sale_invoice_padding * invoice_line.unit_price`
- devise: devise de la facture provisoire
- montant societe: converti avec la devise, le taux et la date de la facture
provisoire
- rattache `lot`, `fee`, `origin` Ecriture creee en `additional_move`:
- gere la conversion devise / second currency
- choisit les comptes stock / stock out / stock in / COG selon le signe, fee et
contexte
- peut creer une variante `drop`
Ce helper est un candidat possible pour reutilisation partielle, mais il est - description: `Sale padding accrual`
aujourd'hui pense pour des ajustements stock/COG, pas pour isoler un padding de - debit: `Default Sale Padding` (`80021`)
facture provisoire vente. - credit: `Default Accrual Padding` (`42021`)
- `origin` des lignes: ligne de facture provisoire
- `lot` des lignes: lot concerne
- `party` renseigne si le compte le requiert
## 5) Question comptable a trancher pour le padding Raison du `additional_move`:
Le besoin restant est: au `Validate` d'une facture provisoire vente avec padding, - ne pas modifier la construction standard du move principal de facture
generer des ecritures propres a ce padding. - isoler l'ecriture padding pour audit et lettrage metier
- permettre le posting coordonne avec la facture
Points a definir avant implementation: ## 7) Ecriture inverse a la finale
- Le move padding doit-il etre: La finale doit extourner exactement le padding comptabilise sur la provisoire.
- integre dans le move principal de facture ? Elle ne doit pas recalculer le montant avec le prix final.
- cree comme `additional_move` ?
- cree comme move separe avec `origin = invoice` ?
- Quels comptes utiliser ?
- compte de revenu temporaire / provision ?
- compte de contrepartie padding ?
- compte lie au produit ?
- compte de configuration dedie ?
- Faut-il neutraliser une partie du revenu principal deja augmente par la
quantity, ou seulement ajouter une ecriture analytique/stock parallele ?
- Le padding doit-il impacter:
- revenu client ?
- stock out ?
- COG ?
- PnL / valuation ?
- Que doit faire la facture finale ?
- reprendre le padding provisoire ?
- le contrepasser ?
- ne rien faire si la finale facture la vraie quantite ?
- Le montant padding a utiliser est:
- `lot.sale_invoice_padding * invoice_line.unit_price`
- dans la devise de facture
- a convertir si devise societe differente selon la logique standard
## 5.1) Decision comptable cible Source du montant:
Comptes de configuration ajoutes sur `account.configuration`: - le lot porte deja le lien vers la ligne provisoire:
- `default_sale_padding_account`
- label UI: `Default Sale Padding`
- compte attendu metier: `80021`
- nature: revenu
- `default_accrual_padding_account`
- label UI: `Default Accrual Padding`
- compte attendu metier: `42021`
- nature: bilan / accrual
Facture provisoire vente:
- condition:
- `invoice.type = out`
- `invoice.reference = Provisional`
- `invoice_line.description = Pro forma`
- `invoice_line.lot.sale_invoice_padding > 0`
- montant:
- `padding_amount = lot.sale_invoice_padding * invoice_line.unit_price`
- le prix est celui de la facture provisoire, pas un prix recalcule plus tard
- ecriture attendue:
- couple `80021 / 42021`
- rattachement au lot obligatoire sur les lignes si possible
Facture finale vente:
- condition:
- lot deja facture en provisoire avec padding
- la finale doit inverser le padding deja provisionne
- montant:
- exactement le montant comptabilise lors de la provisoire
- ne pas recalculer avec le prix de la finale
- ecriture attendue:
- couple inverse `42021 / 80021`
Decision technique retenue:
- ne pas ajouter de nouveau champ montant pour l'instant
- utiliser le lien deja ecrit sur le lot:
- `lot.sale_invoice_line_prov` - `lot.sale_invoice_line_prov`
- au moment de la finale, retrouver la ligne provisoire via ce champ - le montant d'extourne utilise:
- calculer le montant a extourner avec:
- `lot.sale_invoice_padding * lot.sale_invoice_line_prov.unit_price`
- utiliser la devise, le taux et la date de la facture provisoire pour obtenir
le meme montant societe que l'ecriture initiale
- garder le rattachement comptable par `account.move.line.lot`
Raison:
- evite les ecarts si le prix final change
- reutilise le lien direct deja maintenu entre le lot et la ligne provisoire
- rend la reprise finale audit-friendly
- garde le pivot comptable lot coherent
## 6) Invariants a preserver
- Le padding ne change pas la quantite physique du lot.
- Le padding est uniquement pour facture provisoire vente:
- `invoice.type = out`
- `invoice.reference = Provisional`
- lignes `description = Pro forma`
- L'utilisateur doit voir clairement l'ecart:
- `Quantity`
- `Inc. padding`
- Le lien principal reste:
- `account.invoice.line.lot`
- `lot.sale_invoice_padding` - `lot.sale_invoice_padding`
- Les futures ecritures doivent etre rattachees au lot autant que possible pour - `lot.sale_invoice_line_prov.unit_price`
rester visibles dans le pivot comptable du lot. - la devise, la date et le taux de la facture provisoire
## 7) Tests a prevoir pour la suite Condition:
- Validation d'une facture provisoire vente avec padding: - facture client: `invoice.type = out`
- move principal existe - reference facture: `Final`
- montant facture inclut le padding - ligne facture: `description = Final`
- ecritures specifiques padding creees selon la regle retenue - lot avec `sale_invoice_padding > 0`
- lignes rattachees au bon lot - lot avec `sale_invoice_line_prov`
- Facture provisoire vente sans padding:
- aucun move padding specifique Ecriture creee en `additional_move`:
- Facture finale vente:
- aucun nouveau padding applique automatiquement - description: `Sale padding reversal`
- comportement de reprise/contrepassation selon decision metier - debit: `Default Accrual Padding` (`42021`)
- Facture achat: - credit: `Default Sale Padding` (`80021`)
- aucun impact padding vente - montant: identique au montant padding de la provisoire
- Multi-lots: - `origin` des lignes: ligne de facture provisoire
- padding reparti correctement - `lot` des lignes: lot concerne
- ecritures detaillees par lot si la regle comptable l'exige
## 8) Posting
Au `Validate`:
- le move principal de facture est cree
- le ou les `additional_moves` padding sont crees en draft
Au `Post`:
- les `additional_moves` padding deja crees en draft sont postes
- si une facture est postee directement depuis draft, le module cree d'abord les
moves padding manquants puis les poste
Une detection par description evite de recreer deux fois le meme move padding
sur la meme facture:
- `Sale padding accrual`
- `Sale padding reversal`
## 9) Invariants a preserver
- Le padding est uniquement pour les factures provisoires cote vente.
- Le padding ne modifie jamais la quantite physique du lot.
- `lot.sale_invoice_padding` reste la memoire fonctionnelle du padding.
- La facture affiche toujours l'ecart via `Inc. padding`.
- La facture finale ignore le padding pour calculer le delta de quantite.
- L'extourne finale reprend le montant de la provisoire, pas le prix final.
- Les ecritures padding doivent rester rattachees au lot.
## 10) Points de vigilance
- Le sens debit/credit actuellement implemente est:
- provisoire: debit `80021`, credit `42021`
- finale: debit `42021`, credit `80021`
Ce sens doit etre valide par la comptabilite si le plan attendu impose une
convention differente.
- La detection du type de facture s'appuie sur `invoice.reference`:
- `Provisional`
- `Final`
- La detection des lignes s'appuie sur `invoice_line.description`:
- `Pro forma`
- `Final`
- Si ces libelles changent, la logique padding doit etre ajustee.
- Les tests unitaires complets n'ont pas pu etre lances dans l'environnement
local actuel a cause de dependances manquantes (`pytest`, puis `jwt`).
## 11) Validations techniques de session
Validations effectuees localement:
- compilation Python ciblee des fichiers touches
- validation XML ciblee des vues et definitions modifiees
- `git diff --check` sans erreur bloquante, avec seulement des alertes CRLF
existantes dans le repository

View File

@@ -107,6 +107,17 @@ Scope: templates Relatorio + ponts `report_*` Python.
lot ne doit pas changer. lot ne doit pas changer.
- Au `Validate` d'une facture, le move principal inclut deja le padding car il - Au `Validate` d'une facture, le move principal inclut deja le padding car il
est integre dans `account.invoice.line.quantity`. est integre dans `account.invoice.line.quantity`.
- Les ecritures comptables specifiques au padding restent a definir; point - Deux comptes de configuration pilotent les ecritures padding:
d'entree documente: `Default Sale Padding` et `Default Accrual Padding`, dans la section
`Padding` de `Financial / Configuration`.
- A la validation d'une provisoire vente, un `additional_move` est cree:
debit `Default Sale Padding`, credit `Default Accrual Padding`, pour
`sale_invoice_padding * unit_price` de la ligne provisoire.
- A la finale, l'ecriture inverse est creee pour le meme montant, calcule depuis
`lot.sale_invoice_line_prov` afin de reprendre le prix, la devise, la date et
le taux de la provisoire, pas ceux de la finale.
- Le wizard final doit ignorer le padding quand il calcule le delta de quantite:
comparer la quantite physique finale a
`lot.sale_invoice_line_prov.quantity - lot.sale_invoice_padding`.
- Detail complet:
`modules/purchase_trade/docs/padding-invoice-accounting.md`. `modules/purchase_trade/docs/padding-invoice-accounting.md`.