Files
tradon/modules/purchase_trade/docs/template-rules.md

8.1 KiB

Template Rules - Purchase Trade

Statut: draft Version: v0.3 Derniere mise a jour: 2026-04-02

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