Files
tradon/modules/purchase_trade/AGENTS.md

11 KiB

AGENTS.md - Module purchase_trade

Ce guide complete le AGENTS.md racine. Pour ce module, les regles locales ci-dessous priment.

1) Perimetre metier

Le module purchase_trade etend les flux achat/vente Tryton avec une logique de negoce physique:

  • contrats d'achat (purchase.purchase, purchase.line)
  • contrats de vente (sale.sale, sale.line)
  • lots physiques et virtuels
  • matching achat/vente
  • shipments et execution logistique
  • frais (fee.fee)
  • templates de documents metier et facture

2) Fichiers pivots

  • Contrats achat:
    • modules/purchase_trade/purchase.py
  • Contrats vente:
    • modules/purchase_trade/sale.py
  • Lots / matching / invoicing:
    • modules/purchase_trade/lot.py
  • Shipments / lien facture-lot:
    • modules/purchase_trade/stock.py
  • Fees:
    • modules/purchase_trade/fee.py
  • Bridge facture / templates:
    • modules/purchase_trade/invoice.py
  • Vues:
    • modules/purchase_trade/view/*.xml
  • Actions module:
    • modules/purchase_trade/*.xml
  • Manifest:
    • modules/purchase_trade/tryton.cfg

3) Documentation locale a lire en priorite

  • Regles metier:
    • modules/purchase_trade/docs/business-rules.md
  • Regles templates:
    • modules/purchase_trade/docs/template-rules.md
  • Catalogue des proprietes templates:
    • modules/purchase_trade/docs/template-properties.md
  • Padding facture provisoire vente / validation comptable:
    • modules/purchase_trade/docs/padding-invoice-accounting.md

4) Invariants metier a preserver

  • Un lot virtual est la reference d'ouverture de quantite pour une purchase.line.
  • Une sale.line doit aussi avoir au minimum un lot virtual; une valuation cote sale ne doit donc pas disparaitre juste parce que le lot est open.
  • Le lot physique est le pont principal entre:
    • purchase.line
    • sale.line
    • shipment
    • facture
  • Pour remonter d'une facture vers shipment / BL / controller / fret:
    • privilegier le lot physique
    • ne pas multiplier des chemins d'acces concurrents
  • Pour les champs de colis (NB BALES) dans les templates facture:
    • la source de verite est line.lot.lot_qt
    • sur une facture, sommer les lot_qt des lignes de facture
    • tenir compte du signe de la ligne de facture pour les notes finales
    • ne pas proratiser depuis le poids (net / gross)
  • Le FREIGHT VALUE d'un template facture vient du fee.fee du shipment dont le produit est Maritime freight.
  • Pour stock/insurance.fodt, le Amount insured doit venir en priorite de 110% du total des incoming_moves (fallback fee Insurance si aucun montant incoming calculable).
  • Pour le surveyor du certificat d'assurance shipment, la priorite est: shipment.surveyor -> shipment.controller -> fournisseur du fee Insurance.
  • Pour payment_order.fodt, utiliser des proprietes invoice.report_payment_order_* plutot que des tokens legacy <...>.
  • Ajouter un champ de template dans Document Templates ne rend pas le report visible dans la fiche: il faut aussi l'action ir.action.report + ir.action.keyword (form_print) cote account.invoice.
  • Le wizard Create contracts en mode matched peut maintenant partir de plusieurs lot.qt, mais doit conserver un matching par lot source et laisser created_by_code = True sur les lignes creees pour ne pas declencher les creations automatiques de lots dans les validations.
  • En valuation / PnL:
    • la valeur stockee dans type est la cle technique (pur. priced, sale priced, pur. fee, etc.), pas le label affiche dans l'UI
    • les references doivent rester coherentes avec le type de lot: Purchase/Open, Purchase/Physic, Sale/Open, Sale/Physic
    • pour une sale matchee, les lignes de valuation purchase generees sur un lot physique doivent aussi renseigner sale et sale_line afin de remonter dans l'onglet PnL de la sale
    • une sale non matchee doit etre valorisable "sale-first" et alimenter valuation.valuation / valuation.valuation.line
    • si une sale.line basis n'a ni price_summary ni lot_price_sale, creer quand meme une ligne sale priced avec price = 0 et amount = 0 plutot que de ne rien generer
    • le MTM ne doit etre renseigne que pour pur. priced, sale priced et derivative; jamais pour les fees
    • mtm_price doit afficher le prix brut de valorisation (sans ratio), alors que mtm reste le montant calcule selon la logique de strategie
  • En pricing:
    • le unit_price doit rester un prix de base, hors premium
    • le premium doit impacter le prix total economique et donc le amount, aussi bien en priced qu'en basis
    • dans pricing.pricing en saisie manuelle, l'utilisateur renseigne seulement quantity et settl_price
    • fixed_qt, fixed_qt_price, unfixed_qt, unfixed_qt_price et eod_price sont des valeurs derivees et ne doivent pas etre saisies a la main
    • en manuel, fixed_qt = cumul des quantity du groupe trie par pricing_date
    • en manuel, fixed_qt_price = moyenne ponderee cumulee des settl_price
    • en manuel, unfixed_qt_price = settl_price de la ligne
    • pour les documents commerciaux / facture, une ligne basis affiche le premium comme prix visible, pas le prix economique total
    • si linked currency est active, le premium est saisi dans la devise / unite liee (ex: USC/LB) puis converti vers le repere de la ligne pour le calcul du amount
    • en basis + linked currency, le linked_price doit representer le prix basis brut (hors premium) dans la devise liee; le unit_price reste ce prix brut converti, et le premium converti est ajoute seulement dans l'amount
    • si linked currency est cochee, linked_price, linked_currency et linked_unit sont requis
    • dans les forms, presenter le bloc prix dans l'ordre: price_type -> linked fields -> premium -> unit_price -> amount
    • en valuation basis, le premium s'applique a chaque composant, pas uniquement a une ligne de resume
    • pour une ligne basis sans price_summary, la valuation fallback doit utiliser unit_price + premium (et pas unit_price seul)
    • a la validation d'une sale.line, si un lot virtuel est cree et qu'aucun matching purchase n'existe, il faut lancer generate_from_sale_line() pour alimenter le PnL sale-first
  • En padding de facture provisoire vente:
    • le padding est saisi globalement dans lot.invoice
    • il est uniquement applique aux factures provisoires cote vente
    • il est reparti par lot et stocke dans lot.sale_invoice_padding
    • la ligne facture affiche Inc. padding depuis le lot
    • le padding augmente account.invoice.line.quantity, donc le move principal de facture inclut deja le montant padding
    • les comptes de padding viennent de account.configuration: Default Sale Padding et Default Accrual Padding
    • la section Padding doit rester avant la section Invoice dans Financial / Configuration
    • la provisoire cree un additional_move debit Default Sale Padding / credit Default Accrual Padding
    • la finale cree l'inverse en reprenant le montant depuis lot.sale_invoice_line_prov, donc avec le prix, la devise, la date et le taux de la provisoire
    • le wizard final doit calculer son delta depuis la quantite provisoire hors padding: sale_invoice_line_prov.quantity - sale_invoice_padding
  • En modification de quantite contractuelle:
    • quantity_theorical est la source contractuelle; quantity peut refleter l'execute physique.
    • le lot.qt libre doit etre resynchronise sur le solde ouvert reel: quantity_theorical - lots physiques - lot.qt deja matches/shippes.
    • ne jamais ajuster le lot.qt libre uniquement par delta si des lots physiques existent deja.
    • les fees suivent les lots effectifs: physiques s'il en existe dans fee.lots, sinon virtuel.
    • conserver le lien fee.lots vers le virtuel comme fallback; ne pas le supprimer lors de la creation d'un physique.
    • le PnL fee applique la meme regle: full open tant qu'il n'y a que le virtuel, puis uniquement les physiques.
    • detail durable: modules/purchase_trade/docs/business-rules.md BR-PT-020 / BR-PT-021.

5) Conventions de modification

  1. Modifier la logique metier dans le fichier pivot le plus proche.
  2. Si un template .fodt devient complexe, deplacer la logique dans une propriete Python report_*.
  3. Pour une facture trade, preferer enrichir modules/purchase_trade/invoice.py plutot que surcharger lourdement le .fodt.
  4. Si une regle metier durable change, mettre a jour docs/business-rules.md.
  5. Si une convention de template change, mettre a jour docs/template-rules.md.
  6. Pour les vues XML Tryton de ce module, utiliser editable="1" sur les <tree> editables; ne pas utiliser editable="bottom".
  7. Ne pas ajouter keyword_open / open_keyword sur les vues <tree>: ces attributs ne sont pas supportes par Tryton.
  8. Si une regle de texte par defaut durable est demandee sur achat/vente, preferer un singleton de configuration expose dans un menu fonctionnel existant plutot qu'un menu technique purchase_trade.

6) Pieges connus

  • Plusieurs actions de report account.invoice peuvent sembler rendre le meme document a cause du cache invoice_report_cache.
  • Les reports alternatifs (Final Invoice, Prepayment, etc.) ne doivent pas reutiliser le cache du report standard sans verification.
  • Pour les donnees achat/vente partagees, ne pas supposer qu'une facture de vente doit lire directement sur la sale.line: souvent, la verite metier passe par le lot physique et/ou la account.invoice.line.
  • Les templates invoice_ict* peuvent partager les memes proprietes Python; si une regle doit valoir pour provisional et final, la mettre dans modules/purchase_trade/invoice.py plutot que dupliquer dans les .fodt.
  • Dans les ecrans PnL, le label Sale price correspond au type stocke sale priced; idem pour Pur. price / pur. priced.
  • Une ligne basis sans resume de pricing peut sinon disparaitre de la valuation si aucun fallback explicite a 0 n'est prevu.
  • Le calcul du prix peut diverger entre unit_price, linked_price, lot_price et valuation si le premium n'est pas traite explicitement dans chaque maillon.
  • Sur account.invoice, le workflow Validate doit maintenant aligner fournisseur et client pour:
    • creation du account.move
    • attribution du number
    • Post ne doit pas reintroduire une difference de session/fresh login cote client
  • Pour le padding provisoire vente, ne pas changer la quantite physique du lot: l'ecart doit rester porte par lot.sale_invoice_padding et visible sur la facture via Inc. padding.

7) Definition of done (module purchase_trade)

  • Le flux achat/vente/lot cible reste coherent.
  • Les impacts templates/facture ont ete verifies conceptuellement.
  • Les docs locales ont ete mises a jour si une nouvelle regle durable a emerge.
  • Le patch reste minimal et local au domaine demande.