# Padding facture provisoire vente - notes comptables Statut: `draft` Derniere mise a jour: `2026-04-26` Scope: `lot.invoice` -> `account.invoice` -> validation comptable. ## 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. 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` 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) Donnees creees ou utilisees ### `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. ### `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. ### Wizard `lot.invoice` - Champ: `sale_padding` (`Global padding`) - Visible seulement pour: - `type = sale` - `action = prov` - Repartition actuelle: - padding global / nombre de lots selectionnes ## 3) Flux de creation de facture avec padding 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` ## 4) Ce qui se passe actuellement lors de `Validate` d'une facture Bouton UI: `Validate` sur `account.invoice`. Code principal: - `modules/account_invoice/invoice.py` - `Invoice.validate_invoice` - `Invoice.get_move` - `InvoiceLine.get_move_lines` - `Invoice.do_lot_invoicing` - `Invoice.cleanMoves` ### Etapes de `validate_invoice` 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. Note importante deja actee dans le projet: - `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. ### `get_move()` `get_move()` construit le move comptable principal de la facture: - 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` ### `account.invoice.line.get_move_lines()` Pour une ligne facture `type = line`: - 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 Pour le padding actuel, comme il augmente `invoice_line.quantity`, il est deja inclus dans le montant de revenu du move principal. ### `do_lot_invoicing()` `do_lot_invoicing()` traite des ajustements lies aux lots: - 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'` Consequence importante pour le padding: - 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 ### `_get_move_lines(gl, amount, drop, IsUsd=False, stock_move=None)` Helper existant pour creer des paires de lignes de move liees au stock/COG: - 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` 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. ## 5) Question comptable a trancher pour le padding Le besoin restant est: au `Validate` d'une facture provisoire vente avec padding, generer des ecritures propres a ce padding. Points a definir avant implementation: - 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 ## 5.1) Decision comptable cible 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: - `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` - `lot.sale_invoice_padding` - Les futures ecritures doivent etre rattachees au lot autant que possible pour rester visibles dans le pivot comptable du lot. ## 7) Tests a prevoir pour la suite - 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