26.03.26
This commit is contained in:
@@ -38,6 +38,11 @@ Guide rapide pour les agents qui codent dans ce repository.
|
||||
- Lire `wsgi.py`, `rpc.py`, `protocols/*`, `tests/test_rpc.py`, `tests/test_wsgi.py`.
|
||||
- Si bug metier:
|
||||
- Modifier uniquement `modules/<module>/` + ses tests.
|
||||
- Si bug template Relatorio (`.fodt`):
|
||||
- Lire d'abord le template standard voisin du meme domaine (`invoice.fodt`, `sale.fodt`, etc.).
|
||||
- Preferer des proprietes Python simples exposees par le modele plutot que des expressions Genshi complexes dans le template.
|
||||
- Dans les placeholders XML, utiliser `"` et `'` plutot que des antislashs type `\'`.
|
||||
- Si un document facture depend fortement d'une vente/achat, ajouter au besoin un petit pont Python pour exposer des `report_*` stables au template.
|
||||
|
||||
## 5) Workflow de modification (obligatoire)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:officeooo="http://openoffice.org/2009/office" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
|
||||
<office:meta>
|
||||
<dc:title>Invoice no</dc:title>
|
||||
<dc:title>Provisional Sale</dc:title>
|
||||
<meta:initial-creator>willen</meta:initial-creator>
|
||||
<meta:creation-date>2018-12-09T16:20:00</meta:creation-date>
|
||||
<dc:date>2026-03-23T20:46:35.300000000</dc:date>
|
||||
@@ -3839,7 +3839,7 @@
|
||||
<table:table-row table:style-name="Tableau3.1">
|
||||
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
|
||||
<text:p text:style-name="P20" />
|
||||
<text:p text:style-name="P20">Invoice N°</text:p>
|
||||
<text:p text:style-name="P20">Provisional Sale</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
|
||||
<text:p text:style-name="P20" />
|
||||
@@ -3889,8 +3889,8 @@
|
||||
<text:p text:style-name="P14">Port of loading</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:style-name="Tableau4.A1" office:value-type="string">
|
||||
<text:p text:style-name="P14">14.06.2025</text:p>
|
||||
<text:p text:style-name="P14">SANTOS, BRAZIL</text:p>
|
||||
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text"><format_date(invoice.report_bl_date, invoice.party.lang) if invoice.report_bl_date else ''></text:placeholder></text:p>
|
||||
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text"><invoice.report_loading_port></text:placeholder></text:p>
|
||||
</table:table-cell>
|
||||
</table:table-row>
|
||||
<table:table-row table:style-name="Tableau4.1">
|
||||
@@ -3898,7 +3898,7 @@
|
||||
<text:p text:style-name="P14">Port of discharge</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:style-name="Tableau4.A1" office:value-type="string">
|
||||
<text:p text:style-name="P14">PORT QASIM, PAKISTAN</text:p>
|
||||
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text"><invoice.report_discharge_port></text:placeholder></text:p>
|
||||
</table:table-cell>
|
||||
</table:table-row>
|
||||
</table:table>
|
||||
@@ -3915,12 +3915,12 @@
|
||||
<text:p text:style-name="P19"><text:placeholder text:placeholder-type="text"><invoice.report_product_description></text:placeholder> CROP <text:placeholder text:placeholder-type="text"><invoice.report_crop_name></text:placeholder></text:p>
|
||||
<text:p text:style-name="P19"><text:placeholder text:placeholder-type="text"><invoice.report_attributes_name></text:placeholder></text:p>
|
||||
<text:p text:style-name="P30">H.S CODE 5201.0090</text:p>
|
||||
<text:p text:style-name="P30">CFR PORT QASIM, PAKISTAN </text:p>
|
||||
<text:p text:style-name="P30"><text:placeholder text:placeholder-type="text"><invoice.report_incoterm></text:placeholder></text:p>
|
||||
<text:p text:style-name="P27">
|
||||
<text:span text:style-name="T1">ALL DETAILS AND SPECIFICATIONS AS PER</text:span>
|
||||
<text:span text:style-name="T3"> BENEFICIARY’S </text:span>
|
||||
</text:p>
|
||||
<text:p text:style-name="P24">PROFORMA INVOICE NO. 1411-1 DATED 20-05-2025.</text:p>
|
||||
<text:p text:style-name="P24">PROFORMA INVOICE NO. <text:placeholder text:placeholder-type="text"><invoice.report_proforma_invoice_number></text:placeholder> DATED <text:placeholder text:placeholder-type="text"><format_date(invoice.report_proforma_invoice_date, invoice.party.lang) if invoice.report_proforma_invoice_date else ''></text:placeholder>.</text:p>
|
||||
<text:p text:style-name="P24" />
|
||||
<text:p text:style-name="P22" />
|
||||
<text:p text:style-name="P34" />
|
||||
@@ -4063,9 +4063,9 @@
|
||||
<text:p text:style-name="P13">Controller Name</text:p>
|
||||
</table:table-cell>
|
||||
<table:table-cell table:style-name="Tableau10.A1" office:value-type="string">
|
||||
<text:p text:style-name="P23">S/BR/55</text:p>
|
||||
<text:p text:style-name="P23"><text:placeholder text:placeholder-type="text"><invoice.report_si_number></text:placeholder></text:p>
|
||||
<text:p text:style-name="P23" />
|
||||
<text:p text:style-name="P23">INTERTEK </text:p>
|
||||
<text:p text:style-name="P23"><text:placeholder text:placeholder-type="text"><invoice.report_controller_name></text:placeholder></text:p>
|
||||
</table:table-cell>
|
||||
</table:table-row>
|
||||
<table:table-row table:style-name="Tableau10.1">
|
||||
|
||||
109
modules/purchase_trade/docs/template-rules.md
Normal file
109
modules/purchase_trade/docs/template-rules.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Template Rules - Purchase Trade
|
||||
|
||||
Statut: `draft`
|
||||
Version: `v0.1`
|
||||
Derniere mise a jour: `2026-03-26`
|
||||
|
||||
## 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.
|
||||
|
||||
## 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`
|
||||
|
||||
## 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.
|
||||
|
||||
## 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 de `sale.sale`
|
||||
- exposer dans `modules/purchase_trade/invoice.py` des proprietes de pont `account.invoice -> sale`
|
||||
|
||||
### 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`
|
||||
@@ -7,6 +7,8 @@ class Invoice(metaclass=PoolMeta):
|
||||
__name__ = 'account.invoice'
|
||||
|
||||
def _get_report_sale(self):
|
||||
# Bridge invoice templates to the originating sale so FODT files can
|
||||
# reuse stable sale.report_* properties instead of complex expressions.
|
||||
sales = list(self.sales or [])
|
||||
return sales[0] if sales else None
|
||||
|
||||
@@ -15,6 +17,24 @@ class Invoice(metaclass=PoolMeta):
|
||||
if sale and sale.lines:
|
||||
return sale.lines[0]
|
||||
|
||||
def _get_report_lot(self):
|
||||
line = self._get_report_sale_line()
|
||||
if line and line.lots:
|
||||
for lot in line.lots:
|
||||
if lot.lot_type == 'physic':
|
||||
return lot
|
||||
return line.lots[0]
|
||||
|
||||
def _get_report_shipment(self):
|
||||
lot = self._get_report_lot()
|
||||
if not lot:
|
||||
return None
|
||||
return (
|
||||
getattr(lot, 'lot_shipment_in', None)
|
||||
or getattr(lot, 'lot_shipment_out', None)
|
||||
or getattr(lot, 'lot_shipment_internal', None)
|
||||
)
|
||||
|
||||
@property
|
||||
def report_address(self):
|
||||
sale = self._get_report_sale()
|
||||
@@ -111,3 +131,61 @@ class Invoice(metaclass=PoolMeta):
|
||||
if net == '':
|
||||
return ''
|
||||
return Decimal(net) * Decimal('2.20462')
|
||||
|
||||
@property
|
||||
def report_bl_date(self):
|
||||
shipment = self._get_report_shipment()
|
||||
if shipment:
|
||||
return shipment.bl_date
|
||||
|
||||
@property
|
||||
def report_loading_port(self):
|
||||
shipment = self._get_report_shipment()
|
||||
if shipment and shipment.from_location:
|
||||
return shipment.from_location.rec_name
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_discharge_port(self):
|
||||
shipment = self._get_report_shipment()
|
||||
if shipment and shipment.to_location:
|
||||
return shipment.to_location.rec_name
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_incoterm(self):
|
||||
sale = self._get_report_sale()
|
||||
if not sale:
|
||||
return ''
|
||||
incoterm = sale.incoterm.code if sale.incoterm else ''
|
||||
location = sale.incoterm_location.party_name if sale.incoterm_location else ''
|
||||
if incoterm and location:
|
||||
return f"{incoterm} {location}"
|
||||
return incoterm or location
|
||||
|
||||
@property
|
||||
def report_proforma_invoice_number(self):
|
||||
lot = self._get_report_lot()
|
||||
if lot and lot.sale_invoice_line_prov and lot.sale_invoice_line_prov.invoice:
|
||||
return lot.sale_invoice_line_prov.invoice.number or ''
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_proforma_invoice_date(self):
|
||||
lot = self._get_report_lot()
|
||||
if lot and lot.sale_invoice_line_prov and lot.sale_invoice_line_prov.invoice:
|
||||
return lot.sale_invoice_line_prov.invoice.invoice_date
|
||||
|
||||
@property
|
||||
def report_controller_name(self):
|
||||
shipment = self._get_report_shipment()
|
||||
if shipment and shipment.controller:
|
||||
return shipment.controller.rec_name
|
||||
return ''
|
||||
|
||||
@property
|
||||
def report_si_number(self):
|
||||
shipment = self._get_report_shipment()
|
||||
if shipment:
|
||||
return shipment.number or ''
|
||||
return ''
|
||||
|
||||
Reference in New Issue
Block a user