304 lines
13 KiB
Markdown
304 lines
13 KiB
Markdown
# Template Rules - Purchase Trade
|
|
|
|
Statut: `draft`
|
|
Version: `v0.4`
|
|
Derniere mise a jour: `2026-04-07`
|
|
|
|
## 1) Scope
|
|
|
|
- Domaine: `templates Relatorio .fodt`
|
|
- Modules concernes:
|
|
- `purchase_trade`
|
|
- `sale`
|
|
- `account_invoice`
|
|
|
|
## 2) Objectif
|
|
|
|
- Eviter les erreurs de parsing Relatorio/Genshi lors de la generation des documents.
|
|
- Standardiser la maniere d'alimenter les templates metier a partir du code Python.
|
|
- Centraliser les proprietes `report_*` dans une documentation reutilisable.
|
|
|
|
## 2.1) Index de reference
|
|
|
|
- Catalogue des proprietes templates:
|
|
- `modules/purchase_trade/docs/template-properties.md`
|
|
|
|
## 3) Regles pratiques
|
|
|
|
### TR-001 - Toujours partir du template standard voisin
|
|
|
|
- Avant de modifier un template metier (`invoice_ict.fodt`, `sale_ict.fodt`, etc.), comparer avec le template standard du module source:
|
|
- `modules/account_invoice/invoice.fodt`
|
|
- `modules/sale/sale.fodt`
|
|
- Reprendre en priorite la syntaxe Relatorio deja validee dans ces templates.
|
|
|
|
### TR-002 - Eviter les expressions Genshi trop complexes dans le `.fodt`
|
|
|
|
- Preferer des proprietes Python simples exposees par le modele.
|
|
- Le template doit consommer au maximum des champs ou proprietes du type:
|
|
- `record.report_address`
|
|
- `record.report_price`
|
|
- `record.report_payment_date`
|
|
- Si un template a besoin de donnees issues d'un autre modele lie, creer un petit pont Python.
|
|
|
|
### TR-003 - Regles de syntaxe XML/Relatorio dans les placeholders
|
|
|
|
- Dans un `text:placeholder`, utiliser:
|
|
- `"..."` pour les guillemets doubles
|
|
- `'...'` pour les apostrophes
|
|
- Eviter les formes avec antislashs:
|
|
- interdit: `\'\'`
|
|
- interdit: `\'value\'`
|
|
- Exemples corrects:
|
|
- `<replace text:p="set_lang(invoice.party.lang)">`
|
|
- `<if test="invoice.report_payment_description">`
|
|
- `<tax.description or ''>`
|
|
|
|
### TR-004 - Pour une facture issue d'une vente, preferer un pont `account.invoice -> sale`
|
|
|
|
- Si le template facture doit reutiliser la logique de la pro forma vente, ne pas dupliquer les calculs directement dans le `.fodt`.
|
|
- Ajouter plutot dans `purchase_trade` une extension `account.invoice` avec des proprietes `report_*` qui relaient vers `invoice.sales[0]`.
|
|
- Exemple de proprietes utiles:
|
|
- `report_address`
|
|
- `report_contract_number`
|
|
- `report_shipment`
|
|
- `report_product_description`
|
|
- `report_crop_name`
|
|
- `report_attributes_name`
|
|
- `report_price`
|
|
- `report_payment_date`
|
|
- `report_nb_bale`
|
|
- `report_gross`
|
|
- `report_net`
|
|
- `report_lbs`
|
|
|
|
### TR-005 - Reutiliser les proprietes existantes du module `purchase_trade.sale`
|
|
|
|
- Avant d'ajouter une nouvelle logique pour un template vente ou facture issue d'une vente, verifier si une propriete existe deja sur `sale.sale`.
|
|
- Proprietes deja utiles:
|
|
- `report_terms`
|
|
- `report_gross`
|
|
- `report_net`
|
|
- `report_qt`
|
|
- `report_nb_bale`
|
|
- `report_deal`
|
|
- `report_packing`
|
|
- `report_price`
|
|
- `report_delivery`
|
|
- `report_payment_date`
|
|
- `report_shipment`
|
|
|
|
### TR-006 - Penser au cache des reports facture avant d'accuser le `.fodt`
|
|
|
|
- Les actions de report `account.invoice` peuvent partager le meme moteur de rendu.
|
|
- Dans `modules/account_invoice/invoice.py`, le champ `invoice_report_cache` peut reutiliser un document deja genere.
|
|
- Symptome typique:
|
|
- plusieurs actions differentes (`Provisional Invoice`, `Final Invoice`, `Prepayment`, etc.) semblent ouvrir le meme template ou le meme rendu
|
|
- Reflexe a avoir:
|
|
- verifier si le probleme vient du cache avant de modifier le `.fodt`
|
|
- pour un report alternatif, ne pas reutiliser le cache du report standard `account_invoice/invoice.fodt`
|
|
- si besoin, bypasser la lecture/ecriture du cache pour les templates alternatifs
|
|
- pour les clients multi-templates, preferer une configuration metier qui
|
|
stocke le nom du template par action (`Invoice`, `CN/DN`, `Prepayment`)
|
|
plutot qu'une modification manuelle de `ir_action_report.report`
|
|
|
|
### TR-012 - Centraliser les templates client dans `Document Templates`
|
|
|
|
- Pour les templates client-specifiques, ne pas modifier `ir_action_report.report`
|
|
en base a la main selon l'environnement ou le client.
|
|
- Preferer la configuration singleton `purchase_trade.configuration`,
|
|
exposee dans `Documents > Configuration > Document Templates`.
|
|
- Sections actuellement attendues:
|
|
- `Sale`
|
|
- `Invoice`
|
|
- `Payment`
|
|
- `Purchase`
|
|
- `Shipment`
|
|
- Regle:
|
|
- si le champ de template correspondant est vide, le report doit echouer
|
|
explicitement avec `No template found`
|
|
- ne pas masquer dynamiquement l'action d'impression si ce n'est pas
|
|
necessaire
|
|
|
|
### TR-013 - `sale_melya.fodt` et `invoice_melya.fodt` doivent afficher nom + description produit
|
|
|
|
- Dans les templates client Melya, le bloc produit doit prevoir:
|
|
- une ligne pour le nom produit
|
|
- une ligne pour la description produit
|
|
- Ne pas dereferencer directement `line.product.name` / `line.product.description`
|
|
dans les `.fodt`.
|
|
- Preferer:
|
|
- `sale.report_product_name`
|
|
- `sale.report_product_description`
|
|
- `invoice.report_product_name`
|
|
- `invoice.report_product_description`
|
|
|
|
### TR-014 - `invoice_melya.fodt` doit afficher `Invoice` et `Reference` sur les bons champs
|
|
|
|
- Pour `modules/account_invoice/invoice_melya.fodt`:
|
|
- `Invoice` doit afficher `invoice.number`
|
|
- `Reference` doit afficher `invoice.report_contract_number`
|
|
- Ne pas reutiliser `invoice.reference` pour ce label dans ce template client
|
|
sans demande explicite
|
|
|
|
### TR-015 - Le template `stock/insurance.fodt` doit lire sur `stock.shipment.in`
|
|
|
|
- Le template `modules/stock/insurance.fodt` est pilote par le report
|
|
`stock.shipment.in.insurance`.
|
|
- Toutes les croix rouges / placeholders metier doivent etre remplacees par
|
|
des proprietes `report_*` exposees sur `stock.shipment.in`.
|
|
- Pour ce template, ne pas compter sur une variable Genshi locale `shipment`
|
|
dans tout le document; preferer `records[0]....` dans le `.fodt`.
|
|
- Source de verite du montant assure:
|
|
- sommer les montants des `incoming_moves` du shipment
|
|
- montant d'un move = `move.quantity * move.unit_price`
|
|
- si `move.unit_price` est vide, fallback via lot:
|
|
`lot.line.unit_price * lot.get_current_quantity_converted()`
|
|
- exposer au moins:
|
|
- le montant total des incoming moves
|
|
- le montant assure a `110%` de ce total
|
|
- pour le placeholder `Amount insured`, `report_insurance_amount` doit
|
|
afficher ce `110%`, avec fallback fee `Insurance` si aucun montant
|
|
incoming n'est calculable
|
|
|
|
### TR-016 - Hypotheses actuelles pour le certificat d'assurance shipment
|
|
|
|
- Tant qu'une source metier plus precise n'est pas fournie:
|
|
- numero du certificat: `shipment.bl_number`, sinon `shipment.number`
|
|
- `insured for account of`: client de la premiere ligne metier retrouvee via
|
|
lot physique, sinon `shipment.supplier`
|
|
- `surveyor`: `shipment.surveyor`, sinon `shipment.controller`, sinon
|
|
fournisseur du fee `Insurance`
|
|
- lieu/date d'emission: ville de la societe + date du jour
|
|
- Si une source differente est decidee plus tard, corriger la propriete Python
|
|
plutot que complexifier `insurance.fodt`
|
|
|
|
### TR-017 - `payment_order.fodt` doit utiliser des proprietes `report_payment_order_*`
|
|
|
|
- Pour `modules/account_invoice/payment_order.fodt`, ne pas utiliser des
|
|
placeholders externes legacy (tokens metier entre `<...>` du systeme source).
|
|
- Tous les placeholders du template doivent pointer vers des proprietes Python
|
|
stables exposees sur `account.invoice`:
|
|
- `report_payment_order_document_reference`
|
|
- `report_payment_order_from_account_nb`
|
|
- `report_payment_order_to_bank_name`
|
|
- `report_payment_order_to_bank_city`
|
|
- `report_payment_order_amount`
|
|
- `report_payment_order_currency_code`
|
|
- `report_payment_order_amount_text`
|
|
- `report_payment_order_value_date`
|
|
- `report_payment_order_company_address`
|
|
- `report_payment_order_beneficiary_account_nb`
|
|
- `report_payment_order_beneficiary_bank_name`
|
|
- `report_payment_order_beneficiary_bank_city`
|
|
- `report_payment_order_swift_code`
|
|
- `report_payment_order_other_instructions`
|
|
- `report_payment_order_reference`
|
|
- `report_payment_order_current_user`
|
|
- `report_payment_order_current_user_email`
|
|
- Eviter les marqueurs conditionnels heredites de l'ancien moteur (`++...`):
|
|
privilegier des placeholders simples avec fallback `or ''`.
|
|
|
|
### TR-018 - Un template configure n'apparait dans le form que si une action report existe
|
|
|
|
- Ajouter un champ dans `Document Templates` ne suffit pas a rendre un
|
|
template imprimable depuis la fiche.
|
|
- Pour afficher l'entree dans `account.invoice`, il faut aussi:
|
|
- un `ir.action.report` sur `model = account.invoice`
|
|
- un `ir.action.keyword` `form_print` lie a cette action
|
|
- Appliquer cette regle pour `Payment Order` comme pour `Invoice`,
|
|
`Prepayment` et `CN/DN`.
|
|
|
|
### TR-007 - Pour une facture trade, privilegier le lot physique comme chemin de navigation
|
|
|
|
- Pour remonter d'une facture vers des donnees logistiques ou metier, ne pas dupliquer de chemins differents selon achat/vente.
|
|
- Regle pratique:
|
|
- partir de la ligne metier (`purchase.line` ou `sale.line`)
|
|
- retrouver le lot physique associe
|
|
- utiliser ce lot comme pont vers le shipment et les autres objets lies
|
|
- Ce chemin doit etre privilegie pour exposer des proprietes `report_*` comme:
|
|
- `report_bl_date`
|
|
- `report_loading_port`
|
|
- `report_discharge_port`
|
|
- `report_controller_name`
|
|
- `report_si_number`
|
|
- `report_proforma_invoice_number`
|
|
- `report_proforma_invoice_date`
|
|
|
|
### TR-008 - Le freight amount d'un template facture vient du fee de shipment
|
|
|
|
- Ne pas lire le fret directement sur `account.invoice`.
|
|
- Pour les templates `invoice_ict*`, le `FREIGHT VALUE` doit etre expose par une propriete Python du type `invoice.report_freight_amount`.
|
|
- La logique attendue est:
|
|
- retrouver le lot physique pertinent
|
|
- retrouver son shipment
|
|
- chercher le `fee.fee` du shipment avec `product.name = 'Maritime freight'`
|
|
- utiliser `fee.get_amount()`
|
|
- Si le fee a sa propre devise, preferer aussi exposer le symbole de devise depuis le fee plutot que depuis la facture.
|
|
|
|
### TR-009 - Ne pas dereferencer directement `del_period.description` dans les templates
|
|
|
|
- Eviter les expressions du type:
|
|
- `sale.lines[0].del_period.description`
|
|
- `purchase.lines[0].del_period.description`
|
|
- Meme avec un `if ... else`, ces acces sont fragiles dans un `.fodt` et
|
|
rendent le debug plus difficile.
|
|
- Preferer une propriete Python stable:
|
|
- `sale.report_delivery_period_description`
|
|
- `purchase.report_delivery_period_description`
|
|
- `invoice.report_delivery_period_description`
|
|
|
|
### TR-010 - En template, un contrat `basis` affiche le premium comme prix
|
|
|
|
- Pour les templates commerciaux/facture (`sale_ict`, `invoice_ict`, etc.),
|
|
le prix affiche d'une ligne `basis` ne doit pas etre le prix economique total
|
|
(`unit_price`, `linked_price` ou prix basis brut).
|
|
- La valeur a afficher est uniquement le `premium`:
|
|
- en devise/unite liee si `linked currency` est active
|
|
- sinon dans la devise/unite native de la ligne
|
|
- Le texte de curve / pricing (`ON ICE ...`) reste affiche a cote, mais la
|
|
valeur numerique et sa version en lettres doivent representer le premium.
|
|
|
|
### TR-011 - Pour `NB BALES` sur une facture, sommer les `lot_qt` des lignes facture
|
|
|
|
- Pour `invoice_ict.fodt` et `invoice_ict_final.fodt`, la source de verite du
|
|
nombre de bales n'est pas le poids (`report_net`, `report_gross`) mais
|
|
`line.lot.lot_qt`.
|
|
- La regle attendue est:
|
|
- lire les lignes de facture
|
|
- recuperer leur `lot`
|
|
- sommer `lot.lot_qt`
|
|
- sur une note finale, tenir compte du signe de la ligne de facture pour que
|
|
les lignes positives et negatives se compensent
|
|
- Ne pas recalculer le nombre de bales a partir du poids:
|
|
- les poids peuvent varier (humidite, poids net/gross)
|
|
- le nombre de bales peut rester stable
|
|
|
|
## 4) Workflow recommande pour corriger un template en erreur
|
|
|
|
1. Identifier le placeholder exact qui provoque l'erreur Relatorio.
|
|
2. Comparer sa syntaxe avec le template standard equivalent.
|
|
3. Remplacer les guillemets/quotes non valides par `"` / `'`.
|
|
4. Si l'expression devient trop longue, la deplacer dans une propriete Python `report_*`.
|
|
5. Ne modifier que les placeholders necessaires.
|
|
6. Regenerer le document pour verifier la prochaine erreur eventuelle.
|
|
7. Si plusieurs actions affichent le meme rendu, verifier ensuite le cache `invoice_report_cache`.
|
|
|
|
## 5) Cas documentes dans ce repo
|
|
|
|
### Invoice ICT
|
|
|
|
- Fichier: `modules/account_invoice/invoice_ict.fodt`
|
|
- Strategie retenue:
|
|
- aligner la syntaxe sur `modules/account_invoice/invoice.fodt`
|
|
- reutiliser au maximum les proprietes metier deja exposees
|
|
- exposer dans `modules/purchase_trade/invoice.py` des proprietes de pont `account.invoice -> sale/purchase`
|
|
- pour les donnees shipment et freight, passer par le lot physique comme pont achat/vente
|
|
|
|
### Sale ICT
|
|
|
|
- Fichier: `modules/sale/sale_ict.fodt`
|
|
- Usage:
|
|
- reference principale pour les champs metier proches d'une pro forma / facture commerciale
|
|
- source de verite pratique pour les placeholders `report_*` issus de `purchase_trade.sale`
|