# Template Business Rules - Session Memo

Date: 2026-04-08
Scope: templates Relatorio + ponts `report_*` Python.

## 1) Regles metier confirmees

- `insurance.fodt`:
  - "This is to certify that we have insured for account of" doit afficher la compagnie courante (`shipment.company.party`), pas le client.
  - "Amount insured" suit la regle 110% de la valeur incoming.
  - Base incoming: montant des incoming moves lies au shipment, derive des lots et de la source achat (`purchase.line.unit_price * current_quantity_converted`).
- `sale bill`:
  - La 2eme date attendue est une maturity date (echeance), pas le libelle de condition de paiement.
  - Le montant en toutes lettres doit correspondre au montant du bill (montant facture/total), pas au prix unitaire d'une ligne.

## 2) Pratiques templates Relatorio

- Preferer des proprietes Python `report_*` stables sur le modele plutot que des expressions Genshi complexes.
- Pour creer un nouveau report `.fodt`, partir d'un template voisin qui fonctionne
  deja dans le meme module, puis remplacer seulement le contenu metier
  necessaire. Eviter les FODT minimaux faits a la main: Relatorio et
  LibreOffice attendent une enveloppe ODT complete (`office:meta`, settings,
  namespaces comme `draw`/`xlink`, styles, master pages), sinon le parsing ou le
  rendu peut casser.
- Pour `stock.shipment.in`, privilegier `records[0].report_*` dans le template.
- Si un placeholder s'affiche en brut dans le PDF:
  - verifier que c'est un vrai `text:placeholder` ODF et pas du texte simple.
  - verifier le scope de variable (`records[0]` vs variable locale non definie).
- Dans les placeholders XML:
  - utiliser `&quot;` et `&apos;` dans les expressions XML.
  - eviter les echappements de type `\'`.

## 3) Decisions de conception appliquees

- `insurance.fodt`:
  - ajout d'un champ shipment `surveyor` (party.party) via onglet "Surveyor".
  - ajout d'une propriete `report_insurance_contact_surveyor` pour la zone "Contact the following surveyor".
- `payment_order.fodt`:
  - migration des tags `<...>` legacy vers la syntaxe template habituelle du projet.
  - ajout de la section de config template, et exposition depuis `account.invoice` comme pour CN/DN/Invoice/Prepayment.
- `packing_list.fodt`:
  - date en haut droite basee sur la date du jour.
  - unites Net/Gross alignees sur l'unite de `purchase.line`.
- `bill.fodt`:
  - suppression du report `sale_final.fodt` du menu sale.
  - ajout de ponts Python cote sale pour:
    - montant bill numerique,
    - montant bill en lettres,
    - maturity date issue de `invoice.lines_to_pay.maturity_date` (avec fallback metier).

## 4) Check-list rapide avant validation d'un template

- Les placeholders sont-ils tous resolus (aucun `<records[...]...>` brut)?
- Le scope est-il correct (`records[0]` / `sale` / `invoice`) partout, y compris header/footer?
- La source metier est-elle correcte (compagnie vs client, total vs unit_price, maturity date vs payment term)?
- Les formats sont-ils conformes (date, devise, montant en lettres)?
- Le template est-il bien expose dans la config + menu d'impression de la forme cible?

## 5) Session 2026-04-09 - Rappels metier purchase_trade / account_invoice

- Factures trade:
  - `NET` et `GROSS` viennent de `lot.qt.hist` du lot retenu, pas de `invoice.line.quantity`.
  - priorite lots: `physic` d'abord, sinon lot `virtual` unique.
  - l'unite affichee vient de `lot.lot_unit_line`.
  - les infos shipment doivent dependre des lots reels des lignes facture.
  - le label `S/I` doit afficher `shipment.reference`.
  - `invoice_ict_final.fodt`: si `NB BALES = 0`, afficher `Unchanged`.
  - les quantites de `invoice_ict` et `invoice_ict_final` sont uniformisees a `2` decimales.
  - la conversion vers `LBS` doit passer par `product.uom.compute_qty`, pas un facteur fixe.
  - si plusieurs lignes reutilisent le meme lot, les lignes detaillees utilisent la quantite facturee convertie, mais le `GROSS` global doit continuer a refleter le vrai delta historique du lot.
- CN / DN:
  - cote `sale` / `out`: montant negatif => `Credit Note`, montant positif => `Debit Note`.
  - cote `purchase` / `in`: logique inverse conservee.
- Report sale:
  - meme priorite lots que facture.
  - les quantites en lettres suivent l'unite reelle (`MT`, `KILOGRAM`, `LBS`).
  - le total convertit les lignes vers une unite commune.
  - l'unite commune est celle du lot virtuel seulement s'il y a un seul lot virtuel sur tout le report.
- Lots:
  - `lot.report.r_del_period` affiche `sale.line.del_period` pour `lot_s` sans `lot_p`, sinon `purchase.line.del_period`.
  - dans `Do weighing`, `lot_qt` doit etre editable et ecraser directement `lot.lot_qt`.
- Factures client / fournisseur:
  - `Validate` cree aussi le `account.move` pour les factures client.
  - `Validate` attribue aussi le `number` pour les factures client; la numerotation ne doit plus attendre `Post` cote `out`.
  - `Post` ne doit plus forcer une fresh session / demande de mot de passe sur ce flux.
- Pricing:
  - `pricing.pricing` peut etre saisi manuellement meme sans composant.
  - en manuel, l'utilisateur saisit seulement `quantity` et `settl_price`.
  - `fixed_qt`, `fixed_qt_price`, `unfixed_qt`, `unfixed_qt_price` sont derives automatiquement et restent non editables.
  - `fixed_qt` = cumul des `quantity` du groupe.
  - `fixed_qt_price` = moyenne ponderee cumulee des `settl_price`.
  - `unfixed_qt` = quantite de base restante a fixer.
  - `unfixed_qt_price` = dernier prix disponible de la courbe du composant,
    fallback `settl_price` si aucune courbe exploitable n'est disponible.
  - `eod_price` reste non editable et suit le prix moyen pondere.
  - le mode auto suit la meme formule.
  - `last` est gere par groupe metier (`line + component`), avec un seul `last=True` par groupe.
  - la ligne `last=True` est celle de `pricing_date` la plus grande; `id` ne sert qu'en tie-break.
- Divers:
  - `trader` filtre sur `TRADER`.
  - `operator` filtre sur `OPERATOR`.
  - les quotas/pricings doivent fallback sur `quantity` si `quantity_theorical` est vide.
- `sale.line` / `purchase.line`: en mode `basis`, si aucun `price_component` n'est defini, le prix et la progression doivent remonter depuis la ligne `Summary` / `pricing.summary` sans component.

## 6) Session 2026-04-26 - Padding facture provisoire vente

- Le wizard `lot.invoice` peut appliquer un padding global uniquement sur les
  factures provisoires cote vente.
- Le padding global est reparti par lot et conserve sur `lot.lot` dans
  `sale_invoice_padding`.
- La ligne facture affiche ce montant via `Inc. padding`, avec la meme unite que
  `Quantity`.
- La quantite facturee est augmentee du padding, mais la quantite physique du
  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`.
- 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`.
