# Padding facture provisoire vente - notes de session

Statut: `implemente - a valider comptablement`
Derniere mise a jour: `2026-04-26`
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`
  - `Inc. padding = padding du lot`

## 2) Saisie et stockage

### 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`
- 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`
- Unite affichee: meme unite que `Quantity`
- Role: afficher `line.lot.sale_invoice_padding` sur la ligne facture.

La valeur n'est pas stockee sur la ligne facture. Elle lit le padding depuis le
lot pour eviter une deuxieme source de verite.

## 3) Impact sur la facture provisoire

Lors de la creation des lignes de facture vente provisoire:

- 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`

Consequence:

- 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

## 4) Impact sur la facture finale

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.

Regle:

- quantite provisoire reelle =
  `lot.sale_invoice_line_prov.quantity - lot.sale_invoice_padding`
- delta final =
  `lot.quantite_physique_courante - quantite_provisoire_reelle`

Exemple:

- lot initial: `993`
- padding provisoire: `100`
- facture provisoire: `1093`
- apres weighing: `1080`
- delta final attendu: `1080 - 993 = 87`

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.

## 5) Configuration comptable

Deux comptes par defaut sont ajoutes dans `Financial / Configuration`, dans une
section dediee `Padding` placee avant la section `Invoice`.

Champs:

- `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

Les champs suivent le pattern Tryton de `account.configuration`:

- champ `MultiValue` sur `account.configuration`
- stockage dans `account.configuration.default_account`
- domaine par compagnie via le contexte `company`

## 6) Ecriture padding a la validation d'une provisoire

Point d'entree:

- `account.invoice.validate_invoice`
- puis `invoice.do_lot_invoicing()`
- surcharge `purchase_trade.invoice.Invoice.do_lot_invoicing`

Condition:

- facture client: `invoice.type = out`
- reference facture: `Provisional`
- ligne facture: `description = Pro forma`
- ligne rattachee a un lot
- `lot.sale_invoice_padding > 0`

Montant:

- `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

Ecriture creee en `additional_move`:

- 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

Raison du `additional_move`:

- 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

## 7) Ecriture inverse a la finale

La finale doit extourner exactement le padding comptabilise sur la provisoire.
Elle ne doit pas recalculer le montant avec le prix final.

Source du montant:

- le lot porte deja le lien vers la ligne provisoire:
  - `lot.sale_invoice_line_prov`
- le montant d'extourne utilise:
  - `lot.sale_invoice_padding`
  - `lot.sale_invoice_line_prov.unit_price`
  - la devise, la date et le taux de la facture provisoire

Condition:

- 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
