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
- les comptes de padding viennent de `account.configuration`:
`Default Sale Padding` et `Default Accrual Padding`
- la provisoire doit passer le couple sale/accrual, et la finale doit passer
l'inverse pour le montant exact comptabilise en provisoire
- preferer stocker ce montant au moment de la provisoire plutot que le
recalculer depuis la finale
- la section `Padding` doit rester avant la section `Invoice` dans
`Financial / Configuration`
- la provisoire cree un `additional_move` debit `Default Sale Padding` /
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

View File

@@ -431,10 +431,17 @@ Owner technique: `a completer`
- Validation comptable:
- au `Validate`, le move principal de facture inclut deja le padding car il
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`
- 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
- 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`
- Priorite:
- `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`
Scope: `lot.invoice` -> `account.invoice` -> validation comptable.
Scope: `lot.invoice` -> `account.invoice.line` -> `account.move`
## 1) Objectif metier
Le padding sert a augmenter temporairement la quantite facturee sur une facture
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:
- 2 lots factures ensemble
- padding global saisi dans le wizard: `1000`
- repartition actuelle: `500` par lot
- 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`
Le padding ne modifie pas la quantite physique du lot. Il doit rester visible et
traçable comme ecart entre la facture provisoire et le lot.
## 2) Saisie et stockage
## 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`
- Champ: `sale_invoice_padding`
- Role: memoire de la part de padding appliquee au lot pour la facture
provisoire vente.
- UI: readonly sur le lot.
- Label UI: `Sale invoice padding`
- Mode UI: readonly
- 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`
- Champ fonctionnel: `included_padding`
- Label UI: `Inc. padding`
- Role: affichage de `line.lot.sale_invoice_padding` sur la ligne facture.
- La valeur n'est pas stockee sur la ligne; elle lit le padding du lot.
- Unite affichee: meme unite que `Quantity`
- 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`)
- Visible seulement pour:
- `type = sale`
- `action = prov`
- Repartition actuelle:
- padding global / nombre de lots selectionnes
## 3) Impact sur la facture provisoire
## 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.
2. Le wizard prepare deux listes:
- `lot_p` pour achat
- `lot_s` pour vente
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`
- seules les lignes positives `out` / `Pro forma` sont impactees
- `invoice_line.quantity` est augmente de `lot.sale_invoice_padding`
- le montant de ligne augmente naturellement car Tryton calcule:
- `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`
- `Invoice.validate_invoice`
- `Invoice.get_move`
- `InvoiceLine.get_move_lines`
- `Invoice.do_lot_invoicing`
- `Invoice.cleanMoves`
La facture finale doit comparer la quantite physique finale avec la quantite
reelle deja facturee en provisoire, pas avec la quantite provisoire augmentee du
padding.
### Etapes de `validate_invoice`
Regle:
1. Verifie les taxes avec `_check_taxes`.
2. Attribue le numero via `set_number`.
3. Stocke les caches de montants via `_store_cache`.
4. Pour chaque facture:
- 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.
- quantite provisoire reelle =
`lot.sale_invoice_line_prov.quantity - lot.sale_invoice_padding`
- delta final =
`lot.quantite_physique_courante - quantite_provisoire_reelle`
Note importante deja actee dans le projet:
Exemple:
- `Validate` cree deja le `account.move` et attribue le `number` aussi pour les
factures client (`type = out`).
- `Post` ne doit plus etre le premier moment ou ces donnees apparaissent cote
client.
- lot initial: `993`
- padding provisoire: `100`
- facture provisoire: `1093`
- 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)`
- parcourt `invoice.lines`
- 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`
Deux comptes par defaut sont ajoutes dans `Financial / Configuration`, dans une
section dediee `Padding` placee avant la section `Invoice`.
### `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`
- 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
Les champs suivent le pattern Tryton de `account.configuration`:
Pour le padding actuel, comme il augmente `invoice_line.quantity`, il est deja
inclus dans le montant de revenu du move principal.
- champ `MultiValue` sur `account.configuration`
- 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`
- calcule:
- `var_price`
- `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'`
- `account.invoice.validate_invoice`
- puis `invoice.do_lot_invoicing()`
- surcharge `purchase_trade.invoice.Invoice.do_lot_invoicing`
Consequence importante pour le padding:
Condition:
- les ajustements de quantite/prix existants sont principalement effectifs cote
achat (`type = in`)
- une facture client provisoire avec padding augmente deja le move principal de
vente, mais ne genere pas encore d'ecritures specifiques padding separees
- facture client: `invoice.type = out`
- reference facture: `Provisional`
- ligne facture: `description = Pro forma`
- 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`
- 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`
Ecriture creee en `additional_move`:
Ce helper est un candidat possible pour reutilisation partielle, mais il est
aujourd'hui pense pour des ajustements stock/COG, pas pour isoler un padding de
facture provisoire vente.
- description: `Sale padding accrual`
- debit: `Default Sale Padding` (`80021`)
- 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,
generer des ecritures propres a ce padding.
- ne pas modifier la construction standard du move principal de facture
- 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:
- integre dans le move principal de facture ?
- 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
La finale doit extourner exactement le padding comptabilise sur la provisoire.
Elle ne doit pas recalculer le montant avec le prix final.
## 5.1) Decision comptable cible
Source du montant:
Comptes de configuration ajoutes sur `account.configuration`:
- `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:
- le lot porte deja le lien vers la ligne provisoire:
- `lot.sale_invoice_line_prov`
- au moment de la finale, retrouver la ligne provisoire via ce champ
- 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`
- le montant d'extourne utilise:
- `lot.sale_invoice_padding`
- Les futures ecritures doivent etre rattachees au lot autant que possible pour
rester visibles dans le pivot comptable du lot.
- `lot.sale_invoice_line_prov.unit_price`
- 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:
- move principal existe
- montant facture inclut le padding
- ecritures specifiques padding creees selon la regle retenue
- lignes rattachees au bon lot
- Facture provisoire vente sans padding:
- aucun move padding specifique
- Facture finale vente:
- aucun nouveau padding applique automatiquement
- comportement de reprise/contrepassation selon decision metier
- Facture achat:
- aucun impact padding vente
- Multi-lots:
- padding reparti correctement
- ecritures detaillees par lot si la regle comptable l'exige
- facture client: `invoice.type = out`
- reference facture: `Final`
- ligne facture: `description = Final`
- lot avec `sale_invoice_padding > 0`
- lot avec `sale_invoice_line_prov`
Ecriture creee en `additional_move`:
- description: `Sale padding reversal`
- debit: `Default Accrual Padding` (`42021`)
- credit: `Default Sale Padding` (`80021`)
- montant: identique au montant padding de la provisoire
- `origin` des lignes: ligne de facture provisoire
- `lot` des lignes: lot concerne
## 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.
- Au `Validate` d'une facture, le move principal inclut deja le padding car il
est integre dans `account.invoice.line.quantity`.
- Les ecritures comptables specifiques au padding restent a definir; point
d'entree documente:
- Deux comptes de configuration pilotent les ecritures padding:
`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`.