14 KiB
14 KiB
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_tradesaleaccount_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.fodtmodules/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_addressrecord.report_pricerecord.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\'
- interdit:
- 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_tradeune extensionaccount.invoiceavec des proprietesreport_*qui relaient versinvoice.sales[0]. - Exemple de proprietes utiles:
report_addressreport_contract_numberreport_shipmentreport_product_descriptionreport_crop_namereport_attributes_namereport_pricereport_payment_datereport_nb_balereport_grossreport_netreport_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_termsreport_grossreport_netreport_qtreport_nb_balereport_dealreport_packingreport_pricereport_deliveryreport_payment_datereport_shipment
TR-006 - Penser au cache des reports facture avant d'accuser le .fodt
- Les actions de report
account.invoicepeuvent partager le meme moteur de rendu. - Dans
modules/account_invoice/invoice.py, le champinvoice_report_cachepeut 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
- plusieurs actions differentes (
- 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 deir_action_report.report
- verifier si le probleme vient du cache avant de modifier le
TR-012 - Centraliser les templates client dans Document Templates
- Pour les templates client-specifiques, ne pas modifier
ir_action_report.reporten base a la main selon l'environnement ou le client. - Preferer la configuration singleton
purchase_trade.configuration, exposee dansDocuments > Configuration > Document Templates. - Sections actuellement attendues:
SaleInvoicePaymentPurchaseShipment
- Dans la section
Shipment, les templates metier attendus sont:ShippingInsurancePacking List
- 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
- si le champ de template correspondant est vide, le report doit echouer
explicitement avec
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.descriptiondans les.fodt. - Preferer:
sale.report_product_namesale.report_product_descriptioninvoice.report_product_nameinvoice.report_product_description
TR-014 - invoice_melya.fodt doit afficher Invoice et Reference sur les bons champs
- Pour
modules/account_invoice/invoice_melya.fodt:Invoicedoit afficherinvoice.numberReferencedoit afficherinvoice.report_contract_number
- Ne pas reutiliser
invoice.referencepour 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.fodtest pilote par le reportstock.shipment.in.insurance. - Toutes les croix rouges / placeholders metier doivent etre remplacees par
des proprietes
report_*exposees surstock.shipment.in. - Pour ce template, ne pas compter sur une variable Genshi locale
shipmentdans tout le document; prefererrecords[0]....dans le.fodt. - Source de verite du montant assure:
- sommer les montants des
incoming_movesdu shipment - montant d'un move =
move.quantity * move.unit_price - si
move.unit_priceest 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_amountdoit afficher ce110%, avec fallback feeInsurancesi aucun montant incoming n'est calculable
- sommer les montants des
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, sinonshipment.number insured for account of: client de la premiere ligne metier retrouvee via lot physique, sinonshipment.suppliersurveyor:shipment.surveyor, sinonshipment.controller, sinon fournisseur du feeInsurance- lieu/date d'emission: ville de la societe + date du jour
- numero du certificat:
- 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_referencereport_payment_order_from_account_nbreport_payment_order_to_bank_namereport_payment_order_to_bank_cityreport_payment_order_amountreport_payment_order_currency_codereport_payment_order_amount_textreport_payment_order_value_datereport_payment_order_company_addressreport_payment_order_beneficiary_account_nbreport_payment_order_beneficiary_bank_namereport_payment_order_beneficiary_bank_cityreport_payment_order_swift_codereport_payment_order_other_instructionsreport_payment_order_referencereport_payment_order_current_userreport_payment_order_current_user_email
- Eviter les marqueurs conditionnels heredites de l'ancien moteur (
++...): privilegier des placeholders simples avec fallbackor ''.
TR-018 - Un template configure n'apparait dans le form que si une action report existe
- Ajouter un champ dans
Document Templatesne suffit pas a rendre un template imprimable depuis la fiche. - Pour afficher l'entree dans
account.invoice, il faut aussi:- un
ir.action.reportsurmodel = account.invoice - un
ir.action.keywordform_printlie a cette action
- un
- Appliquer cette regle pour
Payment Ordercomme pourInvoice,PrepaymentetCN/DN.
TR-019 - Un placeholder Relatorio doit etre dans une balise text:placeholder
- Dans un
.fodt, une expression du type<records[0].report_* ...>ecrite en texte brut peut s'afficher telle quelle a l'impression. - Regle stricte:
- encapsuler les expressions dans
<text:placeholder text:placeholder-type="text">...</text:placeholder> - ne pas laisser de token
<...>directement dans untext:span,text:p,text:h, etc.
- encapsuler les expressions dans
- Exemple:
- incorrect:
PAYMENT ORDER <records[0].report_payment_order_document_reference or ''> - correct:
PAYMENT ORDER <text:placeholder text:placeholder-type="text"><records[0].report_payment_order_document_reference or ''></text:placeholder>
- incorrect:
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.lineousale.line) - retrouver le lot physique associe
- utiliser ce lot comme pont vers le shipment et les autres objets lies
- partir de la ligne metier (
- Ce chemin doit etre privilegie pour exposer des proprietes
report_*comme:report_bl_datereport_loading_portreport_discharge_portreport_controller_namereport_si_numberreport_proforma_invoice_numberreport_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*, leFREIGHT VALUEdoit etre expose par une propriete Python du typeinvoice.report_freight_amount. - La logique attendue est:
- retrouver le lot physique pertinent
- retrouver son shipment
- chercher le
fee.feedu shipment avecproduct.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.descriptionpurchase.lines[0].del_period.description
- Meme avec un
if ... else, ces acces sont fragiles dans un.fodtet rendent le debug plus difficile. - Preferer une propriete Python stable:
sale.report_delivery_period_descriptionpurchase.report_delivery_period_descriptioninvoice.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 lignebasisne doit pas etre le prix economique total (unit_price,linked_priceou prix basis brut). - La valeur a afficher est uniquement le
premium:- en devise/unite liee si
linked currencyest active - sinon dans la devise/unite native de la ligne
- en devise/unite liee si
- 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.fodtetinvoice_ict_final.fodt, la source de verite du nombre de bales n'est pas le poids (report_net,report_gross) maisline.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
- Identifier le placeholder exact qui provoque l'erreur Relatorio.
- Comparer sa syntaxe avec le template standard equivalent.
- Remplacer les guillemets/quotes non valides par
"/'. - Si l'expression devient trop longue, la deplacer dans une propriete Python
report_*. - Ne modifier que les placeholders necessaires.
- Regenerer le document pour verifier la prochaine erreur eventuelle.
- 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.pydes proprietes de pontaccount.invoice -> sale/purchase - pour les donnees shipment et freight, passer par le lot physique comme pont achat/vente
- aligner la syntaxe sur
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 depurchase_trade.sale