20 Commits
main ... dev

Author SHA1 Message Date
AzureAD\SylvainDUVERNAY
1c8abc7c1e Trade Finance 2026-04-12 17:22:25 +02:00
AzureAD\SylvainDUVERNAY
37bf6ba23b Trade Finance 2026-04-12 17:15:08 +02:00
AzureAD\SylvainDUVERNAY
2e649aa61b Commit 2026-04-12 17:06:26 +02:00
AzureAD\SylvainDUVERNAY
735a72d23e Trade Finance 2026-04-12 16:58:45 +02:00
AzureAD\SylvainDUVERNAY
ebf9b6c495 Trade Finance 2026-04-12 16:47:59 +02:00
AzureAD\SylvainDUVERNAY
13d26ac41b Trade Finance 2026-04-12 16:36:08 +02:00
AzureAD\SylvainDUVERNAY
b829b11791 Trade Finance - Commit 2026-04-12 14:41:12 +02:00
AzureAD\SylvainDUVERNAY
4a056ef402 Change on Facility definition 2026-04-07 21:53:10 +02:00
AzureAD\SylvainDUVERNAY
da65da79c0 Trade Finance - Facility - Limit ordering 2026-03-31 22:06:58 +02:00
AzureAD\SylvainDUVERNAY
aa6b3fb9ad Trade Finance - TF Facility - Order limits 2026-03-31 21:55:34 +02:00
AzureAD\SylvainDUVERNAY
b1dd118628 Trade Finance - Facility - Improve Limits table layout 2026-03-31 21:39:56 +02:00
AzureAD\SylvainDUVERNAY
f1f9d157cc Trade Finance - Facility - Fix error on Save 2026-03-31 16:50:45 +02:00
AzureAD\SylvainDUVERNAY
283b71fda9 Trade Finance - Sub Limit 2026-03-31 14:14:05 +02:00
AzureAD\SylvainDUVERNAY
f27dd5620e Trade Finance - Adjustment on sub-limit 2026-03-31 14:10:43 +02:00
AzureAD\SylvainDUVERNAY
143f59c62e Trade Finance - Facility Fix 3 2026-03-31 13:37:42 +02:00
AzureAD\SylvainDUVERNAY
be6b6517a5 Trade Finance - Facility Fix 2 2026-03-31 13:34:31 +02:00
AzureAD\SylvainDUVERNAY
d96973310b Trade Finance Facility - Fix 1 2026-03-31 13:31:33 +02:00
AzureAD\SylvainDUVERNAY
39278c4483 Trade Finance - Facility 2026-03-31 13:22:18 +02:00
AzureAD\SylvainDUVERNAY
4534ad86f1 Trade Finance - Fix 2026-03-31 12:24:17 +02:00
AzureAD\SylvainDUVERNAY
10e8e5be9b Trade Finance - Initial Commit 2026-03-31 12:14:51 +02:00
135 changed files with 4365 additions and 14830 deletions

View File

@@ -0,0 +1,17 @@
{
"permissions": {
"allow": [
"Bash(cd /c/Users/SylvainDUVERNAY/Documents/Visual Studio Code/Tradon DEV/tradon/modules)",
"Bash(ls -d */)",
"Bash(cd /c/Users/SylvainDUVERNAY/Documents/Visual Studio Code/Tradon DEV/tradon/modules/purchase_trade)",
"Bash(ls -1d */)",
"Bash(for f:*)",
"Bash(do echo:*)",
"Read(//c/Users/SylvainDUVERNAY/Documents/Visual Studio Code/Tradon DEV/tradon/**)",
"Bash(done)",
"Bash(cd /c/Users/SylvainDUVERNAY/Documents/Visual Studio Code/Tradon DEV/tradon/modules/purchase_trade/view)",
"Bash(ls -1 *.xml)",
"Bash(py --version)"
]
}
}

3
.gitignore vendored
View File

@@ -1 +1,2 @@
*.pyc deployment/vps-TradonDev_Instructions.md
deployment/vps/46.202.173.47-credentials.md

View File

@@ -38,34 +38,15 @@ Guide rapide pour les agents qui codent dans ce repository.
- Lire `wsgi.py`, `rpc.py`, `protocols/*`, `tests/test_rpc.py`, `tests/test_wsgi.py`. - Lire `wsgi.py`, `rpc.py`, `protocols/*`, `tests/test_rpc.py`, `tests/test_wsgi.py`.
- Si bug metier: - Si bug metier:
- Modifier uniquement `modules/<module>/` + ses tests. - Modifier uniquement `modules/<module>/` + ses tests.
- Conventions de champs dates:
- Dans ce projet, ne pas introduire de `fields.DateTime`.
- Utiliser `fields.Date` pour les dates metier et les champs de suivi UI, sauf demande explicite deja existante dans le module cible.
- Si bug template Relatorio (`.fodt`): - Si bug template Relatorio (`.fodt`):
- Lire d'abord le template standard voisin du meme domaine (`invoice.fodt`, `sale.fodt`, etc.). - 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. - Preferer des proprietes Python simples exposees par le modele plutot que des expressions Genshi complexes dans le template.
- Dans les placeholders XML, utiliser `&quot;` et `&apos;` plutot que des antislashs type `\'`. - Dans les placeholders XML, utiliser `&quot;` et `&apos;` 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. - Si un document facture depend fortement d'une vente/achat, ajouter au besoin un petit pont Python pour exposer des `report_*` stables au template.
- Pour les templates `stock.shipment.in`, preferer aussi des proprietes `report_*` sur le shipment plutot que des contextes ad hoc (`si_*`) quand le document devient metier ou client-specifique.
- Si plusieurs actions de report pointent vers `report_name = 'account.invoice'`, verifier aussi le cache `invoice_report_cache` dans `modules/account_invoice/invoice.py`: un mauvais cache peut faire croire que plusieurs actions utilisent le meme `.fodt`. - Si plusieurs actions de report pointent vers `report_name = 'account.invoice'`, verifier aussi le cache `invoice_report_cache` dans `modules/account_invoice/invoice.py`: un mauvais cache peut faire croire que plusieurs actions utilisent le meme `.fodt`.
- Avant de conclure qu'un template ou une action est faux, verifier si le report alternatif doit bypasser le cache standard. - Avant de conclure qu'un template ou une action est faux, verifier si le report alternatif doit bypasser le cache standard.
- Pour les templates shipment, ne pas supposer qu'une variable locale comme `shipment` sera definie partout dans Genshi, surtout dans les headers/footers; preferer `records[0]....` ou des placeholders alignes sur le scope reel du report.
- Dans `purchase_trade`, pour remonter d'une facture vers shipment, pro forma, freight ou autres donnees logistiques, privilegier le lot physique comme pont entre `purchase.line`, `sale.line` et shipment. - Dans `purchase_trade`, pour remonter d'une facture vers shipment, pro forma, freight ou autres donnees logistiques, privilegier le lot physique comme pont entre `purchase.line`, `sale.line` et shipment.
- Pour `FREIGHT VALUE`, ne pas lire un champ direct sur la facture: retrouver le fee de shipment (`shipment_in`) dont le produit est `Maritime freight`, puis utiliser `fee.get_amount()`. - Pour `FREIGHT VALUE`, ne pas lire un champ direct sur la facture: retrouver le fee de shipment (`shipment_in`) dont le produit est `Maritime freight`, puis utiliser `fee.get_amount()`.
- Rappels session templates (2026-04-08):
- `insurance.fodt`: le texte "insured for account of" doit afficher la compagnie courante (shipment.company.party), pas le client.
- `insurance.fodt`: exposer des proprietes Python `report_*` sur `stock.shipment.in` pour les montants (incoming moves) et les zones client-specifiques.
- `insurance.fodt`: "Amount insured" suit la regle metier 110% du montant incoming (base calculee via lot -> purchase.line.unit_price * quantite courante convertie).
- `insurance.fodt`: zone "Contact the following surveyor" alimentee par une propriete dediee, avec champ `surveyor` (party.party) cote shipment.
- `packing_list.fodt`: date en haut a droite = date du jour; unites Net/Gross = unite de `purchase.line`.
- `bill.fodt` (sale): la 2eme date doit etre une vraie maturity date (depuis `invoice.lines_to_pay.maturity_date`), pas `payment_term.rec_name`.
- `bill.fodt` (sale): le montant en lettres doit provenir du montant du bill (facture/total), pas du `unit_price` de ligne.
- Quand un template affiche les placeholders en brut, verifier que les champs sont bien des placeholders Relatorio dans le XML (pas du texte litteral).
- Eviter les apostrophes echappees style `\'` dans placeholders; preferer `&quot;` et `&apos;`.
## 4.bis) Memo templates de session
- Voir aussi `notes/template_business_rules.md` pour le recap detaille (business rules + decisions templates de la session).
## 5) Workflow de modification (obligatoire) ## 5) Workflow de modification (obligatoire)
@@ -124,18 +105,3 @@ Toujours fournir:
3. Proposer le patch minimal. 3. Proposer le patch minimal.
4. Implementer + tester cible. 4. Implementer + tester cible.
5. Rendre avec le contrat de sortie (section 8). 5. Rendre avec le contrat de sortie (section 8).
- Rappels session 2026-04-09:
- `invoice_ict.fodt` / `invoice_ict_final.fodt`: poids et unites depuis `lot.qt.hist` / `lot_unit_line`, priorite lots `physic`, sinon lot `virtual` unique.
- `invoice_ict.fodt` / `invoice_ict_final.fodt`: infos shipment depuis les lots reels des lignes facture; ne rien afficher si plusieurs shipments differents.
- `invoice_ict.fodt` / `invoice_ict_final.fodt`: `S/I` = `shipment.reference`; `NB BALES: 0` => `Unchanged` sur le final.
- `invoice_ict.fodt` / `invoice_ict_final.fodt`: quantites uniformisees a `2` decimales; conversion `LBS` via UoM, jamais via un facteur fixe aveugle.
- `invoice_ict.fodt` / `invoice_ict_final.fodt`: si plusieurs lignes reutilisent le meme lot, les lignes detaillees suivent la quantite facturee convertie, mais le `GROSS` global doit rester le vrai delta historique du lot.
- `sale_ict.fodt`: meme priorite lots; les mots suivent l'unite reelle; le total convertit vers une unite commune, qui est celle du lot virtuel seulement s'il y a un seul lot virtuel sur tout le report.
- `lot.report.r_del_period`: utiliser `sale.line.del_period` pour `lot_s` sans `lot_p`, sinon `purchase.line.del_period`.
- `lot.do_weighing`: `lot_qt` editable et ecrasement direct de `lot.lot_qt`.
- `account.invoice`: `Validate` cree aussi le `account.move` pour les factures client, attribue aussi le `number` a ce stade pour les factures client comme fournisseur; `Post` ne doit plus forcer une fresh session sur ce flux.
- `pricing.pricing`: saisie manuelle autorisee meme sans composant; en manuel, l'utilisateur saisit seulement `Qt` et `Settl. price`; `fixed_qt`, `fixed_qt_price`, `unfixed_qt`, `unfixed_qt_price` et `eod_price` sont derives automatiquement.
- `pricing.pricing`: en manuel, `fixed_qt` = cumul des `quantity`, `fixed_qt_price` = moyenne ponderee cumulee des `settl_price`, `unfixed_qt` = reste a fixer, `unfixed_qt_price` = `settl_price` de la ligne.
- `pricing.pricing`: `eod_price` reste non editable et calcule en prix moyen pondere; `last=True` gere par groupe `line + component`, choisi sur la `pricing_date` la plus grande.
- `purchase_trade`: `trader` filtre sur `TRADER`, `operator` sur `OPERATOR`; fallback sur `quantity` si `quantity_theorical` est vide dans les quotas/pricings.
- `sale.line` / `purchase.line`: en mode `basis`, sans `price_component`, le `Price` et le `Fix. progress` de la ligne doivent remonter depuis la ligne `Summary` sans component.

View File

@@ -1 +0,0 @@
[0407/143111.471:ERROR:third_party\crashpad\crashpad\util\win\registration_protocol_win.cc:108] CreateFile: Accès refusé. (0x5)

View File

@@ -1,36 +0,0 @@
# Fiche VPS - 46.202.173.47
Date de reference: 2026-04-07
## Identite serveur
- IP: `46.202.173.47`
- Hostname alias conseille: `vps3`
## Acces
- Cle publique Laurent Barontini (vps-deploy):
`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEm8JMCYsk6I1IoYhIHXNrdyERHdh+eeDCJagOHaRAEK vps-deploy`
- Cle publique Sylvain Duvernay (s.duvernay@singa-associates.com):
`ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG6Xsp/v6q6JO04ETv1880qoSPptUMxlWQvgcBz67o63 s.duvernay@singa-associates.com`
- Fichier local: `$env:USERPROFILE\.ssh\id_ed25519`
- Mot de passe fourni:
`!!OpenSquared!!`
- Utilisateur SSH:
'root'
- Port SSH:
'22'
## Commande de connexion type
- Laurent Barontini (cle vps-deploy):
`ssh -i $env:USERPROFILE\.ssh\vps_deploy_key <user>@46.202.173.47`
- Sylvain Duvernay (cle id_ed25519):
`ssh -i $env:USERPROFILE\.ssh\id_ed25519 <user>@46.202.173.47`
- Avec port custom:
`ssh -i $env:USERPROFILE\.ssh\id_ed25519 -p <port> <user>@46.202.173.47`

View File

@@ -0,0 +1,3 @@
Serveur: 'VPS-62.72.36.116'
Alias Name: 'VPS DEV'
IP Address:'62.72.36.116'

View File

@@ -485,7 +485,7 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin, InvoiceReportMixin):
}) })
cls.__rpc__.update({ cls.__rpc__.update({
'post': RPC( 'post': RPC(
readonly=False, instantiate=0, fresh_session=False), readonly=False, instantiate=0, fresh_session=True),
}) })
@classmethod @classmethod
@@ -1890,11 +1890,13 @@ class Invoice(Workflow, ModelSQL, ModelView, TaxableMixin, InvoiceReportMixin):
cls._check_taxes(invoices) cls._check_taxes(invoices)
# cls._check_similar(invoices) # cls._check_similar(invoices)
cls.set_number(invoices) invoices_in = cls.browse([i for i in invoices if i.type == 'in'])
cls.set_number(invoices_in)
cls._store_cache(invoices) cls._store_cache(invoices)
moves = [] moves = []
for invoice in invoices: for invoice in invoices:
if invoice.type == 'in':
move = invoice.get_move() move = invoice.get_move()
if move != invoice.move: if move != invoice.move:
invoice.move = move invoice.move = move

View File

@@ -288,7 +288,7 @@ this repository contains the full copyright notices and license terms. -->
</record> </record>
<record model="ir.action.report" id="report_invoice"> <record model="ir.action.report" id="report_invoice">
<field name="name">Invoice</field> <field name="name">Provisional Invoice</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="report_name">account.invoice</field> <field name="report_name">account.invoice</field>
<field name="report">account_invoice/invoice.fodt</field> <field name="report">account_invoice/invoice.fodt</field>
@@ -314,7 +314,7 @@ this repository contains the full copyright notices and license terms. -->
</record> </record>
<record model="ir.action.report" id="report_invoice_ict_final"> <record model="ir.action.report" id="report_invoice_ict_final">
<field name="name">CN/DN</field> <field name="name">Final Invoice</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="report_name">account.invoice</field> <field name="report_name">account.invoice</field>
<field name="report">account_invoice/invoice_ict_final.fodt</field> <field name="report">account_invoice/invoice_ict_final.fodt</field>

View File

@@ -2,19 +2,19 @@
<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: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> <office:meta>
<dc:title>Invoice</dc:title> <dc:title>Provisional Invoice</dc:title>
<meta:initial-creator>willen</meta:initial-creator> <meta:initial-creator>willen</meta:initial-creator>
<meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator> <meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator>
<meta:editing-duration>PT3H20M59S</meta:editing-duration> <meta:editing-duration>PT3H16M29S</meta:editing-duration>
<meta:editing-cycles>12</meta:editing-cycles> <meta:editing-cycles>9</meta:editing-cycles>
<dc:date>2026-04-10T10:30:16.567000000</dc:date><meta:document-statistic meta:table-count="10" meta:image-count="2" meta:object-count="0" meta:page-count="2" meta:paragraph-count="66" meta:word-count="168" meta:character-count="2416" meta:non-whitespace-character-count="1896"/></office:meta> <dc:date>2026-03-27T07:35:45.157000000</dc:date><meta:document-statistic meta:table-count="10" meta:image-count="2" meta:object-count="0" meta:page-count="2" meta:paragraph-count="61" meta:word-count="210" meta:character-count="2997" meta:non-whitespace-character-count="2429"/></office:meta>
<office:settings> <office:settings>
<config:config-item-set config:name="ooo:view-settings"> <config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">6879</config:config-item> <config:config-item config:name="ViewAreaTop" config:type="long">28575</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item> <config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">27264</config:config-item> <config:config-item config:name="ViewAreaWidth" config:type="long">27264</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">13187</config:config-item> <config:config-item config:name="ViewAreaHeight" config:type="long">13187</config:config-item>
@@ -23,12 +23,12 @@
<config:config-item-map-indexed config:name="Views"> <config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry> <config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item> <config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">13275</config:config-item> <config:config-item config:name="ViewLeft" config:type="long">7583</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">15563</config:config-item> <config:config-item config:name="ViewTop" config:type="long">33203</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item> <config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">6879</config:config-item> <config:config-item config:name="VisibleTop" config:type="long">28575</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">27263</config:config-item> <config:config-item config:name="VisibleRight" config:type="long">27263</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">20064</config:config-item> <config:config-item config:name="VisibleBottom" config:type="long">41760</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item> <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item> <config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item> <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
@@ -101,7 +101,7 @@
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item> <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item> <config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="Rsid" config:type="int">523469</config:config-item> <config:config-item config:name="Rsid" config:type="int">297701</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">84510</config:config-item> <config:config-item config:name="RsidRoot" config:type="int">84510</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item> <config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item> <config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
@@ -168,20 +168,19 @@
<style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Tahoma" svg:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Tahoma" svg:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/> <style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Times New Roman1" svg:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable"/>
</office:font-face-decls> </office:font-face-decls>
<office:styles> <office:styles>
<style:default-style style:family="graphic"> <style:default-style style:family="graphic">
<style:graphic-properties svg:stroke-color="#808080" draw:fill-color="#cfe7f5" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" style:flow-with-text="true"/> <style:graphic-properties svg:stroke-color="#808080" draw:fill-color="#cfe7f5" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" style:flow-with-text="true"/>
<style:paragraph-properties style:text-autospace="none" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> <style:paragraph-properties style:text-autospace="none" style:line-break="strict" loext:tab-stop-distance="0cm" style:font-independent-line-spacing="false">
<style:tab-stops/> <style:tab-stops/>
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman1" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman1" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman1" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH"/>
</style:default-style> </style:default-style>
<style:default-style style:family="paragraph"> <style:default-style style:family="paragraph">
<style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="none" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="none" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="lr-tb"/>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman1" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman1" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman1" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
</style:default-style> </style:default-style>
<style:default-style style:family="table"> <style:default-style style:family="table">
<style:table-properties table:border-model="collapsing"/> <style:table-properties table:border-model="collapsing"/>
@@ -246,7 +245,7 @@
</style:style> </style:style>
<style:style style:name="No_20_Spacing" style:display-name="No Spacing" style:family="paragraph"> <style:style style:name="No_20_Spacing" style:display-name="No Spacing" style:family="paragraph">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="start" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false" style:text-autospace="ideograph-alpha" style:vertical-align="auto"/> <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="start" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false" style:text-autospace="ideograph-alpha" style:vertical-align="auto"/>
<style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="11pt" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/> <style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="11pt" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/>
</style:style> </style:style>
<style:style style:name="Header_20_and_20_Footer" style:display-name="Header and Footer" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"> <style:style style:name="Header_20_and_20_Footer" style:display-name="Header and Footer" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties text:number-lines="false" text:line-number="0"> <style:paragraph-properties text:number-lines="false" text:line-number="0">
@@ -296,35 +295,30 @@
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="Normal" style:family="paragraph">
<style:paragraph-properties fo:hyphenation-ladder-count="no-limit"/>
<style:text-properties fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
</style:style>
<style:style style:name="Default_20_Paragraph_20_Font" style:display-name="Default Paragraph Font" style:family="text"/> <style:style style:name="Default_20_Paragraph_20_Font" style:display-name="Default Paragraph Font" style:family="text"/>
<style:style style:name="Titolo_20_1_20_Carattere" style:display-name="Titolo 1 Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Titolo_20_1_20_Carattere" style:display-name="Titolo 1 Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Arial1" fo:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="12pt" fo:language="en" fo:country="US" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" fo:font-weight="bold" style:font-name-asian="Arial1" style:font-family-asian="Arial, Arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="12pt" style:language-asian="en" style:country-asian="US" style:font-weight-asian="bold" style:font-name-complex="Arial1" style:font-family-complex="Arial, Arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="12pt" style:font-weight-complex="bold"/> <style:text-properties style:font-name="Arial1" fo:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="12pt" fo:language="en" fo:country="US" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" fo:font-weight="bold" style:font-name-asian="Arial1" style:font-family-asian="Arial, Arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="12pt" style:language-asian="en" style:country-asian="US" style:font-weight-asian="bold" style:font-name-complex="Arial1" style:font-family-complex="Arial, Arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="12pt" style:font-weight-complex="bold"/>
</style:style> </style:style>
<style:style style:name="Intestazione_20_Carattere" style:display-name="Intestazione Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Intestazione_20_Carattere" style:display-name="Intestazione Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="10pt" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable" style:font-size-complex="10pt"/> <style:text-properties style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="10pt" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="Placeholder_20_Text" style:display-name="Placeholder Text" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Placeholder_20_Text" style:display-name="Placeholder Text" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties fo:color="#808080" loext:opacity="100%" style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/> <style:text-properties fo:color="#808080" loext:opacity="100%" style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Testo_20_fumetto_20_Carattere" style:display-name="Testo fumetto Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Testo_20_fumetto_20_Carattere" style:display-name="Testo fumetto Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Tahoma" fo:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="8pt" style:font-name-asian="Tahoma" style:font-family-asian="Tahoma, arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="8pt" style:font-name-complex="Tahoma" style:font-family-complex="Tahoma, arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="8pt"/> <style:text-properties style:font-name="Tahoma" fo:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="8pt" style:font-name-asian="Tahoma" style:font-family-asian="Tahoma, arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="8pt" style:font-name-complex="Tahoma" style:font-family-complex="Tahoma, arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="8pt"/>
</style:style> </style:style>
<style:style style:name="PiÃ_a8__20_di_20_pagina_20_Carattere" style:display-name="Piè di pagina Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="PiÃ_a8__20_di_20_pagina_20_Carattere" style:display-name="Piè di pagina Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/> <style:text-properties style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Nessuna_20_spaziatura_20_Carattere" style:display-name="Nessuna spaziatura Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Nessuna_20_spaziatura_20_Carattere" style:display-name="Nessuna spaziatura Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable"/> <style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Placeholder" style:family="text"> <style:style style:name="Placeholder" style:family="text">
<style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/> <style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/>
</style:style> </style:style>
<style:style style:name="Police_20_par_20_dÃ_a9_faut" style:display-name="Police par défaut" style:family="text"/> <style:style style:name="Police_20_par_20_dÃ_a9_faut" style:display-name="Police par défaut" style:family="text"/>
<style:style style:name="Default_20_Paragraph_20_Font_20__28_WW_29_" style:display-name="Default Paragraph Font (WW)" style:family="text"/> <style:style style:name="Default_20_Paragraph_20_Font_20__28_WW_29_" style:display-name="Default Paragraph Font (WW)" style:family="text"/>
<style:style style:name="Police_20_par_20_défaut" style:display-name="Police par défaut" style:family="text"/>
<style:style style:name="Frame" style:family="graphic"> <style:style style:name="Frame" style:family="graphic">
<style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:background-color="transparent" draw:fill="none" draw:fill-color="#cfe7f5"/> <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:background-color="transparent" draw:fill="none" draw:fill-color="#cfe7f5"/>
</style:style> </style:style>
@@ -670,7 +664,7 @@
</style:style> </style:style>
<style:style style:name="P21" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P22" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -690,7 +684,7 @@
</style:style> </style:style>
<style:style style:name="P26" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P26" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P27" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -702,7 +696,7 @@
</style:style> </style:style>
<style:style style:name="P29" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P30" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P30" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" style:writing-mode="lr-tb"/>
@@ -714,7 +708,7 @@
</style:style> </style:style>
<style:style style:name="P32" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P33" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P33" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="end" style:justify-single-word="false" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="end" style:justify-single-word="false" style:writing-mode="lr-tb"/>
@@ -730,7 +724,7 @@
</style:style> </style:style>
<style:style style:name="P36" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P36" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="1pt" fo:language="en" fo:country="US" style:font-size-asian="1pt" style:font-name-complex="Times New Roman1" style:font-size-complex="1pt" text:display="none"/> <style:text-properties fo:font-size="1pt" fo:language="en" fo:country="US" style:font-size-asian="1pt" style:font-name-complex="Times New Roman" style:font-size-complex="1pt" text:display="none"/>
</style:style> </style:style>
<style:style style:name="P37" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P37" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -765,34 +759,14 @@
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties officeooo:paragraph-rsid="00022035"/> <style:text-properties officeooo:paragraph-rsid="00022035"/>
</style:style> </style:style>
<style:style style:name="P44" style:family="paragraph" style:parent-style-name="Normal"> <style:style style:name="P44" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" fo:font-size="10pt" officeooo:paragraph-rsid="00056da2" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="10pt" style:font-name-complex="Arial" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P45" style:family="paragraph" style:parent-style-name="Normal">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Calibri" fo:font-size="10pt" officeooo:paragraph-rsid="00056da2" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="10pt" style:font-name-complex="Arial" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P46" style:family="paragraph" style:parent-style-name="Normal">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
<style:text-properties officeooo:paragraph-rsid="00056da2"/>
</style:style>
<style:style style:name="P47" style:family="paragraph" style:parent-style-name="Normal">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
<style:text-properties style:font-name="Calibri" fo:font-size="10pt" officeooo:paragraph-rsid="00056da2" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P48" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties style:font-name="Calibri" fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Arial1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" officeooo:paragraph-rsid="000391f3" style:font-size-asian="10pt" style:font-name-complex="Arial1" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P49" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P45" style:family="paragraph" style:parent-style-name="footer">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P50" style:family="paragraph" style:parent-style-name="footer">
<style:paragraph-properties style:writing-mode="lr-tb"/> <style:paragraph-properties style:writing-mode="lr-tb"/>
</style:style> </style:style>
<style:style style:name="P51" style:family="paragraph" style:parent-style-name="header"> <style:style style:name="P46" style:family="paragraph" style:parent-style-name="header">
<style:paragraph-properties style:writing-mode="lr-tb"/> <style:paragraph-properties style:writing-mode="lr-tb"/>
</style:style> </style:style>
<style:style style:name="T1" style:family="text"> <style:style style:name="T1" style:family="text">
@@ -816,24 +790,6 @@
<style:style style:name="T7" style:family="text"> <style:style style:name="T7" style:family="text">
<style:text-properties fo:language="fr" fo:country="CH"/> <style:text-properties fo:language="fr" fo:country="CH"/>
</style:style> </style:style>
<style:style style:name="T8" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" fo:font-size="9pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T9" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" fo:font-size="9pt" officeooo:rsid="00056da2" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T10" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" fo:font-size="9pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T11" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" fo:font-size="9pt" officeooo:rsid="00056da2" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T12" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-name-complex="Arial"/>
</style:style>
<style:style style:name="T13" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" officeooo:rsid="00056da2" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-name-complex="Arial"/>
</style:style>
<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"> <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="background" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="top" style:vertical-rel="baseline" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/> <style:graphic-properties style:run-through="background" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="top" style:vertical-rel="baseline" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>
</style:style> </style:style>
@@ -3910,7 +3866,7 @@
<table:table-row table:style-name="Tableau3.1"> <table:table-row table:style-name="Tableau3.1">
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P22"/> <text:p text:style-name="P22"/>
<text:p text:style-name="P22">Invoice</text:p> <text:p text:style-name="P22">Provisional Invoice</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P22"/> <text:p text:style-name="P22"/>
@@ -3974,19 +3930,15 @@
<text:p text:style-name="P25">Goods description</text:p> <text:p text:style-name="P25">Goods description</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau5.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau5.A1" office:value-type="string">
<text:p text:style-name="P26">QUANTITY: <text:placeholder text:placeholder-type="text">&lt;invoice.report_lbs_display&gt;</text:placeholder><text:s/>LBS (<text:placeholder text:placeholder-type="text">&lt;invoice.report_net_display&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder>)</text:p> <text:p text:style-name="P26">QUANTITY: <text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_lbs, invoice.party.lang) if invoice.report_lbs != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/>LBS (<text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_net, invoice.party.lang) if invoice.report_net != &apos;&apos; else &apos;&apos;&gt;</text:placeholder> MTS)</text:p>
<text:p text:style-name="P26"/> <text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_description_upper or invoice.report_product_description&gt;</text:placeholder><text:s/>CROP <text:placeholder text:placeholder-type="text">&lt;invoice.report_crop_name&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_description_upper or invoice.report_product_description&gt;</text:placeholder><text:placeholder text:placeholder-type="text">&lt;&apos; CROP &apos; + invoice.report_crop_name if invoice.report_crop_name else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_attributes_name&gt;</text:placeholder></text:p> <text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_attributes_name&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;block in invoice.report_trade_blocks&quot;&gt;</text:placeholder></text:p> <text:p text:style-name="P18">At <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_currency_upper&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_value&gt;</text:placeholder><text:s/>PER <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_unit_upper&gt;</text:placeholder><text:s/>(<text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_price_words&gt;</text:placeholder>) <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_pricing_text&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;block[0]&gt;</text:placeholder></text:p>
<text:p text:style-name="P18">At <text:placeholder text:placeholder-type="text">&lt;block[1]&gt;</text:placeholder></text:p>
<text:p text:style-name="P18"/>
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
<text:p text:style-name="P18"/> <text:p text:style-name="P18"/>
<text:p text:style-name="P18"/> <text:p text:style-name="P18"/>
<text:p text:style-name="P29"><text:span text:style-name="T7"><text:placeholder text:placeholder-type="text">&lt;invoice.report_incoterm&gt;</text:placeholder></text:span><text:span text:style-name="T3"><text:s/></text:span></text:p> <text:p text:style-name="P32"><text:placeholder text:placeholder-type="text">&lt;invoice.report_incoterm&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"/> <text:p text:style-name="P29"><text:span text:style-name="T1">ALL DETAILS AND SPECIFICATIONS AS PER</text:span> <text:span text:style-name="T3">BENEFICIARY </text:span></text:p>
<text:p text:style-name="P26">PROFORMA INVOICE NO. <text:placeholder text:placeholder-type="text">&lt;invoice.report_proforma_invoice_number&gt;</text:placeholder><text:s/>DATED <text:placeholder text:placeholder-type="text">&lt;format_date(invoice.report_proforma_invoice_date, invoice.party.lang) if invoice.report_proforma_invoice_date else &apos;&apos;&gt;</text:placeholder>.</text:p>
<text:p text:style-name="P26"/> <text:p text:style-name="P26"/>
<text:p text:style-name="P12"/> <text:p text:style-name="P12"/>
</table:table-cell> </table:table-cell>
@@ -4000,10 +3952,10 @@
<text:p text:style-name="P15"><text:s text:c="19"/>BALES</text:p> <text:p text:style-name="P15"><text:s text:c="19"/>BALES</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P41"><text:s text:c="13"/>Gross <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder></text:p> <text:p text:style-name="P41"><text:s text:c="13"/>Gross KGS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P15"><text:s text:c="13"/>NET <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder></text:p> <text:p text:style-name="P15"><text:s text:c="13"/>NET KGS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P41"><text:s text:c="10"/></text:p> <text:p text:style-name="P41"><text:s text:c="10"/></text:p>
@@ -4017,10 +3969,10 @@
<text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_nb_bale&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_nb_bale&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_gross_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_gross, invoice.party.lang) if invoice.report_gross != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P30"><text:placeholder text:placeholder-type="text">&lt;invoice.report_net_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P30"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_net, invoice.party.lang) if invoice.report_net != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P16"/> <text:p text:style-name="P16"/>
@@ -4044,7 +3996,7 @@
<text:p text:style-name="P16">Equivalent to LBS</text:p> <text:p text:style-name="P16">Equivalent to LBS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau7.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau7.A1" office:value-type="string">
<text:p text:style-name="P16"><text:placeholder text:placeholder-type="text">&lt;invoice.report_lbs_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P16"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_lbs, invoice.party.lang) if invoice.report_lbs != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau7.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau7.A1" office:value-type="string">
<text:p text:style-name="P20"/> <text:p text:style-name="P20"/>
@@ -4057,18 +4009,13 @@
<table:table-column table:style-name="Tableau8.B"/> <table:table-column table:style-name="Tableau8.B"/>
<table:table-row table:style-name="Tableau8.1"> <table:table-row table:style-name="Tableau8.1">
<table:table-cell table:style-name="Tableau8.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau8.A1" office:value-type="string">
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in invoice.report_rate_lines.splitlines()&quot;&gt;</text:placeholder></text:p> <text:p text:style-name="P14">At <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_currency_upper&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_value&gt;</text:placeholder><text:s/>PER <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_unit_upper&gt;</text:placeholder><text:s/>(<text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_price_words&gt;</text:placeholder>) <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_pricing_text&gt;</text:placeholder></text:p>
<text:p text:style-name="P14">At <text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"/> <text:p text:style-name="P14"/>
<text:p text:style-name="P14">FREIGHT VALUE: <text:placeholder text:placeholder-type="text">&lt;invoice.report_freight_currency_symbol&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_freight_amount, invoice.party.lang) if invoice.report_freight_amount != &apos;&apos; else &apos;&apos;&gt;</text:placeholder></text:p> <text:p text:style-name="P14">FREIGHT VALUE: <text:placeholder text:placeholder-type="text">&lt;invoice.report_freight_currency_symbol&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_freight_amount, invoice.party.lang) if invoice.report_freight_amount != &apos;&apos; else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"/> <text:p text:style-name="P14"/>
<text:p text:style-name="P17">WE CERTIFY THAT THE MERCHANDISE IS OF <text:span text:style-name="T7"><text:placeholder text:placeholder-type="text">&lt;invoice.report_origin or &apos;&apos;&gt;</text:placeholder></text:span><text:s/>ORIGIN</text:p> <text:p text:style-name="P17">WE CERTIFY THAT THE MERCHANDISE IS OF <text:span text:style-name="T7"><text:placeholder text:placeholder-type="text">&lt;invoice.report_origin or &apos;&apos;&gt;</text:placeholder></text:span><text:s/>ORIGIN</text:p>
<text:p text:style-name="P17"/> <text:p text:style-name="P31"><text:soft-page-break/>L/C NUMBER </text:p>
<text:p text:style-name="P47"><text:span text:style-name="T12">B</text:span><text:span text:style-name="T13">ANK</text:span><text:span text:style-name="T12">: EFG BANK SA</text:span></text:p> <text:p text:style-name="P31"/>
<text:p text:style-name="P45">IBAN : CH8808667007168111027</text:p>
<text:p text:style-name="P45">SwifT Code: EFGBCHZZ</text:p>
<text:p text:style-name="P48"/>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau8.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau8.A1" office:value-type="string">
<text:p text:style-name="P34"><text:s text:c="3"/><text:placeholder text:placeholder-type="text">&lt;format_currency(invoice.total_amount, invoice.party.lang, invoice.currency)&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P34"><text:s text:c="3"/><text:placeholder text:placeholder-type="text">&lt;format_currency(invoice.total_amount, invoice.party.lang, invoice.currency)&gt;</text:placeholder><text:s/></text:p>
@@ -4080,7 +4027,6 @@
<text:p text:style-name="P11"/> <text:p text:style-name="P11"/>
<table:table table:name="Tableau9" table:style-name="Tableau9"> <table:table table:name="Tableau9" table:style-name="Tableau9">
<table:table-column table:style-name="Tableau9.A"/> <table:table-column table:style-name="Tableau9.A"/>
<text:soft-page-break/>
<table:table-row table:style-name="Tableau9.1"> <table:table-row table:style-name="Tableau9.1">
<table:table-cell table:style-name="Tableau9.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau9.A1" office:value-type="string">
<text:p text:style-name="P21">NET LANDED WEIGHTS, ACTUAL TARE, NO FRANCHISE</text:p> <text:p text:style-name="P21">NET LANDED WEIGHTS, ACTUAL TARE, NO FRANCHISE</text:p>
@@ -4106,7 +4052,7 @@
<text:p text:style-name="P13">Controller Name</text:p> <text:p text:style-name="P13">Controller Name</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau10.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau10.A1" office:value-type="string">
<text:p text:style-name="P25"><text:placeholder text:placeholder-type="text">&lt;invoice.report_si_reference&gt;</text:placeholder></text:p> <text:p text:style-name="P25"><text:placeholder text:placeholder-type="text">&lt;invoice.report_si_number&gt;</text:placeholder></text:p>
<text:p text:style-name="P25"/> <text:p text:style-name="P25"/>
<text:p text:style-name="P25"><text:placeholder text:placeholder-type="text">&lt;invoice.report_controller_name&gt;</text:placeholder></text:p> <text:p text:style-name="P25"><text:placeholder text:placeholder-type="text">&lt;invoice.report_controller_name&gt;</text:placeholder></text:p>
</table:table-cell> </table:table-cell>

View File

@@ -2,33 +2,33 @@
<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: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> <office:meta>
<dc:title>Credit / Debit Note</dc:title> <dc:title>Final Invoice</dc:title>
<meta:initial-creator>willen</meta:initial-creator> <meta:initial-creator>willen</meta:initial-creator>
<meta:creation-date>2018-12-09T16:20:00</meta:creation-date>
<dc:date>2026-03-27T08:01:16.333000000</dc:date>
<meta:print-date>2007-08-28T18:19:00</meta:print-date>
<meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator> <meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator>
<meta:editing-duration>PT3H14M14S</meta:editing-duration> <meta:editing-duration>PT3H13M14S</meta:editing-duration>
<meta:editing-cycles>15</meta:editing-cycles> <meta:editing-cycles>13</meta:editing-cycles>
<dc:date>2026-04-10T09:14:51.284000000</dc:date><meta:document-statistic meta:table-count="10" meta:image-count="2" meta:object-count="0" meta:page-count="2" meta:paragraph-count="67" meta:word-count="175" meta:character-count="2499" meta:non-whitespace-character-count="1973"/></office:meta> <meta:document-statistic meta:table-count="10" meta:image-count="2" meta:object-count="0" meta:page-count="2" meta:paragraph-count="68" meta:word-count="226" meta:character-count="3098" meta:non-whitespace-character-count="2521"/></office:meta>
<office:settings> <office:settings>
<config:config-item-set config:name="ooo:view-settings"> <config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">17727</config:config-item> <config:config-item config:name="ViewAreaTop" config:type="long">9437</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item> <config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">27264</config:config-item> <config:config-item config:name="ViewAreaWidth" config:type="long">27264</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">13187</config:config-item> <config:config-item config:name="ViewAreaHeight" config:type="long">13242</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item> <config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item> <config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views"> <config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry> <config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item> <config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">5639</config:config-item> <config:config-item config:name="ViewLeft" config:type="long">10084</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">26935</config:config-item> <config:config-item config:name="ViewTop" config:type="long">16424</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item> <config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">17727</config:config-item> <config:config-item config:name="VisibleTop" config:type="long">9437</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">27263</config:config-item> <config:config-item config:name="VisibleRight" config:type="long">27263</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">30912</config:config-item> <config:config-item config:name="VisibleBottom" config:type="long">22677</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item> <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item> <config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item> <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
@@ -101,11 +101,11 @@
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item> <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item> <config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="Rsid" config:type="int">890727</config:config-item> <config:config-item config:name="Rsid" config:type="int">665618</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">84510</config:config-item> <config:config-item config:name="RsidRoot" config:type="int">84510</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item> <config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item> <config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">true</config:config-item> <config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item> <config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">true</config:config-item> <config:config-item config:name="SmallCapsPercentage66" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item> <config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
@@ -114,7 +114,7 @@
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item> <config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item> <config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item> <config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">true</config:config-item> <config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item> <config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item> <config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item> <config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
@@ -131,7 +131,6 @@
<config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item> <config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item>
<config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">false</config:config-item> <config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">false</config:config-item>
<config:config-item config:name="HyphenateURLs" config:type="boolean">true</config:config-item> <config:config-item config:name="HyphenateURLs" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotBreakWrappedTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">false</config:config-item> <config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">false</config:config-item>
<config:config-item config:name="DropCapPunctuation" config:type="boolean">false</config:config-item> <config:config-item config:name="DropCapPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item> <config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
@@ -159,20 +158,16 @@
</office:script> </office:script>
</office:scripts> </office:scripts>
<office:font-face-decls> <office:font-face-decls>
<style:font-face style:name="0" svg:font-family="0" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Arial1" svg:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Arial1" svg:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Calibri1" svg:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Calibri1" svg:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="FuturaBookATT" svg:font-family="FuturaBookATT, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="FuturaBookATT" svg:font-family="FuturaBookATT, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Liberation Serif" svg:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable"/> <style:font-face style:name="Lucida Sans" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="swiss"/>
<style:font-face style:name="Lucida Sans" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="roman" style:font-pitch="variable"/> <style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="swiss"/>
<style:font-face style:name="Lucida Sans2" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Tahoma" svg:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Tahoma" svg:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Times New Roman1" svg:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable"/>
</office:font-face-decls> </office:font-face-decls>
<office:styles> <office:styles>
<style:default-style style:family="graphic"> <style:default-style style:family="graphic">
@@ -180,11 +175,11 @@
<style:paragraph-properties style:text-autospace="none" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> <style:paragraph-properties style:text-autospace="none" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
<style:tab-stops/> <style:tab-stops/>
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman1" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman1" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman1" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH"/>
</style:default-style> </style:default-style>
<style:default-style style:family="paragraph"> <style:default-style style:family="paragraph">
<style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="none" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="none" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="page"/>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman1" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman1" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman1" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Times New Roman" fo:font-size="12pt" fo:language="fr" fo:country="CH" style:letter-kerning="true" style:font-name-asian="Times New Roman" style:font-size-asian="12pt" style:language-asian="fr" style:country-asian="CH" style:font-name-complex="Times New Roman" style:font-size-complex="12pt" style:language-complex="fr" style:country-complex="CH" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
</style:default-style> </style:default-style>
<style:default-style style:family="table"> <style:default-style style:family="table">
<style:table-properties table:border-model="collapsing"/> <style:table-properties table:border-model="collapsing"/>
@@ -198,21 +193,21 @@
</style:style> </style:style>
<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text"> <style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always"/> <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Arial" fo:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="&apos;Microsoft YaHei&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans2" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/> <style:text-properties style:font-name="Arial" fo:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="&apos;Microsoft YaHei&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/>
</style:style> </style:style>
<style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text"> <style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false"/>
</style:style> </style:style>
<style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list"> <style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list">
<style:text-properties style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/> <style:text-properties style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/>
</style:style> </style:style>
<style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"> <style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties fo:margin-top="0.212cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" text:number-lines="false" text:line-number="0"/> <style:paragraph-properties fo:margin-top="0.212cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" text:number-lines="false" text:line-number="0"/>
<style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss" style:font-size-complex="12pt" style:font-style-complex="italic"/> <style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss" style:font-size-complex="12pt" style:font-style-complex="italic"/>
</style:style> </style:style>
<style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index"> <style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index">
<style:paragraph-properties text:number-lines="false" text:line-number="0"/> <style:paragraph-properties text:number-lines="false" text:line-number="0"/>
<style:text-properties style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/> <style:text-properties style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/>
</style:style> </style:style>
<style:style style:name="heading_20_1" style:display-name="heading 1" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Standard" style:default-outline-level="1" style:list-style-name=""> <style:style style:name="heading_20_1" style:display-name="heading 1" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Standard" style:default-outline-level="1" style:list-style-name="">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" fo:keep-with-next="always"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" fo:keep-with-next="always"/>
@@ -249,7 +244,7 @@
</style:style> </style:style>
<style:style style:name="No_20_Spacing" style:display-name="No Spacing" style:family="paragraph"> <style:style style:name="No_20_Spacing" style:display-name="No Spacing" style:family="paragraph">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="start" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false" style:text-autospace="ideograph-alpha" style:vertical-align="auto"/> <style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-align="start" style:justify-single-word="false" fo:text-indent="0cm" style:auto-text-indent="false" style:text-autospace="ideograph-alpha" style:vertical-align="auto"/>
<style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="11pt" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/> <style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="11pt" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/>
</style:style> </style:style>
<style:style style:name="Header_20_and_20_Footer" style:display-name="Header and Footer" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"> <style:style style:name="Header_20_and_20_Footer" style:display-name="Header and Footer" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties text:number-lines="false" text:line-number="0"> <style:paragraph-properties text:number-lines="false" text:line-number="0">
@@ -282,70 +277,29 @@
<style:paragraph-properties fo:text-align="center" style:justify-single-word="false" text:number-lines="false" text:line-number="0"/> <style:paragraph-properties fo:text-align="center" style:justify-single-word="false" text:number-lines="false" text:line-number="0"/>
<style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/> <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>
</style:style> </style:style>
<style:style style:name="Normal1" style:family="paragraph">
<style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:writing-mode="lr-tb"/>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="12pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="0" style:font-family-asian="0" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="12pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="roman" style:font-pitch-complex="variable" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="no-limit" loext:hyphenation-zone="no-limit"/>
</style:style>
<style:style style:name="header1" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="0.423cm">
<style:tab-stops>
<style:tab-stop style:position="8.001cm" style:type="center"/>
<style:tab-stop style:position="16.002cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="footer1" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="0.423cm">
<style:tab-stops>
<style:tab-stop style:position="8.001cm" style:type="center"/>
<style:tab-stop style:position="16.002cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
</style:style>
<style:style style:name="footer2" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="0.423cm">
<style:tab-stops>
<style:tab-stop style:position="8.001cm" style:type="center"/>
<style:tab-stop style:position="16.002cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
</style:style>
<style:style style:name="header2" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="0.423cm">
<style:tab-stops>
<style:tab-stop style:position="8.001cm" style:type="center"/>
<style:tab-stop style:position="16.002cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="Default_20_Paragraph_20_Font" style:display-name="Default Paragraph Font" style:family="text"/> <style:style style:name="Default_20_Paragraph_20_Font" style:display-name="Default Paragraph Font" style:family="text"/>
<style:style style:name="Titolo_20_1_20_Carattere" style:display-name="Titolo 1 Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Titolo_20_1_20_Carattere" style:display-name="Titolo 1 Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Arial1" fo:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="12pt" fo:language="en" fo:country="US" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" fo:font-weight="bold" style:font-name-asian="Arial1" style:font-family-asian="Arial, Arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="12pt" style:language-asian="en" style:country-asian="US" style:font-weight-asian="bold" style:font-name-complex="Arial1" style:font-family-complex="Arial, Arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="12pt" style:font-weight-complex="bold"/> <style:text-properties style:font-name="Arial1" fo:font-family="Arial, Arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="12pt" fo:language="en" fo:country="US" style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color" fo:font-weight="bold" style:font-name-asian="Arial1" style:font-family-asian="Arial, Arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="12pt" style:language-asian="en" style:country-asian="US" style:font-weight-asian="bold" style:font-name-complex="Arial1" style:font-family-complex="Arial, Arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="12pt" style:font-weight-complex="bold"/>
</style:style> </style:style>
<style:style style:name="Intestazione_20_Carattere" style:display-name="Intestazione Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Intestazione_20_Carattere" style:display-name="Intestazione Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="10pt" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable" style:font-size-complex="10pt"/> <style:text-properties style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="10pt" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="Placeholder_20_Text" style:display-name="Placeholder Text" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Placeholder_20_Text" style:display-name="Placeholder Text" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties fo:color="#808080" loext:opacity="100%" style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/> <style:text-properties fo:color="#808080" loext:opacity="100%" style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Testo_20_fumetto_20_Carattere" style:display-name="Testo fumetto Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Testo_20_fumetto_20_Carattere" style:display-name="Testo fumetto Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Tahoma" fo:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="8pt" style:font-name-asian="Tahoma" style:font-family-asian="Tahoma, arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="8pt" style:font-name-complex="Tahoma" style:font-family-complex="Tahoma, arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="8pt"/> <style:text-properties style:font-name="Tahoma" fo:font-family="Tahoma, arial" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="8pt" style:font-name-asian="Tahoma" style:font-family-asian="Tahoma, arial" style:font-family-generic-asian="swiss" style:font-pitch-asian="variable" style:font-size-asian="8pt" style:font-name-complex="Tahoma" style:font-family-complex="Tahoma, arial" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable" style:font-size-complex="8pt"/>
</style:style> </style:style>
<style:style style:name="PiÃ_a8__20_di_20_pagina_20_Carattere" style:display-name="Piè di pagina Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="PiÃ_a8__20_di_20_pagina_20_Carattere" style:display-name="Piè di pagina Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Times New Roman1" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman1" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/> <style:text-properties style:font-name="Times New Roman" fo:font-family="&apos;Times New Roman&apos;, Times" style:font-family-generic="roman" style:font-pitch="variable" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;, Times" style:font-family-generic-complex="roman" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Nessuna_20_spaziatura_20_Carattere" style:display-name="Nessuna spaziatura Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font"> <style:style style:name="Nessuna_20_spaziatura_20_Carattere" style:display-name="Nessuna spaziatura Carattere" style:family="text" style:parent-style-name="Default_20_Paragraph_20_Font">
<style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman1" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable"/> <style:text-properties style:font-name="Calibri1" fo:font-family="Calibri, &apos;Century Gothic&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:language="it" fo:country="IT" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;, Times" style:font-family-generic-asian="roman" style:font-pitch-asian="variable" style:language-asian="en" style:country-asian="US" style:font-name-complex="Calibri1" style:font-family-complex="Calibri, &apos;Century Gothic&apos;" style:font-family-generic-complex="swiss" style:font-pitch-complex="variable"/>
</style:style> </style:style>
<style:style style:name="Placeholder" style:family="text"> <style:style style:name="Placeholder" style:family="text">
<style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/> <style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/>
</style:style> </style:style>
<style:style style:name="Police_20_par_20_dÃ_a9_faut" style:display-name="Police par défaut" style:family="text"/> <style:style style:name="Police_20_par_20_dÃ_a9_faut" style:display-name="Police par défaut" style:family="text"/>
<style:style style:name="Police_20_par_20_défaut" style:display-name="Police par défaut" style:family="text"/>
<style:style style:name="Default_20_Paragraph_20_Font_20__28_WW_29_" style:display-name="Default Paragraph Font (WW)" style:family="text"/>
<style:style style:name="Default_20_Paragraph_20_Font1" style:display-name="Default Paragraph Font1" style:family="text"/>
<style:style style:name="Frame" style:family="graphic"> <style:style style:name="Frame" style:family="graphic">
<style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:background-color="transparent" draw:fill="none" draw:fill-color="#cfe7f5"/> <style:graphic-properties text:anchor-type="paragraph" svg:x="0cm" svg:y="0cm" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="top" style:vertical-rel="paragraph-content" style:horizontal-pos="center" style:horizontal-rel="paragraph-content" fo:background-color="transparent" draw:fill="none" draw:fill-color="#cfe7f5"/>
</style:style> </style:style>
@@ -442,9 +396,6 @@
<text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
<text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
<text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
<style:default-page-layout>
<style:page-layout-properties style:writing-mode="lr-tb" style:layout-grid-standard-mode="true"/>
</style:default-page-layout>
<loext:theme loext:name="Office Theme"> <loext:theme loext:name="Office Theme">
<loext:theme-colors loext:name="LibreOffice"> <loext:theme-colors loext:name="LibreOffice">
<loext:color loext:name="dark1" loext:color="#000000"/> <loext:color loext:name="dark1" loext:color="#000000"/>
@@ -691,11 +642,11 @@
</style:style> </style:style>
<style:style style:name="P21" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P21" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P22" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P22" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" officeooo:paragraph-rsid="000681ce" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" officeooo:paragraph-rsid="000681ce" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P23" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P23" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -715,11 +666,11 @@
</style:style> </style:style>
<style:style style:name="P27" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P27" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P28" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P28" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" officeooo:paragraph-rsid="000681ce" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="US" officeooo:paragraph-rsid="000681ce" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P29" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P29" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -731,7 +682,7 @@
</style:style> </style:style>
<style:style style:name="P31" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P31" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P32" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P32" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="center" style:justify-single-word="false" style:writing-mode="lr-tb"/>
@@ -743,7 +694,7 @@
</style:style> </style:style>
<style:style style:name="P34" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P34" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Times New Roman1" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P35" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P35" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="end" style:justify-single-word="false" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" fo:text-align="end" style:justify-single-word="false" style:writing-mode="lr-tb"/>
@@ -759,7 +710,7 @@
</style:style> </style:style>
<style:style style:name="P38" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P38" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:font-size="1pt" fo:language="en" fo:country="US" style:font-size-asian="1pt" style:font-name-complex="Times New Roman1" style:font-size-complex="1pt" text:display="none"/> <style:text-properties fo:font-size="1pt" fo:language="en" fo:country="US" style:font-size-asian="1pt" style:font-name-complex="Times New Roman" style:font-size-complex="1pt" text:display="none"/>
</style:style> </style:style>
<style:style style:name="P39" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P39" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
@@ -794,25 +745,14 @@
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties officeooo:paragraph-rsid="00022035"/> <style:text-properties officeooo:paragraph-rsid="00022035"/>
</style:style> </style:style>
<style:style style:name="P46" style:family="paragraph" style:parent-style-name="Normal1"> <style:style style:name="P46" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
</style:style>
<style:style style:name="P47" style:family="paragraph" style:parent-style-name="Normal1">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%"/>
<style:text-properties style:font-name="Calibri" fo:font-size="10pt" style:font-size-asian="10pt" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P48" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Calibri" fo:font-size="10pt" fo:language="fr" fo:country="CH" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="10pt" style:font-name-complex="Arial" style:font-size-complex="10pt"/> <style:text-properties fo:font-size="10pt" fo:language="en" fo:country="GB" style:font-size-asian="10pt" style:font-name-complex="Times New Roman" style:font-size-complex="10pt"/>
</style:style> </style:style>
<style:style style:name="P49" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P47" style:family="paragraph" style:parent-style-name="footer">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:line-height="100%" style:writing-mode="lr-tb"/>
<style:text-properties style:font-name="Calibri" fo:font-size="10pt" fo:language="fr" fo:country="CH" style:font-size-asian="10pt" style:font-name-complex="Arial1" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="P50" style:family="paragraph" style:parent-style-name="footer">
<style:paragraph-properties style:writing-mode="lr-tb"/> <style:paragraph-properties style:writing-mode="lr-tb"/>
</style:style> </style:style>
<style:style style:name="P51" style:family="paragraph" style:parent-style-name="header"> <style:style style:name="P48" style:family="paragraph" style:parent-style-name="header">
<style:paragraph-properties style:writing-mode="lr-tb"/> <style:paragraph-properties style:writing-mode="lr-tb"/>
</style:style> </style:style>
<style:style style:name="T1" style:family="text"> <style:style style:name="T1" style:family="text">
@@ -836,32 +776,11 @@
<style:style style:name="T7" style:family="text"> <style:style style:name="T7" style:family="text">
<style:text-properties fo:language="fr" fo:country="CH"/> <style:text-properties fo:language="fr" fo:country="CH"/>
</style:style> </style:style>
<style:style style:name="T8" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%"/>
</style:style>
<style:style style:name="T9" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" fo:font-size="9pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T10" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" fo:font-size="10pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="10pt" style:font-name-complex="Arial" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="T11" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:font-name="Arial" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-name-complex="Arial"/>
</style:style>
<style:style style:name="T12" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" fo:font-size="9pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="9pt" style:font-name-complex="Arial" style:font-size-complex="9pt"/>
</style:style>
<style:style style:name="T13" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" fo:font-size="10pt" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-size-asian="10pt" style:font-name-complex="Arial" style:font-size-complex="10pt"/>
</style:style>
<style:style style:name="T14" style:family="text">
<style:text-properties fo:color="#000000" loext:opacity="100%" style:letter-kerning="false" style:font-name-asian="Times New Roman" style:font-name-complex="Arial"/>
</style:style>
<style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"> <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics">
<style:graphic-properties style:run-through="background" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="top" style:vertical-rel="baseline" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/> <style:graphic-properties style:run-through="background" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="top" style:vertical-rel="baseline" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>
</style:style> </style:style>
<style:page-layout style:name="pm1"> <style:page-layout style:name="pm1">
<style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.75cm" fo:margin-bottom="1.499cm" fo:margin-left="2cm" fo:margin-right="2cm" fo:border="none" fo:padding="0cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="44" style:layout-grid-base-height="0.55cm" style:layout-grid-ruby-height="0cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="true" style:layout-grid-display="true" style:layout-grid-base-width="0.37cm" style:layout-grid-snap-to="true" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="0.75cm" fo:margin-bottom="1.499cm" fo:margin-left="2cm" fo:margin-right="2cm" fo:border="none" fo:padding="0cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm">
<style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
</style:page-layout-properties> </style:page-layout-properties>
<style:header-style> <style:header-style>
@@ -3933,7 +3852,7 @@
<table:table-row table:style-name="Tableau3.1"> <table:table-row table:style-name="Tableau3.1">
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P23"/> <text:p text:style-name="P23"/>
<text:p text:style-name="P23"><text:placeholder text:placeholder-type="text">&lt;invoice.report_note_title&gt;</text:placeholder></text:p> <text:p text:style-name="P23">Final Invoice</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P23"/> <text:p text:style-name="P23"/>
@@ -3997,19 +3916,23 @@
<text:p text:style-name="P26">Goods description</text:p> <text:p text:style-name="P26">Goods description</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau5.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau5.A1" office:value-type="string">
<text:p text:style-name="P27">QUANTITY: <text:placeholder text:placeholder-type="text">&lt;invoice.report_lbs_display&gt;</text:placeholder><text:s/>LBS (<text:placeholder text:placeholder-type="text">&lt;invoice.report_net_display&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder>)</text:p> <text:p text:style-name="P27"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in invoice.lines&quot;&gt;</text:placeholder></text:p>
<text:p text:style-name="P27"/> <text:p text:style-name="P28"><text:placeholder text:placeholder-type="text">&lt;if test=&quot;line.type == &apos;line&apos;&quot;&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_description_upper or invoice.report_product_description&gt;</text:placeholder><text:placeholder text:placeholder-type="text">&lt;&apos; CROP &apos; + invoice.report_crop_name if invoice.report_crop_name else &apos;&apos;&gt;</text:placeholder></text:p> <text:p text:style-name="P22"><text:placeholder text:placeholder-type="text">&lt;if test=&quot;line.report_description_upper&quot;&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;invoice.report_attributes_name&gt;</text:placeholder></text:p> <text:p text:style-name="P22"><text:placeholder text:placeholder-type="text">&lt;line.report_description_upper&gt;</text:placeholder></text:p>
<text:p text:style-name="P27"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;block in invoice.report_trade_blocks&quot;&gt;</text:placeholder></text:p> <text:p text:style-name="P22"><text:placeholder text:placeholder-type="text">&lt;/if&gt;</text:placeholder></text:p>
<text:p text:style-name="P27"><text:placeholder text:placeholder-type="text">&lt;block[0]&gt;</text:placeholder></text:p> <text:p text:style-name="P27">QUANTITY <text:placeholder text:placeholder-type="text">&lt;format_number(line.report_lbs, invoice.party.lang) if line.report_lbs != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/>LBS (<text:placeholder text:placeholder-type="text">&lt;format_number(line.report_net, invoice.party.lang) if line.report_net != &apos;&apos; else &apos;&apos;&gt;</text:placeholder> MTS)</text:p>
<text:p text:style-name="P18">At <text:placeholder text:placeholder-type="text">&lt;block[1]&gt;</text:placeholder></text:p> <text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;line.report_product_description or line.product_name or &apos;&apos;&gt;</text:placeholder><text:s/>CROP <text:placeholder text:placeholder-type="text">&lt;line.report_crop_name&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;line.report_attributes_name&gt;</text:placeholder></text:p>
<text:p text:style-name="P18">At <text:placeholder text:placeholder-type="text">&lt;line.report_rate_currency_upper&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;line.report_rate_value&gt;</text:placeholder><text:s/>PER <text:placeholder text:placeholder-type="text">&lt;line.report_rate_unit_upper&gt;</text:placeholder><text:s/>(<text:placeholder text:placeholder-type="text">&lt;line.report_rate_price_words&gt;</text:placeholder>) <text:placeholder text:placeholder-type="text">&lt;line.report_rate_pricing_text&gt;</text:placeholder></text:p>
<text:p text:style-name="P18"/> <text:p text:style-name="P18"/>
<text:p text:style-name="P27"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p> <text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;/if&gt;</text:placeholder></text:p>
<text:p text:style-name="P18"/>
<text:p text:style-name="P21"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
<text:p text:style-name="P21"/> <text:p text:style-name="P21"/>
<text:p text:style-name="P34"><text:placeholder text:placeholder-type="text">&lt;invoice.report_incoterm&gt;</text:placeholder></text:p> <text:p text:style-name="P34"><text:placeholder text:placeholder-type="text">&lt;invoice.report_incoterm&gt;</text:placeholder></text:p>
<text:p text:style-name="P31"><text:span text:style-name="T1">ALL DETAILS AND SPECIFICATIONS AS PER</text:span> <text:span text:style-name="T3">BENEFICIARY </text:span></text:p> <text:p text:style-name="P31"><text:span text:style-name="T1">ALL DETAILS AND SPECIFICATIONS AS PER</text:span> <text:span text:style-name="T3">BENEFICIARY </text:span></text:p>
<text:p text:style-name="P27"/> <text:p text:style-name="P27">PROFORMA INVOICE NO. <text:placeholder text:placeholder-type="text">&lt;invoice.report_proforma_invoice_number&gt;</text:placeholder><text:s/>DATED <text:placeholder text:placeholder-type="text">&lt;format_date(invoice.report_proforma_invoice_date, invoice.party.lang) if invoice.report_proforma_invoice_date else &apos;&apos;&gt;</text:placeholder>.</text:p>
<text:p text:style-name="P27"/> <text:p text:style-name="P27"/>
<text:p text:style-name="P12"/> <text:p text:style-name="P12"/>
</table:table-cell> </table:table-cell>
@@ -4023,10 +3946,10 @@
<text:p text:style-name="P15"><text:s text:c="19"/>BALES</text:p> <text:p text:style-name="P15"><text:s text:c="19"/>BALES</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P43"><text:s text:c="13"/>Gross <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder></text:p> <text:p text:style-name="P43"><text:s text:c="13"/>Gross KGS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P15"><text:s text:c="13"/>NET <text:placeholder text:placeholder-type="text">&lt;invoice.report_weight_unit_upper&gt;</text:placeholder></text:p> <text:p text:style-name="P15"><text:s text:c="13"/>NET KGS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A1" office:value-type="string">
<text:p text:style-name="P43"><text:s text:c="10"/></text:p> <text:p text:style-name="P43"><text:s text:c="10"/></text:p>
@@ -4037,13 +3960,13 @@
</table:table-row> </table:table-row>
<table:table-row table:style-name="Tableau6.1"> <table:table-row table:style-name="Tableau6.1">
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_cndn_nb_bale&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_nb_bale&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;invoice.report_gross_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P15"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_gross, invoice.party.lang) if invoice.report_gross != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P32"><text:placeholder text:placeholder-type="text">&lt;invoice.report_net_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P32"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_net, invoice.party.lang) if invoice.report_net != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau6.A2" office:value-type="string"> <table:table-cell table:style-name="Tableau6.A2" office:value-type="string">
<text:p text:style-name="P16"/> <text:p text:style-name="P16"/>
@@ -4067,7 +3990,7 @@
<text:p text:style-name="P16">Equivalent to LBS</text:p> <text:p text:style-name="P16">Equivalent to LBS</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau7.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau7.A1" office:value-type="string">
<text:p text:style-name="P16"><text:placeholder text:placeholder-type="text">&lt;invoice.report_lbs_display&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P16"><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_lbs, invoice.party.lang) if invoice.report_lbs != &apos;&apos; else &apos;&apos;&gt;</text:placeholder><text:s/></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau7.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau7.A1" office:value-type="string">
<text:p text:style-name="P20"/> <text:p text:style-name="P20"/>
@@ -4080,22 +4003,17 @@
<table:table-column table:style-name="Tableau8.B"/> <table:table-column table:style-name="Tableau8.B"/>
<table:table-row table:style-name="Tableau8.1"> <table:table-row table:style-name="Tableau8.1">
<table:table-cell table:style-name="Tableau8.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau8.A1" office:value-type="string">
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in invoice.report_positive_rate_lines.splitlines()&quot;&gt;</text:placeholder></text:p> <text:p text:style-name="P14">At <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_currency_upper&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_value&gt;</text:placeholder><text:s/>PER <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_unit_upper&gt;</text:placeholder><text:s/>(<text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_price_words&gt;</text:placeholder>) <text:placeholder text:placeholder-type="text">&lt;invoice.report_rate_pricing_text&gt;</text:placeholder></text:p>
<text:p text:style-name="P14">At <text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"/> <text:p text:style-name="P14"/>
<text:p text:style-name="P14">FREIGHT VALUE: <text:placeholder text:placeholder-type="text">&lt;invoice.report_freight_currency_symbol&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_freight_amount, invoice.party.lang) if invoice.report_freight_amount != &apos;&apos; else &apos;&apos;&gt;</text:placeholder></text:p> <text:p text:style-name="P14"><text:soft-page-break/>FREIGHT VALUE: <text:placeholder text:placeholder-type="text">&lt;invoice.report_freight_currency_symbol&gt;</text:placeholder><text:s/><text:placeholder text:placeholder-type="text">&lt;format_number(invoice.report_freight_amount, invoice.party.lang) if invoice.report_freight_amount != &apos;&apos; else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P14"/> <text:p text:style-name="P14"/>
<text:p text:style-name="P17">WE CERTIFY THAT THE MERCHANDISE IS OF <text:span text:style-name="T7"><text:placeholder text:placeholder-type="text">&lt;invoice.report_origin or &apos;&apos;&gt;</text:placeholder></text:span><text:s/>ORIGIN</text:p> <text:p text:style-name="P17">WE CERTIFY THAT THE MERCHANDISE IS OF <text:span text:style-name="T7"><text:placeholder text:placeholder-type="text">&lt;invoice.report_origin or &apos;&apos;&gt;</text:placeholder></text:span><text:s/>ORIGIN</text:p>
<text:p text:style-name="P17"/> <text:p text:style-name="P33">L/C NUMBER </text:p>
<text:p text:style-name="P47" loext:marker-style-name="T8"><text:span text:style-name="T14">BANK: EFG BANK SA</text:span></text:p> <text:p text:style-name="P33"/>
<text:p text:style-name="P47" loext:marker-style-name="T8"><text:span text:style-name="T14">IBAN : CH8808667007168111027</text:span><text:span text:style-name="T14"/></text:p>
<text:p text:style-name="P48">SwifT Code: EFGBCHZZ</text:p>
<text:p text:style-name="P49"/>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau8.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau8.A1" office:value-type="string">
<text:p text:style-name="P36"><text:s text:c="3"/><text:placeholder text:placeholder-type="text">&lt;format_currency(invoice.total_amount, invoice.party.lang, invoice.currency)&gt;</text:placeholder><text:s/></text:p> <text:p text:style-name="P36"><text:s text:c="3"/><text:placeholder text:placeholder-type="text">&lt;format_currency(invoice.total_amount, invoice.party.lang, invoice.currency)&gt;</text:placeholder><text:s/></text:p>
<text:p text:style-name="P24"/> <text:p text:style-name="P24"><text:soft-page-break/></text:p>
<text:p text:style-name="P35"/> <text:p text:style-name="P35"/>
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
@@ -4103,7 +4021,6 @@
<text:p text:style-name="P11"/> <text:p text:style-name="P11"/>
<table:table table:name="Tableau9" table:style-name="Tableau9"> <table:table table:name="Tableau9" table:style-name="Tableau9">
<table:table-column table:style-name="Tableau9.A"/> <table:table-column table:style-name="Tableau9.A"/>
<text:soft-page-break/>
<table:table-row table:style-name="Tableau9.1"> <table:table-row table:style-name="Tableau9.1">
<table:table-cell table:style-name="Tableau9.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau9.A1" office:value-type="string">
<text:p text:style-name="P21">NET LANDED WEIGHTS, ACTUAL TARE, NO FRANCHISE</text:p> <text:p text:style-name="P21">NET LANDED WEIGHTS, ACTUAL TARE, NO FRANCHISE</text:p>
@@ -4129,7 +4046,7 @@
<text:p text:style-name="P13">Controller Name</text:p> <text:p text:style-name="P13">Controller Name</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau10.A1" office:value-type="string"> <table:table-cell table:style-name="Tableau10.A1" office:value-type="string">
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;invoice.report_si_reference&gt;</text:placeholder></text:p> <text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;invoice.report_si_number&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"/> <text:p text:style-name="P26"/>
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;invoice.report_controller_name&gt;</text:placeholder></text:p> <text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;invoice.report_controller_name&gt;</text:placeholder></text:p>
</table:table-cell> </table:table-cell>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,6 @@
import datetime import datetime
from decimal import Decimal from decimal import Decimal
from unittest.mock import Mock, patch
from trytond.modules.account_invoice.exceptions import ( from trytond.modules.account_invoice.exceptions import (
PaymentTermValidationError) PaymentTermValidationError)
@@ -252,70 +251,5 @@ class AccountInvoiceTestCase(
(datetime.date(2012, 1, 14), Decimal('-1.0')), (datetime.date(2012, 1, 14), Decimal('-1.0')),
]) ])
def test_post_rpc_does_not_require_fresh_session(self):
'posting invoices does not force a fresh session'
Invoice = Pool().get('account.invoice')
self.assertFalse(Invoice.__rpc__['post'].fresh_session)
@with_transaction()
def test_validate_invoice_creates_move_for_customer_invoice(self):
'validating customer invoices now creates the account move'
Invoice = Pool().get('account.invoice')
move = Mock()
invoice = Invoice()
invoice.type = 'out'
invoice.move = None
invoice.get_move = Mock(return_value=move)
invoice.do_lot_invoicing = Mock()
move_model = Mock()
with patch.object(Invoice, '_check_taxes'), patch.object(
Invoice, '_store_cache'), patch.object(
Invoice, 'browse', return_value=[]), patch.object(
Invoice, 'cleanMoves') as clean_moves, patch.object(
Invoice, 'save') as save_invoices, patch(
'trytond.modules.account_invoice.invoice.Pool'
) as PoolMock:
PoolMock.return_value.get.return_value = move_model
Invoice.validate_invoice([invoice])
self.assertIs(invoice.move, move)
invoice.get_move.assert_called_once_with()
invoice.do_lot_invoicing.assert_called_once_with()
move_model.save.assert_called_once_with([move])
clean_moves.assert_called_once_with([move])
save_invoices.assert_called()
@with_transaction()
def test_validate_invoice_sets_number_for_customer_invoice(self):
'validating customer invoices now assigns the invoice number'
Invoice = Pool().get('account.invoice')
move = Mock()
invoice = Invoice()
invoice.type = 'out'
invoice.move = None
invoice.get_move = Mock(return_value=move)
invoice.do_lot_invoicing = Mock()
move_model = Mock()
with patch.object(Invoice, '_check_taxes'), patch.object(
Invoice, '_store_cache'), patch.object(
Invoice, 'set_number') as set_number, patch.object(
Invoice, 'cleanMoves'), patch.object(
Invoice, 'save'), patch(
'trytond.modules.account_invoice.invoice.Pool'
) as PoolMock:
PoolMock.return_value.get.return_value = move_model
Invoice.validate_invoice([invoice])
set_number.assert_called_once_with([invoice])
del ModuleTestCase del ModuleTestCase

View File

@@ -248,10 +248,29 @@ class AutomationDocument(ModelSQL, ModelView, Workflow):
ShipmentWR.save([swr]) ShipmentWR.save([swr])
doc.notes = (doc.notes or "") + f"Shipment found: {sh[0].number}\n" doc.notes = (doc.notes or "") + f"Shipment found: {sh[0].number}\n"
logger.info("BL_NUMBER:%s",sh[0].bl_number) logger.info("BL_NUMBER:%s",sh[0].bl_number)
doc.notes = ( if sh[0].incoming_moves:
(doc.notes or "") factor_net = wr.net_landed_kg / wr.bales if wr.bales else 1
+ "Global WR linked to shipment. " factor_gross = wr.gross_landed_kg / wr.bales if wr.bales else 1
+ "Create remote lot WRs from the weight report form.\n") for move in sh[0].incoming_moves:
lot = move.lot
if lot.lot_type == 'physic':
wr_payload = {
"chunk_key": lot.lot_chunk_key,
"gross_weight": float(round(Decimal(lot.lot_qt) * factor_gross,5)),
"net_weight": float(round(Decimal(lot.lot_qt) * factor_net,5)),
"tare_total": float(round(wr.tare_kg * (Decimal(lot.lot_qt) / wr.bales),5)) ,
"bags": int(lot.lot_qt),
"surveyor_code": sh[0].controller.get_alf(),
"place_key": sh[0].to_location.get_places(),
"report_date": int(wr.report_date.strftime("%Y%m%d")),#wr.report_date.isoformat() if wr.report_date else None,
"weight_date": int(wr.weight_date.strftime("%Y%m%d")),#wr.weight_date.isoformat() if wr.weight_date else None,
"agent": sh[0].agent.get_alf(),
"forwarder_ref": sh[0].returned_id
}
logger.info("PAYLOAD:%s",wr_payload)
data = doc.create_weight_report(wr_payload)
doc.notes = (doc.notes or "") + f"WR created in Fintrade: {data.get('success')}\n"
doc.notes = (doc.notes or "") + f"WR key: {data.get('weight_report_key')}\n"
# if cls.rule_set.ocr_required:[] # if cls.rule_set.ocr_required:[]
# cls.run_ocr([doc]) # cls.run_ocr([doc])

View File

@@ -1,183 +0,0 @@
# 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`
## 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
## 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. 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
## 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.

View File

@@ -5,7 +5,6 @@ from trytond.pool import Pool
from . import ( from . import (
account, account,
configuration,
purchase, purchase,
sale, sale,
global_reporting, global_reporting,
@@ -57,7 +56,6 @@ def register():
lc.LCMessage, lc.LCMessage,
lc.CreateLCStart, lc.CreateLCStart,
global_reporting.GRConfiguration, global_reporting.GRConfiguration,
configuration.Configuration,
module='purchase_trade', type_='model') module='purchase_trade', type_='model')
Pool.register( Pool.register(
incoming.ImportSwift, incoming.ImportSwift,
@@ -110,9 +108,6 @@ def register():
valuation.ValuationDyn, valuation.ValuationDyn,
valuation.ValuationReport, valuation.ValuationReport,
valuation.ValuationReportContext, valuation.ValuationReportContext,
valuation.ValuationProcessDimension,
valuation.ValuationProcessStart,
valuation.ValuationProcessResult,
derivative.Derivative, derivative.Derivative,
derivative.DerivativeMatch, derivative.DerivativeMatch,
derivative.MatchWizardStart, derivative.MatchWizardStart,
@@ -267,19 +262,10 @@ def register():
forex.ForexReport, forex.ForexReport,
purchase.PnlReport, purchase.PnlReport,
purchase.PositionReport, purchase.PositionReport,
valuation.ValuationProcess,
derivative.DerivativeMatchWizard, derivative.DerivativeMatchWizard,
module='purchase', type_='wizard') module='purchase', type_='wizard')
Pool.register( Pool.register(
sale.SaleCreatePurchase, sale.SaleCreatePurchase,
sale.SaleAllocationsWizard, sale.SaleAllocationsWizard,
module='sale', type_='wizard') module='sale', type_='wizard')
Pool.register(
invoice.InvoiceReport,
invoice.SaleReport,
invoice.PurchaseReport,
stock.ShipmentShippingReport,
stock.ShipmentInsuranceReport,
stock.ShipmentPackingListReport,
module='purchase_trade', type_='report')

View File

@@ -1,19 +0,0 @@
from trytond.model import ModelSingleton, ModelSQL, ModelView, fields
class Configuration(ModelSingleton, ModelSQL, ModelView):
"Purchase Trade Configuration"
__name__ = 'purchase_trade.configuration'
pricing_rule = fields.Text("Pricing Rule")
sale_report_template = fields.Char("Sale Template")
sale_bill_report_template = fields.Char("Sale Bill Template")
sale_final_report_template = fields.Char("Sale Final Template")
invoice_report_template = fields.Char("Invoice Template")
invoice_cndn_report_template = fields.Char("CN/DN Template")
invoice_prepayment_report_template = fields.Char("Prepayment Template")
invoice_payment_order_report_template = fields.Char("Payment Order Template")
purchase_report_template = fields.Char("Purchase Template")
shipment_shipping_report_template = fields.Char("Shipping Template")
shipment_insurance_report_template = fields.Char("Insurance Template")
shipment_packing_list_report_template = fields.Char("Packing List Template")

View File

@@ -1,48 +0,0 @@
<tryton>
<data>
<record model="ir.ui.view" id="purchase_trade_configuration_view_form">
<field name="model">purchase_trade.configuration</field>
<field name="type">form</field>
<field name="name">configuration_form</field>
</record>
<record model="ir.ui.view" id="purchase_trade_template_configuration_view_form">
<field name="model">purchase_trade.configuration</field>
<field name="type">form</field>
<field name="name">template_configuration_form</field>
</record>
<record model="ir.action.act_window" id="act_purchase_trade_configuration_form">
<field name="name">Pricing Configuration</field>
<field name="res_model">purchase_trade.configuration</field>
</record>
<record model="ir.action.act_window.view" id="act_purchase_trade_configuration_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="purchase_trade_configuration_view_form"/>
<field name="act_window" ref="act_purchase_trade_configuration_form"/>
</record>
<record model="ir.action.act_window" id="act_purchase_trade_template_configuration_form">
<field name="name">Document Templates</field>
<field name="res_model">purchase_trade.configuration</field>
</record>
<record model="ir.action.act_window.view" id="act_purchase_trade_template_configuration_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="purchase_trade_template_configuration_view_form"/>
<field name="act_window" ref="act_purchase_trade_template_configuration_form"/>
</record>
<menuitem
name="Configuration"
parent="price.menu_price"
action="act_purchase_trade_configuration_form"
sequence="10"
id="menu_purchase_trade_configuration"
icon="tryton-settings"/>
<menuitem
name="Document Templates"
parent="document_incoming.menu_configuration"
action="act_purchase_trade_template_configuration_form"
sequence="20"
id="menu_purchase_trade_template_configuration"
icon="tryton-settings"/>
</data>
</tryton>

View File

@@ -1,8 +1,8 @@
# Business Rules - Purchase Trade # Business Rules - Purchase Trade
Statut: `draft` Statut: `draft`
Version: `v0.5` Version: `v0.2`
Derniere mise a jour: `2026-04-10` Derniere mise a jour: `2026-03-27`
Owner metier: `a completer` Owner metier: `a completer`
Owner technique: `a completer` Owner technique: `a completer`
@@ -100,334 +100,6 @@ Owner technique: `a completer`
- Priorite: - Priorite:
- `importante` - `importante`
### BR-PT-004 - La valuation doit couvrir les flux purchase et sale, y compris les sales non matchees
- Intent: obtenir un PnL coherent cote achat et cote vente, meme lorsqu'une
sale n'est pas encore matchee a une purchase.
- Description:
- Le flux historique de valuation part de `purchase.line` puis remonte vers
les ventes via les lots/lots matchants.
- Le systeme doit egalement savoir valoriser directement une `sale.line`
non matchee ("sale-first").
- Une sale non matchee doit creer des lignes dans
`valuation.valuation` et `valuation.valuation.line` afin d'apparaitre dans
l'onglet PnL de la sale.
- Resultat attendu:
- pour une `sale.line` non matchee, generer au minimum les types:
- `sale priced`
- `sale fee`
- `derivative` si la ligne porte des derives
- si la sale est matchee via un lot physique, les lignes purchase portees par
ce lot physique doivent aussi renseigner `sale` et `sale_line`
- une sale matchee doit donc voir:
- ses lignes `sale *`
- les lignes purchase portees par le lot physique partage
- Priorite:
- `structurante`
### BR-PT-005 - Les references de valuation doivent decrire la nature du lot de la ligne
- Intent: eviter les ambiguïtes dans les ecrans PnL entre lots `open` et lots
`physic`.
- Description:
- La reference affichee dans la valuation doit decrire la ligne elle-meme,
pas son vis-a-vis.
- Les references autorisees pour les lignes de prix sont:
- `Purchase/Open`
- `Purchase/Physic`
- `Sale/Open`
- `Sale/Physic`
- Resultat attendu:
- un lot `virtual` cote purchase ne doit jamais sortir avec la reference
`Purchase/Physic`
- un lot `virtual` cote sale ne doit jamais sortir avec la reference
`Sale/Physic`
- un lot physique matche peut produire:
- une ligne purchase en `Purchase/Physic`
- une ligne sale en `Sale/Physic`
- un open sale matche a un open purchase peut produire des quantites egales
tout en gardant des references differentes (`Purchase/Open` vs `Sale/Open`)
- Priorite:
- `importante`
### BR-PT-006 - Une sale basis sans prix detaille doit quand meme apparaitre en valuation
- Intent: ne pas perdre les lignes de PnL lorsque le detail de pricing n'est
pas encore renseigne.
- Description:
- Une `sale.line` de type `basis` peut exister avec un lot `virtual`, sans
`price_summary` et sans `lot_price_sale`.
- Dans ce cas, la valuation doit quand meme creer une ligne `sale priced`.
- Resultat attendu:
- si `price_summary` est vide:
- creer une ligne `sale priced`
- avec `price = 0`
- avec `amount = 0`
- avec un `state` de type `unfixed`
- si `lot_price_sale` est vide sur un lot sale, utiliser `sale_line.unit_price`
comme fallback quand il existe
- Priorite:
- `importante`
### BR-PT-007 - Le MTM de valuation ne s'applique pas aux fees
- Intent: distinguer les lignes de prix marquables au marche des lignes de
frais qui ne doivent pas etre mark-to-market.
- Description:
- Le systeme peut renseigner `mtm_price`, `mtm` et `strategy` uniquement pour:
- `pur. priced`
- `sale priced`
- `derivative`
- Les fees (`pur. fee`, `sale fee`, `shipment fee`, `line fee`) ne doivent
jamais porter de valorisation MTM.
- Resultat attendu:
- les lignes de fee doivent conserver:
- `mtm_price = NULL`
- `mtm = NULL`
- `strategy = NULL`
- `mtm_price` doit representer le prix brut de valorisation sans appliquer le
ratio de composant
- `mtm` reste le montant calcule selon la logique de strategie
- Priorite:
- `structurante`
### BR-PT-008 - Le premium fait partie du prix contractuel en `priced` et en `basis`
- Intent: garantir que le montant total valorise et facture reflete toujours le
premium/discount saisi sur la ligne.
- Description:
- Le `premium` d'une `purchase.line` ou `sale.line` doit impacter le prix
total quelle que soit la `price_type`.
- Cette regle vaut pour:
- les calculs de `amount`
- la valuation / PnL
- Resultat attendu:
- le `unit_price` reste le prix de base, hors premium
- en `priced`, le montant economique = `unit_price + premium`
- en `basis`, le premium s'ajoute aussi au prix total economique
- en valuation `basis`, le premium s'applique a chaque composant valorise
(ex: meme premium repete sur chaque bloc ICE)
- Exemple metier:
- `8.30 USC/LB 500 TONS ON ICE MCH'26`
- `8.30 USC/LB 500 TONS ON ICE MAY 26`
- le premium `8.30 USC/LB` s'applique a chaque composant
- Priorite:
- `structurante`
### BR-PT-009 - En linked currency, le premium est exprime dans la devise/unite liee
- Intent: respecter la facon dont les traders saisissent les prix sur certains
produits (ex: coton en `USC/LB`).
- Description:
- Quand `enable_linked_currency` est coche, le `premium` est saisi dans la
devise / unite liee, pas dans la devise / unite native de la ligne.
- Le systeme doit convertir ce premium vers le repere de la ligne pour les
calculs internes de montant et de valuation.
- Resultat attendu:
- `premium` est interprete dans le repere `linked_currency` / `linked_unit`
- le `unit_price` ne doit pas absorber ce premium
- les `amount` et valuations doivent refleter ce premium converti
- si `linked currency` est cochee, `linked_price`, `linked_currency` et
`linked_unit` sont obligatoires
- Priorite:
- `structurante`
### BR-PT-010 - En `basis + linked currency`, le linked price suit le basis brut
- Intent: rendre lisible la decomposition entre prix basis de marche et premium.
- Description:
- Quand une ligne est en `basis` et `linked currency`, le bloc
`linked_price` doit etre recalcule automatiquement.
- Ce `linked_price` doit representer le prix basis brut, hors premium.
- Le `unit_price` de la ligne doit rester ce prix brut converti.
- Le premium converti n'est ajoute qu'au niveau du `amount`.
- Resultat attendu:
- modification du basis -> mise a jour automatique du `linked_price`
- `linked_price` = base market / basis
- `unit_price` = `linked_price` converti
- `amount` = quantite * (`unit_price` + premium converti)
- Priorite:
- `importante`
### BR-PT-011 - Une sale line non matchee avec lot virtuel doit generer une valuation sale-first des la validation
- Intent: ne pas attendre un matching purchase pour afficher le PnL d'une sale
ouverte.
- Description:
- Lors de la validation d'une `sale.line`, le systeme peut creer un lot
`virtual`.
- Si aucun `lot.qt` ne relie ce lot a une `purchase.line`, il faut tout de
meme generer la valuation cote sale.
### BR-PT-012 - Le wizard Create contracts peut creer un seul achat matche a plusieurs open sales
- Intent: permettre la creation d'un contrat achat unique a partir de plusieurs
`lot.qt` de vente selectionnes.
- Description:
- En mode `matched`, le wizard `Create contracts` peut recevoir plusieurs
`lot.qt` selectionnes.
- Il doit creer un seul contrat, avec une ligne par lot source selectionne.
- Chaque ligne doit conserver son lot d'origine pour le matching.
- Resultat attendu:
- le wizard agrege les quantites de la selection
- il refuse une quantite saisie differente du total selectionne
- il conserve `created_by_code = True` sur les lignes creees pour ne pas
declencher les creations automatiques parasites lors des validations
- Priorite:
- `importante`
### BR-PT-013 - Le texte par defaut de pricing_rule est configure globalement
- Intent: centraliser un texte metier recurrent reutilise a la creation des
lignes achat et vente.
- Description:
- Le module expose un singleton `purchase_trade.configuration` avec un champ
texte `pricing_rule`.
- Toute nouvelle `purchase.line` et `sale.line` doit prendre ce texte comme
valeur par defaut de `pricing_rule`.
- Resultat attendu:
- la configuration est accessible depuis le menu `Prices`
- la valeur sert de defaut a la creation des lignes
- les lignes existantes ne sont pas modifiees retroactivement
- Priorite:
- `importante`
### BR-PT-014 - L'affectation d'un controller doit suivre l'ecart a l'objectif regional
- Intent: repartir les controllers selon les cibles definies dans l'onglet
`Execution` des `party.party`.
- Description:
- chaque ligne `party.execution` fixe une cible `% targeted` pour un
controller sur une `country.region`
- le `% achieved` est calcule a partir des `stock.shipment.in` deja affectes
a un controller dans cette zone
- la zone d'un shipment est determinee par `shipment.to_location.country`
- une region parente couvre aussi ses sous-regions
- Resultat attendu:
- pour une ligne `party.execution`, `achieved_percent` =
`shipments de la zone avec ce controller / shipments controles de la zone`
- le denominateur ne compte que les `stock.shipment.in` qui ont deja un
`controller`; les shipments encore non affectes ne biaisent donc pas la
statistique affichee
- lors d'un choix automatique de controller, la priorite va a la regle dont
l'ecart `targeted - achieved` est le plus eleve
- un controller a `80%` cible et `40%` reel doit donc passer avant un
controller a `50%` cible et `45%` reel sur la meme zone
- l'appartenance a la zone se lit depuis `shipment.to_location.country`, et
une region parente couvre aussi ses sous-regions
- Priorite:
- `importante`
### BR-PT-015 - Les weight reports distants par lot partent du weight report global attache au shipment
- Intent: separer la creation du `weight.report` global et l'export detaille
par lot vers le systeme distant.
- Description:
- l'automation cree le `weight.report` global et l'attache au
`stock.shipment.in`
- l'export FastAPI par lot ne part plus directement de l'automation
- l'utilisateur ouvre le `weight.report` voulu depuis le shipment et lance
l'action d'export depuis ce rapport
- Resultat attendu:
- le rapport choisi sert de base unique pour calculer les payloads par lot
- seuls les lots physiques des `incoming_moves` du shipment sont exportes
- l'action exige au minimum un `controller` et un `returned_id` sur le
shipment
- les cles renvoyees par le systeme distant et la date d'envoi sont
conservees sur le `weight.report` local
- Priorite:
- `importante`
### BR-PT-016 - En pricing manuel, seules la quantite fixee du jour et le prix de marche sont saisis
- Intent: simplifier la saisie utilisateur et garantir une coherence unique
entre les colonnes de `pricing.pricing`.
- Description:
- Pour une ligne de `pricing.pricing` en mode manuel, l'utilisateur ne doit
saisir que:
- `quantity`
- `settl_price`
- Les autres colonnes de suivi sont derivees automatiquement sur tout le
groupe metier (`line + component` ou `sale_line + component`) trie par
`pricing_date`.
- Resultat attendu:
- `fixed_qt` = cumul des `quantity`
- `fixed_qt_price` = moyenne ponderee cumulee des `settl_price`
- `unfixed_qt` = quantite de base de la ligne - `fixed_qt`
- `unfixed_qt_price` = `settl_price` de la ligne
- `eod_price` = moyenne ponderee entre jambe fixee et non fixee
- `last=True` reste unique par groupe et suit la plus grande `pricing_date`
- Hors scope:
- la generation automatique des lignes quand `pricing.component.auto = True`
ne doit pas changer de comportement
- Priorite:
- `structurante`
### BR-PT-017 - Le workflow Validate des factures client doit aussi attribuer le numero
- Intent: aligner le comportement des factures client et fournisseur au moment
de `Validate`.
- Description:
- Lors du workflow `Validate` sur `account.invoice`, une facture client
(`type = out`) doit maintenant:
- creer son `account.move`
- recevoir son `number`
- La numerotation ne doit plus etre repoussee au `Post` cote client.
- Resultat attendu:
- a l'issue de `Validate`, une facture fournisseur ou client possede deja:
- son `account.move`
- son `number`
- `Post` conserve son role de posting comptable sans reintroduire de
difference de session/fresh login cote client
- Priorite:
- `importante`
- Resultat attendu:
- apres creation du lot virtuel, si aucun matching purchase n'existe:
- appeler `Valuation.generate_from_sale_line(line)`
- creer au moins la ligne `sale priced` fallback si la ligne porte un prix
economique via le premium
- Priorite:
- `importante`
### BR-PT-012 - Fallback valuation basis sans summary: utiliser le prix economique de la ligne
- Intent: eviter qu'une valuation `basis` ouverte sorte a zero alors que la
ligne a bien une valeur economique via le premium.
- Description:
- Une ligne `basis` peut ne pas avoir encore de `price_summary`.
- Dans ce cas, la valuation fallback ne doit pas prendre `unit_price` seul si
celui-ci est brut et hors premium.
- Resultat attendu:
- le fallback valuation `basis` doit utiliser:
- `unit_price + premium converti`
- cette regle vaut au minimum pour:
- `sale.line` non matchee
- `purchase.line` sans summary
- Priorite:
- `importante`
### BR-PT-013 - Create Contracts multi-lots doit conserver un matching par lot source
- Intent: permettre la creation d'un seul contrat mirror a partir de plusieurs
open quantities sans perdre le lien lot-a-lot.
- Description:
- Le wizard `Create contracts` peut etre lance avec plusieurs `lot.qt`
selectionnes.
- En creation `matched`, le systeme doit creer un seul contrat avec une ligne
par lot source selectionne, et chaque ligne doit etre matchee avec son lot
d'origine.
- Resultat attendu:
- la quantite totale du wizard = somme des open quantities selectionnees
- le contrat cree porte plusieurs lignes si plusieurs lots source sont
selectionnes
- chaque ligne creee reutilise le `shipment_origin` et le lot source qui lui
correspondent
- `created_by_code` doit rester positionne sur les lignes creees par wizard
pour eviter la recreation automatique de lots virtuels dans les `validate`
de `purchase.line`, `sale.line` et `lot.lot`
- Priorite:
- `importante`
## 4) Exemples concrets ## 4) Exemples concrets
### Exemple E1 - Augmentation simple ### Exemple E1 - Augmentation simple
@@ -474,8 +146,6 @@ Owner technique: `a completer`
- Fichiers Python concernes: - Fichiers Python concernes:
- `modules/purchase_trade/purchase.py` - `modules/purchase_trade/purchase.py`
- `modules/purchase_trade/lot.py` - `modules/purchase_trade/lot.py`
- `modules/purchase_trade/valuation.py`
- `modules/purchase_trade/sale.py`
## 6) Strategie de tests ## 6) Strategie de tests
@@ -485,11 +155,3 @@ Pour cette regle, couvrir au minimum:
- augmentation sans `lot.qt` ouvert - augmentation sans `lot.qt` ouvert
- diminution possible - diminution possible
- diminution impossible avec erreur - diminution impossible avec erreur
- valuation purchase/sale sur lot physique matche
- valuation sale-first sur sale non matchee avec lot virtual
- valuation sale `basis` sans `price_summary`
- absence de MTM sur les fees
- premium en `priced`
- premium en `basis`
- premium en `linked currency`
- synchro `basis` -> `linked_price` -> `unit_price`

View File

@@ -1,417 +0,0 @@
# Template Properties - Purchase Trade
Statut: `draft`
Version: `v0.2`
Derniere mise a jour: `2026-04-07`
## 1) Objectif
- Lister les proprietes Python exposees pour alimenter les templates Relatorio.
- Donner un point d'entree rapide aux createurs de templates.
- Eviter de reparser tout `modules/purchase_trade/invoice.py`, `sale.py` ou `purchase.py`.
## 2) Fichiers sources
- Bridge facture:
- `modules/purchase_trade/invoice.py`
- Proprietes de vente reutilisables:
- `modules/purchase_trade/sale.py`
- Proprietes d'achat reutilisables:
- `modules/purchase_trade/purchase.py`
## 3) Principes de lecture
- Pour une facture:
- preferer les proprietes `report_*` exposees sur `account.invoice`
- pour une facture finale detaillee, utiliser aussi les proprietes `report_*`
exposees sur `account.invoice.line`
- Pour une vente:
- reutiliser si possible les proprietes `report_*` deja presentes sur `sale.sale`
- Pour un achat:
- reutiliser si possible les proprietes `report_*` deja presentes sur `purchase.purchase`
- Pour un shipment entrant:
- reutiliser si possible les proprietes `report_*` exposees sur `stock.shipment.in`
## 4) Propriete disponibles sur `account.invoice`
Source code: `modules/purchase_trade/invoice.py`
### Identite du document / parties
- `report_address`
- Usage: adresse d'affichage de la facture
- Source de verite: `sale.report_address` ou `purchase.report_address`, fallback `invoice.invoice_address.full_address`
- `report_contract_number`
- Usage: numero de contrat
- Source de verite: `sale.full_number` ou `purchase.full_number`
- `report_trader_initial`
- Usage: initiales trader dans les templates
- Source de verite: contrat lie
- `report_operator_initial`
- Usage: initiales operator dans les templates
- Source de verite: contrat lie
### Produit / contrat / quantites
- `report_origin`
- Usage: origine produit
- Source de verite: `sale.product_origin` ou `purchase.product_origin`
- `report_product_description`
- Usage: description produit principale
- Source de verite: premiere ligne metier liee a la facture
- `report_product_name`
- Usage: nom produit principal
- Source de verite: premiere ligne metier liee a la facture
- `report_description_upper`
- Usage: description de ligne en majuscules
- Source de verite: premiere `account.invoice.line`
- `report_crop_name`
- Usage: campagne / crop
- Source de verite: contrat lie
- `report_attributes_name`
- Usage: attributs produit
- Source de verite: premiere ligne metier liee a la facture
- `report_price`
- Usage: prix en toutes lettres
- Source de verite: `sale.report_price` ou `purchase.report_price`
- `report_nb_bale`
- Usage: nombre de balles
- Source de verite: `sale.report_nb_bale` ou recalcul sur les lots physiques
- `report_gross`
- Usage: poids brut
- Source de verite: `sale.report_gross` ou recalcul sur les lots physiques
- `report_net`
- Usage: poids net
- Source de verite: `sale.report_net` ou `purchase.report_net` ou recalcul sur les lots physiques
- `report_lbs`
- Usage: poids net converti en LBS
- Source de verite: conversion de `report_net`
- `report_quantity_lines`
- Usage: detail quantite multi-lignes pour les templates facture
- Source de verite: `sale.report_quantity_lines` si vente source, sinon aggregation des `account.invoice.line`
### Bloc prix type `sale_ict`
- `report_rate_currency_upper`
- Usage: devise du bloc `At ... PER ...`
- Source de verite: premiere `account.invoice.line` de type `line`
- `report_rate_value`
- Usage: prix numerique du bloc `At ... PER ...`
- Source de verite: premiere `account.invoice.line` de type `line`
- `report_rate_unit_upper`
- Usage: unite du bloc `At ... PER ...`
- Source de verite: premiere `account.invoice.line` de type `line`
- `report_rate_price_words`
- Usage: prix en toutes lettres dans le bloc `At ... PER ...`
- Source de verite: premiere `account.invoice.line` de type `line`, fallback `report_price`
- `report_rate_pricing_text`
- Usage: texte de pricing additionnel
- Source de verite: premiere `account.invoice.line` de type `line`
- `report_rate_lines`
- Usage: detail multi-lignes du bloc `At ... PER ...`
- Source de verite: `sale.report_price_lines` si vente source, sinon aggregation des `account.invoice.line`
### Logistique / shipment
- `report_shipment`
- Usage: resume vessel / BL / shipment
- Source de verite: contrat lie
- `report_bl_date`
- Usage: date de BL
- Source de verite: shipment du lot physique
- `report_bl_nb`
- Usage: numero de BL
- Source de verite: shipment du lot physique
- `report_vessel`
- Usage: nom du vessel
- Source de verite: shipment du lot physique
- `report_loading_port`
- Usage: port of loading
- Source de verite: shipment du lot physique
- `report_discharge_port`
- Usage: port of discharge
- Source de verite: shipment du lot physique
- `report_controller_name`
- Usage: nom du controller
- Source de verite: shipment du lot physique
- `report_si_number`
- Usage: S/I number
- Source de verite: shipment du lot physique
### Conditions commerciales
- `report_incoterm`
- Usage: incoterm + location
- Source de verite: contrat lie
- `report_payment_date`
- Usage: date de paiement
- Source de verite: contrat lie
- `report_payment_description`
- Usage: description des conditions de paiement
- Source de verite: payment term du contrat ou de la facture
### Pro forma / freight
- `report_proforma_invoice_number`
- Usage: numero de facture provisoire
- Source de verite: lot physique via `invoice_line_prov` ou `sale_invoice_line_prov`
- `report_proforma_invoice_date`
- Usage: date de facture provisoire
- Source de verite: lot physique via `invoice_line_prov` ou `sale_invoice_line_prov`
- `report_freight_amount`
- Usage: `FREIGHT VALUE`
- Source de verite:
- lot physique
- shipment du lot
- `fee.fee` avec `product.name = 'Maritime freight'`
- montant = `fee.get_amount()`
- `report_freight_currency_symbol`
- Usage: devise du `FREIGHT VALUE`
- Source de verite: devise du fee `Maritime freight`, fallback devise facture
### Payment order
- `report_payment_order_short_name`
- Usage: nom court emetteur du payment order
- Source de verite: `invoice.company.party.rec_name`
- `report_payment_order_document_reference`
- Usage: reference du document payment order
- Source de verite: `invoice.number`, fallback `invoice.reference`
- `report_payment_order_from_account_nb`
- Usage: compte bancaire emetteur
- Source de verite: premier `bank.account` de la societe
- `report_payment_order_to_bank_name`
- Usage: banque destinataire
- Source de verite: banque du premier compte bancaire du partenaire facture
- `report_payment_order_to_bank_city`
- Usage: ville banque destinataire
- Source de verite: adresse de la banque destinataire
- `report_payment_order_amount`
- Usage: montant payment order
- Source de verite: `invoice.total_amount`
- `report_payment_order_currency_code`
- Usage: devise payment order
- Source de verite: `invoice.currency` (`code`, fallback `rec_name/symbol`)
- `report_payment_order_amount_text`
- Usage: montant en lettres
- Source de verite: conversion `amount_to_currency_words(invoice.total_amount)`
- `report_payment_order_value_date`
- Usage: date valeur
- Source de verite: `invoice.payment_term_date`, fallback `invoice.invoice_date`
- `report_payment_order_company_address`
- Usage: bloc beneficiaire
- Source de verite: `invoice.invoice_address.full_address`, fallback
`invoice.report_address`
- `report_payment_order_beneficiary_account_nb`
- Usage: compte beneficiaire
- Source de verite: premier compte bancaire du `invoice.party`
- `report_payment_order_beneficiary_bank_name`
- Usage: banque beneficiaire
- Source de verite: banque du compte beneficiaire
- `report_payment_order_beneficiary_bank_city`
- Usage: ville banque beneficiaire
- Source de verite: adresse banque beneficiaire
- `report_payment_order_swift_code`
- Usage: swift/bic beneficiaire
- Source de verite: `bank.bic`
- `report_payment_order_other_instructions`
- Usage: instructions complementaires
- Source de verite: `invoice.description`
- `report_payment_order_reference`
- Usage: reference business de paiement
- Source de verite: `invoice.reference`, fallback `invoice.number`
- `report_payment_order_current_user`
- Usage: signataire payment order
- Source de verite: utilisateur courant (`res.user`)
- `report_payment_order_current_user_email`
- Usage: email retour swift
- Source de verite: contact email du `party` utilisateur, fallback `user.email`
## 5) Proprietes disponibles sur `account.invoice.line`
Source code: `modules/purchase_trade/invoice.py`
- `report_product_description`
- Usage: description produit de la ligne
- Source de verite: `invoice_line.product` ou `origin.product`
- `report_description_upper`
- Usage: description de ligne en uppercase
- Source de verite: `invoice_line.description`
- `report_crop_name`
- Usage: crop de la ligne
- Source de verite: contrat relie via `origin`
- `report_attributes_name`
- Usage: attributs de la ligne
- Source de verite: `origin.attributes_name`
- `report_net`
- Usage: quantite nette de la ligne
- Source de verite: `invoice_line.quantity`
- `report_lbs`
- Usage: quantite convertie en LBS
- Source de verite: conversion de `report_net`
- `report_rate_currency_upper`
- Usage: devise de prix de la ligne
- Source de verite: `origin.linked_currency` ou `invoice_line.currency`
- `report_rate_value`
- Usage: prix numerique de la ligne
- Source de verite: `invoice_line.unit_price`
- `report_rate_unit_upper`
- Usage: unite de prix de la ligne
- Source de verite: `origin.linked_unit` ou `invoice_line.unit`
- `report_rate_price_words`
- Usage: prix en toutes lettres de la ligne
- Source de verite: contrat relie via `trade.report_price`
- `report_rate_pricing_text`
- Usage: texte de pricing de la ligne
- Source de verite: `origin.get_pricing_text`
## 6) Proprietes utiles deja presentes sur `sale.sale`
Source code: `modules/purchase_trade/sale.py`
- `report_terms`
- `report_crop_name`
- `report_gross`
- `report_net`
- `report_qt`
- `report_total_quantity`
- `report_quantity_unit_upper`
- `report_quantity_lines`
- `report_nb_bale`
- `report_deal`
- `report_packing`
- `report_price`
- `report_price_lines`
- `report_delivery`
- `report_payment_date`
- `report_shipment`
- `report_shipment_periods`
- `report_product_name`
- `report_product_description`
Usage typique:
- base de travail pour les templates de type `sale_ict.fodt`
- source de verite de plusieurs proprietes du bridge facture
## 7) Proprietes utiles deja presentes sur `purchase.purchase`
Source code: `modules/purchase_trade/purchase.py`
- `report_terms`
- `report_qt`
- `report_price`
- `report_delivery`
- `report_payment_date`
- `report_shipment`
Usage typique:
- templates et bridges pour facturation fournisseur
- fallback achat quand une facture n'est pas liee a une vente
## 8) Templates connus qui utilisent ces proprietes
- `modules/account_invoice/invoice_ict.fodt`
- `modules/account_invoice/invoice_ict_final.fodt`
- `modules/sale/sale_ict.fodt`
- `modules/stock/insurance.fodt`
## 9) Proprietes utiles deja presentes sur `stock.shipment.in`
Source code: `modules/purchase_trade/stock.py`
- `report_product_name`
- `report_product_description`
- `report_insurance_footer_ref`
- `report_insurance_certificate_number`
- `report_insurance_account_of`
- `report_insurance_goods_description`
- `report_insurance_loading_port`
- `report_insurance_discharge_port`
- `report_insurance_transport`
- `report_insurance_amount`
- `report_insurance_incoming_amount`
- `report_insurance_amount_insured`
- `report_insurance_surveyor`
- `report_insurance_contact_surveyor`
- `report_insurance_issue_place_and_date`
Usage typique:
- templates shipment relies a l'assurance
- `report_insurance_amount`: montant affiche dans `Amount insured` (priorite a
`110%` du total incoming, fallback fee `Insurance`)
- `report_insurance_incoming_amount`: somme `incoming_moves` de
`quantity * unit_price`, avec fallback lot
(`lot.line.unit_price * lot.get_current_quantity_converted()`)
- `report_insurance_amount_insured`: `110%` de
`report_insurance_incoming_amount`
- `report_insurance_contact_surveyor`: surveyor affiche sous
`Contact the following surveyor` (priorite au champ shipment `surveyor`,
puis fallback controller / fee `Insurance`)
- base de travail pour un certificat d'assurance lie a un shipment
## 10) Recommandations
- Avant d'ajouter une nouvelle expression dans un `.fodt`, verifier si une
propriete `report_*` existe deja ici.
- Si une nouvelle propriete est ajoutee pour un template, la documenter dans ce
fichier.
- Pour les donnees logistiques facture, privilegier toujours:
- facture -> ligne metier -> lot physique -> shipment / fee

View File

@@ -1,8 +1,8 @@
# Template Rules - Purchase Trade # Template Rules - Purchase Trade
Statut: `draft` Statut: `draft`
Version: `v0.4` Version: `v0.2`
Derniere mise a jour: `2026-04-07` Derniere mise a jour: `2026-03-27`
## 1) Scope ## 1) Scope
@@ -16,12 +16,6 @@ Derniere mise a jour: `2026-04-07`
- Eviter les erreurs de parsing Relatorio/Genshi lors de la generation des documents. - 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. - 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 ## 3) Regles pratiques
@@ -98,135 +92,6 @@ Derniere mise a jour: `2026-04-07`
- verifier si le probleme vient du cache avant de modifier le `.fodt` - 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` - 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 - 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`
- Dans la section `Shipment`, les templates metier attendus sont:
- `Shipping`
- `Insurance`
- `Packing 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
### 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-019 - Un placeholder Relatorio doit etre dans une balise `text:placeholder`
- Dans un `.fodt`, une expression du type `&lt;records[0].report_* ...&gt;`
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 `&lt;...&gt;` directement dans un `text:span`,
`text:p`, `text:h`, etc.
- Exemple:
- incorrect:
`PAYMENT ORDER &lt;records[0].report_payment_order_document_reference or &apos;&apos;&gt;`
- correct:
`PAYMENT ORDER <text:placeholder text:placeholder-type="text">&lt;records[0].report_payment_order_document_reference or &apos;&apos;&gt;</text:placeholder>`
### TR-007 - Pour une facture trade, privilegier le lot physique comme chemin de navigation ### TR-007 - Pour une facture trade, privilegier le lot physique comme chemin de navigation
@@ -255,44 +120,6 @@ Derniere mise a jour: `2026-04-07`
- utiliser `fee.get_amount()` - 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. - 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 ## 4) Workflow recommande pour corriger un template en erreur
1. Identifier le placeholder exact qui provoque l'erreur Relatorio. 1. Identifier le placeholder exact qui provoque l'erreur Relatorio.

View File

@@ -1,294 +1,17 @@
from decimal import Decimal, ROUND_HALF_UP from decimal import Decimal
from datetime import date as dt_date
from trytond.pool import Pool, PoolMeta from trytond.pool import Pool, PoolMeta
from trytond.modules.purchase_trade.numbers_to_words import amount_to_currency_words
from trytond.exceptions import UserError
from trytond.transaction import Transaction
from trytond.modules.account_invoice.invoice import (
InvoiceReport as BaseInvoiceReport)
from trytond.modules.sale.sale import SaleReport as BaseSaleReport
from trytond.modules.purchase.purchase import (
PurchaseReport as BasePurchaseReport)
class Invoice(metaclass=PoolMeta): class Invoice(metaclass=PoolMeta):
__name__ = 'account.invoice' __name__ = 'account.invoice'
@staticmethod
def _format_report_number(value, digits='0.0000', keep_trailing_decimal=False,
strip_trailing_zeros=True):
value = Decimal(str(value or 0)).quantize(Decimal(digits))
text = format(value, 'f')
if strip_trailing_zeros:
text = text.rstrip('0').rstrip('.')
if keep_trailing_decimal and '.' not in text:
text += '.0'
return text or '0'
@classmethod
def _format_report_quantity_display(cls, value):
return cls._format_report_number(
value, digits='0.01', strip_trailing_zeros=False)
def _get_report_invoice_line(self): def _get_report_invoice_line(self):
for line in self.lines or []: for line in self.lines or []:
if getattr(line, 'type', None) == 'line': if getattr(line, 'type', None) == 'line':
return line return line
return self.lines[0] if self.lines else None return self.lines[0] if self.lines else None
def _get_report_invoice_lines(self):
lines = [
line for line in (self.lines or [])
if getattr(line, 'type', None) == 'line'
]
return lines or list(self.lines or [])
@staticmethod
def _get_report_related_lots(line):
lots = []
seen = set()
def add_lot(lot):
if not lot:
return
lot_id = getattr(lot, 'id', None)
key = ('id', lot_id) if lot_id is not None else ('obj', id(lot))
if key in seen:
return
seen.add(key)
lots.append(lot)
add_lot(getattr(line, 'lot', None))
origin = getattr(line, 'origin', None)
for lot in getattr(origin, 'lots', []) or []:
add_lot(lot)
return lots
@classmethod
def _get_report_preferred_lots(cls, line):
lots = cls._get_report_related_lots(line)
physicals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'physic'
]
if physicals:
return physicals
virtuals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'virtual'
]
if len(virtuals) == 1:
return virtuals
return []
@staticmethod
def _get_report_line_sign(line):
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return Decimal(-1) if quantity < 0 else Decimal(1)
@staticmethod
def _get_report_lot_hist_weights(lot):
if not lot:
return None, None
if hasattr(lot, 'get_hist_quantity'):
net, gross = lot.get_hist_quantity()
return (
Decimal(str(net or 0)),
Decimal(str(gross if gross not in (None, '') else net or 0)),
)
hist = list(getattr(lot, 'lot_hist', []) or [])
state = getattr(lot, 'lot_state', None)
state_id = getattr(state, 'id', None)
if state_id is not None:
for entry in hist:
quantity_type = getattr(entry, 'quantity_type', None)
if getattr(quantity_type, 'id', None) == state_id:
net = Decimal(str(getattr(entry, 'quantity', 0) or 0))
gross = Decimal(str(
getattr(entry, 'gross_quantity', None)
if getattr(entry, 'gross_quantity', None) not in (None, '')
else net))
return net, gross
return None, None
def _get_report_invoice_line_weights(self, line):
lots = self._get_report_preferred_lots(line)
if lots and self._report_invoice_line_reuses_lot(line):
quantity = self._get_report_invoice_line_quantity_from_line(line)
return quantity, quantity
if lots:
sign = self._get_report_line_sign(line)
net_total = Decimal(0)
gross_total = Decimal(0)
for lot in lots:
net, gross = self._get_report_lot_hist_weights(lot)
if net is None:
continue
net_total += net
gross_total += gross
if net_total or gross_total:
return net_total * sign, gross_total * sign
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return quantity, quantity
@staticmethod
def _get_report_line_lot_keys(line):
keys = []
for lot in Invoice._get_report_preferred_lots(line):
lot_id = getattr(lot, 'id', None)
keys.append(lot_id if lot_id is not None else id(lot))
return tuple(sorted(keys))
def _report_invoice_line_reuses_lot(self, line):
line_keys = self._get_report_line_lot_keys(line)
if not line_keys:
return False
for other in self._get_report_invoice_lines():
if other is line:
continue
if self._get_report_line_lot_keys(other) == line_keys:
return True
return False
def _get_report_reused_lot_lines(self):
groups = {}
for line in self._get_report_invoice_lines():
lots = self._get_report_preferred_lots(line)
if not lots:
continue
for lot in lots:
lot_id = getattr(lot, 'id', None)
key = lot_id if lot_id is not None else id(lot)
groups.setdefault(key, {'lot': lot, 'lines': []})
groups[key]['lines'].append(line)
return {
key: value for key, value in groups.items()
if len(value['lines']) > 1
}
@staticmethod
def _convert_report_quantity(quantity, from_unit, to_unit):
value = Decimal(str(quantity or 0))
if not from_unit or not to_unit:
return value
if getattr(from_unit, 'id', None) == getattr(to_unit, 'id', None):
return value
from_name = getattr(from_unit, 'rec_name', None)
to_name = getattr(to_unit, 'rec_name', None)
if from_name and to_name and from_name == to_name:
return value
converted = Pool().get('product.uom').compute_qty(
from_unit, float(value), to_unit) or 0
return Decimal(str(converted))
@classmethod
def _get_report_invoice_line_quantity_from_line(cls, line):
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return cls._convert_report_quantity(
quantity,
getattr(line, 'unit', None),
cls._get_report_invoice_line_unit(line),
)
@classmethod
def _find_report_hist_entry_for_quantity(cls, lot, quantity, exclude_state_id=None):
target = Decimal(str(quantity or 0)).copy_abs()
for entry in list(getattr(lot, 'lot_hist', []) or []):
quantity_type = getattr(entry, 'quantity_type', None)
if getattr(quantity_type, 'id', None) == exclude_state_id:
continue
entry_quantity = Decimal(str(getattr(entry, 'quantity', 0) or 0))
if entry_quantity == target:
return entry
return None
def _get_report_reused_lot_gross_total(self):
reused_lots = self._get_report_reused_lot_lines()
if not reused_lots:
return None
total = Decimal(0)
for data in reused_lots.values():
lot = data['lot']
_, current_gross = self._get_report_lot_hist_weights(lot)
if current_gross is None:
continue
current_state = getattr(getattr(lot, 'lot_state', None), 'id', None)
negative_lines = [
line for line in data['lines']
if Decimal(str(getattr(line, 'quantity', 0) or 0)) < 0
]
previous_gross = Decimal(0)
matched = False
for line in negative_lines:
previous_entry = self._find_report_hist_entry_for_quantity(
lot,
self._get_report_invoice_line_quantity_from_line(line),
exclude_state_id=current_state,
)
if not previous_entry:
continue
previous_gross += Decimal(str(
getattr(previous_entry, 'gross_quantity', 0) or 0))
matched = True
if matched:
total += current_gross - previous_gross
return total
@staticmethod
def _get_report_invoice_line_unit(line):
lots = Invoice._get_report_preferred_lots(line)
if lots and getattr(lots[0], 'lot_unit_line', None):
return lots[0].lot_unit_line
return getattr(line, 'unit', None)
@staticmethod
def _get_report_lbs_unit():
Uom = Pool().get('product.uom')
for domain in (
[('symbol', '=', 'LBS')],
[('rec_name', '=', 'LBS')],
[('name', '=', 'LBS')],
[('symbol', '=', 'LB')],
[('rec_name', '=', 'LB')],
[('name', '=', 'LB')]):
units = Uom.search(domain, limit=1)
if units:
return units[0]
return None
@classmethod
def _convert_report_quantity_to_lbs(cls, quantity, unit):
value = Decimal(str(quantity or 0))
if value == 0:
return Decimal('0.00')
if not unit:
return (value * Decimal('2204.62')).quantize(Decimal('0.01'))
label = (
getattr(unit, 'symbol', None)
or getattr(unit, 'rec_name', None)
or getattr(unit, 'name', None)
or ''
).strip().upper()
if label in {'LBS', 'LB', 'POUND', 'POUNDS'}:
return value.quantize(Decimal('0.01'))
lbs_unit = cls._get_report_lbs_unit()
if lbs_unit:
converted = Pool().get('product.uom').compute_qty(
unit, float(value), lbs_unit) or 0
return Decimal(str(converted)).quantize(Decimal('0.01'))
if label in {'KG', 'KGS', 'KILOGRAM', 'KILOGRAMS'}:
return (value * Decimal('2.20462')).quantize(Decimal('0.01'))
return (value * Decimal('2204.62')).quantize(Decimal('0.01'))
@staticmethod
def _clean_report_description(value):
text = (value or '').strip()
normalized = text.replace(' ', '').upper()
if normalized == 'PROFORMA':
return ''
return text.upper() if text else ''
def _get_report_purchase(self): def _get_report_purchase(self):
purchases = list(self.purchases or []) purchases = list(self.purchases or [])
return purchases[0] if purchases else None return purchases[0] if purchases else None
@@ -323,81 +46,6 @@ class Invoice(metaclass=PoolMeta):
return lot return lot
return line.lots[0] return line.lots[0]
@staticmethod
def _get_report_lot_shipment(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)
)
def _get_report_invoice_shipments(self):
shipments = []
seen = set()
for line in self._get_report_invoice_lines():
for lot in self._get_report_preferred_lots(line):
shipment = self._get_report_lot_shipment(lot)
if not shipment:
continue
shipment_id = getattr(shipment, 'id', None)
key = (
getattr(shipment, '__name__', None),
shipment_id if shipment_id is not None else id(shipment),
)
if key in seen:
continue
seen.add(key)
shipments.append(shipment)
return shipments
def _get_report_invoice_lots(self):
invoice_lines = self._get_report_invoice_lines()
if not invoice_lines:
return []
def _same_invoice_line(left, right):
if not left or not right:
return False
left_id = getattr(left, 'id', None)
right_id = getattr(right, 'id', None)
if left_id is not None and right_id is not None:
return left_id == right_id
return left is right
trade = self._get_report_trade()
trade_lines = getattr(trade, 'lines', []) if trade else []
lots = []
for line in trade_lines or []:
for lot in getattr(line, 'lots', []) or []:
if getattr(lot, 'lot_type', None) != 'physic':
continue
refs = [
getattr(lot, 'sale_invoice_line', None),
getattr(lot, 'sale_invoice_line_prov', None),
getattr(lot, 'invoice_line', None),
getattr(lot, 'invoice_line_prov', None),
]
if any(
_same_invoice_line(ref, invoice_line)
for ref in refs for invoice_line in invoice_lines):
lots.append(lot)
return lots
@staticmethod
def _format_report_package_label(unit):
label = (
getattr(unit, 'symbol', None)
or getattr(unit, 'rec_name', None)
or getattr(unit, 'name', None)
or 'BALE'
)
label = label.upper()
if not label.endswith('S'):
label += 'S'
return label
def _get_report_freight_fee(self): def _get_report_freight_fee(self):
pool = Pool() pool = Pool()
Fee = pool.get('fee.fee') Fee = pool.get('fee.fee')
@@ -411,165 +59,14 @@ class Invoice(metaclass=PoolMeta):
return fees[0] if fees else None return fees[0] if fees else None
def _get_report_shipment(self): def _get_report_shipment(self):
shipments = self._get_report_invoice_shipments()
if len(shipments) == 1:
return shipments[0]
if len(shipments) > 1:
return None
lot = self._get_report_lot() lot = self._get_report_lot()
return self._get_report_lot_shipment(lot) if not lot:
@staticmethod
def _get_report_bank_account(party):
accounts = list(getattr(party, 'bank_accounts', []) or [])
return accounts[0] if accounts else None
@staticmethod
def _get_report_bank_account_number(account):
if not account:
return ''
numbers = list(getattr(account, 'numbers', []) or [])
for number in numbers:
if getattr(number, 'type', None) == 'iban' and getattr(number, 'number', None):
return number.number or ''
for number in numbers:
if getattr(number, 'number', None):
return number.number or ''
return ''
@staticmethod
def _get_report_bank_name(account):
bank = getattr(account, 'bank', None) if account else None
party = getattr(bank, 'party', None) if bank else None
return getattr(party, 'rec_name', None) or getattr(bank, 'rec_name', None) or ''
@staticmethod
def _get_report_bank_city(account):
bank = getattr(account, 'bank', None) if account else None
party = getattr(bank, 'party', None) if bank else None
address = party.address_get() if party and hasattr(party, 'address_get') else None
return getattr(address, 'city', None) or ''
@staticmethod
def _get_report_bank_swift(account):
bank = getattr(account, 'bank', None) if account else None
return getattr(bank, 'bic', None) or ''
@staticmethod
def _format_report_payment_amount(value):
amount = Decimal(str(value or 0)).quantize(Decimal('0.01'))
return format(amount, 'f')
@property
def _report_payment_order_company_account(self):
return self._get_report_bank_account(getattr(self.company, 'party', None))
@property
def _report_payment_order_beneficiary_account(self):
return self._get_report_bank_account(self.party)
@property
def report_payment_order_short_name(self):
company_party = getattr(self.company, 'party', None)
return getattr(company_party, 'rec_name', '') or ''
@property
def report_payment_order_document_reference(self):
return self.number or self.reference or ''
@property
def report_payment_order_from_account_nb(self):
return self._get_report_bank_account_number(
self._report_payment_order_company_account)
@property
def report_payment_order_to_bank_name(self):
return self._get_report_bank_name(self._report_payment_order_beneficiary_account)
@property
def report_payment_order_to_bank_city(self):
return self._get_report_bank_city(self._report_payment_order_beneficiary_account)
@property
def report_payment_order_amount(self):
return self._format_report_payment_amount(self.total_amount)
@property
def report_payment_order_currency_code(self):
currency = self.currency
code = getattr(currency, 'code', None) or ''
rec_name = getattr(currency, 'rec_name', None) or ''
symbol = getattr(currency, 'symbol', None) or ''
if code and any(ch.isalpha() for ch in code):
return code
if rec_name and any(ch.isalpha() for ch in rec_name):
return rec_name
if symbol and any(ch.isalpha() for ch in symbol):
return symbol
return code or rec_name or symbol or ''
@property
def report_payment_order_amount_text(self):
return amount_to_currency_words(self.total_amount)
@property
def report_payment_order_value_date(self):
value_date = self.payment_term_date or self.invoice_date
if isinstance(value_date, dt_date):
return value_date.strftime('%d-%m-%Y')
return ''
@property
def report_payment_order_company_address(self):
if self.invoice_address and getattr(self.invoice_address, 'full_address', None):
return self.invoice_address.full_address
return self.report_address
@property
def report_payment_order_beneficiary_account_nb(self):
return self._get_report_bank_account_number(
self._report_payment_order_beneficiary_account)
@property
def report_payment_order_beneficiary_bank_name(self):
return self._get_report_bank_name(self._report_payment_order_beneficiary_account)
@property
def report_payment_order_beneficiary_bank_city(self):
return self._get_report_bank_city(self._report_payment_order_beneficiary_account)
@property
def report_payment_order_swift_code(self):
return self._get_report_bank_swift(self._report_payment_order_beneficiary_account)
@property
def report_payment_order_other_instructions(self):
return self.description or ''
@property
def report_payment_order_reference(self):
return self.reference or self.number or ''
@staticmethod
def _get_report_current_user():
user_id = Transaction().user
if not user_id:
return None return None
User = Pool().get('res.user') return (
return User(user_id) getattr(lot, 'lot_shipment_in', None)
or getattr(lot, 'lot_shipment_out', None)
@property or getattr(lot, 'lot_shipment_internal', None)
def report_payment_order_current_user(self): )
user = self._get_report_current_user()
return getattr(user, 'rec_name', None) or ''
@property
def report_payment_order_current_user_email(self):
user = self._get_report_current_user()
party = getattr(user, 'party', None) if user else None
if party and hasattr(party, 'contact_mechanism_get'):
return party.contact_mechanism_get('email') or ''
return getattr(user, 'email', None) or ''
@property @property
def report_address(self): def report_address(self):
@@ -622,17 +119,10 @@ class Invoice(metaclass=PoolMeta):
return line.product.description or '' return line.product.description or ''
return '' return ''
@property
def report_product_name(self):
line = self._get_report_trade_line()
if line and line.product:
return line.product.name or ''
return ''
@property @property
def report_description_upper(self): def report_description_upper(self):
if self.lines: if self.lines:
return self._clean_report_description(self.lines[0].description) return (self.lines[0].description or '').upper()
return '' return ''
@property @property
@@ -656,36 +146,6 @@ class Invoice(metaclass=PoolMeta):
return trade.report_price return trade.report_price
return '' return ''
@property
def report_quantity_lines(self):
details = []
for line in self._get_report_invoice_lines():
quantity, _ = self._get_report_invoice_line_weights(line)
if quantity == '':
continue
quantity_text = self._format_report_quantity_display(quantity)
unit = self._get_report_invoice_line_unit(line)
unit_name = unit.rec_name.upper() if unit and unit.rec_name else ''
lbs = self._convert_report_quantity_to_lbs(quantity, unit)
parts = [quantity_text, unit_name]
if lbs != '':
parts.append(
f"({self._format_report_quantity_display(lbs)} LBS)")
detail = ' '.join(part for part in parts if part)
if detail:
details.append(detail)
return '\n'.join(details)
@property
def report_trade_blocks(self):
blocks = []
quantity_lines = self.report_quantity_lines.splitlines()
rate_lines = self.report_rate_lines.splitlines()
for index, quantity_line in enumerate(quantity_lines):
price_line = rate_lines[index] if index < len(rate_lines) else ''
blocks.append((quantity_line, price_line))
return blocks
@property @property
def report_rate_currency_upper(self): def report_rate_currency_upper(self):
line = self._get_report_invoice_line() line = self._get_report_invoice_line()
@@ -721,66 +181,6 @@ class Invoice(metaclass=PoolMeta):
return line.report_rate_pricing_text return line.report_rate_pricing_text
return '' return ''
@property
def report_rate_lines(self):
details = []
for line in self._get_report_invoice_lines():
currency = getattr(line, 'report_rate_currency_upper', '') or ''
value = getattr(line, 'report_rate_value', '')
value_text = ''
if value != '':
value_text = self._format_report_number(
value, strip_trailing_zeros=False)
unit = getattr(line, 'report_rate_unit_upper', '') or ''
words = getattr(line, 'report_rate_price_words', '') or ''
pricing_text = getattr(line, 'report_rate_pricing_text', '') or ''
detail = ' '.join(
part for part in [
currency,
value_text,
'PER' if unit else '',
unit,
f"({words})" if words else '',
pricing_text,
] if part)
if detail:
details.append(detail)
return '\n'.join(details)
@property
def report_positive_rate_lines(self):
sale = self._get_report_sale()
if sale and getattr(sale, 'report_price_lines', None):
return sale.report_price_lines
details = []
for line in self._get_report_invoice_lines():
quantity = getattr(line, 'report_net', '')
if quantity == '':
quantity = getattr(line, 'quantity', '')
if Decimal(str(quantity or 0)) <= 0:
continue
currency = getattr(line, 'report_rate_currency_upper', '') or ''
value = getattr(line, 'report_rate_value', '')
value_text = ''
if value != '':
value_text = self._format_report_number(
value, strip_trailing_zeros=False)
unit = getattr(line, 'report_rate_unit_upper', '') or ''
words = getattr(line, 'report_rate_price_words', '') or ''
pricing_text = getattr(line, 'report_rate_pricing_text', '') or ''
detail = ' '.join(
part for part in [
currency,
value_text,
'PER' if unit else '',
unit,
f"({words})" if words else '',
pricing_text,
] if part)
if detail:
details.append(detail)
return '\n'.join(details)
@property @property
def report_payment_date(self): def report_payment_date(self):
trade = self._get_report_trade() trade = self._get_report_trade()
@@ -788,16 +188,6 @@ class Invoice(metaclass=PoolMeta):
return trade.report_payment_date return trade.report_payment_date
return '' return ''
@property
def report_delivery_period_description(self):
trade = self._get_report_trade()
if trade and getattr(trade, 'report_delivery_period_description', None):
return trade.report_delivery_period_description
line = self._get_report_trade_line()
if line and getattr(line, 'del_period', None):
return line.del_period.description or ''
return ''
@property @property
def report_payment_description(self): def report_payment_description(self):
trade = self._get_report_trade() trade = self._get_report_trade()
@@ -809,39 +199,6 @@ class Invoice(metaclass=PoolMeta):
@property @property
def report_nb_bale(self): def report_nb_bale(self):
total_packages = Decimal(0)
package_unit = None
has_invoice_line_packages = False
for line in self._get_report_invoice_lines():
lot = getattr(line, 'lot', None)
if not lot or getattr(lot, 'lot_qt', None) in (None, ''):
continue
has_invoice_line_packages = True
if not package_unit and getattr(lot, 'lot_unit', None):
package_unit = lot.lot_unit
sign = Decimal(1)
if Decimal(str(getattr(line, 'quantity', 0) or 0)) < 0:
sign = Decimal(-1)
total_packages += (
Decimal(str(lot.lot_qt or 0)).quantize(
Decimal('1'), rounding=ROUND_HALF_UP) * sign)
if has_invoice_line_packages:
label = self._format_report_package_label(package_unit)
return f"NB {label}: {int(total_packages)}"
lots = self._get_report_invoice_lots()
if lots:
total_packages = Decimal(0)
package_unit = None
for lot in lots:
if getattr(lot, 'lot_qt', None):
total_packages += Decimal(str(lot.lot_qt or 0))
if not package_unit and getattr(lot, 'lot_unit', None):
package_unit = lot.lot_unit
package_qty = total_packages.quantize(
Decimal('1'), rounding=ROUND_HALF_UP)
label = self._format_report_package_label(package_unit)
return f"NB {label}: {int(package_qty)}"
sale = self._get_report_sale() sale = self._get_report_sale()
if sale and sale.report_nb_bale: if sale and sale.report_nb_bale:
return sale.report_nb_bale return sale.report_nb_bale
@@ -853,47 +210,11 @@ class Invoice(metaclass=PoolMeta):
return 'NB BALES: ' + str(int(nb_bale)) return 'NB BALES: ' + str(int(nb_bale))
return '' return ''
@property
def report_cndn_nb_bale(self):
nb_bale = self.report_nb_bale
if nb_bale == 'NB BALES: 0':
return 'Unchanged'
return nb_bale
@property
def report_net_display(self):
net = self.report_net
if net == '':
return ''
return self._format_report_quantity_display(net)
@property
def report_gross_display(self):
gross = self.report_gross
if gross == '':
return ''
return self._format_report_quantity_display(gross)
@property
def report_lbs_display(self):
lbs = self.report_lbs
if lbs == '':
return ''
return self._format_report_quantity_display(lbs)
@property @property
def report_gross(self): def report_gross(self):
if self.lines: sale = self._get_report_sale()
reused_gross = self._get_report_reused_lot_gross_total() if sale and sale.report_gross != '':
if reused_gross is not None: return sale.report_gross
non_reused_total = sum(
self._get_report_invoice_line_weights(line)[1]
for line in self._get_report_invoice_lines()
if not self._report_invoice_line_reuses_lot(line))
return non_reused_total + reused_gross
return sum(
self._get_report_invoice_line_weights(line)[1]
for line in self._get_report_invoice_lines())
line = self._get_report_trade_line() line = self._get_report_trade_line()
if line and line.lots: if line and line.lots:
return sum( return sum(
@@ -904,10 +225,9 @@ class Invoice(metaclass=PoolMeta):
@property @property
def report_net(self): def report_net(self):
if self.lines: trade = self._get_report_trade()
return sum( if trade and getattr(trade, 'report_net', '') != '':
self._get_report_invoice_line_weights(line)[0] return trade.report_net
for line in self._get_report_invoice_lines())
line = self._get_report_trade_line() line = self._get_report_trade_line()
if line and line.lots: if line and line.lots:
return sum( return sum(
@@ -923,41 +243,7 @@ class Invoice(metaclass=PoolMeta):
net = self.report_net net = self.report_net
if net == '': if net == '':
return '' return ''
invoice_line = self._get_report_invoice_line() return round(Decimal(net) * Decimal('2204.62'),2)
unit = self._get_report_invoice_line_unit(invoice_line) if invoice_line else None
return self._convert_report_quantity_to_lbs(net, unit)
@property
def report_weight_unit_upper(self):
invoice_line = self._get_report_invoice_line()
unit = self._get_report_invoice_line_unit(invoice_line) if invoice_line else None
if not unit:
line = self._get_report_trade_line()
lot = self._get_report_lot()
unit = (
getattr(lot, 'lot_unit_line', None)
or getattr(line, 'unit', None) if line else None
)
if unit and unit.rec_name:
return unit.rec_name.upper()
return 'KGS'
@property
def report_note_title(self):
total = Decimal(str(self.total_amount or 0))
invoice_type = getattr(self, 'type', None)
if not invoice_type:
if self.sales:
invoice_type = 'out'
elif self.purchases:
invoice_type = 'in'
if invoice_type == 'out':
if total < 0:
return 'Credit Note'
return 'Debit Note'
if total < 0:
return 'Debit Note'
return 'Credit Note'
@property @property
def report_bl_date(self): def report_bl_date(self):
@@ -1042,13 +328,6 @@ class Invoice(metaclass=PoolMeta):
return shipment.number or '' return shipment.number or ''
return '' return ''
@property
def report_si_reference(self):
shipment = self._get_report_shipment()
if shipment:
return getattr(shipment, 'reference', None) or ''
return ''
@property @property
def report_freight_amount(self): def report_freight_amount(self):
fee = self._get_report_freight_fee() fee = self._get_report_freight_fee()
@@ -1087,18 +366,9 @@ class InvoiceLine(metaclass=PoolMeta):
return origin.product.description or '' return origin.product.description or ''
return '' return ''
@property
def report_product_name(self):
if self.product:
return self.product.name or ''
origin = getattr(self, 'origin', None)
if origin and getattr(origin, 'product', None):
return origin.product.name or ''
return ''
@property @property
def report_description_upper(self): def report_description_upper(self):
return Invoice._clean_report_description(self.description) return (self.description or '').upper()
@property @property
def report_rate_currency_upper(self): def report_rate_currency_upper(self):
@@ -1110,11 +380,6 @@ class InvoiceLine(metaclass=PoolMeta):
@property @property
def report_rate_value(self): def report_rate_value(self):
origin = self._get_report_trade_line()
if origin and getattr(origin, 'price_type', None) == 'basis':
if getattr(origin, 'enable_linked_currency', False) and getattr(origin, 'linked_currency', None):
return Decimal(str(origin.premium or 0))
return Decimal(str(origin._get_premium_price() or 0))
return self.unit_price if self.unit_price is not None else '' return self.unit_price if self.unit_price is not None else ''
@property @property
@@ -1127,12 +392,6 @@ class InvoiceLine(metaclass=PoolMeta):
@property @property
def report_rate_price_words(self): def report_rate_price_words(self):
origin = self._get_report_trade_line()
if origin and getattr(origin, 'price_type', None) == 'basis':
value = self.report_rate_value
if self.report_rate_currency_upper == 'USC':
return amount_to_currency_words(value, 'USC', 'USC')
return amount_to_currency_words(value)
trade = self._get_report_trade() trade = self._get_report_trade()
if trade and getattr(trade, 'report_price', None): if trade and getattr(trade, 'report_price', None):
return trade.report_price return trade.report_price
@@ -1160,16 +419,6 @@ class InvoiceLine(metaclass=PoolMeta):
@property @property
def report_net(self): def report_net(self):
if self.type == 'line': if self.type == 'line':
invoice = getattr(self, 'invoice', None)
if invoice and invoice._report_invoice_line_reuses_lot(self):
return Invoice._get_report_invoice_line_quantity_from_line(self)
lot = getattr(self, 'lot', None)
if lot:
net, _ = Invoice._get_report_lot_hist_weights(lot)
if net is None:
net = 0
sign = Invoice._get_report_line_sign(self)
return Decimal(str(net or 0)) * sign
return self.quantity return self.quantity
return '' return ''
@@ -1178,98 +427,4 @@ class InvoiceLine(metaclass=PoolMeta):
net = self.report_net net = self.report_net
if net == '': if net == '':
return '' return ''
unit = Invoice._get_report_invoice_line_unit(self) return round(Decimal(net) * Decimal('2204.62'),2)
return Invoice._convert_report_quantity_to_lbs(net, unit)
class ReportTemplateMixin:
@classmethod
def _get_purchase_trade_configuration(cls):
Configuration = Pool().get('purchase_trade.configuration')
configurations = Configuration.search([], limit=1)
return configurations[0] if configurations else None
@classmethod
def _get_action_name(cls, action):
if isinstance(action, dict):
return action.get('name') or ''
return getattr(action, 'name', '') or ''
@classmethod
def _get_action_report_path(cls, action):
if isinstance(action, dict):
return action.get('report') or ''
return getattr(action, 'report', '') or ''
@classmethod
def _resolve_template_path(cls, action, field_name, default_prefix):
config = cls._get_purchase_trade_configuration()
template = getattr(config, field_name, '') if config else ''
template = (template or '').strip()
if not template:
raise UserError('No template found')
if '/' not in template:
return f'{default_prefix}/{template}'
return template
@classmethod
def _get_resolved_action(cls, action):
report_path = cls._resolve_configured_report_path(action)
if isinstance(action, dict):
resolved = dict(action)
resolved['report'] = report_path
return resolved
setattr(action, 'report', report_path)
return action
@classmethod
def _execute(cls, records, header, data, action):
resolved_action = cls._get_resolved_action(action)
return super()._execute(records, header, data, resolved_action)
class InvoiceReport(ReportTemplateMixin, BaseInvoiceReport):
__name__ = 'account.invoice'
@classmethod
def _resolve_configured_report_path(cls, action):
report_path = cls._get_action_report_path(action) or ''
action_name = cls._get_action_name(action)
if (report_path.endswith('/prepayment.fodt')
or action_name == 'Prepayment'):
field_name = 'invoice_prepayment_report_template'
elif (report_path.endswith('/payment_order.fodt')
or action_name == 'Payment Order'):
field_name = 'invoice_payment_order_report_template'
elif (report_path.endswith('/invoice_ict_final.fodt')
or action_name == 'CN/DN'):
field_name = 'invoice_cndn_report_template'
else:
field_name = 'invoice_report_template'
return cls._resolve_template_path(action, field_name, 'account_invoice')
class SaleReport(ReportTemplateMixin, BaseSaleReport):
__name__ = 'sale.sale'
@classmethod
def _resolve_configured_report_path(cls, action):
report_path = cls._get_action_report_path(action)
action_name = cls._get_action_name(action)
if report_path.endswith('/bill.fodt') or action_name == 'Bill':
field_name = 'sale_bill_report_template'
elif report_path.endswith('/sale_final.fodt') or action_name == 'Sale (final)':
field_name = 'sale_final_report_template'
else:
field_name = 'sale_report_template'
return cls._resolve_template_path(action, field_name, 'sale')
class PurchaseReport(ReportTemplateMixin, BasePurchaseReport):
__name__ = 'purchase.purchase'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
action, 'purchase_report_template', 'purchase')

View File

@@ -1,16 +0,0 @@
<tryton>
<data>
<record model="ir.action.report" id="report_payment_order">
<field name="name">Payment Order</field>
<field name="model">account.invoice</field>
<field name="report_name">account.invoice</field>
<field name="report">account_invoice/payment_order.fodt</field>
<field name="single" eval="True"/>
</record>
<record model="ir.action.keyword" id="report_payment_order_keyword">
<field name="keyword">form_print</field>
<field name="model">account.invoice,-1</field>
<field name="action" ref="report_payment_order"/>
</record>
</data>
</tryton>

View File

@@ -1336,11 +1336,6 @@ class LotQt(
Case((lp.id>0, lp.lot_himself),else_=ls.lot_himself).as_('r_lot_himself'), Case((lp.id>0, lp.lot_himself),else_=ls.lot_himself).as_('r_lot_himself'),
Case((lp.id>0, lp.lot_container),else_=ls.lot_container).as_('r_lot_container'), Case((lp.id>0, lp.lot_container),else_=ls.lot_container).as_('r_lot_container'),
Case((lp.id>0, lp.line),else_=None).as_('r_line'), Case((lp.id>0, lp.line),else_=None).as_('r_line'),
Case(
(((lqt.lot_s != None) & (lqt.lot_p == None) & (sl.id > 0)),
sl.del_period),
else_=Case((pl.id>0, pl.del_period),else_=None)
).as_('r_del_period'),
Case((pu.id>0, pu.id),else_=None).as_('r_purchase'), Case((pu.id>0, pu.id),else_=None).as_('r_purchase'),
Case((sa.id>0, sa.id),else_=None).as_('r_sale'), Case((sa.id>0, sa.id),else_=None).as_('r_sale'),
Case((ls.id>0, ls.sale_line),else_=None).as_('r_sale_line'), Case((ls.id>0, ls.sale_line),else_=None).as_('r_sale_line'),
@@ -1448,7 +1443,6 @@ class LotQt(
lp.lot_himself.as_("r_lot_himself"), lp.lot_himself.as_("r_lot_himself"),
lp.lot_container.as_("r_lot_container"), lp.lot_container.as_("r_lot_container"),
lp.line.as_("r_line"), lp.line.as_("r_line"),
pl.del_period.as_("r_del_period"),
Case((pu.id > 0, pu.id), else_=None).as_("r_purchase"), Case((pu.id > 0, pu.id), else_=None).as_("r_purchase"),
Case((sa.id > 0, sa.id), else_=None).as_("r_sale"), Case((sa.id > 0, sa.id), else_=None).as_("r_sale"),
lp.sale_line.as_("r_sale_line"), lp.sale_line.as_("r_sale_line"),
@@ -1514,7 +1508,6 @@ class LotQt(
Literal(None).as_("r_lot_himself"), Literal(None).as_("r_lot_himself"),
Max(lp.lot_container).as_("r_lot_container"), Max(lp.lot_container).as_("r_lot_container"),
lp.line.as_("r_line"), lp.line.as_("r_line"),
Max(pl.del_period).as_("r_del_period"),
Max(Case((pu.id > 0, pu.id), else_=None)).as_("r_purchase"), Max(Case((pu.id > 0, pu.id), else_=None)).as_("r_purchase"),
Max(Case((sa.id > 0, sa.id), else_=None)).as_("r_sale"), Max(Case((sa.id > 0, sa.id), else_=None)).as_("r_sale"),
lp.sale_line.as_("r_sale_line"), lp.sale_line.as_("r_sale_line"),
@@ -1568,7 +1561,6 @@ class LotQt(
union.r_lot_himself.as_("r_lot_himself"), union.r_lot_himself.as_("r_lot_himself"),
union.r_lot_container.as_("r_lot_container"), union.r_lot_container.as_("r_lot_container"),
union.r_line.as_("r_line"), union.r_line.as_("r_line"),
union.r_del_period.as_("r_del_period"),
union.r_purchase.as_("r_purchase"), union.r_purchase.as_("r_purchase"),
union.r_sale.as_("r_sale"), union.r_sale.as_("r_sale"),
union.r_sale_line.as_("r_sale_line"), union.r_sale_line.as_("r_sale_line"),
@@ -1644,7 +1636,6 @@ class LotReport(
r_lot_unit_line = fields.Function(fields.Many2One('product.uom', "Unit"),'get_unit') r_lot_unit_line = fields.Function(fields.Many2One('product.uom', "Unit"),'get_unit')
r_lot_price = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_price') r_lot_price = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_price')
r_lot_price_sale = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_sale_price') r_lot_price_sale = fields.Function(fields.Numeric("Price", digits='r_lot_unit_line'),'get_lot_sale_price')
r_del_period = fields.Many2One('product.month', "Delivery Period")
r_sale_line = fields.Many2One('sale.line',"S. line") r_sale_line = fields.Many2One('sale.line',"S. line")
r_sale = fields.Many2One('sale.sale',"Sale") r_sale = fields.Many2One('sale.sale',"Sale")
r_tot = fields.Numeric("Qt tot", digits='r_lot_unit_line') r_tot = fields.Numeric("Qt tot", digits='r_lot_unit_line')
@@ -2788,16 +2779,12 @@ class LotInvoice(Wizard):
Purchase = Pool().get('purchase.purchase') Purchase = Pool().get('purchase.purchase')
Sale = Pool().get('sale.sale') Sale = Pool().get('sale.sale')
lots = [] lots = []
purchases = []
sales = []
action = self.inv.action action = self.inv.action
for r in self.records: for r in self.records:
purchase = r.r_line.purchase if r.r_line else None purchase = r.r_line.purchase
sale = r.r_sale_line.sale if r.r_sale_line else None sale = None
if purchase and purchase not in purchases: if r.r_sale_line:
purchases.append(purchase) sale = r.r_sale_line.sale
if sale and sale not in sales:
sales.append(sale)
lot = Lot(r.r_lot_p) lot = Lot(r.r_lot_p)
# if lot.move == None: # if lot.move == None:
# Warning = Pool().get('res.user.warning') # Warning = Pool().get('res.user.warning')
@@ -2812,22 +2799,12 @@ class LotInvoice(Wizard):
invoice_line = None invoice_line = None
if self.inv.type == 'purchase': if self.inv.type == 'purchase':
Purchase._process_invoice(purchases, lots, action, self.inv.pp_pur) Purchase._process_invoice([purchase],lots,action,self.inv.pp_pur)
for lot in lots: invoice_line = r.r_lot_p.invoice_line if r.r_lot_p.invoice_line else r.r_lot_p.invoice_line_prov
lot = Lot(lot.id)
invoice_line = lot.invoice_line or lot.invoice_line_prov
if invoice_line:
break
else: else:
if sales: if sale:
Sale._process_invoice(sales, lots, action, self.inv.pp_sale) Sale._process_invoice([sale],lots,action,self.inv.pp_sale)
for lot in lots: invoice_line = r.r_lot_p.invoice_line if r.r_lot_p.sale_invoice_line else r.r_lot_p.sale_invoice_line_prov
lot = Lot(lot.id)
invoice_line = lot.sale_invoice_line or lot.sale_invoice_line_prov
if invoice_line:
break
if not invoice_line:
raise UserError("No invoice line was generated from the selected lots.")
self.message.invoice = invoice_line.invoice self.message.invoice = invoice_line.invoice
return 'message' return 'message'
@@ -3064,7 +3041,6 @@ class LotWeighing(Wizard):
if lot.lot_shipment_out: if lot.lot_shipment_out:
val['lot_shipment_out'] = lot.lot_shipment_out.id val['lot_shipment_out'] = lot.lot_shipment_out.id
val['lot_product'] = lot.lot_product.id val['lot_product'] = lot.lot_product.id
val['lot_qt'] = lot.lot_qt
val['lot_quantity'] = lot.lot_quantity val['lot_quantity'] = lot.lot_quantity
val['lot_gross_quantity'] = lot.lot_gross_quantity val['lot_gross_quantity'] = lot.lot_gross_quantity
val['lot_unit'] = lot.lot_unit.id val['lot_unit'] = lot.lot_unit.id
@@ -3091,7 +3067,6 @@ class LotWeighing(Wizard):
lh.quantity = round(l.lot_quantity_new,5) lh.quantity = round(l.lot_quantity_new,5)
lh.gross_quantity = round(l.lot_gross_quantity_new,5) lh.gross_quantity = round(l.lot_gross_quantity_new,5)
LotHist.save([lh]) LotHist.save([lh])
l.lot.lot_qt = l.lot_qt
if self.w.lot_update_state : if self.w.lot_update_state :
l.lot.lot_state = self.w.lot_state l.lot.lot_state = self.w.lot_state
@@ -3132,7 +3107,6 @@ class LotWeighingLot(ModelView):
lot_shipment_internal = fields.Many2One('stock.shipment.internal',"Shipment Internal") lot_shipment_internal = fields.Many2One('stock.shipment.internal',"Shipment Internal")
lot_shipment_out = fields.Many2One('stock.shipment.out',"Shipment Out") lot_shipment_out = fields.Many2One('stock.shipment.out',"Shipment Out")
lot_product = fields.Many2One('product.product',"Product",readonly=True) lot_product = fields.Many2One('product.product',"Product",readonly=True)
lot_qt = fields.Integer("Qt")
lot_quantity = fields.Numeric("Net weight",digits=(1,5),readonly=True) lot_quantity = fields.Numeric("Net weight",digits=(1,5),readonly=True)
lot_gross_quantity = fields.Numeric("Gross weight",digits=(1,5),readonly=True) lot_gross_quantity = fields.Numeric("Gross weight",digits=(1,5),readonly=True)
lot_unit = fields.Many2One('product.uom',"Unit",readonly=True) lot_unit = fields.Many2One('product.uom',"Unit",readonly=True)
@@ -3191,41 +3165,23 @@ class CreateContracts(Wizard):
sh_int = None sh_int = None
sh_out = None sh_out = None
lot = None lot = None
qt = Decimal(0) qt = None
type = None type = None
shipment_in_values = set()
shipment_internal_values = set()
shipment_out_values = set()
for i in ids: for i in ids:
val = {}
if i < 10000000: if i < 10000000:
raise UserError("You must create contract from an open quantity !") raise UserError("You must create contract from an open quantity !")
l = LotQt(i - 10000000) l = LotQt(i - 10000000)
ll = Lot(l.lot_p if l.lot_p else l.lot_s) ll = Lot(l.lot_p if l.lot_p else l.lot_s)
current_type = "Sale" if l.lot_p else "Purchase" type = "Sale" if l.lot_p else "Purchase"
if type and current_type != type:
raise UserError("You must select open quantities from the same side.")
type = current_type
if product and ll.lot_product.id != product:
raise UserError("You must select open quantities with the same product.")
if unit and l.lot_unit.id != unit:
raise UserError("You must select open quantities with the same unit.")
unit = l.lot_unit.id unit = l.lot_unit.id
qt += abs(Decimal(str(l.lot_quantity or 0))) qt = l.lot_quantity
product = ll.lot_product.id product = ll.lot_product.id
shipment_in_values.add(l.lot_shipment_in.id if l.lot_shipment_in else None) sh_in = l.lot_shipment_in.id if l.lot_shipment_in else None
shipment_internal_values.add( sh_int = l.lot_shipment_internal.id if l.lot_shipment_internal else None
l.lot_shipment_internal.id if l.lot_shipment_internal else None) sh_out = l.lot_shipment_out.id if l.lot_shipment_out else None
shipment_out_values.add(l.lot_shipment_out.id if l.lot_shipment_out else None)
if lot is None:
lot = ll.id lot = ll.id
if len(shipment_in_values) == 1:
sh_in = next(iter(shipment_in_values))
if len(shipment_internal_values) == 1:
sh_int = next(iter(shipment_internal_values))
if len(shipment_out_values) == 1:
sh_out = next(iter(shipment_out_values))
return { return {
'quantity': qt, 'quantity': qt,
'unit': unit, 'unit': unit,

View File

@@ -16,65 +16,8 @@ class PartyExecution(ModelSQL,ModelView):
percent = fields.Numeric("% targeted") percent = fields.Numeric("% targeted")
achieved_percent = fields.Function(fields.Numeric("% achieved"),'get_percent') achieved_percent = fields.Function(fields.Numeric("% achieved"),'get_percent')
@staticmethod
def _to_decimal(value):
if value is None:
return Decimal('0')
if isinstance(value, Decimal):
return value
return Decimal(str(value))
@classmethod
def _round_percent(cls, value):
return cls._to_decimal(value).quantize(
Decimal('0.01'), rounding=ROUND_HALF_UP)
def matches_country(self, country):
if not self.area or not country or not getattr(country, 'region', None):
return False
region = country.region
while region:
if region.id == self.area.id:
return True
region = getattr(region, 'parent', None)
return False
def matches_shipment(self, shipment):
location = getattr(shipment, 'to_location', None)
country = getattr(location, 'country', None)
return self.matches_country(country)
@classmethod
def compute_achieved_percent_for(cls, party, area):
if not party or not area:
return Decimal('0')
Shipment = Pool().get('stock.shipment.in')
shipments = Shipment.search([
('controller', '!=', None),
])
execution = cls()
execution.area = area
shipments = [
shipment for shipment in shipments
if execution.matches_shipment(shipment)]
total = len(shipments)
if not total:
return Decimal('0')
achieved = sum(
1 for shipment in shipments
if shipment.controller and shipment.controller.id == party.id)
return cls._round_percent(
(Decimal(achieved) * Decimal('100')) / Decimal(total))
def compute_achieved_percent(self):
return self.__class__.compute_achieved_percent_for(
self.party, self.area)
def get_target_gap(self):
return self._to_decimal(self.percent) - self.compute_achieved_percent()
def get_percent(self,name): def get_percent(self,name):
return self.compute_achieved_percent() return 2
class PartyExecutionSla(ModelSQL,ModelView): class PartyExecutionSla(ModelSQL,ModelView):
"Party Execution Sla" "Party Execution Sla"
@@ -127,18 +70,6 @@ class Party(metaclass=PoolMeta):
def IsAvailableForControl(self,sh): def IsAvailableForControl(self,sh):
return True return True
def get_controller_execution_priority(self, shipment):
best_rule = None
best_gap = None
for execution in self.execution or []:
if not execution.matches_shipment(shipment):
continue
gap = execution.get_target_gap()
if best_gap is None or gap > best_gap:
best_gap = gap
best_rule = execution
return best_gap, best_rule
def get_sla_cost(self,location): def get_sla_cost(self,location):
if self.sla: if self.sla:
for sla in self.sla: for sla in self.sla:

View File

@@ -333,10 +333,10 @@ class Pricing(ModelSQL,ModelView):
price_component = fields.Many2One('pricing.component', "Component")#, domain=[('id', 'in', Eval('line.price_components'))], ondelete='CASCADE') price_component = fields.Many2One('pricing.component', "Component")#, domain=[('id', 'in', Eval('line.price_components'))], ondelete='CASCADE')
quantity = fields.Numeric("Qt",digits='unit') quantity = fields.Numeric("Qt",digits='unit')
settl_price = fields.Numeric("Settl. price",digits='unit') settl_price = fields.Numeric("Settl. price",digits='unit')
fixed_qt = fields.Numeric("Fixed qt",digits='unit', readonly=True) fixed_qt = fields.Numeric("Fixed qt",digits='unit',readonly=True)
fixed_qt_price = fields.Numeric("Fixed qt price",digits='unit', readonly=True) fixed_qt_price = fields.Numeric("Fixed qt price",digits='unit',readonly=True)
unfixed_qt = fields.Numeric("Unfixed qt",digits='unit', readonly=True) unfixed_qt = fields.Numeric("Unfixed qt",digits='unit',readonly=True)
unfixed_qt_price = fields.Numeric("Unfixed qt price",digits='unit', readonly=True) unfixed_qt_price = fields.Numeric("Unfixed qt price",digits='unit',readonly=True)
eod_price = fields.Numeric("EOD price",digits='unit',readonly=True) eod_price = fields.Numeric("EOD price",digits='unit',readonly=True)
last = fields.Boolean("Last") last = fields.Boolean("Last")
@@ -368,236 +368,16 @@ class Pricing(ModelSQL,ModelView):
def default_eod_price(cls): def default_eod_price(cls):
return Decimal(0) return Decimal(0)
@staticmethod
def _weighted_average_price(fixed_qt, fixed_price, unfixed_qt, unfixed_price):
fixed_qt = Decimal(str(fixed_qt or 0))
fixed_price = Decimal(str(fixed_price or 0))
unfixed_qt = Decimal(str(unfixed_qt or 0))
unfixed_price = Decimal(str(unfixed_price or 0))
total_qty = fixed_qt + unfixed_qt
if total_qty == 0:
return Decimal(0)
return round(
((fixed_qt * fixed_price) + (unfixed_qt * unfixed_price)) / total_qty,
4,
)
def compute_eod_price(self):
if getattr(self, 'sale_line', None) and hasattr(self, 'get_eod_price_sale'):
return self.get_eod_price_sale()
if getattr(self, 'line', None) and hasattr(self, 'get_eod_price_purchase'):
return self.get_eod_price_purchase()
return self._weighted_average_price(
self.fixed_qt,
self.fixed_qt_price,
self.unfixed_qt,
self.unfixed_qt_price,
)
@fields.depends('fixed_qt', 'fixed_qt_price', 'unfixed_qt', 'unfixed_qt_price')
def on_change_fixed_qt(self):
self.eod_price = self.compute_eod_price()
@fields.depends('fixed_qt', 'fixed_qt_price', 'unfixed_qt', 'unfixed_qt_price')
def on_change_fixed_qt_price(self):
self.eod_price = self.compute_eod_price()
@fields.depends('fixed_qt', 'fixed_qt_price', 'unfixed_qt', 'unfixed_qt_price')
def on_change_unfixed_qt(self):
self.eod_price = self.compute_eod_price()
@fields.depends('fixed_qt', 'fixed_qt_price', 'unfixed_qt', 'unfixed_qt_price')
def on_change_unfixed_qt_price(self):
self.eod_price = self.compute_eod_price()
@classmethod
def create(cls, vlist):
records = super(Pricing, cls).create(vlist)
cls._sync_manual_values(records)
cls._sync_manual_last(records)
cls._sync_eod_price(records)
return records
@classmethod
def write(cls, *args):
super(Pricing, cls).write(*args)
if (Transaction().context.get('skip_pricing_eod_sync')
or Transaction().context.get('skip_pricing_last_sync')):
return
records = []
actions = iter(args)
for record_set, values in zip(actions, actions):
if values:
records.extend(record_set)
cls._sync_manual_values(records)
cls._sync_manual_last(records)
cls._sync_eod_price(records)
@classmethod
def _sync_eod_price(cls, records):
if not records:
return
with Transaction().set_context(skip_pricing_eod_sync=True):
for record in records:
eod_price = record.compute_eod_price()
if Decimal(str(record.eod_price or 0)) == Decimal(str(eod_price or 0)):
continue
super(Pricing, cls).write([record], {
'eod_price': eod_price,
})
@classmethod
def _is_manual_pricing_record(cls, record):
component = getattr(record, 'price_component', None)
if component is None:
return True
return not bool(getattr(component, 'auto', False))
@classmethod
def _get_pricing_group_domain(cls, record):
component = getattr(record, 'price_component', None)
if getattr(record, 'sale_line', None):
return [
('sale_line', '=', record.sale_line.id),
('price_component', '=',
component.id if getattr(component, 'id', None) else None),
]
if getattr(record, 'line', None):
return [
('line', '=', record.line.id),
('price_component', '=',
component.id if getattr(component, 'id', None) else None),
]
return None
@classmethod
def _get_base_quantity(cls, record):
owner = getattr(record, 'sale_line', None) or getattr(record, 'line', None)
if not owner:
return Decimal(0)
if hasattr(owner, '_get_pricing_base_quantity'):
return Decimal(str(owner._get_pricing_base_quantity() or 0))
quantity = getattr(owner, 'quantity_theorical', None)
if quantity is None:
quantity = getattr(owner, 'quantity', None)
return Decimal(str(quantity or 0))
@classmethod
def _sync_manual_values(cls, records):
if (not records
or Transaction().context.get('skip_pricing_manual_sync')):
return
domains = []
seen = set()
for record in records:
if not cls._is_manual_pricing_record(record):
continue
domain = cls._get_pricing_group_domain(record)
if not domain:
continue
key = tuple(domain)
if key in seen:
continue
seen.add(key)
domains.append(domain)
if not domains:
return
with Transaction().set_context(
skip_pricing_manual_sync=True,
skip_pricing_last_sync=True,
skip_pricing_eod_sync=True):
for domain in domains:
pricings = cls.search(
domain,
order=[('pricing_date', 'ASC'), ('id', 'ASC')])
if not pricings:
continue
base_quantity = cls._get_base_quantity(pricings[0])
cumul_qt = Decimal(0)
cumul_qt_price = Decimal(0)
total = len(pricings)
for index, pricing in enumerate(pricings):
quantity = Decimal(str(pricing.quantity or 0))
settl_price = Decimal(str(pricing.settl_price or 0))
cumul_qt += quantity
cumul_qt_price += quantity * settl_price
fixed_qt = cumul_qt
if fixed_qt > 0:
fixed_qt_price = round(cumul_qt_price / fixed_qt, 4)
else:
fixed_qt_price = Decimal(0)
unfixed_qt = base_quantity - fixed_qt
if unfixed_qt < Decimal('0.001'):
unfixed_qt = Decimal(0)
fixed_qt = base_quantity
values = {
'fixed_qt': fixed_qt,
'fixed_qt_price': fixed_qt_price,
'unfixed_qt': unfixed_qt,
'unfixed_qt_price': settl_price,
'last': index == (total - 1),
}
eod_price = cls._weighted_average_price(
values['fixed_qt'],
values['fixed_qt_price'],
values['unfixed_qt'],
values['unfixed_qt_price'],
)
values['eod_price'] = eod_price
super(Pricing, cls).write([pricing], values)
@classmethod
def _get_manual_last_group_domain(cls, record):
return cls._get_pricing_group_domain(record)
@classmethod
def _sync_manual_last(cls, records):
if not records:
return
domains = []
seen = set()
for record in records:
domain = cls._get_manual_last_group_domain(record)
if not domain:
continue
key = tuple(domain)
if key in seen:
continue
seen.add(key)
domains.append(domain)
if not domains:
return
with Transaction().set_context(
skip_pricing_last_sync=True,
skip_pricing_eod_sync=True):
for domain in domains:
pricings = cls.search(
domain,
order=[('pricing_date', 'ASC'), ('id', 'ASC')])
if not pricings:
continue
last_pricing = pricings[-1]
for pricing in pricings[:-1]:
if pricing.last:
super(Pricing, cls).write([pricing], {'last': False})
if not last_pricing.last:
super(Pricing, cls).write([last_pricing], {'last': True})
def get_fixed_price(self): def get_fixed_price(self):
price = Decimal(0) price = Decimal(0)
Pricing = Pool().get('pricing.pricing') Pricing = Pool().get('pricing.pricing')
domain = self._get_pricing_group_domain(self) pricings = Pricing.search(['price_component','=',self.price_component.id],order=[('pricing_date', 'ASC')])
if not domain:
return price
pricings = Pricing.search(domain, order=[('pricing_date', 'ASC'), ('id', 'ASC')])
if pricings: if pricings:
cumul_qt = Decimal(0) cumul_qt = Decimal(0)
cumul_qt_price = Decimal(0) cumul_qt_price = Decimal(0)
for pr in pricings: for pr in pricings:
quantity = Decimal(str(pr.quantity or 0)) cumul_qt += pr.quantity
settl_price = Decimal(str(pr.settl_price or 0)) cumul_qt_price += pr.quantity * pr.settl_price
cumul_qt += quantity
cumul_qt_price += quantity * settl_price
if pr.id == self.id: if pr.id == self.id:
break break
if cumul_qt > 0: if cumul_qt > 0:

View File

@@ -141,12 +141,8 @@ class Component(metaclass=PoolMeta):
def get_quota_purchase(self, name): def get_quota_purchase(self, name):
if self.line: if self.line:
quantity = getattr(self.line, 'quantity_theorical', None) if self.line.quantity:
if quantity is None: return round(self.line.quantity_theorical / (self.nbdays if self.nbdays > 0 else 1),5)
quantity = getattr(self.line, 'quantity', None)
if quantity is not None:
nbdays = self.nbdays if self.nbdays and self.nbdays > 0 else 1
return round(Decimal(quantity) / nbdays, 5)
class Pricing(metaclass=PoolMeta): class Pricing(metaclass=PoolMeta):
"Pricing" "Pricing"
@@ -160,12 +156,9 @@ class Pricing(metaclass=PoolMeta):
return self.line.unit return self.line.unit
def get_eod_price_purchase(self): def get_eod_price_purchase(self):
return self._weighted_average_price( if self.line:
self.fixed_qt, return round((self.fixed_qt * self.fixed_qt_price + self.unfixed_qt * self.unfixed_qt_price)/Decimal(self.line.quantity_theorical),4)
self.fixed_qt_price, return Decimal(0)
self.unfixed_qt,
self.unfixed_qt_price,
)
class Summary(ModelSQL,ModelView): class Summary(ModelSQL,ModelView):
"Pricing summary" "Pricing summary"
@@ -296,12 +289,8 @@ class Purchase(metaclass=PoolMeta):
'purchase', 'purchase',
'Analytic Dimensions' 'Analytic Dimensions'
) )
trader = fields.Many2One( trader = fields.Many2One('party.party',"Trader")
'party.party', "Trader", operator = fields.Many2One('party.party',"Operator")
domain=[('categories.name', '=', 'TRADER')])
operator = fields.Many2One(
'party.party', "Operator",
domain=[('categories.name', '=', 'OPERATOR')])
our_reference = fields.Char("Our Reference") our_reference = fields.Char("Our Reference")
company_visible = fields.Function( company_visible = fields.Function(
fields.Boolean("Visible"), 'on_change_with_company_visible') fields.Boolean("Visible"), 'on_change_with_company_visible')
@@ -406,12 +395,6 @@ class Purchase(metaclass=PoolMeta):
del_date = format_date_en(del_date) del_date = format_date_en(del_date)
return del_date return del_date
@property
def report_delivery_period_description(self):
if self.lines and self.lines[0].del_period:
return self.lines[0].del_period.description or ''
return ''
@property @property
def report_payment_date(self): def report_payment_date(self):
if self.lines: if self.lines:
@@ -562,11 +545,9 @@ class Purchase(metaclass=PoolMeta):
#line unit_price calculation #line unit_price calculation
if line.price_type == 'basis' and line.lots: #line.price_pricing and line.price_components and if line.price_type == 'basis' and line.lots: #line.price_pricing and line.price_components and
previous_linked_price = line.linked_price
line.sync_linked_price_from_basis()
unit_price = line.get_basis_price() unit_price = line.get_basis_price()
logger.info("VALIDATEPURCHASE:%s",unit_price) logger.info("VALIDATEPURCHASE:%s",unit_price)
if unit_price != line.unit_price or line.linked_price != previous_linked_price: if unit_price != line.unit_price:
line.unit_price = unit_price line.unit_price = unit_price
logger.info("VALIDATEPURCHASE2:%s",line.unit_price) logger.info("VALIDATEPURCHASE2:%s",line.unit_price)
Line.save([line]) Line.save([line])
@@ -1040,17 +1021,6 @@ class QualityAnalysis(ModelSQL,ModelView):
class Line(metaclass=PoolMeta): class Line(metaclass=PoolMeta):
__name__ = 'purchase.line' __name__ = 'purchase.line'
@classmethod
def default_pricing_rule(cls):
try:
Configuration = Pool().get('purchase_trade.configuration')
except KeyError:
return ''
configurations = Configuration.search([], limit=1)
if configurations:
return configurations[0].pricing_rule or ''
return ''
quantity_theorical = fields.Numeric("Contractual Qt", digits='unit', readonly=False) quantity_theorical = fields.Numeric("Contractual Qt", digits='unit', readonly=False)
price_type = fields.Selection([ price_type = fields.Selection([
('cash', 'Cash Price'), ('cash', 'Cash Price'),
@@ -1109,20 +1079,15 @@ class Line(metaclass=PoolMeta):
enable_linked_currency = fields.Boolean("Linked currencies") enable_linked_currency = fields.Boolean("Linked currencies")
linked_price = fields.Numeric("Price", digits='unit',states={ linked_price = fields.Numeric("Price", digits='unit',states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
'readonly': Eval('price_type') == 'basis',
}, depends=['enable_linked_currency', 'price_type'])
linked_currency = fields.Many2One('currency.linked',"Currency",states={ linked_currency = fields.Many2One('currency.linked',"Currency",states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
}, depends=['enable_linked_currency'])
linked_unit = fields.Many2One('product.uom', 'Unit',states={ linked_unit = fields.Many2One('product.uom', 'Unit',states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
}, depends=['enable_linked_currency'])
premium = fields.Numeric("Premium/Discount",digits='unit') premium = fields.Numeric("Premium/Discount",digits='unit')
fee_ = fields.Many2One('fee.fee',"Fee") fee_ = fields.Many2One('fee.fee',"Fee")
pricing_rule = fields.Text("Pricing description")
attributes = fields.Dict( attributes = fields.Dict(
'product.attribute', 'Attributes', 'product.attribute', 'Attributes',
@@ -1164,13 +1129,6 @@ class Line(metaclass=PoolMeta):
def default_finished(cls): def default_finished(cls):
return False return False
@property
def report_fixing_rule(self):
pricing_rule = ''
if self.pricing_rule:
pricing_rule = self.pricing_rule
return pricing_rule
@fields.depends('product') @fields.depends('product')
def on_change_with_attribute_set(self, name=None): def on_change_with_attribute_set(self, name=None):
@@ -1244,70 +1202,18 @@ class Line(metaclass=PoolMeta):
PS = Pool().get('purchase.pricing.summary') PS = Pool().get('purchase.pricing.summary')
ps = PS.search(['line','=',self.id]) ps = PS.search(['line','=',self.id])
if ps: if ps:
if not self.price_components:
manual = [e for e in ps if not e.price_component]
if manual:
return manual[0].progress or 0
return sum((e.progress if e.progress else 0) * (e.ratio if e.ratio else 0) / 100 for e in ps) return sum((e.progress if e.progress else 0) * (e.ratio if e.ratio else 0) / 100 for e in ps)
def getVirtualLot(self): def getVirtualLot(self):
if self.lots: if self.lots:
return [l for l in self.lots if l.lot_type=='virtual'][0] return [l for l in self.lots if l.lot_type=='virtual'][0]
def _get_linked_unit_factor(self): def get_basis_price(self):
if not (self.enable_linked_currency and self.linked_currency):
return None
factor = Decimal(self.linked_currency.factor or 0)
if not factor:
return None
unit_factor = Decimal(1)
if self.linked_unit:
source_unit = getattr(self, 'unit', None)
if not source_unit and self.product:
source_unit = self.product.purchase_uom or self.product.default_uom
if not source_unit:
return factor
Uom = Pool().get('product.uom')
unit_factor = Decimal(str(
Uom.compute_qty(source_unit, float(1), self.linked_unit) or 0))
return factor * unit_factor
def _linked_to_line_price(self, price):
factor = self._get_linked_unit_factor()
price = Decimal(price or 0)
if not factor:
return price
return round(price * factor, 4)
def _line_to_linked_price(self, price):
factor = self._get_linked_unit_factor()
price = Decimal(price or 0)
if not factor:
return price
return round(price / factor, 4)
def _get_premium_price(self):
premium = Decimal(self.premium or 0)
if not premium:
return Decimal(0)
if self.enable_linked_currency and self.linked_currency:
return self._linked_to_line_price(premium)
return premium
def _get_basis_component_price(self):
price = Decimal(0) price = Decimal(0)
if self.terms: if self.terms:
for t in self.terms: for t in self.terms:
price += (t.manual_price if t.manual_price else Decimal(0)) price += (t.manual_price if t.manual_price else Decimal(0))
else: else:
if not self.price_components:
PP = Pool().get('purchase.pricing.summary')
pp = PP.search([
('line', '=', self.id),
('price_component', '=', None),
], limit=1)
if pp:
return round(Decimal(pp[0].price or 0), 4)
for pc in self.price_components: for pc in self.price_components:
PP = Pool().get('purchase.pricing.summary') PP = Pool().get('purchase.pricing.summary')
pp = PP.search([('price_component','=',pc.id),('line','=',self.id)]) pp = PP.search([('price_component','=',pc.id),('line','=',self.id)])
@@ -1315,33 +1221,22 @@ class Line(metaclass=PoolMeta):
price += pp[0].price * (pc.ratio / 100) price += pp[0].price * (pc.ratio / 100)
return round(price,4) return round(price,4)
def get_basis_price(self):
return round(self._get_basis_component_price(), 4)
def sync_linked_price_from_basis(self):
if self.enable_linked_currency and self.linked_currency:
self.linked_price = self._line_to_linked_price(
self._get_basis_component_price())
def get_price(self,lot_premium=0): def get_price(self,lot_premium=0):
return round( return (self.unit_price + Decimal(lot_premium)) if self.unit_price else Decimal(0) + (self.premium if self.premium else Decimal(0))
Decimal(self.unit_price or 0)
+ Decimal(lot_premium or 0),
4)
def get_price_linked_currency(self,lot_premium=0): def get_price_linked_currency(self,lot_premium=0):
return round( if self.linked_unit:
self._linked_to_line_price( Uom = Pool().get('product.uom')
Decimal(self.linked_price or 0) qt = Uom.compute_qty(self.unit, float(1), self.linked_unit)
+ Decimal(lot_premium or 0)), return round(((self.linked_price + Decimal(lot_premium) + (self.premium if self.premium else Decimal(0))) * self.linked_currency.factor) * Decimal(qt), 4)
4) else:
return round((self.linked_price + Decimal(lot_premium) + (self.premium if self.premium else Decimal(0))) * self.linked_currency.factor, 4)
@fields.depends('id','unit','quantity','unit_price','price_pricing','price_type','price_components','estimated_date','lots','fees','enable_linked_currency','linked_price','linked_currency','linked_unit') @fields.depends('id','unit','quantity','unit_price','price_pricing','price_type','price_components','premium','estimated_date','lots','fees','enable_linked_currency','linked_price','linked_currency','linked_unit')
def on_change_with_unit_price(self, name=None): def on_change_with_unit_price(self, name=None):
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
logger.info("ONCHANGEUNITPRICE:%s",self.unit_price) logger.info("ONCHANGEUNITPRICE:%s",self.unit_price)
if self.price_type == 'basis': if self.price_type == 'basis' and self.lots: #self.price_pricing and self.price_components and
self.sync_linked_price_from_basis()
price = self.get_basis_price() price = self.get_basis_price()
logger.info("ONCHANGEUNITPRICE_IN:%s",price) logger.info("ONCHANGEUNITPRICE_IN:%s",price)
return price return price
@@ -1351,55 +1246,7 @@ class Line(metaclass=PoolMeta):
if hasattr(self, 'derivatives') and self.derivatives: if hasattr(self, 'derivatives') and self.derivatives:
for d in self.derivatives: for d in self.derivatives:
return round(d.price_index.get_price(Date.today(),self.unit,self.purchase.currency,True),4) return round(d.price_index.get_price(Date.today(),self.unit,self.purchase.currency,True),4)
return self.get_price() return self.unit_price
@fields.depends(
'type', 'quantity', 'unit_price', 'unit', 'product',
'purchase', '_parent_purchase.currency',
'premium', 'enable_linked_currency', 'linked_currency', 'linked_unit')
def on_change_with_amount(self):
if (self.type == 'line'
and self.quantity is not None
and self.unit_price is not None):
currency = self.purchase.currency if self.purchase else None
amount = Decimal(str(self.quantity)) * (
Decimal(self.unit_price or 0) + self._get_premium_price())
if currency:
return currency.round(amount)
return amount
return Decimal(0)
@fields.depends(
'unit', 'product', 'price_type', 'enable_linked_currency',
'linked_currency', 'linked_unit', 'linked_price', 'premium',
methods=['on_change_with_unit_price', 'on_change_with_amount'])
def _recompute_trade_price_fields(self):
self.unit_price = self.on_change_with_unit_price()
self.amount = self.on_change_with_amount()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_premium(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_price_type(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_enable_linked_currency(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_price(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_currency(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_unit(self):
self._recompute_trade_price_fields()
@classmethod @classmethod
def write(cls, *args): def write(cls, *args):
@@ -1650,9 +1497,19 @@ class Line(metaclass=PoolMeta):
Pricing = Pool().get('pricing.pricing') Pricing = Pool().get('pricing.pricing')
pricings = Pricing.search(['price_component','=',pc.id],order=[('pricing_date', 'ASC')]) pricings = Pricing.search(['price_component','=',pc.id],order=[('pricing_date', 'ASC')])
if pricings: if pricings:
Pricing._sync_manual_values(pricings) cumul_qt = Decimal(0)
Pricing._sync_manual_last(pricings) index = 0
Pricing._sync_eod_price(pricings) for pr in pricings:
cumul_qt += pr.quantity
pr.fixed_qt = cumul_qt
pr.fixed_qt_price = pr.get_fixed_price()
pr.unfixed_qt = Decimal(pr.line.quantity_theorical) - pr.fixed_qt
pr.unfixed_qt_price = pr.fixed_qt_price
pr.eod_price = pr.get_eod_price_purchase()
if index == len(pricings) - 1:
pr.last = True
index += 1
Pricing.save([pr])
if pc.triggers and pc.auto: if pc.triggers and pc.auto:
prDate = [] prDate = []
@@ -1704,18 +1561,11 @@ class Line(metaclass=PoolMeta):
return pl_sorted[len(pl)-1][t] return pl_sorted[len(pl)-1][t]
return Decimal(0) return Decimal(0)
def _get_pricing_base_quantity(self):
quantity = self.quantity_theorical
if quantity is None:
quantity = self.quantity
return Decimal(str(quantity or 0))
def generate_pricing(self,pc,dl,pl): def generate_pricing(self,pc,dl,pl):
Pricing = Pool().get('pricing.pricing') Pricing = Pool().get('pricing.pricing')
pricing = Pricing.search(['price_component','=',pc.id]) pricing = Pricing.search(['price_component','=',pc.id])
if pricing: if pricing:
Pricing.delete(pricing) Pricing.delete(pricing)
base_quantity = self._get_pricing_base_quantity()
cumul_qt = 0 cumul_qt = 0
index = 0 index = 0
dl_sorted = sorted(dl) dl_sorted = sorted(dl)
@@ -1736,10 +1586,10 @@ class Line(metaclass=PoolMeta):
#p.fixed_qt_price = p.get_fixed_price() #p.fixed_qt_price = p.get_fixed_price()
if p.fixed_qt_price == 0: if p.fixed_qt_price == 0:
p.fixed_qt_price = round(Decimal(self.getnearprice(pl,d,'avg_minus_1')),4) p.fixed_qt_price = round(Decimal(self.getnearprice(pl,d,'avg_minus_1')),4)
p.unfixed_qt = round(base_quantity - Decimal(cumul_qt),5) p.unfixed_qt = round(Decimal(self.quantity_theorical) - Decimal(cumul_qt),5)
if p.unfixed_qt < 0.001: if p.unfixed_qt < 0.001:
p.unfixed_qt = Decimal(0) p.unfixed_qt = Decimal(0)
p.fixed_qt = base_quantity p.fixed_qt = Decimal(self.quantity_theorical)
if price > 0: if price > 0:
p.unfixed_qt_price = price p.unfixed_qt_price = price
else: else:

View File

@@ -105,12 +105,8 @@ class Component(metaclass=PoolMeta):
def get_quota_sale(self, name): def get_quota_sale(self, name):
if self.sale_line: if self.sale_line:
quantity = getattr(self.sale_line, 'quantity_theorical', None) if self.sale_line.quantity:
if quantity is None: return round(self.sale_line.quantity_theorical / (self.nbdays if self.nbdays > 0 else 1),4)
quantity = getattr(self.sale_line, 'quantity', None)
if quantity is not None:
nbdays = self.nbdays if self.nbdays and self.nbdays > 0 else 1
return round(Decimal(quantity) / nbdays, 4)
class Pricing(metaclass=PoolMeta): class Pricing(metaclass=PoolMeta):
"Pricing" "Pricing"
@@ -124,12 +120,9 @@ class Pricing(metaclass=PoolMeta):
return self.sale_line.unit return self.sale_line.unit
def get_eod_price_sale(self): def get_eod_price_sale(self):
return self._weighted_average_price( if self.sale_line:
self.fixed_qt, return round((self.fixed_qt * self.fixed_qt_price + self.unfixed_qt * self.unfixed_qt_price)/Decimal(self.sale_line.quantity),4)
self.fixed_qt_price, return Decimal(0)
self.unfixed_qt,
self.unfixed_qt_price,
)
class Summary(ModelSQL,ModelView): class Summary(ModelSQL,ModelView):
"Pricing summary" "Pricing summary"
@@ -260,12 +253,8 @@ class Sale(metaclass=PoolMeta):
'sale', 'sale',
'Analytic Dimensions' 'Analytic Dimensions'
) )
trader = fields.Many2One( trader = fields.Many2One('party.party',"Trader")
'party.party', "Trader", operator = fields.Many2One('party.party',"Operator")
domain=[('categories.name', '=', 'TRADER')])
operator = fields.Many2One(
'party.party', "Operator",
domain=[('categories.name', '=', 'OPERATOR')])
our_reference = fields.Char("Our Reference") our_reference = fields.Char("Our Reference")
company_visible = fields.Function( company_visible = fields.Function(
fields.Boolean("Visible"), 'on_change_with_company_visible') fields.Boolean("Visible"), 'on_change_with_company_visible')
@@ -334,331 +323,43 @@ class Sale(metaclass=PoolMeta):
def default_tol_max(cls): def default_tol_max(cls):
return 0 return 0
def _get_report_lines(self):
return [line for line in self.lines if getattr(line, 'type', None) == 'line']
def _get_report_first_line(self):
lines = self._get_report_lines()
if lines:
return lines[0]
@staticmethod
def _format_report_number(value, digits='0.0000', keep_trailing_decimal=False,
strip_trailing_zeros=True):
value = Decimal(str(value or 0)).quantize(Decimal(digits))
text = format(value, 'f')
if strip_trailing_zeros:
text = text.rstrip('0').rstrip('.')
if keep_trailing_decimal and '.' not in text:
text += '.0'
return text or '0'
def _format_report_price_words(self, line):
value = self._get_report_display_price_value(line)
currency = self._get_report_display_currency(line)
if currency and (currency.rec_name or '').upper() == 'USC':
return amount_to_currency_words(value, 'USC', 'USC')
return amount_to_currency_words(value)
def _get_report_display_currency(self, line):
if getattr(line, 'price_type', None) == 'basis':
if getattr(line, 'enable_linked_currency', False) and getattr(line, 'linked_currency', None):
return line.linked_currency
return self.currency
return getattr(line, 'linked_currency', None) or self.currency
def _get_report_display_unit(self, line):
if getattr(line, 'price_type', None) == 'basis':
if getattr(line, 'enable_linked_currency', False) and getattr(line, 'linked_unit', None):
return line.linked_unit
return getattr(line, 'unit', None)
return getattr(line, 'linked_unit', None) or getattr(line, 'unit', None)
def _get_report_display_price_value(self, line):
if getattr(line, 'price_type', None) == 'basis':
if getattr(line, 'enable_linked_currency', False) and getattr(line, 'linked_currency', None):
return Decimal(str(line.premium or 0))
return Decimal(str(line._get_premium_price() or 0))
if getattr(line, 'linked_price', None):
return Decimal(str(line.linked_price or 0))
return Decimal(str(line.unit_price or 0))
def _format_report_price_line(self, line):
currency = self._get_report_display_currency(line)
unit = self._get_report_display_unit(line)
pricing_text = getattr(line, 'get_pricing_text', '') or ''
parts = [
(currency.rec_name.upper() if currency and currency.rec_name else '').strip(),
self._format_report_number(
self._get_report_display_price_value(line),
strip_trailing_zeros=False),
'PER',
(unit.rec_name.upper() if unit and unit.rec_name else '').strip(),
f"({self._format_report_price_words(line)})",
]
if pricing_text:
parts.append(pricing_text)
return ' '.join(part for part in parts if part)
@property @property
def report_terms(self): def report_terms(self):
line = self._get_report_first_line() if self.lines:
if line: return self.lines[0].note
return line.note else:
return '' return ''
@staticmethod
def _get_report_line_lots(line):
return list(getattr(line, 'lots', []) or [])
@classmethod
def _get_report_preferred_lots(cls, line):
lots = cls._get_report_line_lots(line)
physicals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'physic'
]
if physicals:
return physicals
virtuals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'virtual'
]
if len(virtuals) == 1:
return virtuals
return []
@staticmethod
def _get_report_lot_hist_weights(lot):
if not lot:
return None, None
if hasattr(lot, 'get_hist_quantity'):
net, gross = lot.get_hist_quantity()
return (
Decimal(str(net or 0)),
Decimal(str(gross if gross not in (None, '') else net or 0)),
)
hist = list(getattr(lot, 'lot_hist', []) or [])
state = getattr(lot, 'lot_state', None)
state_id = getattr(state, 'id', None)
if state_id is not None:
for entry in hist:
quantity_type = getattr(entry, 'quantity_type', None)
if getattr(quantity_type, 'id', None) == state_id:
net = Decimal(str(getattr(entry, 'quantity', 0) or 0))
gross = Decimal(str(
getattr(entry, 'gross_quantity', None)
if getattr(entry, 'gross_quantity', None) not in (None, '')
else net))
return net, gross
return None, None
@classmethod
def _get_report_line_weights(cls, line):
lots = cls._get_report_preferred_lots(line)
if lots:
net_total = Decimal(0)
gross_total = Decimal(0)
for lot in lots:
net, gross = cls._get_report_lot_hist_weights(lot)
if net is None:
continue
net_total += net
gross_total += gross
if net_total or gross_total:
return net_total, gross_total
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return quantity, quantity
@classmethod
def _get_report_line_unit(cls, line):
lots = cls._get_report_preferred_lots(line)
if lots and getattr(lots[0], 'lot_unit_line', None):
return lots[0].lot_unit_line
return getattr(line, 'unit', None)
def _get_report_total_unit(self):
virtual_units = []
for line in self._get_report_lines():
for lot in self._get_report_line_lots(line):
if (
getattr(lot, 'lot_type', None) == 'virtual'
and getattr(lot, 'lot_unit_line', None)):
virtual_units.append(lot.lot_unit_line)
if len(virtual_units) == 1:
return virtual_units[0]
line = self._get_report_first_line()
if line:
return self._get_report_line_unit(line)
return None
@staticmethod
def _get_report_unit_wording(unit):
label = ''
for attr in ('symbol', 'rec_name', 'name'):
value = getattr(unit, attr, None)
if value:
label = str(value).strip().upper()
break
mapping = {
'MT': ('METRIC TON', 'METRIC TONS'),
'METRIC TON': ('METRIC TON', 'METRIC TONS'),
'METRIC TONS': ('METRIC TON', 'METRIC TONS'),
'KG': ('KILOGRAM', 'KILOGRAMS'),
'KGS': ('KILOGRAM', 'KILOGRAMS'),
'KILOGRAM': ('KILOGRAM', 'KILOGRAMS'),
'KILOGRAMS': ('KILOGRAM', 'KILOGRAMS'),
'LB': ('POUND', 'POUNDS'),
'LBS': ('POUND', 'POUNDS'),
'POUND': ('POUND', 'POUNDS'),
'POUNDS': ('POUND', 'POUNDS'),
'BALE': ('BALE', 'BALES'),
'BALES': ('BALE', 'BALES'),
}
if label in mapping:
return mapping[label]
if label.endswith('S') and len(label) > 1:
return label[:-1], label
return label, label
@classmethod
def _report_quantity_to_words(cls, quantity, unit):
singular, plural = cls._get_report_unit_wording(unit)
return quantity_to_words(
quantity,
unit_singular=singular,
unit_plural=plural,
)
@staticmethod
def _convert_report_quantity(quantity, from_unit, to_unit):
value = Decimal(str(quantity or 0))
if not from_unit or not to_unit:
return value
if getattr(from_unit, 'id', None) == getattr(to_unit, 'id', None):
return value
from_name = getattr(from_unit, 'rec_name', None)
to_name = getattr(to_unit, 'rec_name', None)
if from_name and to_name and from_name == to_name:
return value
Uom = Pool().get('product.uom')
converted = Uom.compute_qty(from_unit, float(value), to_unit) or 0
return Decimal(str(converted))
def _get_report_total_weight(self, index):
lines = self._get_report_lines()
if not lines:
return None
total_unit = self._get_report_total_unit()
total = Decimal(0)
for line in lines:
quantity = self._get_report_line_weights(line)[index]
total += self._convert_report_quantity(
quantity,
self._get_report_line_unit(line),
total_unit,
)
return total
@property @property
def report_gross(self): def report_gross(self):
total = self._get_report_total_weight(1) if self.lines:
if total is not None: return sum([l.get_current_gross_quantity() for l in self.lines[0].lots if l.lot_type == 'physic'])
return total else:
return '' return ''
@property @property
def report_net(self): def report_net(self):
total = self._get_report_total_weight(0) if self.lines:
if total is not None: return sum([l.get_current_quantity() for l in self.lines[0].lots if l.lot_type == 'physic'])
return total else:
return '' return ''
@property
def report_total_quantity(self):
total = self._get_report_total_weight(0)
if total is not None:
return self._format_report_number(total, keep_trailing_decimal=True)
return '0.0'
@property
def report_quantity_unit_upper(self):
line = self._get_report_first_line()
unit = self._get_report_line_unit(line) if line else None
if unit and unit.rec_name:
return unit.rec_name.upper()
return ''
def _get_report_line_quantity(self, line):
return self._get_report_line_weights(line)[0]
@property @property
def report_qt(self): def report_qt(self):
total = self._get_report_total_weight(0) if self.lines:
if total is not None: return quantity_to_words(self.lines[0].quantity)
return self._report_quantity_to_words( else:
total, self._get_report_total_unit())
return '' return ''
@property
def report_quantity_lines(self):
lines = self._get_report_lines()
if not lines:
return ''
details = []
for line in lines:
current_quantity = self._get_report_line_quantity(line)
quantity = self._format_report_number(
current_quantity, keep_trailing_decimal=True)
line_unit = self._get_report_line_unit(line)
unit = (
line_unit.rec_name.upper()
if line_unit and line_unit.rec_name else ''
)
words = self._report_quantity_to_words(current_quantity, line_unit)
period = line.del_period.description if getattr(line, 'del_period', None) else ''
detail = ' '.join(
part for part in [
quantity,
unit,
f"({words})",
f"- {period}" if period else '',
] if part)
if detail:
details.append(detail)
return '\n'.join(details)
@property @property
def report_nb_bale(self): def report_nb_bale(self):
text_bale = 'NB BALES: '
nb_bale = 0 nb_bale = 0
lines = self._get_report_lines() if self.lines:
if lines: for line in self.lines:
for line in lines:
if line.lots: if line.lots:
nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic']) nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
if nb_bale: return text_bale + str(int(nb_bale))
return 'NB BALES: ' + str(int(nb_bale))
return ''
@property
def report_product_name(self):
line = self._get_report_first_line()
if line and line.product:
return line.product.name or ''
return ''
@property
def report_product_description(self):
line = self._get_report_first_line()
if line and line.product:
return line.product.description or ''
return ''
@property
def report_crop_name(self):
if self.crop:
return self.crop.name or ''
return ''
@property @property
def report_deal(self): def report_deal(self):
@@ -671,9 +372,8 @@ class Sale(metaclass=PoolMeta):
def report_packing(self): def report_packing(self):
nb_packing = 0 nb_packing = 0
unit = '' unit = ''
lines = self._get_report_lines() if self.lines:
if lines: for line in self.lines:
for line in lines:
if line.lots: if line.lots:
nb_packing += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic']) nb_packing += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
if len(line.lots)>1: if len(line.lots)>1:
@@ -682,44 +382,17 @@ class Sale(metaclass=PoolMeta):
@property @property
def report_price(self): def report_price(self):
line = self._get_report_first_line() if self.lines:
if line: if self.lines[0].price_type == 'priced':
return self._format_report_price_words(line) if self.lines[0].linked_price:
return amount_to_currency_words(self.lines[0].linked_price,'USC','USC')
else:
return amount_to_currency_words(self.lines[0].unit_price)
elif self.lines[0].price_type == 'basis':
return amount_to_currency_words(self.lines[0].unit_price) + ' ' + self.lines[0].get_pricing_text()
else:
return '' return ''
@property
def report_price_lines(self):
lines = self._get_report_lines()
if lines:
return '\n'.join(self._format_report_price_line(line) for line in lines)
return ''
@property
def report_trade_blocks(self):
lines = self._get_report_lines()
blocks = []
for line in lines:
current_quantity = self._get_report_line_quantity(line)
quantity = self._format_report_number(
current_quantity, keep_trailing_decimal=True)
line_unit = self._get_report_line_unit(line)
unit = (
line_unit.rec_name.upper()
if line_unit and line_unit.rec_name else ''
)
words = self._report_quantity_to_words(current_quantity, line_unit)
period = line.del_period.description if getattr(line, 'del_period', None) else ''
quantity_line = ' '.join(
part for part in [
quantity,
unit,
f"({words})",
f"- {period}" if period else '',
] if part)
price_line = self._format_report_price_line(line)
blocks.append((quantity_line, price_line))
return blocks
@property @property
def report_delivery(self): def report_delivery(self):
del_date = 'PROMPT' del_date = 'PROMPT'
@@ -732,81 +405,17 @@ class Sale(metaclass=PoolMeta):
del_date = format_date_en(del_date) del_date = format_date_en(del_date)
return del_date return del_date
@property
def report_delivery_period_description(self):
line = self._get_report_first_line()
if line and line.del_period:
return line.del_period.description or ''
return ''
@property
def report_shipment_periods(self):
periods = []
for line in self._get_report_lines():
period = line.del_period.description if line.del_period else ''
if period and period not in periods:
periods.append(period)
if periods:
return '\n'.join(periods)
return ''
@property @property
def report_payment_date(self): def report_payment_date(self):
line = self._get_report_first_line() if self.lines:
if line:
if self.lc_date: if self.lc_date:
return format_date_en(self.lc_date) return format_date_en(self.lc_date)
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
payment_date = line.sale.payment_term.lines[0].get_date(Date.today(), line) payment_date = self.lines[0].sale.payment_term.lines[0].get_date(Date.today(),self.lines[0])
if payment_date: if payment_date:
payment_date = format_date_en(payment_date) payment_date = format_date_en(payment_date)
return payment_date return payment_date
def _get_report_bill_amount(self):
invoices = [
invoice for invoice in (self.invoices or [])
if getattr(invoice, 'state', None) != 'cancelled'
]
if invoices:
invoice = sorted(
invoices,
key=lambda i: (
getattr(i, 'invoice_date', None) or datetime.date.min,
getattr(i, 'id', 0)))[0]
return Decimal(str(getattr(invoice, 'total_amount', 0) or 0))
return Decimal(str(self.total_amount or 0))
@property
def report_bill_amount(self):
return self._get_report_bill_amount()
@property
def report_bill_amount_words(self):
value = self._get_report_bill_amount()
if self.currency and (self.currency.rec_name or '').upper() == 'USC':
return amount_to_currency_words(value, 'USC', 'USC')
return amount_to_currency_words(value)
@property
def report_bill_maturity_date(self):
maturity_dates = []
for invoice in (self.invoices or []):
if getattr(invoice, 'state', None) == 'cancelled':
continue
for line in (invoice.lines_to_pay or []):
if getattr(line, 'maturity_date', None):
maturity_dates.append(line.maturity_date)
if maturity_dates:
return min(maturity_dates)
if self.lc_date:
return self.lc_date
line = self._get_report_first_line()
if line and self.payment_term and self.payment_term.lines:
Date = Pool().get('ir.date')
return self.payment_term.lines[0].get_date(Date.today(), line)
@property @property
def report_shipment(self): def report_shipment(self):
if self.lines: if self.lines:
@@ -939,10 +548,8 @@ class Sale(metaclass=PoolMeta):
# OpenPosition.create_from_sale_line(line) # OpenPosition.create_from_sale_line(line)
if line.price_type == 'basis' and line.lots: #line.price_pricing and line.price_components and if line.price_type == 'basis' and line.lots: #line.price_pricing and line.price_components and
previous_linked_price = line.linked_price
line.sync_linked_price_from_basis()
unit_price = line.get_basis_price() unit_price = line.get_basis_price()
if unit_price != line.unit_price or line.linked_price != previous_linked_price: if unit_price != line.unit_price:
Line = Pool().get('sale.line') Line = Pool().get('sale.line')
line.unit_price = unit_price line.unit_price = unit_price
Line.save([line]) Line.save([line])
@@ -960,21 +567,10 @@ class PriceComposition(metaclass=PoolMeta):
class SaleLine(metaclass=PoolMeta): class SaleLine(metaclass=PoolMeta):
__name__ = 'sale.line' __name__ = 'sale.line'
@classmethod
def default_pricing_rule(cls):
try:
Configuration = Pool().get('purchase_trade.configuration')
except KeyError:
return ''
configurations = Configuration.search([], limit=1)
if configurations:
return configurations[0].pricing_rule or ''
return ''
del_period = fields.Many2One('product.month',"Delivery Period") del_period = fields.Many2One('product.month',"Delivery Period")
lots = fields.One2Many('lot.lot','sale_line',"Lots",readonly=True) lots = fields.One2Many('lot.lot','sale_line',"Lots",readonly=True)
fees = fields.One2Many('fee.fee', 'sale_line', 'Fees') fees = fields.One2Many('fee.fee', 'sale_line', 'Fees')
quantity_theorical = fields.Numeric("Th. quantity", digits='unit', readonly=False) quantity_theorical = fields.Numeric("Th. quantity", digits='unit', readonly=True)
premium = fields.Numeric("Premium/Discount",digits='unit') premium = fields.Numeric("Premium/Discount",digits='unit')
price_type = fields.Selection([ price_type = fields.Selection([
('cash', 'Cash Price'), ('cash', 'Cash Price'),
@@ -1028,17 +624,13 @@ class SaleLine(metaclass=PoolMeta):
enable_linked_currency = fields.Boolean("Linked currencies") enable_linked_currency = fields.Boolean("Linked currencies")
linked_price = fields.Numeric("Price", digits='unit',states={ linked_price = fields.Numeric("Price", digits='unit',states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
'readonly': Eval('price_type') == 'basis',
}, depends=['enable_linked_currency', 'price_type'])
linked_currency = fields.Many2One('currency.linked',"Currency",states={ linked_currency = fields.Many2One('currency.linked',"Currency",states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
}, depends=['enable_linked_currency'])
linked_unit = fields.Many2One('product.uom', 'Unit',states={ linked_unit = fields.Many2One('product.uom', 'Unit',states={
'invisible': (~Eval('enable_linked_currency')), 'invisible': (~Eval('enable_linked_currency')),
'required': Eval('enable_linked_currency'), })
}, depends=['enable_linked_currency'])
premium = fields.Numeric("Premium/Discount",digits='unit') premium = fields.Numeric("Premium/Discount",digits='unit')
fee_ = fields.Many2One('fee.fee',"Fee") fee_ = fields.Many2One('fee.fee',"Fee")
@@ -1081,20 +673,12 @@ class SaleLine(metaclass=PoolMeta):
@property @property
def get_pricing_text(self): def get_pricing_text(self):
parts = [] pricing_text = ''
if self.price_components: if self.price_components:
for pc in self.price_components: for pc in self.price_components:
if pc.price_index: if pc.price_index:
price_desc = pc.price_index.price_desc or '' pricing_text += 'ON ' + pc.price_index.price_desc + ' ' + (pc.price_index.price_period.description if pc.price_index.price_period else '')
period_desc = ( return pricing_text
pc.price_index.price_period.description
if pc.price_index.price_period else '') or ''
part = ' '.join(
piece for piece in ['ON', price_desc, period_desc]
if piece)
if part:
parts.append(part)
return ' '.join(parts)
@fields.depends('product') @fields.depends('product')
def on_change_with_attribute_set(self, name=None): def on_change_with_attribute_set(self, name=None):
@@ -1171,72 +755,17 @@ class SaleLine(metaclass=PoolMeta):
PS = Pool().get('sale.pricing.summary') PS = Pool().get('sale.pricing.summary')
ps = PS.search(['sale_line','=',self.id]) ps = PS.search(['sale_line','=',self.id])
if ps: if ps:
if not self.price_components:
manual = [e for e in ps if not e.price_component]
if manual:
return manual[0].progress or 0
return sum((e.progress if e.progress else 0) * (e.ratio if e.ratio else 0) / 100 for e in ps) return sum((e.progress if e.progress else 0) * (e.ratio if e.ratio else 0) / 100 for e in ps)
def getVirtualLot(self): def getVirtualLot(self):
if self.lots: if self.lots:
return [l for l in self.lots if l.lot_type=='virtual'][0] return [l for l in self.lots if l.lot_type=='virtual'][0]
def _get_linked_unit_factor(self):
if not (self.enable_linked_currency and self.linked_currency):
return None
factor = Decimal(self.linked_currency.factor or 0)
if not factor:
return None
unit_factor = Decimal(1)
if self.linked_unit:
source_unit = getattr(self, 'unit', None)
if not source_unit and self.product:
source_unit = self.product.sale_uom
if not source_unit:
return factor
Uom = Pool().get('product.uom')
unit_factor = Decimal(str(
Uom.compute_qty(source_unit, float(1), self.linked_unit) or 0))
return factor * unit_factor
def _linked_to_line_price(self, price):
factor = self._get_linked_unit_factor()
price = Decimal(price or 0)
if not factor:
return price
return round(price * factor, 4)
def _line_to_linked_price(self, price):
factor = self._get_linked_unit_factor()
price = Decimal(price or 0)
if not factor:
return price
return round(price / factor, 4)
def _get_premium_price(self):
premium = Decimal(self.premium or 0)
if not premium:
return Decimal(0)
if self.enable_linked_currency and self.linked_currency:
return self._linked_to_line_price(premium)
return premium
def get_price(self,lot_premium=0): def get_price(self,lot_premium=0):
return round( return (self.unit_price + Decimal(lot_premium) + (self.premium if self.premium else Decimal(0))) if self.unit_price else Decimal(0)
Decimal(self.unit_price or 0)
+ Decimal(lot_premium or 0),
4)
def _get_basis_component_price(self): def get_basis_price(self):
price = Decimal(0) price = Decimal(0)
if not self.price_components:
PP = Pool().get('sale.pricing.summary')
pp = PP.search([
('sale_line', '=', self.id),
('price_component', '=', None),
], limit=1)
if pp:
return round(Decimal(pp[0].price or 0), 4)
for pc in self.price_components: for pc in self.price_components:
PP = Pool().get('sale.pricing.summary') PP = Pool().get('sale.pricing.summary')
pp = PP.search([('price_component','=',pc.id),('sale_line','=',self.id)]) pp = PP.search([('price_component','=',pc.id),('sale_line','=',self.id)])
@@ -1244,27 +773,19 @@ class SaleLine(metaclass=PoolMeta):
price += pp[0].price * (pc.ratio / 100) price += pp[0].price * (pc.ratio / 100)
return round(price,4) return round(price,4)
def get_basis_price(self):
return round(self._get_basis_component_price(), 4)
def sync_linked_price_from_basis(self):
if self.enable_linked_currency and self.linked_currency:
self.linked_price = self._line_to_linked_price(
self._get_basis_component_price())
def get_price_linked_currency(self,lot_premium=0): def get_price_linked_currency(self,lot_premium=0):
return round( if self.linked_unit:
self._linked_to_line_price( Uom = Pool().get('product.uom')
Decimal(self.linked_price or 0) qt = Uom.compute_qty(self.unit, float(1), self.linked_unit)
+ Decimal(lot_premium or 0)), return round(((self.linked_price + Decimal(lot_premium) + (self.premium if self.premium else Decimal(0))) * self.linked_currency.factor) * Decimal(qt), 4)
4) else:
return round((self.linked_price + Decimal(lot_premium) + (self.premium if self.premium else Decimal(0))) * self.linked_currency.factor, 4)
@fields.depends('id','unit','quantity','unit_price','price_pricing','price_type','price_components','estimated_date','lots','fees','enable_linked_currency','linked_price','linked_currency','linked_unit') @fields.depends('id','unit','quantity','unit_price','price_pricing','price_type','price_components','premium','estimated_date','lots','fees','enable_linked_currency','linked_price','linked_currency','linked_unit')
def on_change_with_unit_price(self, name=None): def on_change_with_unit_price(self, name=None):
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
logger.info("ONCHANGEUNITPRICE:%s",self.unit_price) logger.info("ONCHANGEUNITPRICE:%s",self.unit_price)
if self.price_type == 'basis': if self.price_type == 'basis' and self.lots: #self.price_pricing and self.price_components and
self.sync_linked_price_from_basis()
logger.info("ONCHANGEUNITPRICE_IN:%s",self.get_basis_price()) logger.info("ONCHANGEUNITPRICE_IN:%s",self.get_basis_price())
return self.get_basis_price() return self.get_basis_price()
if self.enable_linked_currency and self.linked_price and self.linked_currency and self.price_type == 'priced': if self.enable_linked_currency and self.linked_price and self.linked_currency and self.price_type == 'priced':
@@ -1275,52 +796,6 @@ class SaleLine(metaclass=PoolMeta):
return d.price_index.get_price(Date.today(),self.unit,self.sale.currency,True) return d.price_index.get_price(Date.today(),self.unit,self.sale.currency,True)
return self.get_price() return self.get_price()
@fields.depends(
'type', 'quantity', 'unit_price', 'unit', 'product',
'sale', '_parent_sale.currency',
'premium', 'enable_linked_currency', 'linked_currency', 'linked_unit')
def on_change_with_amount(self):
if self.type == 'line':
currency = self.sale.currency if self.sale else None
amount = Decimal(str(self.quantity or 0)) * (
Decimal(self.unit_price or 0) + self._get_premium_price())
if currency:
return currency.round(amount)
return amount
return Decimal(0)
@fields.depends(
'unit', 'product', 'price_type', 'enable_linked_currency',
'linked_currency', 'linked_unit', 'linked_price', 'premium',
methods=['on_change_with_unit_price', 'on_change_with_amount'])
def _recompute_trade_price_fields(self):
self.unit_price = self.on_change_with_unit_price()
self.amount = self.on_change_with_amount()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_premium(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_price_type(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_enable_linked_currency(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_price(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_currency(self):
self._recompute_trade_price_fields()
@fields.depends(methods=['_recompute_trade_price_fields'])
def on_change_linked_unit(self):
self._recompute_trade_price_fields()
def check_from_to(self,tr): def check_from_to(self,tr):
if tr.pricing_period: if tr.pricing_period:
date_from,date_to, d, include, dates = tr.getDateWithEstTrigger(1) date_from,date_to, d, include, dates = tr.getDateWithEstTrigger(1)
@@ -1344,9 +819,19 @@ class SaleLine(metaclass=PoolMeta):
Pricing = Pool().get('pricing.pricing') Pricing = Pool().get('pricing.pricing')
pricings = Pricing.search(['price_component','=',pc.id],order=[('pricing_date', 'ASC')]) pricings = Pricing.search(['price_component','=',pc.id],order=[('pricing_date', 'ASC')])
if pricings: if pricings:
Pricing._sync_manual_values(pricings) cumul_qt = Decimal(0)
Pricing._sync_manual_last(pricings) index = 0
Pricing._sync_eod_price(pricings) for pr in pricings:
cumul_qt += pr.quantity
pr.fixed_qt = cumul_qt
pr.fixed_qt_price = pr.get_fixed_price()
pr.unfixed_qt = Decimal(pr.sale_line.quantity_theorical) - pr.fixed_qt
pr.unfixed_qt_price = pr.fixed_qt_price
pr.eod_price = pr.get_eod_price_sale()
if index == len(pricings) - 1:
pr.last = True
index += 1
Pricing.save([pr])
if pc.triggers and pc.auto: if pc.triggers and pc.auto:
prDate = [] prDate = []
@@ -1398,18 +883,11 @@ class SaleLine(metaclass=PoolMeta):
return pl_sorted[len(pl)-1][t] return pl_sorted[len(pl)-1][t]
return Decimal(0) return Decimal(0)
def _get_pricing_base_quantity(self):
quantity = self.quantity_theorical
if quantity is None:
quantity = self.quantity
return Decimal(str(quantity or 0))
def generate_pricing(self,pc,dl,pl): def generate_pricing(self,pc,dl,pl):
Pricing = Pool().get('pricing.pricing') Pricing = Pool().get('pricing.pricing')
pricing = Pricing.search(['price_component','=',pc.id]) pricing = Pricing.search(['price_component','=',pc.id])
if pricing: if pricing:
Pricing.delete(pricing) Pricing.delete(pricing)
base_quantity = self._get_pricing_base_quantity()
cumul_qt = 0 cumul_qt = 0
index = 0 index = 0
dl_sorted = sorted(dl) dl_sorted = sorted(dl)
@@ -1432,10 +910,10 @@ class SaleLine(metaclass=PoolMeta):
#p.fixed_qt_price = p.get_fixed_price() #p.fixed_qt_price = p.get_fixed_price()
if p.fixed_qt_price == 0: if p.fixed_qt_price == 0:
p.fixed_qt_price = round(Decimal(self.getnearprice(pl,d,'avg_minus_1',pc.pricing_date)),4) p.fixed_qt_price = round(Decimal(self.getnearprice(pl,d,'avg_minus_1',pc.pricing_date)),4)
p.unfixed_qt = round(base_quantity - Decimal(cumul_qt),4) p.unfixed_qt = round(Decimal(self.quantity_theorical) - Decimal(cumul_qt),4)
if p.unfixed_qt < 0.001: if p.unfixed_qt < 0.001:
p.unfixed_qt = Decimal(0) p.unfixed_qt = Decimal(0)
p.fixed_qt = base_quantity p.fixed_qt = Decimal(self.quantity_theorical)
if price > 0: if price > 0:
logger.info("GENERATE_1:%s",price) logger.info("GENERATE_1:%s",price)
p.unfixed_qt_price = price p.unfixed_qt_price = price
@@ -1451,77 +929,28 @@ class SaleLine(metaclass=PoolMeta):
Pricing.save([p]) Pricing.save([p])
index += 1 index += 1
@classmethod # @classmethod
def write(cls, *args): # def write(cls, records, values):
Lot = Pool().get('lot.lot') # if 'quantity' in values:
LotQt = Pool().get('lot.qt') # for record in records:
old_values = {} # old_qt = record.quantity
# new_qt = values['quantity']
# logger.info("WRITE_OLD_QT:%s",old_qt)
# logger.info("WRITE_NEW_QT:%s",new_qt)
# if old_qt != new_qt:
# LotQt = Pool().get('lot.qt')
# lqts = LotQt.search(['lot_s','=',record.lots[0]])
# if len(lqts)>1:
# raise UserError("You cannot changed quantity with open quantities defined !")
# return
# elif len(lqts)==1:
# if lqts[0].lot_p or lqts[0].lot_shipment_origin:
# raise UserError("You cannot changed quantity with open quantities defined !")
# return
# lqts[0].lot_quantity = new_qt
# LotQt.save(lqts)
for records, values in zip(args[::2], args[1::2]): # super().write(records, values)
if 'quantity_theorical' in values:
for record in records:
old_values[record.id] = record.quantity_theorical
super().write(*args)
lines = sum(args[::2], [])
for line in lines:
if line.id not in old_values:
continue
old = Decimal(old_values[line.id] or 0)
new = Decimal(line.quantity_theorical or 0)
delta = new - old
if delta == 0:
continue
virtual_lots = [
lot for lot in (line.lots or [])
if lot.lot_type == 'virtual'
]
if not virtual_lots:
continue
vlot = virtual_lots[0]
lqts = LotQt.search([
('lot_s', '=', vlot.id),
('lot_p', '=', None),
('lot_shipment_in', '=', None),
('lot_shipment_internal', '=', None),
('lot_shipment_out', '=', None),
])
if delta > 0:
new_qty = round(
Decimal(vlot.get_current_quantity_converted() or 0) + delta,
5)
vlot.set_current_quantity(new_qty, new_qty, 1)
Lot.save([vlot])
if lqts:
lqt = lqts[0]
lqt.lot_quantity = round(
Decimal(lqt.lot_quantity or 0) + delta, 5)
LotQt.save([lqt])
else:
lqt = LotQt()
lqt.lot_p = None
lqt.lot_s = vlot.id
lqt.lot_quantity = round(delta, 5)
lqt.lot_unit = line.unit
LotQt.save([lqt])
elif delta < 0:
decrease = abs(delta)
if not lqts or Decimal(lqts[0].lot_quantity or 0) < decrease:
raise UserError("Please unlink or unmatch lot")
new_qty = round(
Decimal(vlot.get_current_quantity_converted() or 0)
- decrease,
5)
vlot.set_current_quantity(new_qty, new_qty, 1)
Lot.save([vlot])
lqt = lqts[0]
lqt.lot_quantity = round(
Decimal(lqt.lot_quantity or 0) - decrease, 5)
LotQt.save([lqt])
@classmethod @classmethod
def delete(cls, lines): def delete(cls, lines):
@@ -1563,7 +992,6 @@ class SaleLine(metaclass=PoolMeta):
def validate(cls, salelines): def validate(cls, salelines):
LotQtHist = Pool().get('lot.qt.hist') LotQtHist = Pool().get('lot.qt.hist')
LotQtType = Pool().get('lot.qt.type') LotQtType = Pool().get('lot.qt.type')
Pnl = Pool().get('valuation.valuation')
super(SaleLine, cls).validate(salelines) super(SaleLine, cls).validate(salelines)
for line in salelines: for line in salelines:
if line.price_components: if line.price_components:
@@ -1607,20 +1035,16 @@ class SaleLine(metaclass=PoolMeta):
#generate valuation for purchase and sale #generate valuation for purchase and sale
LotQt = Pool().get('lot.qt') LotQt = Pool().get('lot.qt')
line = cls(line.id)
generated_purchase_side = False
if line.lots: if line.lots:
for lot in line.lots: for lot in line.lots:
lqts = LotQt.search([('lot_s','=',lot.id),('lot_p','>',0)]) lqts = LotQt.search([('lot_s','=',lot.id),('lot_p','>',0)])
logger.info("VALIDATE_SL:%s",lqts) logger.info("VALIDATE_SL:%s",lqts)
if lqts: if lqts:
generated_purchase_side = True
purchase_lines = [e.lot_p.line for e in lqts] purchase_lines = [e.lot_p.line for e in lqts]
if purchase_lines: if purchase_lines:
for pl in purchase_lines: for pl in purchase_lines:
Pnl = Pool().get('valuation.valuation')
Pnl.generate(pl) Pnl.generate(pl)
if line.lots and not generated_purchase_side:
Pnl.generate_from_sale_line(line)
class SaleCreatePurchase(Wizard): class SaleCreatePurchase(Wizard):
"Create mirror purchase" "Create mirror purchase"
@@ -1761,7 +1185,6 @@ class ValuationDyn(metaclass=PoolMeta):
Sum(val.amount).as_('r_amount'), Sum(val.amount).as_('r_amount'),
Sum(val.base_amount).as_('r_base_amount'), Sum(val.base_amount).as_('r_base_amount'),
Sum(val.rate).as_('r_rate'), Sum(val.rate).as_('r_rate'),
Avg(val.mtm_price).as_('r_mtm_price'),
Sum(val.mtm).as_('r_mtm'), Sum(val.mtm).as_('r_mtm'),
Max(val.strategy).as_('r_strategy'), Max(val.strategy).as_('r_strategy'),
Max(val.lot).as_('r_lot'), Max(val.lot).as_('r_lot'),

View File

@@ -4,7 +4,6 @@ import logging
from trytond.pool import Pool from trytond.pool import Pool
from trytond.transaction import Transaction from trytond.transaction import Transaction
from trytond.exceptions import UserError
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -36,11 +35,16 @@ class ContractFactory:
Date = pool.get('ir.date') Date = pool.get('ir.date')
created = [] created = []
sources = cls._get_sources(ct, type_)
base_contract = cls._get_base_contract(sources, ct, type_) base_contract = (
ct.lot.sale_line.sale
if type_ == 'Purchase'
else ct.lot.line.purchase
)
for c in contracts: for c in contracts:
contract = Purchase() if type_ == 'Purchase' else Sale() contract = Purchase() if type_ == 'Purchase' else Sale()
line = PurchaseLine() if type_ == 'Purchase' else SaleLine()
# ---------- CONTRACT ---------- # ---------- CONTRACT ----------
parts = c.currency_unit.split("_") parts = c.currency_unit.split("_")
@@ -75,13 +79,9 @@ class ContractFactory:
contract.save() contract.save()
line_sources = cls._get_line_sources(c, sources, ct)
for source in line_sources:
line = PurchaseLine() if type_ == 'Purchase' else SaleLine()
# ---------- LINE ---------- # ---------- LINE ----------
line.quantity = source['quantity'] line.quantity = c.quantity
line.quantity_theorical = source['quantity'] line.quantity_theorical = c.quantity
line.product = ct.product line.product = ct.product
line.unit = ct.unit line.unit = ct.unit
line.price_type = c.price_type line.price_type = c.price_type
@@ -94,7 +94,10 @@ class ContractFactory:
line.sale = contract.id line.sale = contract.id
cls._apply_price(line, c, parts) cls._apply_price(line, c, parts)
cls._apply_delivery(line, c, source)
line.del_period = c.del_period
line.from_del = c.from_del
line.to_del = c.to_del
line.save() line.save()
@@ -102,7 +105,7 @@ class ContractFactory:
logger.info("CREATE_LINE_ID:%s", line.id) logger.info("CREATE_LINE_ID:%s", line.id)
if ct.matched: if ct.matched:
cls._create_lot(line, c, source, type_) cls._create_lot(line, c, ct, type_)
created.append(contract) created.append(contract)
@@ -152,124 +155,12 @@ class ContractFactory:
else: else:
line.unit_price = c.price if c.price else Decimal(0) line.unit_price = c.price if c.price else Decimal(0)
@staticmethod
def _apply_delivery(line, c, source):
source_line = source.get('trade_line')
if source.get('use_source_delivery') and source_line:
line.del_period = getattr(source_line, 'del_period', None)
line.from_del = getattr(source_line, 'from_del', None)
line.to_del = getattr(source_line, 'to_del', None)
return
line.del_period = c.del_period
line.from_del = c.from_del
line.to_del = c.to_del
@staticmethod
def _normalize_quantity(quantity):
return abs(Decimal(str(quantity or 0))).quantize(Decimal('0.00001'))
@classmethod
def _get_base_contract(cls, sources, ct, type_):
if sources:
source_lot = sources[0]['lot']
return (
source_lot.sale_line.sale
if type_ == 'Purchase'
else source_lot.line.purchase
)
return (
ct.lot.sale_line.sale
if type_ == 'Purchase'
else ct.lot.line.purchase
)
@classmethod
def _get_sources(cls, ct, type_):
pool = Pool()
LotQt = pool.get('lot.qt')
context = Transaction().context or {}
active_ids = context.get('active_ids') or []
sources = []
if active_ids:
for record_id in active_ids:
if record_id < 10000000:
continue
lqt = LotQt(record_id - 10000000)
lot = lqt.lot_p or lqt.lot_s
if not lot:
continue
trade_line = (
lot.sale_line if type_ == 'Purchase' else lot.line
)
sources.append({
'lqt': lqt,
'lot': lot,
'trade_line': trade_line,
'quantity': cls._normalize_quantity(lqt.lot_quantity),
'shipment_origin': lqt.lot_shipment_origin,
})
elif getattr(ct, 'lot', None):
lot = ct.lot
trade_line = (
lot.sale_line if type_ == 'Purchase' else lot.line
)
sources.append({
'lqt': None,
'lot': lot,
'trade_line': trade_line,
'quantity': cls._normalize_quantity(getattr(ct, 'quantity', 0)),
'shipment_origin': cls._get_shipment_origin(ct),
})
cls._validate_sources(sources, type_)
return sources
@classmethod
def _validate_sources(cls, sources, type_):
if not sources:
return
first_line = sources[0]['trade_line']
for source in sources[1:]:
line = source['trade_line']
if bool(getattr(line, 'sale', None)) != bool(getattr(first_line, 'sale', None)):
raise UserError('Selected lots must all come from the same side.')
if getattr(line.product, 'id', None) != getattr(first_line.product, 'id', None):
raise UserError('Selected lots must share the same product.')
if getattr(line.unit, 'id', None) != getattr(first_line.unit, 'id', None):
raise UserError('Selected lots must share the same unit.')
@classmethod
def _get_line_sources(cls, contract_detail, sources, ct):
if not ct.matched or len(sources) <= 1:
quantity = cls._normalize_quantity(contract_detail.quantity)
source = sources[0] if sources else {
'lot': getattr(ct, 'lot', None),
'trade_line': None,
'shipment_origin': cls._get_shipment_origin(ct),
}
return [{
**source,
'quantity': quantity,
'use_source_delivery': False,
}]
selected_total = sum(source['quantity'] for source in sources)
requested = cls._normalize_quantity(contract_detail.quantity)
if requested != selected_total:
raise UserError(
'For multi-lot matched creation, quantity must equal the total selected open quantity.'
)
return [{
**source,
'use_source_delivery': True,
} for source in sources]
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# LOT / MATCHING (repris tel quel du wizard) # LOT / MATCHING (repris tel quel du wizard)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
@classmethod @classmethod
def _create_lot(cls, line, c, source, type_): def _create_lot(cls, line, c, ct, type_):
pool = Pool() pool = Pool()
Lot = pool.get('lot.lot') Lot = pool.get('lot.lot')
LotQtHist = pool.get('lot.qt.hist') LotQtHist = pool.get('lot.qt.hist')
@@ -301,9 +192,10 @@ class ContractFactory:
lot.save() lot.save()
vlot = source['lot'] vlot = ct.lot
shipment_origin = source.get('shipment_origin') shipment_origin = cls._get_shipment_origin(ct)
qt = source['quantity']
qt = c.quantity
if type_ == 'Purchase': if type_ == 'Purchase':
if not lot.updateVirtualPart(qt, shipment_origin, vlot): if not lot.updateVirtualPart(qt, shipment_origin, vlot):

View File

@@ -25,8 +25,6 @@ import logging
import json import json
import re import re
import html import html
from trytond.exceptions import UserError
from trytond.modules.stock.shipment import SupplierShipping as BaseSupplierShipping
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -443,7 +441,6 @@ class ShipmentIn(metaclass=PoolMeta):
) )
shipment_wr = fields.One2Many('shipment.wr','shipment_in',"WR") shipment_wr = fields.One2Many('shipment.wr','shipment_in',"WR")
controller = fields.Many2One('party.party',"Controller") controller = fields.Many2One('party.party',"Controller")
surveyor = fields.Many2One('party.party', "Surveyor")
controller_target = fields.Char("Targeted controller") controller_target = fields.Char("Targeted controller")
send_instruction = fields.Boolean("Send instruction") send_instruction = fields.Boolean("Send instruction")
instructions = fields.Text("Instructions") instructions = fields.Text("Instructions")
@@ -466,333 +463,6 @@ class ShipmentIn(metaclass=PoolMeta):
if self.vessel: if self.vessel:
return self.vessel.vessel_type return self.vessel.vessel_type
def _get_report_primary_move(self):
moves = list(self.incoming_moves or self.moves or [])
return moves[0] if moves else None
def _get_report_primary_lot(self):
move = self._get_report_primary_move()
return getattr(move, 'lot', None) if move else None
def _get_report_trade_line(self):
lot = self._get_report_primary_lot()
if not lot:
return None
return getattr(lot, 'sale_line', None) or getattr(lot, 'line', None)
def _get_report_insurance_fee(self):
for fee in self.fees or []:
product = getattr(fee, 'product', None)
name = ((getattr(product, 'name', '') or '')).strip().lower()
if 'insurance' in name:
return fee
return None
def _get_report_incoming_amount_data(self):
total = Decimal('0.0')
currency = None
for move in (self.incoming_moves or []):
move_amount, move_currency = self._get_report_incoming_move_amount(
move)
total += move_amount
if not currency and move_currency:
currency = move_currency
return total, currency
def _get_report_incoming_move_amount(self, move):
quantity = Decimal(str(getattr(move, 'quantity', 0) or 0))
unit_price = getattr(move, 'unit_price', None)
if unit_price not in (None, ''):
move_currency = getattr(move, 'currency', None)
return quantity * Decimal(str(unit_price or 0)), move_currency
lot = getattr(move, 'lot', None)
line = getattr(lot, 'line', None) if lot else None
if not lot or not line:
return Decimal('0.0'), None
lot_quantity = Decimal(str(
lot.get_current_quantity_converted() or 0))
line_unit_price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
trade = getattr(line, 'purchase', None)
line_currency = getattr(trade, 'currency', None) if trade else None
return lot_quantity * line_unit_price, line_currency
@staticmethod
def _get_report_currency_text(currency):
return (
getattr(currency, 'rec_name', None)
or getattr(currency, 'code', None)
or getattr(currency, 'symbol', None)
or '')
@staticmethod
def _format_report_amount(value):
if value in (None, ''):
return ''
value = Decimal(str(value or 0)).quantize(Decimal('0.01'))
return format(value, 'f')
@staticmethod
def _format_report_quantity(value, digits='0.001'):
if value in (None, ''):
return ''
quantity = Decimal(str(value or 0)).quantize(Decimal(digits))
text = format(quantity, 'f')
return text.rstrip('0').rstrip('.') or '0'
def _get_report_trade(self):
line = self._get_report_trade_line()
if not line:
return None
return getattr(line, 'sale', None) or getattr(line, 'purchase', None)
def _get_report_weight_totals(self):
net = Decimal('0')
gross = Decimal('0')
for move in (self.incoming_moves or self.moves or []):
lot = getattr(move, 'lot', None)
if lot:
lot_net = (
lot.get_current_quantity()
if hasattr(lot, 'get_current_quantity')
else lot.get_current_quantity_converted()
if hasattr(lot, 'get_current_quantity_converted')
else getattr(move, 'quantity', 0)
)
lot_gross = (
lot.get_current_gross_quantity()
if hasattr(lot, 'get_current_gross_quantity')
else lot_net
)
net += Decimal(str(lot_net or 0))
gross += Decimal(str(lot_gross or 0))
else:
quantity = Decimal(str(getattr(move, 'quantity', 0) or 0))
net += quantity
gross += quantity
return net, gross
@property
def report_product_name(self):
line = self._get_report_trade_line()
product = getattr(line, 'product', None) if line else None
if product:
return product.name or ''
move = self._get_report_primary_move()
product = getattr(move, 'product', None) if move else None
return getattr(product, 'name', '') or ''
@property
def report_product_description(self):
line = self._get_report_trade_line()
product = getattr(line, 'product', None) if line else None
if product:
return product.description or ''
move = self._get_report_primary_move()
product = getattr(move, 'product', None) if move else None
return getattr(product, 'description', '') or ''
@property
def report_insurance_footer_ref(self):
return self.bl_number or self.number or ''
@property
def report_insurance_certificate_number(self):
return self.bl_number or self.number or ''
@property
def report_insurance_account_of(self):
line = self._get_report_trade_line()
trade = getattr(line, 'sale', None) or getattr(line, 'purchase', None)
party = getattr(trade, 'party', None) if trade else None
if party:
return party.rec_name or ''
return getattr(self.supplier, 'rec_name', '') or ''
@property
def report_insurance_goods_description(self):
name = self.report_product_name
description = self.report_product_description
if description and description != name:
return ' - '.join(part for part in [name, description] if part)
return name or description
@property
def report_insurance_loading_port(self):
return getattr(self.from_location, 'name', '') or ''
@property
def report_insurance_discharge_port(self):
return getattr(self.to_location, 'name', '') or ''
@property
def report_insurance_transport(self):
if self.vessel and self.vessel.vessel_name:
return self.vessel.vessel_name
return self.transport_type or ''
@property
def report_insurance_amount(self):
insured_amount, insured_currency = self._get_report_incoming_amount_data()
if insured_amount:
insured_amount *= Decimal('1.10')
currency_text = self._get_report_currency_text(insured_currency)
amount_text = self._format_report_amount(insured_amount)
return ' '.join(part for part in [currency_text, amount_text] if part)
fee = self._get_report_insurance_fee()
if not fee:
return ''
currency = getattr(fee, 'currency', None)
currency_text = self._get_report_currency_text(currency)
amount = self._format_report_amount(fee.get_amount())
return ' '.join(part for part in [currency_text, amount] if part)
@property
def report_insurance_incoming_amount(self):
amount, currency = self._get_report_incoming_amount_data()
currency_text = self._get_report_currency_text(currency)
amount_text = self._format_report_amount(amount)
return ' '.join(part for part in [currency_text, amount_text] if part)
@property
def report_insurance_amount_insured(self):
amount, currency = self._get_report_incoming_amount_data()
insured_amount = amount * Decimal('1.10')
currency_text = self._get_report_currency_text(currency)
amount_text = self._format_report_amount(insured_amount)
return ' '.join(part for part in [currency_text, amount_text] if part)
@property
def report_insurance_surveyor(self):
if self.surveyor:
return self.surveyor.rec_name or ''
if self.controller:
return self.controller.rec_name or ''
fee = self._get_report_insurance_fee()
supplier = getattr(fee, 'supplier', None) if fee else None
return getattr(supplier, 'rec_name', '') or ''
@property
def report_insurance_contact_surveyor(self):
return self.report_insurance_surveyor
@property
def report_insurance_issue_place_and_date(self):
Date = Pool().get('ir.date')
address = None
if self.company and getattr(self.company, 'party', None):
address = self.company.party.address_get()
place = (
getattr(address, 'city', None)
or getattr(self.company.party, 'rec_name', None)
if self.company and getattr(self.company, 'party', None) else ''
) or ''
today = Date.today()
date_text = today.strftime('%d-%m-%Y') if today else ''
return ', '.join(part for part in [place, date_text] if part)
@property
def report_packing_product_class(self):
return self.report_product_name
@property
def report_packing_contract_number(self):
trade = self._get_report_trade()
return (
getattr(trade, 'reference', None)
or getattr(trade, 'number', None)
or self.reference
or self.number
or '')
@property
def report_packing_invoice_qty(self):
quantity = self.quantity if self.quantity not in (None, '') else 0
return self._format_report_quantity(quantity)
@property
def report_packing_invoice_qty_unit(self):
unit = self.unit
return (
getattr(unit, 'symbol', None)
or getattr(unit, 'rec_name', None)
or '')
@property
def report_packing_origin(self):
trade = self._get_report_trade()
return (
getattr(trade, 'product_origin', None)
or getattr(self.from_location, 'name', None)
or '')
@property
def report_packing_product(self):
return self.report_product_name
@property
def report_packing_counterparty_name(self):
trade = self._get_report_trade()
party = getattr(trade, 'party', None) if trade else None
if party:
return party.rec_name or ''
return getattr(self.supplier, 'rec_name', '') or ''
@property
def report_packing_ship_name(self):
if self.vessel and self.vessel.vessel_name:
return self.vessel.vessel_name
return self.transport_type or ''
@property
def report_packing_loading_port(self):
return getattr(self.from_location, 'name', '') or ''
@property
def report_packing_destination_port(self):
return getattr(self.to_location, 'name', '') or ''
@property
def report_packing_chunk_number(self):
return self.bl_number or self.number or ''
@property
def report_packing_chunk_date(self):
if self.bl_date:
return self.bl_date.strftime('%d-%m-%Y')
return ''
@property
def report_packing_today_date(self):
Date = Pool().get('ir.date')
today = Date.today()
if not today:
return ''
return f"{today.strftime('%B')} {today.day}, {today.year}"
@property
def report_packing_weight_unit(self):
line = self._get_report_trade_line()
unit = getattr(line, 'unit', None) if line else None
if unit:
return (
getattr(unit, 'symbol', None)
or getattr(unit, 'rec_name', None)
or '')
return self.report_packing_invoice_qty_unit or 'KGS'
@property
def report_packing_gross_weight(self):
_, gross = self._get_report_weight_totals()
return self._format_report_quantity(gross)
@property
def report_packing_net_weight(self):
net, _ = self._get_report_weight_totals()
return self._format_report_quantity(net)
def get_rec_name(self, name=None): def get_rec_name(self, name=None):
if self.number: if self.number:
return self.number + '[' + (self.vessel.vessel_name if self.vessel else '') + (('-' + self.travel_nb) if self.travel_nb else '') + ']' return self.number + '[' + (self.vessel.vessel_name if self.vessel else '') + (('-' + self.travel_nb) if self.travel_nb else '') + ']'
@@ -824,19 +494,9 @@ class ShipmentIn(metaclass=PoolMeta):
if cc: if cc:
cc = cc[0] cc = cc[0]
controllers = PartyCategory.search(['category','=',cc.id]) controllers = PartyCategory.search(['category','=',cc.id])
prioritized = []
for c in controllers: for c in controllers:
if not c.party.IsAvailableForControl(self): if c.party.IsAvailableForControl(self):
continue return c.party
gap, rule = c.party.get_controller_execution_priority(self)
prioritized.append((
1 if rule else 0,
gap if gap is not None else Decimal('-999999'),
c.party,
))
if prioritized:
prioritized.sort(key=lambda item: (item[0], item[1]), reverse=True)
return prioritized[0][2]
def get_instructions_html(self,inv_date,inv_nb): def get_instructions_html(self,inv_date,inv_nb):
vessel = self.vessel.vessel_name if self.vessel else "" vessel = self.vessel.vessel_name if self.vessel else ""
@@ -2234,71 +1894,3 @@ class RevaluateStart(ModelView):
@classmethod @classmethod
def default_delete_after(cls): def default_delete_after(cls):
return False return False
class ShipmentTemplateReportMixin:
@classmethod
def _get_purchase_trade_configuration(cls):
Configuration = Pool().get('purchase_trade.configuration')
configurations = Configuration.search([], limit=1)
return configurations[0] if configurations else None
@classmethod
def _get_action_report_path(cls, action):
if isinstance(action, dict):
return action.get('report') or ''
return getattr(action, 'report', '') or ''
@classmethod
def _resolve_template_path(cls, field_name, default_prefix):
config = cls._get_purchase_trade_configuration()
template = getattr(config, field_name, '') if config else ''
template = (template or '').strip()
if not template:
raise UserError('No template found')
if '/' not in template:
return f'{default_prefix}/{template}'
return template
@classmethod
def _get_resolved_action(cls, action):
report_path = cls._resolve_configured_report_path(action)
if isinstance(action, dict):
resolved = dict(action)
resolved['report'] = report_path
return resolved
setattr(action, 'report', report_path)
return action
@classmethod
def _execute(cls, records, header, data, action):
resolved_action = cls._get_resolved_action(action)
return super()._execute(records, header, data, resolved_action)
class ShipmentShippingReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
__name__ = 'stock.shipment.in.shipping'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_shipping_report_template', 'stock')
class ShipmentInsuranceReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
__name__ = 'stock.shipment.in.insurance'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_insurance_report_template', 'stock')
class ShipmentPackingListReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
__name__ = 'stock.shipment.in.packing_list'
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
'shipment_packing_list_report_template', 'stock')

View File

@@ -61,30 +61,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="url">https://www.vesselfinder.com</field> <field name="url">https://www.vesselfinder.com</field>
</record> </record>
<record model="ir.action.report" id="report_shipment_in_insurance">
<field name="name">Insurance</field>
<field name="model">stock.shipment.in</field>
<field name="report_name">stock.shipment.in.insurance</field>
<field name="report">stock/insurance.fodt</field>
</record>
<record model="ir.action.keyword" id="report_shipment_in_insurance_keyword">
<field name="keyword">form_print</field>
<field name="model">stock.shipment.in,-1</field>
<field name="action" ref="report_shipment_in_insurance"/>
</record>
<record model="ir.action.report" id="report_shipment_in_packing_list">
<field name="name">Packing List</field>
<field name="model">stock.shipment.in</field>
<field name="report_name">stock.shipment.in.packing_list</field>
<field name="report">stock/packing_list.fodt</field>
</record>
<record model="ir.action.keyword" id="report_shipment_in_packing_list_keyword">
<field name="keyword">form_print</field>
<field name="model">stock.shipment.in,-1</field>
<field name="action" ref="report_shipment_in_packing_list"/>
</record>
<record model="ir.action.wizard" id="act_update_sof"> <record model="ir.action.wizard" id="act_update_sof">
<field name="name">Update with SoF PDF</field> <field name="name">Update with SoF PDF</field>
<field name="wiz_name">sof.update</field> <field name="wiz_name">sof.update</field>

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@
version=7.2.7 version=7.2.7
depends: depends:
ir ir
price
purchase purchase
sale sale
account_invoice account_invoice
@@ -16,7 +15,6 @@ xml:
sale.xml sale.xml
lot.xml lot.xml
pricing.xml pricing.xml
configuration.xml
stock.xml stock.xml
workflow.xml workflow.xml
lc.xml lc.xml
@@ -36,5 +34,4 @@ xml:
weight_report.xml weight_report.xml
dimension.xml dimension.xml
backtoback.xml backtoback.xml
invoice.xml
account.xml account.xml

View File

@@ -1,7 +1,7 @@
from trytond.model import fields from trytond.model import fields
from trytond.report import Report from trytond.report import Report
from trytond.pool import Pool, PoolMeta from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, Id, If, PYSONEncoder from trytond.pyson import Bool, Eval, Id, If
from trytond.model import (ModelSQL, ModelView) from trytond.model import (ModelSQL, ModelView)
from trytond.tools import is_full_text, lstrip_wildcard from trytond.tools import is_full_text, lstrip_wildcard
from trytond.transaction import Transaction, inactive_records from trytond.transaction import Transaction, inactive_records
@@ -10,12 +10,11 @@ from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr
from sql.conditionals import Case from sql.conditionals import Case
from sql import Column, Literal from sql import Column, Literal
from sql.functions import CurrentTimestamp, DateTrunc from sql.functions import CurrentTimestamp, DateTrunc
from trytond.wizard import Button, StateAction, StateTransition, StateView, Wizard from trytond.wizard import Button, StateTransition, StateView, Wizard
from itertools import chain, groupby from itertools import chain, groupby
from operator import itemgetter from operator import itemgetter
import datetime import datetime
import logging import logging
import re
from collections import defaultdict from collections import defaultdict
from trytond.exceptions import UserWarning, UserError from trytond.exceptions import UserWarning, UserError
@@ -35,13 +34,6 @@ VALTYPE = [
('derivative', 'Derivative'), ('derivative', 'Derivative'),
] ]
VALUATION_TYPE_GROUPS = [
('all', 'All'),
('fees', 'PnL Fees'),
('goods', 'PnL Goods'),
('derivatives', 'PnL Derivatives'),
]
class ValuationBase(ModelSQL): class ValuationBase(ModelSQL):
purchase = fields.Many2One('purchase.purchase',"Purchase") purchase = fields.Many2One('purchase.purchase',"Purchase")
line = fields.Many2One('purchase.line',"Purch. Line") line = fields.Many2One('purchase.line',"Purch. Line")
@@ -56,7 +48,6 @@ class ValuationBase(ModelSQL):
quantity = fields.Numeric("Quantity",digits=(16,5)) quantity = fields.Numeric("Quantity",digits=(16,5))
unit = fields.Many2One('product.uom',"Unit") unit = fields.Many2One('product.uom',"Unit")
amount = fields.Numeric("Amount",digits=(16,2)) amount = fields.Numeric("Amount",digits=(16,2))
mtm_price = fields.Numeric("Mtm Price", digits=(16,4))
mtm = fields.Numeric("Mtm",digits=(16,2)) mtm = fields.Numeric("Mtm",digits=(16,2))
strategy = fields.Many2One('mtm.strategy',"Strategy") strategy = fields.Many2One('mtm.strategy',"Strategy")
lot = fields.Many2One('lot.lot',"Lot") lot = fields.Many2One('lot.lot',"Lot")
@@ -64,74 +55,7 @@ class ValuationBase(ModelSQL):
rate = fields.Numeric("Rate", digits=(16,6)) rate = fields.Numeric("Rate", digits=(16,6))
@classmethod @classmethod
def _get_generate_types(cls, valuation_type='all'): def _base_pnl(cls, *, line, lot, pnl_type, sale=None):
type_map = {
'all': None,
'fees': {'line fee', 'pur. fee', 'sale fee', 'shipment fee'},
'goods': {
'priced', 'pur. priced', 'pur. efp',
'sale priced', 'sale efp', 'market',
},
'derivatives': {'derivative'},
}
return type_map.get(valuation_type, None)
@classmethod
def _filter_values_by_types(cls, values, selected_types):
if selected_types is None:
return values
return [value for value in values if value.get('type') in selected_types]
@classmethod
def _delete_existing(cls, line, selected_types=None):
Date = Pool().get('ir.date')
Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
valuation_domain = [
('line', '=', line.id),
('date', '=', Date.today()),
]
valuation_line_domain = [('line', '=', line.id)]
if selected_types is not None:
valuation_domain.append(('type', 'in', list(selected_types)))
valuation_line_domain.append(('type', 'in', list(selected_types)))
valuations = Valuation.search(valuation_domain)
if valuations:
Valuation.delete(valuations)
valuation_lines = ValuationLine.search(valuation_line_domain)
if valuation_lines:
ValuationLine.delete(valuation_lines)
@classmethod
def _delete_existing_sale_line(cls, sale_line, selected_types=None):
Date = Pool().get('ir.date')
Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
valuation_domain = [
('sale_line', '=', sale_line.id),
('date', '=', Date.today()),
]
valuation_line_domain = [('sale_line', '=', sale_line.id)]
if selected_types is not None:
valuation_domain.append(('type', 'in', list(selected_types)))
valuation_line_domain.append(('type', 'in', list(selected_types)))
valuations = Valuation.search(valuation_domain)
if valuations:
Valuation.delete(valuations)
valuation_lines = ValuationLine.search(valuation_line_domain)
if valuation_lines:
ValuationLine.delete(valuation_lines)
@classmethod
def _base_pnl(cls, *, line, lot, pnl_type, sale=None, sale_line=None):
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
values = { values = {
@@ -144,76 +68,17 @@ class ValuationBase(ModelSQL):
if sale: if sale:
values['sale'] = sale.id values['sale'] = sale.id
if sale_line:
values['sale_line'] = sale_line.id
return values return values
@classmethod @classmethod
def _base_sale_pnl(cls, *, sale_line, lot, pnl_type): def _build_basis_pnl(cls, *, line, lot, sale_line, pc, sign):
Date = Pool().get('ir.date')
return {
'sale': sale_line.sale.id,
'sale_line': sale_line.id,
'type': pnl_type,
'date': Date.today(),
'lot': lot.id,
}
@classmethod
def _get_strategy_mtm_price(cls, strategy, line):
total = Decimal(0)
scenario = getattr(strategy, 'scenario', None)
if not scenario:
return None
for comp in strategy.components or []:
value = Decimal(0)
if comp.price_source_type == 'curve' and comp.price_index:
value = Decimal(comp.price_index.get_price(
scenario.valuation_date,
line.unit,
strategy.currency,
last=scenario.use_last_price
))
elif comp.price_source_type == 'matrix' and comp.price_matrix:
value = Decimal(strategy._get_matrix_price(
comp, line, scenario.valuation_date))
total += value
return round(total, 4)
@staticmethod
def _supports_strategy_mtm(values):
return values and values.get('type') in {'pur. priced', 'sale priced'}
@staticmethod
def _get_basis_component_total(record):
getter = getattr(record, '_get_basis_component_price', None)
if getter:
return Decimal(getter() or 0)
return Decimal(0)
@classmethod
def _get_basis_premium_delta(cls, record):
premium_getter = getattr(record, '_get_premium_price', None)
if premium_getter:
return round(Decimal(premium_getter() or 0), 4)
total = Decimal(record.get_basis_price() or 0)
components = cls._get_basis_component_total(record)
return round(total - components, 4)
@classmethod
def _build_basis_pnl(cls, *, line, lot, sale_line, pc, sign, extra_price=Decimal(0)):
Currency = Pool().get('currency.currency') Currency = Pool().get('currency.currency')
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
values = cls._base_pnl( values = cls._base_pnl(
line=line, line=line,
lot=lot, lot=lot,
sale=sale_line.sale if sale_line else None, sale=sale_line.sale if sale_line else None,
sale_line=sale_line if sale_line else None,
pnl_type='sale priced' if sale_line else 'pur. priced' pnl_type='sale priced' if sale_line else 'pur. priced'
) )
@@ -226,7 +91,6 @@ class ValuationBase(ModelSQL):
logger.info("COMPONENTS:%s",c) logger.info("COMPONENTS:%s",c)
if c: if c:
price = c[0].manual_price price = c[0].manual_price
price = Decimal(price or 0) + Decimal(extra_price or 0)
values.update({ values.update({
'reference': f"{pc.get_name()} / {pc.ratio}%", 'reference': f"{pc.get_name()} / {pc.ratio}%",
@@ -260,7 +124,6 @@ class ValuationBase(ModelSQL):
'amount': amount, 'amount': amount,
'base_amount': base_amount, 'base_amount': base_amount,
'rate': rate, 'rate': rate,
'mtm_price': None,
'mtm': None, #round(amount - (mtm * pc.ratio / 100), 2), 'mtm': None, #round(amount - (mtm * pc.ratio / 100), 2),
'unit': sale_line.unit.id if sale_line else line.unit.id, 'unit': sale_line.unit.id if sale_line else line.unit.id,
'currency': currency, 'currency': currency,
@@ -276,7 +139,6 @@ class ValuationBase(ModelSQL):
line=line, line=line,
lot=lot, lot=lot,
sale=sale_line.sale if sale_line else None, sale=sale_line.sale if sale_line else None,
sale_line=sale_line if sale_line else None,
pnl_type=pnl_type pnl_type=pnl_type
) )
@@ -298,7 +160,6 @@ class ValuationBase(ModelSQL):
'amount': amount, 'amount': amount,
'base_amount': base_amount, 'base_amount': base_amount,
'rate': rate, 'rate': rate,
'mtm_price': None,
'mtm': Decimal(0), 'mtm': Decimal(0),
'state': state, 'state': state,
'unit': sale_line.unit.id if sale_line else line.unit.id, 'unit': sale_line.unit.id if sale_line else line.unit.id,
@@ -306,9 +167,9 @@ class ValuationBase(ModelSQL):
'counterparty': sale_line.sale.party.id if sale_line else line.purchase.party.id, 'counterparty': sale_line.sale.party.id if sale_line else line.purchase.party.id,
'product': sale_line.product.id if sale_line else line.product.id, 'product': sale_line.product.id if sale_line else line.product.id,
'reference': ( 'reference': (
('Sale/Physic' if lot.lot_type == 'physic' else 'Sale/Open') 'Sale/Physic' if lot.lot_type == 'physic'
if sale_line else else 'Sale/Open' if sale_line
('Purchase/Physic' if lot.lot_type == 'physic' else 'Purchase/Open') else 'Purchase/Physic'
), ),
}) })
@@ -322,44 +183,10 @@ class ValuationBase(ModelSQL):
for lot in line.lots: for lot in line.lots:
if line.price_type == 'basis': if line.price_type == 'basis':
premium_delta = cls._get_basis_premium_delta(line) for pc in line.price_summary or []:
summaries = line.price_summary or [] values = cls._build_basis_pnl(line=line, lot=lot, sale_line=None, pc=pc, sign=-1)
if not summaries: if line.mtm:
values = cls._build_simple_pnl(
line=line,
lot=lot,
sale_line=None,
price=Decimal(line.unit_price or 0) + premium_delta,
state='unfixed',
sign=-1,
pnl_type='pur. priced'
)
if values and lot.sale_line:
values['sale'] = lot.sale_line.sale.id
values['sale_line'] = lot.sale_line.id
if line.mtm and cls._supports_strategy_mtm(values):
for strat in line.mtm: for strat in line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, line)
values['mtm'] = strat.get_mtm(line, values['quantity'])
values['strategy'] = strat
if values:
price_lines.append(values)
else:
if values:
price_lines.append(values)
continue
for pc in summaries:
values = cls._build_basis_pnl(
line=line, lot=lot, sale_line=None, pc=pc, sign=-1,
extra_price=premium_delta)
if values and lot.sale_line:
values['sale'] = lot.sale_line.sale.id
values['sale_line'] = lot.sale_line.id
if line.mtm and cls._supports_strategy_mtm(values):
for strat in line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, line)
values['mtm'] = strat.get_mtm(line,values['quantity']) values['mtm'] = strat.get_mtm(line,values['quantity'])
values['strategy'] = strat values['strategy'] = strat
@@ -379,12 +206,8 @@ class ValuationBase(ModelSQL):
sign=-1, sign=-1,
pnl_type=f'pur. {line.price_type}' pnl_type=f'pur. {line.price_type}'
) )
if values and lot.sale_line: if line.mtm:
values['sale'] = lot.sale_line.sale.id
values['sale_line'] = lot.sale_line.id
if line.mtm and cls._supports_strategy_mtm(values):
for strat in line.mtm: for strat in line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, line)
values['mtm'] = strat.get_mtm(line,values['quantity']) values['mtm'] = strat.get_mtm(line,values['quantity'])
values['strategy'] = strat values['strategy'] = strat
@@ -408,14 +231,10 @@ class ValuationBase(ModelSQL):
continue continue
if sl_line.price_type == 'basis': if sl_line.price_type == 'basis':
premium_delta = cls._get_basis_premium_delta(sl_line)
for pc in sl_line.price_summary or []: for pc in sl_line.price_summary or []:
values = cls._build_basis_pnl( values = cls._build_basis_pnl(line=line, lot=sl, sale_line=sl_line, pc=pc, sign=+1)
line=line, lot=sl, sale_line=sl_line, pc=pc, sign=+1, if sl_line.mtm:
extra_price=premium_delta)
if sl_line.mtm and cls._supports_strategy_mtm(values):
for strat in line.mtm: for strat in line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, sl_line)
values['mtm'] = strat.get_mtm(sl_line,values['quantity']) values['mtm'] = strat.get_mtm(sl_line,values['quantity'])
values['strategy'] = strat values['strategy'] = strat
@@ -435,9 +254,8 @@ class ValuationBase(ModelSQL):
sign=+1, sign=+1,
pnl_type=f'sale {sl_line.price_type}' pnl_type=f'sale {sl_line.price_type}'
) )
if sl_line.mtm and cls._supports_strategy_mtm(values): if sl_line.mtm:
for strat in sl_line.mtm: for strat in sl_line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, sl_line)
values['mtm'] = strat.get_mtm(sl_line,values['quantity']) values['mtm'] = strat.get_mtm(sl_line,values['quantity'])
values['strategy'] = strat values['strategy'] = strat
@@ -449,172 +267,6 @@ class ValuationBase(ModelSQL):
return price_lines return price_lines
@classmethod
def _build_basis_pnl_from_sale_line(cls, *, sale_line, lot, pc, extra_price=Decimal(0)):
Currency = Pool().get('currency.currency')
Date = Pool().get('ir.date')
values = cls._base_sale_pnl(
sale_line=sale_line,
lot=lot,
pnl_type='sale priced'
)
qty = lot.get_current_quantity_converted()
price = Decimal(pc.price or 0) + Decimal(extra_price or 0)
values.update({
'reference': f"{pc.get_name()} / {pc.ratio}%",
'price': round(price, 4),
'counterparty': sale_line.sale.party.id,
'product': sale_line.product.id,
})
if pc.unfixed_qt == 0:
values['state'] = 'fixed'
elif pc.fixed_qt == 0:
values['state'] = 'unfixed'
else:
base = sale_line.quantity_theorical
values['state'] = f"part. fixed {round(pc.fixed_qt / Decimal(base) * 100, 0)}%"
if price is not None:
amount = round(price * qty, 2)
base_amount = amount
currency = sale_line.sale.currency.id
rate = Decimal(1)
if sale_line.sale.company.currency != currency:
with Transaction().set_context(date=Date.today()):
base_amount = Currency.compute(
currency, amount, sale_line.sale.company.currency)
rate = round(amount / (base_amount if base_amount else 1), 6)
values.update({
'quantity': round(qty, 5),
'amount': amount,
'base_amount': base_amount,
'rate': rate,
'mtm_price': None,
'mtm': None,
'unit': sale_line.unit.id,
'currency': currency,
})
return values
@classmethod
def _build_simple_pnl_from_sale_line(cls, *, sale_line, lot, price, state, pnl_type):
Currency = Pool().get('currency.currency')
Date = Pool().get('ir.date')
values = cls._base_sale_pnl(
sale_line=sale_line,
lot=lot,
pnl_type=pnl_type
)
qty = lot.get_current_quantity_converted()
amount = round(price * qty, 2)
base_amount = amount
currency = sale_line.sale.currency.id
company_currency = sale_line.sale.company.currency
rate = Decimal(1)
if sale_line.sale.company.currency != currency:
with Transaction().set_context(date=Date.today()):
base_amount = Currency.compute(currency, amount, company_currency)
if base_amount and amount:
rate = round(amount / base_amount, 6)
values.update({
'price': round(price, 4),
'quantity': round(qty, 5),
'amount': amount,
'base_amount': base_amount,
'rate': rate,
'mtm_price': None,
'mtm': Decimal(0),
'state': state,
'unit': sale_line.unit.id,
'currency': currency,
'counterparty': sale_line.sale.party.id,
'product': sale_line.product.id,
'reference': 'Sale/Physic' if lot.lot_type == 'physic' else 'Sale/Open',
})
return values
@classmethod
def _get_sale_lot_price(cls, sale_line, lot):
if lot.lot_price_sale is not None:
return lot.lot_price_sale
return sale_line.unit_price
@classmethod
def create_pnl_price_from_sale_line(cls, sale_line):
price_lines = []
for lot in sale_line.lots or []:
if sale_line.price_type == 'basis':
summaries = sale_line.price_summary or []
premium_delta = cls._get_basis_premium_delta(sale_line)
if not summaries:
values = cls._build_simple_pnl_from_sale_line(
sale_line=sale_line,
lot=lot,
price=Decimal(sale_line.unit_price or 0) + premium_delta,
state='unfixed',
pnl_type='sale priced'
)
if sale_line.mtm and cls._supports_strategy_mtm(values):
for strat in sale_line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, sale_line)
values['mtm'] = strat.get_mtm(sale_line, values['quantity'])
values['strategy'] = strat
if values:
price_lines.append(values)
else:
if values:
price_lines.append(values)
continue
for pc in summaries:
values = cls._build_basis_pnl_from_sale_line(
sale_line=sale_line, lot=lot, pc=pc,
extra_price=premium_delta)
if sale_line.mtm and cls._supports_strategy_mtm(values):
for strat in sale_line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, sale_line)
values['mtm'] = strat.get_mtm(sale_line, values['quantity'])
values['strategy'] = strat
if values:
price_lines.append(values)
else:
if values:
price_lines.append(values)
elif sale_line.price_type in ('priced', 'efp'):
price = cls._get_sale_lot_price(sale_line, lot)
if price is None:
continue
values = cls._build_simple_pnl_from_sale_line(
sale_line=sale_line,
lot=lot,
price=price,
state='fixed' if sale_line.price_type == 'priced' else 'not fixed',
pnl_type=f'sale {sale_line.price_type}'
)
if sale_line.mtm and cls._supports_strategy_mtm(values):
for strat in sale_line.mtm:
values['mtm_price'] = cls._get_strategy_mtm_price(strat, sale_line)
values['mtm'] = strat.get_mtm(sale_line, values['quantity'])
values['strategy'] = strat
if values:
price_lines.append(values)
else:
if values:
price_lines.append(values)
return price_lines
@classmethod @classmethod
def group_fees_by_type_supplier(cls,line,fees): def group_fees_by_type_supplier(cls,line,fees):
grouped = defaultdict(list) grouped = defaultdict(list)
@@ -665,6 +317,8 @@ class ValuationBase(ModelSQL):
if sf.currency != line.purchase.currency: if sf.currency != line.purchase.currency:
with Transaction().set_context(date=Date.today()): with Transaction().set_context(date=Date.today()):
price = Currency.compute(sf.currency, price, line.purchase.currency) price = Currency.compute(sf.currency, price, line.purchase.currency)
if line.mtm:
for strat in line.mtm:
fee_lines.append({ fee_lines.append({
'lot': lot.id, 'lot': lot.id,
'sale': lot.sale_line.sale.id if lot.sale_line else None, 'sale': lot.sale_line.sale.id if lot.sale_line else None,
@@ -683,54 +337,21 @@ class ValuationBase(ModelSQL):
'state': sf.type, 'state': sf.type,
'quantity': qty, 'quantity': qty,
'amount': amount, 'amount': amount,
'mtm_price': None, 'mtm': strat.get_mtm(line,qty),
'mtm': None, 'strategy': strat,
'strategy': None,
'unit': sf.unit.id if sf.unit else line.unit.id, 'unit': sf.unit.id if sf.unit else line.unit.id,
'currency': sf.currency.id, 'currency': sf.currency.id,
}) })
return fee_lines
@classmethod
def create_pnl_fee_from_sale_line(cls, sale_line):
fee_lines = []
Date = Pool().get('ir.date')
Currency = Pool().get('currency.currency')
FeeLots = Pool().get('fee.lots')
for lot in sale_line.lots or ():
fl = FeeLots.search([('lot', '=', lot.id)])
if not fl:
continue
fees = [
e.fee for e in fl
if e.fee and (not e.fee.sale_line or e.fee.sale_line.id == sale_line.id)
]
for sf in cls.group_fees_by_type_supplier(sale_line, fees):
sign = -1 if sf.p_r == 'pay' else 1
qty = round(lot.get_current_quantity_converted(), 5)
if sf.mode == 'ppack' or sf.mode == 'rate':
price = sf.price
amount = sf.amount * sign
elif sf.mode == 'lumpsum':
price = sf.price
amount = sf.price * sign
qty = 1
else: else:
price = Decimal(sf.get_price_per_qt())
amount = round(price * lot.get_current_quantity_converted() * sign, 2)
if sf.currency != sale_line.sale.currency:
with Transaction().set_context(date=Date.today()):
price = Currency.compute(sf.currency, price, sale_line.sale.currency)
fee_lines.append({ fee_lines.append({
'lot': lot.id, 'lot': lot.id,
'sale': sale_line.sale.id, 'sale': lot.sale_line.sale.id if lot.sale_line else None,
'sale_line': sale_line.id, 'purchase': line.purchase.id,
'line': line.id,
'type': ( 'type': (
'shipment fee' if sf.shipment_in 'shipment fee' if sf.shipment_in
else 'sale fee' else 'sale fee' if sf.sale_line
else 'pur. fee'
), ),
'date': Date.today(), 'date': Date.today(),
'price': price, 'price': price,
@@ -740,10 +361,9 @@ class ValuationBase(ModelSQL):
'state': sf.type, 'state': sf.type,
'quantity': qty, 'quantity': qty,
'amount': amount, 'amount': amount,
'mtm_price': None, 'mtm': Decimal(0),
'mtm': None,
'strategy': None, 'strategy': None,
'unit': sf.unit.id if sf.unit else sale_line.unit.id, 'unit': sf.unit.id if sf.unit else line.unit.id,
'currency': sf.currency.id, 'currency': sf.currency.id,
}) })
@@ -759,7 +379,7 @@ class ValuationBase(ModelSQL):
d.price, line.unit, line.purchase.currency d.price, line.unit, line.purchase.currency
)) ))
mtm_price = Decimal(d.price_index.get_price( mtm = Decimal(d.price_index.get_price(
Date.today(), line.unit, line.purchase.currency, True Date.today(), line.unit, line.purchase.currency, True
)) ))
@@ -775,8 +395,7 @@ class ValuationBase(ModelSQL):
'state': 'fixed', 'state': 'fixed',
'quantity': round(d.quantity, 5), 'quantity': round(d.quantity, 5),
'amount': round(price * d.quantity * Decimal(-1), 2), 'amount': round(price * d.quantity * Decimal(-1), 2),
'mtm_price': round(mtm_price, 4), 'mtm': round((price * d.quantity * Decimal(-1)) - (mtm * d.quantity * Decimal(-1)), 2),
'mtm': round((price * d.quantity * Decimal(-1)) - (mtm_price * d.quantity * Decimal(-1)), 2),
'unit': line.unit.id, 'unit': line.unit.id,
'currency': line.purchase.currency.id, 'currency': line.purchase.currency.id,
}) })
@@ -784,68 +403,24 @@ class ValuationBase(ModelSQL):
return der_lines return der_lines
@classmethod @classmethod
def create_pnl_der_from_sale_line(cls, sale_line): def generate(cls, line):
Date = Pool().get('ir.date') Date = Pool().get('ir.date')
der_lines = [] Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
Valuation.delete(Valuation.search([
('line', '=', line.id),
('date', '=', Date.today()),
]))
for d in sale_line.derivatives or []: ValuationLine.delete(ValuationLine.search([
price = Decimal(d.price_index.get_price_per_qt( ('line', '=', line.id),
d.price, sale_line.unit, sale_line.sale.currency ]))
))
mtm_price = Decimal(d.price_index.get_price(
Date.today(), sale_line.unit, sale_line.sale.currency, True
))
der_lines.append({
'sale': sale_line.sale.id,
'sale_line': sale_line.id,
'type': 'derivative',
'date': Date.today(),
'reference': d.price_index.price_index,
'price': round(price, 4),
'counterparty': d.party.id,
'product': d.product.id,
'state': 'fixed',
'quantity': round(d.quantity, 5),
'amount': round(price * d.quantity * Decimal(-1), 2),
'mtm_price': round(mtm_price, 4),
'mtm': round((price * d.quantity * Decimal(-1)) - (mtm_price * d.quantity * Decimal(-1)), 2),
'unit': sale_line.unit.id,
'currency': sale_line.sale.currency.id,
})
return der_lines
@classmethod
def generate(cls, line, valuation_type='all'):
selected_types = cls._get_generate_types(valuation_type)
cls._delete_existing(line, selected_types=selected_types)
values = [] values = []
values.extend(cls.create_pnl_fee_from_line(line)) values.extend(cls.create_pnl_fee_from_line(line))
values.extend(cls.create_pnl_price_from_line(line)) values.extend(cls.create_pnl_price_from_line(line))
values.extend(cls.create_pnl_der_from_line(line)) values.extend(cls.create_pnl_der_from_line(line))
values = cls._filter_values_by_types(values, selected_types)
if values:
Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
Valuation.create(values)
ValuationLine.create(values)
@classmethod
def generate_from_sale_line(cls, sale_line, valuation_type='all'):
selected_types = cls._get_generate_types(valuation_type)
cls._delete_existing_sale_line(sale_line, selected_types=selected_types)
values = []
values.extend(cls.create_pnl_fee_from_sale_line(sale_line))
values.extend(cls.create_pnl_price_from_sale_line(sale_line))
values.extend(cls.create_pnl_der_from_sale_line(sale_line))
values = cls._filter_values_by_types(values, selected_types)
if values:
Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
Valuation.create(values) Valuation.create(values)
ValuationLine.create(values) ValuationLine.create(values)
@@ -915,7 +490,6 @@ class ValuationDyn(ModelSQL,ModelView):
r_amount = fields.Numeric("Amount",digits='r_unit') r_amount = fields.Numeric("Amount",digits='r_unit')
r_base_amount = fields.Numeric("Base Amount",digits='r_unit') r_base_amount = fields.Numeric("Base Amount",digits='r_unit')
r_rate = fields.Numeric("Rate",digits=(16,6)) r_rate = fields.Numeric("Rate",digits=(16,6))
r_mtm_price = fields.Numeric("Mtm Price",digits='r_unit')
r_mtm = fields.Numeric("Mtm",digits='r_unit') r_mtm = fields.Numeric("Mtm",digits='r_unit')
r_strategy = fields.Many2One('mtm.strategy',"Strategy") r_strategy = fields.Many2One('mtm.strategy',"Strategy")
r_lot = fields.Many2One('lot.lot',"Lot") r_lot = fields.Many2One('lot.lot',"Lot")
@@ -949,7 +523,6 @@ class ValuationDyn(ModelSQL,ModelView):
Sum(val.amount).as_('r_amount'), Sum(val.amount).as_('r_amount'),
Sum(val.base_amount).as_('r_base_amount'), Sum(val.base_amount).as_('r_base_amount'),
Sum(val.rate).as_('r_rate'), Sum(val.rate).as_('r_rate'),
Avg(val.mtm_price).as_('r_mtm_price'),
Sum(val.mtm).as_('r_mtm'), Sum(val.mtm).as_('r_mtm'),
Max(val.strategy).as_('r_strategy'), Max(val.strategy).as_('r_strategy'),
Max(val.lot).as_('r_lot'), Max(val.lot).as_('r_lot'),
@@ -999,7 +572,6 @@ class ValuationReport(ValuationBase, ModelView):
val.amount.as_('amount'), val.amount.as_('amount'),
val.base_amount.as_('base_amount'), val.base_amount.as_('base_amount'),
val.rate.as_('rate'), val.rate.as_('rate'),
val.mtm_price.as_('mtm_price'),
val.mtm.as_('mtm'), val.mtm.as_('mtm'),
val.strategy.as_('strategy'), val.strategy.as_('strategy'),
val.lot.as_('lot'), val.lot.as_('lot'),
@@ -1034,297 +606,3 @@ class ValuationReportContext(ModelView):
@classmethod @classmethod
def default_state(cls): def default_state(cls):
return 'all' return 'all'
class ValuationProcessDimension(ModelView):
"Valuation Process Dimension"
__name__ = 'valuation.process.dimension'
start = fields.Many2One('valuation.process.start', "Start")
dimension = fields.Many2One(
'analytic.dimension',
'Dimension',
required=True
)
value = fields.Many2One(
'analytic.dimension.value',
'Value',
required=True,
domain=[
('dimension', '=', Eval('dimension')),
],
depends=['dimension']
)
class ValuationProcessStart(ModelView):
"Valuation Process Start"
__name__ = 'valuation.process.start'
purchase_from_date = fields.Date("Purchase From Date")
purchase_to_date = fields.Date("Purchase To Date")
sale_from_date = fields.Date("Sale From Date")
sale_to_date = fields.Date("Sale To Date")
purchase_numbers = fields.Char("Purchase Numbers")
sale_numbers = fields.Char("Sale Numbers")
analytic_dimensions = fields.One2Many(
'valuation.process.dimension',
'start',
'Analytic Dimensions'
)
valuation_type = fields.Selection(
VALUATION_TYPE_GROUPS,
"Type",
required=True
)
@classmethod
def default_valuation_type(cls):
return 'all'
class ValuationProcessResult(ModelView):
"Valuation Process Result"
__name__ = 'valuation.process.result'
message = fields.Text("Message", readonly=True)
class ValuationProcess(Wizard):
"Process Valuation"
__name__ = 'valuation.process'
start = StateView(
'valuation.process.start',
'purchase_trade.valuation_process_start_view_form',
[
Button('Cancel', 'end', 'tryton-cancel'),
Button('Process', 'process', 'tryton-ok', default=True),
]
)
process = StateTransition()
result = StateView(
'valuation.process.result',
'purchase_trade.valuation_process_result_view_form',
[
Button('Close', 'end', 'tryton-cancel'),
Button('See Valuation', 'open_report', 'tryton-go-next', default=True),
]
)
open_report = StateAction('purchase_trade.act_valuation_form')
_result_message = None
@staticmethod
def _parse_numbers(text):
if not text:
return []
return [item for item in re.split(r'[\s,;]+', text) if item]
@staticmethod
def _matches_dimensions(record, dimension_filters):
assignments = getattr(record, 'analytic_dimensions', []) or []
assignment_pairs = {
(assignment.dimension.id, assignment.value.id)
for assignment in assignments
if assignment.dimension and assignment.value
}
return all(
(dimension.id, value.id) in assignment_pairs
for dimension, value in dimension_filters
)
@classmethod
def _get_dimension_filters(cls, start):
return [
(line.dimension, line.value)
for line in start.analytic_dimensions or []
if line.dimension and line.value
]
@classmethod
def _search_purchase_ids(cls, start, dimension_filters):
Purchase = Pool().get('purchase.purchase')
domain = []
numbers = cls._parse_numbers(start.purchase_numbers)
if start.purchase_from_date:
domain.append(('purchase_date', '>=', start.purchase_from_date))
if start.purchase_to_date:
domain.append(('purchase_date', '<=', start.purchase_to_date))
if numbers:
domain.append(('number', 'in', numbers))
purchases = Purchase.search(domain)
if dimension_filters:
purchases = [
purchase for purchase in purchases
if cls._matches_dimensions(purchase, dimension_filters)
]
return {purchase.id for purchase in purchases}
@classmethod
def _search_sale_ids(cls, start, dimension_filters):
Sale = Pool().get('sale.sale')
domain = []
numbers = cls._parse_numbers(start.sale_numbers)
if start.sale_from_date:
domain.append(('sale_date', '>=', start.sale_from_date))
if start.sale_to_date:
domain.append(('sale_date', '<=', start.sale_to_date))
if numbers:
domain.append(('number', 'in', numbers))
sales = Sale.search(domain)
if dimension_filters:
sales = [sale for sale in sales if cls._matches_dimensions(sale, dimension_filters)]
return {sale.id for sale in sales}
@classmethod
def _purchase_line_ids_from_purchase_ids(cls, purchase_ids):
if not purchase_ids:
return set()
PurchaseLine = Pool().get('purchase.line')
return {
line.id for line in PurchaseLine.search([('purchase', 'in', list(purchase_ids))])
}
@classmethod
def _purchase_line_ids_from_sale_ids(cls, sale_ids):
if not sale_ids:
return set()
SaleLine = Pool().get('sale.line')
purchase_line_ids = set()
sale_lines = SaleLine.search([('sale', 'in', list(sale_ids))])
for sale_line in sale_lines:
for matched_line in sale_line.get_matched_lines() or []:
if matched_line.lot_p and matched_line.lot_p.line:
purchase_line_ids.add(matched_line.lot_p.line.id)
return purchase_line_ids
@classmethod
def _sale_line_is_unmatched(cls, sale_line):
for matched_line in sale_line.get_matched_lines() or []:
if matched_line.lot_p and matched_line.lot_p.line:
return False
return True
@classmethod
def _sale_line_ids_from_sale_ids(cls, sale_ids, unmatched_only=False):
if not sale_ids:
return set()
SaleLine = Pool().get('sale.line')
sale_lines = SaleLine.search([('sale', 'in', list(sale_ids))])
if unmatched_only:
sale_lines = [
sale_line for sale_line in sale_lines
if cls._sale_line_is_unmatched(sale_line)
]
return {sale_line.id for sale_line in sale_lines}
@classmethod
def _get_target_sale_line_ids(cls, start):
Sale = Pool().get('sale.sale')
dimension_filters = cls._get_dimension_filters(start)
has_purchase_filters = bool(
start.purchase_from_date
or start.purchase_to_date
or cls._parse_numbers(start.purchase_numbers)
)
has_sale_filters = bool(
start.sale_from_date
or start.sale_to_date
or cls._parse_numbers(start.sale_numbers)
)
if has_sale_filters:
sale_ids = cls._search_sale_ids(start, dimension_filters)
return cls._sale_line_ids_from_sale_ids(sale_ids, unmatched_only=True)
if dimension_filters and not has_purchase_filters:
sale_ids = cls._search_sale_ids(start, dimension_filters)
return cls._sale_line_ids_from_sale_ids(sale_ids, unmatched_only=True)
if not has_purchase_filters and not has_sale_filters and not dimension_filters:
sale_ids = {sale.id for sale in Sale.search([])}
return cls._sale_line_ids_from_sale_ids(sale_ids, unmatched_only=True)
return set()
@classmethod
def _get_target_purchase_line_ids(cls, start):
PurchaseLine = Pool().get('purchase.line')
dimension_filters = cls._get_dimension_filters(start)
has_purchase_filters = bool(
start.purchase_from_date
or start.purchase_to_date
or cls._parse_numbers(start.purchase_numbers)
)
has_sale_filters = bool(
start.sale_from_date
or start.sale_to_date
or cls._parse_numbers(start.sale_numbers)
)
purchase_side_ids = cls._purchase_line_ids_from_purchase_ids(
cls._search_purchase_ids(
start,
dimension_filters if (dimension_filters and (has_purchase_filters or not has_sale_filters)) else [],
)
) if (has_purchase_filters or (dimension_filters and not has_sale_filters)) else set()
sale_side_ids = cls._purchase_line_ids_from_sale_ids(
cls._search_sale_ids(
start,
dimension_filters if (dimension_filters and (has_sale_filters or not has_purchase_filters)) else [],
)
) if (has_sale_filters or (dimension_filters and not has_purchase_filters)) else set()
if has_purchase_filters and has_sale_filters:
target_ids = purchase_side_ids & sale_side_ids
elif has_purchase_filters:
target_ids = purchase_side_ids
elif has_sale_filters:
target_ids = sale_side_ids
elif dimension_filters:
target_ids = purchase_side_ids | sale_side_ids
else:
target_ids = {line.id for line in PurchaseLine.search([])}
return target_ids
def transition_process(self):
PurchaseLine = Pool().get('purchase.line')
SaleLine = Pool().get('sale.line')
target_ids = self._get_target_purchase_line_ids(self.start)
target_sale_line_ids = self._get_target_sale_line_ids(self.start)
lines = PurchaseLine.browse(list(target_ids))
sale_lines = SaleLine.browse(list(target_sale_line_ids))
purchase_ids = {line.purchase.id for line in lines if line.purchase}
sale_ids = set()
for line in lines:
for matched_line in line.get_matched_lines() or []:
if matched_line.lot_s and matched_line.lot_s.sale_line:
sale_ids.add(matched_line.lot_s.sale_line.sale.id)
Valuation.generate(line, valuation_type=self.start.valuation_type)
for sale_line in sale_lines:
sale_ids.add(sale_line.sale.id)
Valuation.generate_from_sale_line(
sale_line, valuation_type=self.start.valuation_type)
self._result_message = (
f"Processed {len(lines)} purchase line(s) "
f"and {len(sale_lines)} unmatched sale line(s) "
f"from {len(purchase_ids)} purchase(s) "
f"and {len(sale_ids)} sale(s)."
)
return 'result'
def default_result(self, fields):
return {
'message': self._result_message or 'No valuation was processed.',
}
def do_open_report(self, action):
Date = Pool().get('ir.date')
action['pyson_context'] = PYSONEncoder().encode({
'valuation_date': Date.today(),
})
return action, {}

View File

@@ -1,25 +1,5 @@
<tryton> <tryton>
<data> <data>
<record model="ir.ui.view" id="valuation_process_dimension_view_tree">
<field name="model">valuation.process.dimension</field>
<field name="type">tree</field>
<field name="name">valuation_process_dimension_tree</field>
</record>
<record model="ir.ui.view" id="valuation_process_dimension_view_form">
<field name="model">valuation.process.dimension</field>
<field name="type">form</field>
<field name="name">valuation_process_dimension_form</field>
</record>
<record model="ir.ui.view" id="valuation_process_start_view_form">
<field name="model">valuation.process.start</field>
<field name="type">form</field>
<field name="name">valuation_process_start_form</field>
</record>
<record model="ir.ui.view" id="valuation_process_result_view_form">
<field name="model">valuation.process.result</field>
<field name="type">form</field>
<field name="name">valuation_process_result_form</field>
</record>
<record model="ir.ui.view" id="valuation_view_tree_sequence3"> <record model="ir.ui.view" id="valuation_view_tree_sequence3">
<field name="model">valuation.valuation</field> <field name="model">valuation.valuation</field>
<field name="type">tree</field> <field name="type">tree</field>
@@ -56,10 +36,6 @@
<field name="res_model">valuation.report</field> <field name="res_model">valuation.report</field>
<field name="context_model">valuation.report.context</field> <field name="context_model">valuation.report.context</field>
</record> </record>
<record model="ir.action.wizard" id="act_valuation_process">
<field name="name">Process valuation</field>
<field name="wiz_name">valuation.process</field>
</record>
<record model="ir.action.act_window.view" id="act_valuation_form_view"> <record model="ir.action.act_window.view" id="act_valuation_form_view">
<field name="sequence" eval="70"/> <field name="sequence" eval="70"/>
<field name="view" ref="valuation_view_list"/> <field name="view" ref="valuation_view_list"/>
@@ -67,17 +43,8 @@
</record> </record>
<menuitem <menuitem
name="Valuation" parent="purchase_trade.menu_global_reporting"
sequence="98" sequence="120"
id="menu_valuation"/>
<menuitem
parent="menu_valuation"
sequence="10"
action="act_valuation_process"
id="menu_valuation_process"/>
<menuitem
parent="menu_valuation"
sequence="20"
action="act_valuation_form" action="act_valuation_form"
id="menu_valuation_form"/> id="menu_valuation_form"/>
</data> </data>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0"?>
<form col="4">
<label name="pricing_rule"/>
<field name="pricing_rule" colspan="3"/>
</form>

View File

@@ -9,13 +9,13 @@
<field name="tol_min"/> <field name="tol_min"/>
<field name="tol_max"/> <field name="tol_max"/>
<field name="price_type"/> <field name="price_type"/>
<field name="from_location"/>
<field name="to_location"/>
<field name="payment_term"/> <field name="payment_term"/>
<field name="incoterm"/> <field name="incoterm"/>
<field name="crop"/> <field name="crop"/>
<field name="del_period"/> <field name="del_period"/>
<field name="from_del"/> <field name="from_del"/>
<field name="to_del"/> <field name="to_del"/>
<field name="from_location"/>
<field name="to_location"/>
<field name="category" tree_invisible="1"/> <field name="category" tree_invisible="1"/>
</tree> </tree>

View File

@@ -1,9 +1,8 @@
<tree> <tree editable="1">
<field name="r_lot_type" width="80"> <field name="r_lot_type" width="80">
<prefix name="qt_icon"/> <prefix name="qt_icon"/>
</field> </field>
<field name="r_lot_p" width="60"/> <field name="r_lot_p" width="60"/>
<field name="r_del_period" width="110"/>
<field name="r_supplier" width="90"/> <field name="r_supplier" width="90"/>
<field name="r_purchase" width="120"/> <field name="r_purchase" width="120"/>
<field name="r_lot_pur_inv" width="120"/> <field name="r_lot_pur_inv" width="120"/>

View File

@@ -4,7 +4,6 @@
<field name="lot_shipment_origin"/> <field name="lot_shipment_origin"/>
<field name="lot_product"/> <field name="lot_product"/>
<field name="lot_unit_line"/> <field name="lot_unit_line"/>
<field name="lot_qt"/>
<field name="lot_quantity"/> <field name="lot_quantity"/>
<field name="lot_gross_quantity"/> <field name="lot_gross_quantity"/>
<field name="lot_quantity_new"/> <field name="lot_quantity_new"/>

View File

@@ -9,27 +9,27 @@ this repository contains the full copyright notices and license terms. -->
<label name="finished"/> <label name="finished"/>
<field name="finished"/> <field name="finished"/>
<newline/> <newline/>
<label name="price_type"/>
<field name="price_type"/>
<label name="enable_linked_currency"/> <label name="enable_linked_currency"/>
<field name="enable_linked_currency"/> <field name="enable_linked_currency"/>
<newline/> <newline/>
<label name="linked_price"/>
<field name="linked_price"/>
<label name="linked_currency"/> <label name="linked_currency"/>
<field name="linked_currency"/> <field name="linked_currency"/>
<label name="linked_unit"/> <label name="linked_unit"/>
<field name="linked_unit"/> <field name="linked_unit"/>
<newline/> <newline/>
<label name="linked_price"/>
<field name="linked_price"/>
<label name="premium"/>
<field name="premium"/>
<newline/>
</xpath> </xpath>
<xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after"> <xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after">
<newline/> <newline/>
<label name="price_type"/>
<field name="price_type"/>
<label name="progress"/> <label name="progress"/>
<field name="progress" widget="progressbar"/> <field name="progress" widget="progressbar"/>
<newline/> <newline/>
<label name="premium"/>
<field name="premium"/>
<newline/>
<label name="inherit_tol"/> <label name="inherit_tol"/>
<field name="inherit_tol"/> <field name="inherit_tol"/>
<newline/> <newline/>
@@ -96,10 +96,6 @@ this repository contains the full copyright notices and license terms. -->
<page string="Summary" col="4" id="summary"> <page string="Summary" col="4" id="summary">
<field name="price_summary" /> <field name="price_summary" />
</page> </page>
<page string="Report" col="4" id="report">
<label name="pricing_rule" />
<field name="pricing_rule" />
</page>
</notebook> </notebook>
</page> </page>
<page string="Estimated dates" col="4" id="estimated"> <page string="Estimated dates" col="4" id="estimated">

View File

@@ -7,7 +7,4 @@ this repository contains the full copyright notices and license terms. -->
<field name="from_del"/> <field name="from_del"/>
<field name="to_del"/> <field name="to_del"/>
</xpath> </xpath>
<xpath expr="//field[@name='unit_price']" position="after">
<field name="premium"/>
</xpath>
</data> </data>

View File

@@ -9,27 +9,27 @@ this repository contains the full copyright notices and license terms. -->
<label name="finished"/> <label name="finished"/>
<field name="finished"/> <field name="finished"/>
<newline/> <newline/>
<label name="price_type"/>
<field name="price_type"/>
<label name="enable_linked_currency"/> <label name="enable_linked_currency"/>
<field name="enable_linked_currency"/> <field name="enable_linked_currency"/>
<newline/> <newline/>
<label name="linked_price"/>
<field name="linked_price"/>
<label name="linked_currency"/> <label name="linked_currency"/>
<field name="linked_currency"/> <field name="linked_currency"/>
<label name="linked_unit"/> <label name="linked_unit"/>
<field name="linked_unit"/> <field name="linked_unit"/>
<newline/> <newline/>
<label name="linked_price"/>
<field name="linked_price"/>
<label name="premium"/>
<field name="premium"/>
<newline/>
</xpath> </xpath>
<xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after"> <xpath expr="/form/notebook/page[@id='general']/field[@name='amount']" position="after">
<newline/> <newline/>
<label name="price_type"/>
<field name="price_type"/>
<label name="progress"/> <label name="progress"/>
<field name="progress" widget="progressbar"/> <field name="progress" widget="progressbar"/>
<newline/> <newline/>
<label name="premium"/>
<field name="premium"/>
<newline/>
<label name="inherit_tol"/> <label name="inherit_tol"/>
<field name="inherit_tol"/> <field name="inherit_tol"/>
<newline/> <newline/>

View File

@@ -7,7 +7,4 @@ this repository contains the full copyright notices and license terms. -->
<field name="from_del"/> <field name="from_del"/>
<field name="to_del"/> <field name="to_del"/>
</xpath> </xpath>
<xpath expr="//field[@name='unit_price']" position="after">
<field name="premium"/>
</xpath>
</data> </data>

View File

@@ -137,9 +137,5 @@ this repository contains the full copyright notices and license terms. -->
<newline/> <newline/>
<field name="shipment_wr" colspan="4" mode="tree" view_ids="purchase_trade.shipment_wr_view_tree"/> <field name="shipment_wr" colspan="4" mode="tree" view_ids="purchase_trade.shipment_wr_view_tree"/>
</page> </page>
<page string="Surveyor" col="4" id="surveyor">
<label name="surveyor"/>
<field name="surveyor"/>
</page>
</xpath> </xpath>
</data> </data>

View File

@@ -1,34 +0,0 @@
<?xml version="1.0"?>
<form col="4">
<separator id="sale_templates" string="Sale" colspan="4"/>
<label name="sale_report_template"/>
<field name="sale_report_template" colspan="3"/>
<label name="sale_bill_report_template"/>
<field name="sale_bill_report_template" colspan="3"/>
<label name="sale_final_report_template"/>
<field name="sale_final_report_template" colspan="3"/>
<separator id="invoice_templates" string="Invoice" colspan="4"/>
<label name="invoice_report_template"/>
<field name="invoice_report_template" colspan="3"/>
<label name="invoice_cndn_report_template"/>
<field name="invoice_cndn_report_template" colspan="3"/>
<label name="invoice_prepayment_report_template"/>
<field name="invoice_prepayment_report_template" colspan="3"/>
<separator id="payment_templates" string="Payment" colspan="4"/>
<label name="invoice_payment_order_report_template"/>
<field name="invoice_payment_order_report_template" colspan="3"/>
<separator id="purchase_templates" string="Purchase" colspan="4"/>
<label name="purchase_report_template"/>
<field name="purchase_report_template" colspan="3"/>
<separator id="shipment_templates" string="Shipment" colspan="4"/>
<label name="shipment_shipping_report_template"/>
<field name="shipment_shipping_report_template" colspan="3"/>
<label name="shipment_insurance_report_template"/>
<field name="shipment_insurance_report_template" colspan="3"/>
<label name="shipment_packing_list_report_template"/>
<field name="shipment_packing_list_report_template" colspan="3"/>
</form>

View File

@@ -12,6 +12,5 @@
<field name="base_amount" sum="1"/> <field name="base_amount" sum="1"/>
<field name="rate"/> <field name="rate"/>
<field name="strategy"/> <field name="strategy"/>
<field name="mtm_price"/>
<field name="mtm" optional="0" sum="1"/> <field name="mtm" optional="0" sum="1"/>
</tree> </tree>

View File

@@ -1,6 +0,0 @@
<form col="4">
<label name="dimension"/>
<field name="dimension"/>
<label name="value"/>
<field name="value"/>
</form>

View File

@@ -1,4 +0,0 @@
<tree editable="1">
<field name="dimension"/>
<field name="value"/>
</tree>

View File

@@ -1,3 +0,0 @@
<form>
<field name="message"/>
</form>

View File

@@ -1,18 +0,0 @@
<form col="4">
<label name="valuation_type"/>
<field name="valuation_type"/>
<newline/>
<label name="purchase_from_date"/>
<field name="purchase_from_date"/>
<label name="purchase_to_date"/>
<field name="purchase_to_date"/>
<label name="purchase_numbers"/>
<field name="purchase_numbers" colspan="3"/>
<label name="sale_from_date"/>
<field name="sale_from_date"/>
<label name="sale_to_date"/>
<field name="sale_to_date"/>
<label name="sale_numbers"/>
<field name="sale_numbers" colspan="3"/>
<field name="analytic_dimensions" colspan="4"/>
</form>

View File

@@ -11,6 +11,5 @@ this repository contains the full copyright notices and license terms. -->
<field name="quantity" symbol="unit"/> <field name="quantity" symbol="unit"/>
<field name="amount" sum="1"/> <field name="amount" sum="1"/>
<field name="strategy"/> <field name="strategy"/>
<field name="mtm_price"/>
<field name="mtm" optional="0" sum="1"/> <field name="mtm" optional="0" sum="1"/>
</tree> </tree>

View File

@@ -11,7 +11,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="r_quantity" symbol="r_unit"/> <field name="r_quantity" symbol="r_unit"/>
<field name="r_amount" sum="1"/> <field name="r_amount" sum="1"/>
<field name="r_strategy"/> <field name="r_strategy"/>
<field name="r_mtm_price"/>
<field name="r_mtm" optional="0" sum="1"/> <field name="r_mtm" optional="0" sum="1"/>
</tree> </tree>

View File

@@ -79,13 +79,6 @@
<label name="weight_date"/> <label name="weight_date"/>
<field name="weight_date"/> <field name="weight_date"/>
</group> </group>
<group id="remote_wr" colspan="8" col="4">
<button name="create_remote_weight_reports" string="Create Remote WRs" colspan="4"/>
<label name="remote_weight_report_sent_at"/>
<field name="remote_weight_report_sent_at"/>
<label name="remote_weight_report_keys"/>
<field name="remote_weight_report_keys" colspan="4"/>
</group>
<!-- <group id="buttons" colspan="8"> <!-- <group id="buttons" colspan="8">
<button name="import_json" string="Import JSON"/> <button name="import_json" string="Import JSON"/>

View File

@@ -12,7 +12,6 @@
<field name="invoice_net_kg"/> <field name="invoice_net_kg"/>
<field name="gain_loss_kg"/> <field name="gain_loss_kg"/>
<field name="gain_loss_percent"/> <field name="gain_loss_percent"/>
<field name="remote_weight_report_sent_at"/>
<!-- <button name="import_json" tree_invisible="1"/> <!-- <button name="import_json" tree_invisible="1"/>
<button name="export_json" tree_invisible="1"/> --> <button name="export_json" tree_invisible="1"/> -->
</tree> </tree>

View File

@@ -1,10 +1,7 @@
from trytond.model import ModelSQL, ModelView, fields from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool from trytond.pool import Pool
from trytond.exceptions import UserError
from decimal import Decimal, ROUND_HALF_UP from decimal import Decimal, ROUND_HALF_UP
from datetime import datetime as dt from datetime import datetime as dt
import datetime
import requests
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -52,127 +49,21 @@ class WeightReport(ModelSQL, ModelView):
invoice_net_kg = fields.Numeric('Invoice Net (kg)', digits=(16, 2)) invoice_net_kg = fields.Numeric('Invoice Net (kg)', digits=(16, 2))
gain_loss_kg = fields.Numeric('Gain/Loss (kg)', digits=(16, 2)) gain_loss_kg = fields.Numeric('Gain/Loss (kg)', digits=(16, 2))
gain_loss_percent = fields.Numeric('Gain/Loss (%)', digits=(16, 2)) gain_loss_percent = fields.Numeric('Gain/Loss (%)', digits=(16, 2))
remote_weight_report_keys = fields.Text('Remote WR Keys', readonly=True)
remote_weight_report_sent_at = fields.Date(
'Remote WR Sent At', readonly=True)
@classmethod @classmethod
def __setup__(cls): def __setup__(cls):
super().__setup__() super().__setup__()
cls._order = [('report_date', 'DESC')] cls._order = [('report_date', 'DESC')]
cls._buttons.update({ # cls._buttons.update({
'create_remote_weight_reports': {}, # 'import_json': {},
}) # 'export_json': {},
# })
def get_rec_name(self, name): def get_rec_name(self, name):
items = [self.lab] items = [self.lab]
if self.reference: if self.reference:
items.append('[%s]' % self.reference) items.append('[%s]' % self.reference)
return ' '.join(items) return ' '.join(items)
def create_remote_weight_report(self, wr_payload):
response = requests.post(
"http://automation-service:8006/weight-report",
json=wr_payload,
timeout=10
)
response.raise_for_status()
return response.json()
def get_related_shipments(self):
ShipmentWR = Pool().get('shipment.wr')
links = ShipmentWR.search([('wr', '=', self.id)])
return [link.shipment_in for link in links if link.shipment_in]
def get_source_shipment(self):
shipments = self.get_related_shipments()
if not shipments:
raise UserError('No shipment is linked to this weight report.')
unique_shipments = {shipment.id: shipment for shipment in shipments}
if len(unique_shipments) > 1:
raise UserError(
'This weight report is linked to multiple shipments.')
return next(iter(unique_shipments.values()))
def get_remote_weight_report_lots(self, shipment):
lots = []
seen = set()
for move in shipment.incoming_moves or []:
lot = getattr(move, 'lot', None)
if (not lot or lot.lot_type != 'physic'
or lot.id in seen):
continue
seen.add(lot.id)
lots.append(lot)
if not lots:
raise UserError(
'No physical lot was found on the incoming moves.')
return lots
def validate_remote_weight_report_context(self, shipment):
if not shipment.controller:
raise UserError(
'A controller is required before creating remote weight reports.')
if not shipment.returned_id:
raise UserError(
'A returned ID is required before creating remote weight reports.')
if not shipment.agent:
raise UserError(
'A booking agent is required before creating remote weight reports.')
if not shipment.to_location:
raise UserError(
'A destination location is required before creating remote weight reports.')
if not self.bales:
raise UserError(
'The global weight report must define the number of bales.')
if not self.report_date or not self.weight_date:
raise UserError(
'Report date and weight date are required.')
def build_remote_weight_report_payload(self, shipment, lot):
if not lot.lot_chunk_key:
raise UserError(
'Each physical lot must have a chunk key before export.')
factor_net = self.net_landed_kg / self.bales
factor_gross = self.gross_landed_kg / self.bales
lot_ratio = Decimal(lot.lot_qt) / self.bales
return {
"chunk_key": lot.lot_chunk_key,
"gross_weight": float(round(
Decimal(lot.lot_qt) * factor_gross, 5)),
"net_weight": float(round(
Decimal(lot.lot_qt) * factor_net, 5)),
"tare_total": float(round(self.tare_kg * lot_ratio, 5)),
"bags": int(lot.lot_qt),
"surveyor_code": shipment.controller.get_alf(),
"place_key": shipment.to_location.get_places(),
"report_date": int(self.report_date.strftime("%Y%m%d")),
"weight_date": int(self.weight_date.strftime("%Y%m%d")),
"agent": shipment.agent.get_alf(),
"forwarder_ref": shipment.returned_id,
}
@classmethod
@ModelView.button
def create_remote_weight_reports(cls, reports):
to_save = []
for report in reports:
shipment = report.get_source_shipment()
report.validate_remote_weight_report_context(shipment)
lots = report.get_remote_weight_report_lots(shipment)
created = []
for lot in lots:
payload = report.build_remote_weight_report_payload(
shipment, lot)
logger.info("REMOTE_WR_PAYLOAD:%s", payload)
data = report.create_remote_weight_report(payload)
created.append(
f"{lot.rec_name}: {data.get('weight_report_key')}")
report.remote_weight_report_keys = '\n'.join(created)
report.remote_weight_report_sent_at = datetime.date.today()
to_save.append(report)
if to_save:
cls.save(to_save)
# @classmethod # @classmethod
# @ModelView.button_action('weight_report.act_import_json') # @ModelView.button_action('weight_report.act_import_json')
# def import_json(cls, reports): # def import_json(cls, reports):

View File

@@ -103,12 +103,18 @@
</record> --> </record> -->
<!-- Model Buttons --> <!-- Model Buttons -->
<record model="ir.model.button" id="weight_report_create_remote_button"> <!-- <record model="ir.model.button" id="weight_report_import_button">
<field name="model">weight.report</field> <field name="model">weight.report</field>
<field name="name">create_remote_weight_reports</field> <field name="name">import_json</field>
<field name="string">Create Remote WRs</field> <field name="string">Import JSON</field>
</record> </record>
<record model="ir.model.button" id="weight_report_export_button">
<field name="model">weight.report</field>
<field name="name">export_json</field>
<field name="string">Export JSON</field>
</record> -->
<!-- Menu Structure --> <!-- Menu Structure -->
<menuitem <menuitem
name="Weight Reports" name="Weight Reports"

View File

@@ -1,28 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?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: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><meta:initial-creator>Giorgio Calligaro</meta:initial-creator><meta:creation-date>2026-03-12T13:26:00</meta:creation-date><dc:date>2026-03-12T17:30:00</dc:date><meta:print-date>2026-03-12T17:29:00</meta:print-date><meta:editing-cycles>3</meta:editing-cycles><meta:editing-duration>P0D</meta:editing-duration><meta:document-statistic meta:table-count="1" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="11" meta:word-count="30" meta:character-count="221" meta:non-whitespace-character-count="186"/><meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator><meta:user-defined meta:name="Company">Fintel S.A.</meta:user-defined><meta:user-defined meta:name="Operator">HACER</meta:user-defined></office:meta> <office:meta>
<meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator>
<dc:date>2026-03-15T13:01:38.668000000</dc:date><meta:editing-duration>PT10M4S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="7" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="22" meta:word-count="122" meta:character-count="932" meta:non-whitespace-character-count="828"/></office:meta>
<office:settings> <office:settings>
<config:config-item-set config:name="ooo:view-settings"> <config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item> <config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item> <config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">43623</config:config-item> <config:config-item config:name="ViewAreaWidth" config:type="long">31487</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">21098</config:config-item> <config:config-item config:name="ViewAreaHeight" config:type="long">15713</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item> <config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item> <config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views"> <config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry> <config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item> <config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">17221</config:config-item> <config:config-item config:name="ViewLeft" config:type="long">6627</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">7202</config:config-item> <config:config-item config:name="ViewTop" config:type="long">7108</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item> <config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">0</config:config-item> <config:config-item config:name="VisibleTop" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">43621</config:config-item> <config:config-item config:name="VisibleRight" config:type="long">31485</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">21096</config:config-item> <config:config-item config:name="VisibleBottom" config:type="long">15711</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item> <config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item> <config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item> <config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
<config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item> <config:config-item config:name="ZoomFactor" config:type="short">140</config:config-item>
<config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item> <config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
<config:config-item config:name="KeepRatio" config:type="boolean">false</config:config-item> <config:config-item config:name="KeepRatio" config:type="boolean">false</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item> <config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
@@ -35,9 +37,9 @@
<config:config-item-set config:name="ooo:configuration-settings"> <config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item> <config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/> <config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">false</config:config-item> <config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item> <config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">true</config:config-item> <config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item> <config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item> <config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item> <config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
@@ -66,13 +68,13 @@
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item> <config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item> <config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item> <config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">true</config:config-item> <config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item> <config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item> <config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item> <config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">true</config:config-item> <config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">false</config:config-item> <config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">true</config:config-item> <config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item> <config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item> <config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item> <config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
@@ -91,11 +93,11 @@
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> <config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item> <config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item> <config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="Rsid" config:type="int">1475016</config:config-item> <config:config-item config:name="Rsid" config:type="int">1907347</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">1475016</config:config-item> <config:config-item config:name="RsidRoot" config:type="int">1907347</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item> <config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">true</config:config-item> <config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">true</config:config-item> <config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item> <config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item> <config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item> <config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
@@ -104,25 +106,24 @@
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item> <config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item> <config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item> <config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">true</config:config-item> <config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">true</config:config-item> <config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item> <config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item> <config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">true</config:config-item> <config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item> <config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item> <config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">true</config:config-item> <config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item> <config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item> <config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item> <config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item>
<config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">true</config:config-item> <config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">false</config:config-item>
<config:config-item config:name="GutterAtTop" config:type="boolean">false</config:config-item> <config:config-item config:name="GutterAtTop" config:type="boolean">false</config:config-item>
<config:config-item config:name="FootnoteInColumnToPageEnd" config:type="boolean">true</config:config-item> <config:config-item config:name="FootnoteInColumnToPageEnd" config:type="boolean">true</config:config-item>
<config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item> <config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item>
<config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">true</config:config-item> <config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">true</config:config-item>
<config:config-item config:name="HyphenateURLs" config:type="boolean">false</config:config-item> <config:config-item config:name="HyphenateURLs" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotBreakWrappedTables" config:type="boolean">true</config:config-item> <config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">false</config:config-item>
<config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">true</config:config-item>
<config:config-item config:name="DropCapPunctuation" config:type="boolean">true</config:config-item> <config:config-item config:name="DropCapPunctuation" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item> <config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item> <config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
@@ -150,15 +151,11 @@
</office:scripts> </office:scripts>
<office:font-face-decls> <office:font-face-decls>
<style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="roman" style:font-pitch="variable"/> <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Arial1" svg:font-family="Arial" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Calibri" svg:font-family="Calibri" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Liberation Sans" svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/> <style:font-face style:name="Liberation Sans" svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Liberation Serif" svg:font-family="&apos;Liberation Serif&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Lucida Sans" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="swiss"/> <style:font-face style:name="Lucida Sans" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="swiss"/>
<style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="NSimSun" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/> <style:font-face style:name="NSimSun" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
</office:font-face-decls> </office:font-face-decls>
<office:styles> <office:styles>
<style:default-style style:family="graphic"> <style:default-style style:family="graphic">
@@ -166,11 +163,11 @@
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
<style:tab-stops/> <style:tab-stops/>
</style:paragraph-properties> </style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Arial" fo:font-size="9pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
</style:default-style> </style:default-style>
<style:default-style style:family="paragraph"> <style:default-style style:family="paragraph">
<style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.249cm" style:writing-mode="page"/> <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Arial" fo:font-size="9pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
</style:default-style> </style:default-style>
<style:default-style style:family="table"> <style:default-style style:family="table">
<style:table-properties table:border-model="collapsing"/> <style:table-properties table:border-model="collapsing"/>
@@ -178,10 +175,7 @@
<style:default-style style:family="table-row"> <style:default-style style:family="table-row">
<style:table-row-properties fo:keep-together="auto"/> <style:table-row-properties fo:keep-together="auto"/>
</style:default-style> </style:default-style>
<style:style style:name="Standard" style:family="paragraph" style:class="text"> <style:style style:name="Standard" style:family="paragraph" style:class="text"/>
<style:paragraph-properties fo:text-align="start" style:justify-single-word="false" fo:orphans="2" fo:widows="2" style:vertical-align="auto"/>
<style:text-properties style:font-name="Arial" fo:font-family="Arial" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="11pt" fo:language="fr" fo:country="FR" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="fr" style:country-asian="FR" style:font-name-complex="Arial1" style:font-family-complex="Arial" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/>
</style:style>
<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text"> <style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always"/> <style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Liberation Sans" fo:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="&apos;Microsoft YaHei&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/> <style:text-properties style:font-name="Liberation Sans" fo:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="&apos;Microsoft YaHei&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/>
@@ -200,12 +194,12 @@
<style:paragraph-properties text:number-lines="false" text:line-number="0"/> <style:paragraph-properties text:number-lines="false" text:line-number="0"/>
<style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/> <style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/>
</style:style> </style:style>
<style:style style:name="Normal_20_Table_20__28_WW_29_" style:display-name="Normal Table (WW)" style:family="paragraph"> <style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.353cm" style:contextual-spacing="false" fo:line-height="115%" fo:text-align="start" style:justify-single-word="false" fo:orphans="2" fo:widows="2" style:vertical-align="auto"/> <style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/>
<style:text-properties style:font-name="Calibri" fo:font-family="Calibri" style:font-family-generic="roman" style:font-pitch="variable" fo:font-size="11pt" fo:language="en" fo:country="GB" style:font-name-asian="Times New Roman" style:font-family-asian="&apos;Times New Roman&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="11pt" style:language-asian="en" style:country-asian="GB" style:font-name-complex="Times New Roman" style:font-family-complex="&apos;Times New Roman&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="11pt" style:language-complex="ar" style:country-complex="SA"/> </style:style>
<style:style style:name="Placeholder" style:family="text">
<style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/>
</style:style> </style:style>
<style:style style:name="Style1" style:family="paragraph" style:parent-style-name="Standard"/>
<style:style style:name="Default_20_Paragraph_20_Font_20__28_WW_29_" style:display-name="Default Paragraph Font (WW)" style:family="text"/>
<text:outline-style style:name="Outline"> <text:outline-style style:name="Outline">
<text:outline-level-style text:level="1" style:num-format=""> <text:outline-level-style text:level="1" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
@@ -261,9 +255,6 @@
<text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
<text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
<text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
<style:default-page-layout>
<style:page-layout-properties style:layout-grid-standard-mode="true"/>
</style:default-page-layout>
<loext:theme loext:name="Office Theme"> <loext:theme loext:name="Office Theme">
<loext:theme-colors loext:name="LibreOffice"> <loext:theme-colors loext:name="LibreOffice">
<loext:color loext:name="dark1" loext:color="#000000"/> <loext:color loext:name="dark1" loext:color="#000000"/>
@@ -282,154 +273,239 @@
</loext:theme> </loext:theme>
</office:styles> </office:styles>
<office:automatic-styles> <office:automatic-styles>
<style:style style:name="Tableau1" style:family="table"> <style:style style:name="BillOfExchange" style:family="table">
<style:table-properties style:width="15.24cm" fo:margin-left="0.635cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left" style:writing-mode="lr-tb"/> <style:table-properties style:width="20.001cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style> </style:style>
<style:style style:name="Tableau1.A" style:family="table-column"> <style:style style:name="BillOfExchange.A" style:family="table-column">
<style:table-column-properties style:column-width="1.905cm"/> <style:table-column-properties style:column-width="4.75cm"/>
</style:style> </style:style>
<style:style style:name="Tableau1.B" style:family="table-column"> <style:style style:name="BillOfExchange.B" style:family="table-column">
<style:table-column-properties style:column-width="2.54cm"/> <style:table-column-properties style:column-width="15.251cm"/>
</style:style> </style:style>
<style:style style:name="Tableau1.C" style:family="table-column"> <style:style style:name="BillOfExchange.A1" style:family="table-cell">
<style:table-column-properties style:column-width="2.332cm"/> <style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style> </style:style>
<style:style style:name="Tableau1.D" style:family="table-column"> <style:style style:name="BillOfExchange.B1" style:family="table-cell">
<style:table-column-properties style:column-width="1.478cm"/> <style:table-cell-properties fo:padding="0.101cm" fo:border="0.5pt solid #000000"/>
</style:style> </style:style>
<style:style style:name="Tableau1.E" style:family="table-column"> <style:style style:name="Inner1" style:family="table">
<style:table-column-properties style:column-width="0.953cm"/> <style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style> </style:style>
<style:style style:name="Tableau1.F" style:family="table-column"> <style:style style:name="Inner1.A" style:family="table-column">
<style:table-column-properties style:column-width="6.031cm"/> <style:table-column-properties style:column-width="4.001cm"/>
</style:style> </style:style>
<style:style style:name="Tableau1.1" style:family="table-row"> <style:style style:name="Inner1.B" style:family="table-column">
<style:table-row-properties style:min-row-height="2.223cm" fo:keep-together="auto"/> <style:table-column-properties style:column-width="3.5cm"/>
</style:style> </style:style>
<style:style style:name="Tableau1.A1" style:family="table-cell"> <style:style style:name="Inner1.C" style:family="table-column">
<style:table-cell-properties style:vertical-align="" fo:padding-left="0.123cm" fo:padding-right="0.123cm" fo:padding-top="0cm" fo:padding-bottom="0cm" fo:border="none" style:writing-mode="lr-tb"/> <style:table-column-properties style:column-width="10.899cm"/>
</style:style> </style:style>
<style:style style:name="Tableau1.2" style:family="table-row"> <style:style style:name="Inner1.A1" style:family="table-cell">
<style:table-row-properties fo:keep-together="always"/> <style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style> </style:style>
<style:style style:name="Tableau1.3" style:family="table-row"> <style:style style:name="Inner1.C1" style:family="table-cell">
<style:table-row-properties fo:keep-together="always"/> <style:table-cell-properties style:vertical-align="middle" fo:padding="0.101cm" fo:border="1.5pt solid #000000"/>
</style:style> </style:style>
<style:style style:name="Tableau1.4" style:family="table-row"> <style:style style:name="Inner2" style:family="table">
<style:table-row-properties fo:keep-together="always"/> <style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style> </style:style>
<style:style style:name="Tableau1.5" style:family="table-row"> <style:style style:name="Inner2.A" style:family="table-column">
<style:table-row-properties fo:keep-together="auto"/> <style:table-column-properties style:column-width="4.5cm"/>
</style:style>
<style:style style:name="Inner2.B" style:family="table-column">
<style:table-column-properties style:column-width="13.899cm"/>
</style:style>
<style:style style:name="Inner2.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner2.B1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner3" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner3.A" style:family="table-column">
<style:table-column-properties style:column-width="18.399cm"/>
</style:style>
<style:style style:name="Inner3.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner4" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner4.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner4.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner4.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner4.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner5" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner5.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner5.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner5.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner5.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner6" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner6.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner6.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner6.F" style:family="table-column">
<style:table-column-properties style:column-width="3.902cm"/>
</style:style>
<style:style style:name="Inner6.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner6.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner1" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner1.A" style:family="table-column">
<style:table-column-properties style:column-width="4.001cm"/>
</style:style>
<style:style style:name="Inner1.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner1.C" style:family="table-column">
<style:table-column-properties style:column-width="10.899cm"/>
</style:style>
<style:style style:name="Inner1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner1.C1" style:family="table-cell">
<style:table-cell-properties style:vertical-align="middle" fo:padding="0.101cm" fo:border="1.5pt solid #000000"/>
</style:style>
<style:style style:name="Inner2" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner2.A" style:family="table-column">
<style:table-column-properties style:column-width="4.5cm"/>
</style:style>
<style:style style:name="Inner2.B" style:family="table-column">
<style:table-column-properties style:column-width="13.899cm"/>
</style:style>
<style:style style:name="Inner2.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner2.B1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner3" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner3.A" style:family="table-column">
<style:table-column-properties style:column-width="18.399cm"/>
</style:style>
<style:style style:name="Inner3.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner4" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner4.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner4.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner4.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner4.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner5" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner5.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner5.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner5.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner5.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner6" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner6.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner6.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner6.F" style:family="table-column">
<style:table-column-properties style:column-width="3.902cm"/>
</style:style>
<style:style style:name="Inner6.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner6.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style> </style:style>
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
</style:style> </style:style>
<style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="8pt" fo:font-weight="bold"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" style:font-size-asian="8pt" style:font-size-complex="8pt"/>
</style:style> </style:style>
<style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="5pt" fo:language="en" fo:country="GB" fo:font-weight="bold" style:font-size-asian="5pt" style:font-weight-asian="bold" style:font-size-complex="5pt" style:font-weight-complex="bold"/>
</style:style> </style:style>
<style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="end" style:justify-single-word="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="3pt" fo:language="en" fo:country="GB" style:font-size-asian="3pt" style:font-size-complex="3pt"/>
</style:style> </style:style>
<style:style style:name="P5" style:family="paragraph" style:parent-style-name="Style1"> <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" style:font-size-asian="8pt" style:font-size-complex="8pt" text:display="none"/>
</style:style> </style:style>
<style:style style:name="P6" style:family="paragraph" style:parent-style-name="Style1"> <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" style:font-size-asian="8pt" style:font-size-complex="8pt"/>
</style:style> </style:style>
<style:style style:name="P7" style:family="paragraph" style:parent-style-name="Style1"> <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="9pt" fo:font-weight="bold"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
</style:style> </style:style>
<style:style style:name="P8" style:family="paragraph" style:parent-style-name="Style1"> <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-left="0cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:writing-mode="lr-tb"> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:tab-stops> <style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
<style:tab-stop style:position="7.303cm"/>
<style:tab-stop style:position="10.795cm"/>
<style:tab-stop style:position="22.86cm" style:type="right"/>
<style:tab-stop style:position="26.988cm" style:type="right"/>
</style:tab-stops>
</style:paragraph-properties>
<style:text-properties fo:font-size="12pt" fo:language="en" fo:country="GB" style:font-size-asian="12pt" style:font-size-complex="12pt"/>
</style:style> </style:style>
<style:style style:name="T1" style:family="text"> <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard">
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" style:font-size-asian="8pt" style:font-size-complex="8pt"/> <style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
</style:style> <style:text-properties style:font-name="Arial" fo:font-size="7pt" officeooo:paragraph-rsid="001d1a93"/>
<style:style style:name="T2" style:family="text">
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" style:font-size-asian="8pt" style:font-size-complex="8pt" text:display="none"/>
</style:style>
<style:style style:name="T3" style:family="text">
<style:text-properties fo:font-size="8pt" fo:language="en" fo:country="GB" fo:font-weight="bold" style:font-size-asian="8pt" style:font-weight-asian="bold" style:font-size-complex="8pt" style:font-weight-complex="bold"/>
</style:style>
<style:style style:name="T4" style:family="text">
<style:text-properties fo:font-size="12pt" fo:language="en" fo:country="GB" style:font-size-asian="12pt" style:font-size-complex="12pt"/>
</style:style>
<style:style style:name="T5" style:family="text">
<style:text-properties fo:language="en" fo:country="GB"/>
</style:style>
<style:style style:name="T6" style:family="text">
<style:text-properties fo:font-size="5pt" fo:language="en" fo:country="GB" fo:font-weight="bold" style:font-size-asian="5pt" style:font-weight-asian="bold" style:font-size-complex="5pt" style:font-weight-complex="bold"/>
</style:style>
<style:style style:name="T7" style:family="text">
<style:text-properties fo:font-size="3pt" fo:language="en" fo:country="GB" style:font-size-asian="3pt" style:font-size-complex="3pt"/>
</style:style> </style:style>
<style:page-layout style:name="pm1"> <style:page-layout style:name="pm1">
<style:page-layout-properties fo:page-width="29.7cm" fo:page-height="21.001cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="6.701cm" fo:margin-bottom="1.501cm" fo:margin-left="9.502cm" fo:margin-right="1.501cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="12798" style:layout-grid-base-height="0.176cm" style:layout-grid-ruby-height="0cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:layout-grid-base-width="0.388cm" style:layout-grid-snap-to="true" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="9.999cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="0.4cm" fo:margin-bottom="0.4cm" fo:margin-left="0.499cm" fo:margin-right="0.499cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm">
<style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
</style:page-layout-properties> </style:page-layout-properties>
<style:header-style/> <style:header-style/>
@@ -451,103 +527,127 @@
<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
<text:sequence-decl text:display-outline-level="0" text:name="Figure"/> <text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
</text:sequence-decls> </text:sequence-decls>
<text:p text:style-name="P5" loext:marker-style-name="T2"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;sale in records&quot;&gt;</text:placeholder></text:p> <text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;sale in records&quot;&gt;</text:placeholder></text:p>
<table:table table:name="Tableau1" table:style-name="Tableau1"> <table:table table:name="BillOfExchange" table:style-name="BillOfExchange">
<table:table-column table:style-name="Tableau1.A"/> <table:table-column table:style-name="BillOfExchange.A"/>
<table:table-column table:style-name="Tableau1.B"/> <table:table-column table:style-name="BillOfExchange.B"/>
<table:table-column table:style-name="Tableau1.C"/> <table:table-row>
<table:table-column table:style-name="Tableau1.D"/> <table:table-cell table:style-name="BillOfExchange.A1" table:number-rows-spanned="2" office:value-type="string">
<table:table-column table:style-name="Tableau1.E"/> <text:p text:style-name="P6">Accepted by:</text:p>
<table:table-column table:style-name="Tableau1.F"/> <text:p text:style-name="P6"/>
<table:table-row table:style-name="Tableau1.1"> <text:p text:style-name="P6"/>
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string"> <text:p text:style-name="P6"/>
<text:p text:style-name="P6" loext:marker-style-name="T1"/> <text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P9">Per aval:</text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="2" office:value-type="string"> <table:table-cell table:style-name="BillOfExchange.B1" office:value-type="string">
<text:p text:style-name="P7" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;format_date(sale.sale_date, sale.party.lang)&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p> <table:table table:name="Inner1" table:style-name="Inner1">
<text:p text:style-name="P8" loext:marker-style-name="T4"/> <table:table-column table:style-name="Inner1.A"/>
<text:p text:style-name="P7" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;format_date(sale.report_bill_maturity_date, sale.party.lang) if sale.report_bill_maturity_date else &apos;&apos;&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p> <table:table-column table:style-name="Inner1.B"/>
<text:p text:style-name="P6" loext:marker-style-name="T1"/> <table:table-column table:style-name="Inner1.C"/>
<text:p text:style-name="P6" loext:marker-style-name="T1"/> <table:table-row>
<text:p text:style-name="P6" loext:marker-style-name="T1"/> <table:table-cell table:style-name="Inner1.A1" office:value-type="string">
<text:p text:style-name="P1">Geneva, <text:placeholder text:placeholder-type="text">&lt;format_date(sale.sale_date, sale.party.lang)&gt;</text:placeholder></text:p>
</table:table-cell> </table:table-cell>
<table:covered-table-cell/> <table:table-cell table:style-name="Inner1.A1" office:value-type="string">
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="2" office:value-type="string"> <text:p text:style-name="P1">For</text:p>
<text:p text:style-name="P6" loext:marker-style-name="T1"/>
</table:table-cell> </table:table-cell>
<table:covered-table-cell/> <table:table-cell table:style-name="Inner1.C1" office:value-type="string">
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string"> <text:p text:style-name="P7"><text:placeholder text:placeholder-type="text">&lt;format_currency(sale.lines[0].unit_price, sale.party.lang, sale.currency) if sale.lines else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P7" loext:marker-style-name="T5"><text:span text:style-name="T3"><text:placeholder text:placeholder-type="text">&lt;format_currency(sale.report_bill_amount, sale.party.lang, sale.currency)&gt;</text:placeholder></text:span><text:span text:style-name="T3"/></text:p>
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
<table:table-row table:style-name="Tableau1.2">
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="6" office:value-type="string">
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1">***<text:placeholder text:placeholder-type="text">&lt;sale.report_bill_amount_words&gt;</text:placeholder>***</text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
</table:table-row>
<table:table-row table:style-name="Tableau1.3">
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="4" office:value-type="string">
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;sale.currency.symbol if sale.currency else &apos;&apos;&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P3" loext:marker-style-name="T6"/>
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:s text:c="13"/><text:placeholder text:placeholder-type="text">&lt;(sale.party.addresses[0].country.name.upper()) if sale.party and sale.party.addresses and sale.party.addresses[0].country else &apos;&apos;&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
</table:table-row>
<table:table-row table:style-name="Tableau1.4">
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="5" office:value-type="string">
<text:p text:style-name="P4" loext:marker-style-name="T7"/>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;sale.party.rec_name&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;sale.full_number&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;sale.party.addresses[0].city if sale.party and sale.party.addresses else &apos;&apos;&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P1" loext:marker-style-name="T1"><text:span text:style-name="T1"><text:placeholder text:placeholder-type="text">&lt;sale.reference if sale.reference else &apos;&apos;&gt;</text:placeholder></text:span><text:span text:style-name="T1"/></text:p>
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
<table:covered-table-cell/>
</table:table-row>
<table:table-row table:style-name="Tableau1.5">
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string">
<text:p text:style-name="P1" loext:marker-style-name="T5"><text:span text:style-name="T1"><text:s/></text:span><text:span text:style-name="T1"/></text:p>
</table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="2" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:covered-table-cell/>
<table:table-cell table:style-name="Tableau1.A1" table:number-columns-spanned="2" office:value-type="string">
<text:p text:style-name="P2" loext:marker-style-name="T1"/>
</table:table-cell>
<table:covered-table-cell/>
</table:table-row>
</table:table> </table:table>
<text:p text:style-name="P2" loext:marker-style-name="T1"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p> <table:table table:name="Inner2" table:style-name="Inner2">
<table:table-column table:style-name="Inner2.A"/>
<table:table-column table:style-name="Inner2.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner2.A1" office:value-type="string">
<text:p text:style-name="P1">At / on <text:placeholder text:placeholder-type="text">&lt;sale.payment_term.rec_name if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner2.B1" office:value-type="string">
<text:p text:style-name="P1">for value received, please pay against this sole Bill of Exchange</text:p>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P1">to our order of Melya S.A., Switzerland, the amount of</text:p>
<table:table table:name="Inner3" table:style-name="Inner3">
<table:table-column table:style-name="Inner3.A"/>
<table:table-row>
<table:table-cell table:style-name="Inner3.A1" office:value-type="string">
<text:p text:style-name="P1"> </text:p>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P5">effective payment to be made in <text:placeholder text:placeholder-type="text">&lt;sale.currency.symbol if sale.currency else &apos;&apos;&gt;</text:placeholder> only, without deduction for and free of any taxes, impost, levies or duties present or future of any nature under the laws of <text:placeholder text:placeholder-type="text">&lt;sale.party.addresses[0].country.name if sale.party and sale.party.addresses else &apos;&apos;&gt;</text:placeholder> or any political subdivision thereof or therein.</text:p>
<table:table table:name="Inner4" table:style-name="Inner4">
<table:table-column table:style-name="Inner4.A"/>
<table:table-column table:style-name="Inner4.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner4.A1" office:value-type="string">
<text:p text:style-name="P1">Payable at</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner4.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.party.addresses[0].city if sale.party and sale.party.addresses else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
<table:table table:name="Inner5" table:style-name="Inner5">
<table:table-column table:style-name="Inner5.A"/>
<table:table-column table:style-name="Inner5.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner5.A1" office:value-type="string">
<text:p text:style-name="P1">Drawn on at</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner5.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.party.rec_name&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
<table:table table:name="Inner6" table:style-name="Inner6">
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.B"/>
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.B"/>
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.F"/>
<table:table-row>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">No</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"> </text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">/ Invoice No</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.full_number&gt;</text:placeholder></text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">/ D:</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.reference if sale.reference else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
</table:table-cell>
</table:table-row>
<table:table-row>
<table:covered-table-cell table:style-name="BillOfExchange.A1"/>
<table:table-cell table:style-name="BillOfExchange.A1" office:value-type="string">
<text:p text:style-name="P6"/>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
</office:text> </office:text>
</office:body> </office:body>
</office:document> </office:document>

View File

@@ -1,653 +0,0 @@
<?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>
<meta:generator>LibreOffice/7.6.0.3$Windows_X86_64 LibreOffice_project/69edd8b8ebc41d00b4de3915dc82f8f0fc3b6265</meta:generator>
<dc:date>2026-03-15T13:01:38.668000000</dc:date><meta:editing-duration>PT10M4S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="7" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="22" meta:word-count="122" meta:character-count="932" meta:non-whitespace-character-count="828"/></office:meta>
<office:settings>
<config:config-item-set config:name="ooo:view-settings">
<config:config-item config:name="ViewAreaTop" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaLeft" config:type="long">0</config:config-item>
<config:config-item config:name="ViewAreaWidth" config:type="long">31487</config:config-item>
<config:config-item config:name="ViewAreaHeight" config:type="long">15713</config:config-item>
<config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item>
<config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item>
<config:config-item-map-indexed config:name="Views">
<config:config-item-map-entry>
<config:config-item config:name="ViewId" config:type="string">view2</config:config-item>
<config:config-item config:name="ViewLeft" config:type="long">6627</config:config-item>
<config:config-item config:name="ViewTop" config:type="long">7108</config:config-item>
<config:config-item config:name="VisibleLeft" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleTop" config:type="long">0</config:config-item>
<config:config-item config:name="VisibleRight" config:type="long">31485</config:config-item>
<config:config-item config:name="VisibleBottom" config:type="long">15711</config:config-item>
<config:config-item config:name="ZoomType" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item>
<config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item>
<config:config-item config:name="ZoomFactor" config:type="short">140</config:config-item>
<config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item>
<config:config-item config:name="KeepRatio" config:type="boolean">false</config:config-item>
<config:config-item config:name="AnchoredTextOverflowLegacy" config:type="boolean">false</config:config-item>
<config:config-item config:name="LegacySingleLineFontwork" config:type="boolean">false</config:config-item>
<config:config-item config:name="ConnectorUseSnapRect" config:type="boolean">false</config:config-item>
<config:config-item config:name="IgnoreBreakAfterMultilineField" config:type="boolean">false</config:config-item>
</config:config-item-map-entry>
</config:config-item-map-indexed>
</config:config-item-set>
<config:config-item-set config:name="ooo:configuration-settings">
<config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterSetup" config:type="base64Binary"/>
<config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item>
<config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item>
<config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item>
<config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item>
<config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item>
<config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterName" config:type="string"/>
<config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/>
<config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrinterPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseCommand" config:type="string"/>
<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item>
<config:config-item config:name="DisableOffPagePositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveThumbnail" config:type="boolean">true</config:config-item>
<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item>
<config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item>
<config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item>
<config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/>
<config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item>
<config:config-item config:name="EmbeddedDatabaseName" config:type="string"/>
<config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item>
<config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddVerticalFrameOffsets" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item>
<config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item>
<config:config-item config:name="HeaderSpacingBelowLastPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item>
<config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item>
<config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item>
<config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item>
<config:config-item config:name="AddParaLineSpacingToTableCells" config:type="boolean">true</config:config-item>
<config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item>
<config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item>
<config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item>
<config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item>
<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item>
<config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item>
<config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item>
<config:config-item config:name="Rsid" config:type="int">1907347</config:config-item>
<config:config-item config:name="RsidRoot" config:type="int">1907347</config:config-item>
<config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompTrailingBlanks" config:type="boolean">false</config:config-item>
<config:config-item config:name="MsWordCompMinLineHeightByFly" config:type="boolean">false</config:config-item>
<config:config-item config:name="MathBaselineAlignment" config:type="boolean">true</config:config-item>
<config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedComplexScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedOnlyUsedFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmbedLatinScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="EmbedAsianScriptFonts" config:type="boolean">true</config:config-item>
<config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item>
<config:config-item config:name="ApplyParagraphMarkFormatToNumbering" config:type="boolean">false</config:config-item>
<config:config-item config:name="TabOverSpacing" config:type="boolean">false</config:config-item>
<config:config-item config:name="TreatSingleColumnBreakAsPageBreak" config:type="boolean">false</config:config-item>
<config:config-item config:name="SurroundTextWrapSmall" config:type="boolean">false</config:config-item>
<config:config-item config:name="PropLineSpacingShrinksFirstLine" config:type="boolean">true</config:config-item>
<config:config-item config:name="SubtractFlysAnchoredAtFlys" config:type="boolean">false</config:config-item>
<config:config-item config:name="EmptyDbFieldHidesPara" config:type="boolean">false</config:config-item>
<config:config-item config:name="ContinuousEndnotes" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectBookmarks" config:type="boolean">false</config:config-item>
<config:config-item config:name="ProtectFields" config:type="boolean">false</config:config-item>
<config:config-item config:name="FrameAutowidthWithMorePara" config:type="boolean">false</config:config-item>
<config:config-item config:name="GutterAtTop" config:type="boolean">false</config:config-item>
<config:config-item config:name="FootnoteInColumnToPageEnd" config:type="boolean">true</config:config-item>
<config:config-item config:name="ImagePreferredDPI" config:type="int">0</config:config-item>
<config:config-item config:name="AutoFirstLineIndentDisregardLineSpace" config:type="boolean">true</config:config-item>
<config:config-item config:name="HyphenateURLs" config:type="boolean">false</config:config-item>
<config:config-item config:name="NoNumberingShowFollowBy" config:type="boolean">false</config:config-item>
<config:config-item config:name="DropCapPunctuation" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item>
<config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintEmptyPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintFaxName" config:type="string"/>
<config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item>
<config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item>
<config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item>
</config:config-item-set>
</office:settings>
<office:scripts>
<office:script script:language="ooo:Basic">
<ooo:libraries xmlns:ooo="http://openoffice.org/2004/office" xmlns:xlink="http://www.w3.org/1999/xlink"/>
</office:script>
</office:scripts>
<office:font-face-decls>
<style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="roman" style:font-pitch="variable"/>
<style:font-face style:name="Liberation Sans" svg:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable"/>
<style:font-face style:name="Lucida Sans" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="swiss"/>
<style:font-face style:name="Lucida Sans1" svg:font-family="&apos;Lucida Sans&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="Microsoft YaHei" svg:font-family="&apos;Microsoft YaHei&apos;" style:font-family-generic="system" style:font-pitch="variable"/>
<style:font-face style:name="NSimSun" svg:font-family="NSimSun" style:font-family-generic="system" style:font-pitch="variable"/>
</office:font-face-decls>
<office:styles>
<style:default-style style:family="graphic">
<style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/>
<style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false">
<style:tab-stops/>
</style:paragraph-properties>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Arial" fo:font-size="9pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/>
</style:default-style>
<style:default-style style:family="paragraph">
<style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/>
<style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Arial" fo:font-size="9pt" fo:language="en" fo:country="GB" style:letter-kerning="true" style:font-name-asian="NSimSun" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lucida Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/>
</style:default-style>
<style:default-style style:family="table">
<style:table-properties table:border-model="collapsing"/>
</style:default-style>
<style:default-style style:family="table-row">
<style:table-row-properties fo:keep-together="auto"/>
</style:default-style>
<style:style style:name="Standard" style:family="paragraph" style:class="text"/>
<style:style style:name="Heading" style:family="paragraph" style:parent-style-name="Standard" style:next-style-name="Text_20_body" style:class="text">
<style:paragraph-properties fo:margin-top="0.423cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" fo:keep-with-next="always"/>
<style:text-properties style:font-name="Liberation Sans" fo:font-family="&apos;Liberation Sans&apos;" style:font-family-generic="swiss" style:font-pitch="variable" fo:font-size="14pt" style:font-name-asian="Microsoft YaHei" style:font-family-asian="&apos;Microsoft YaHei&apos;" style:font-family-generic-asian="system" style:font-pitch-asian="variable" style:font-size-asian="14pt" style:font-name-complex="Lucida Sans1" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="system" style:font-pitch-complex="variable" style:font-size-complex="14pt"/>
</style:style>
<style:style style:name="Text_20_body" style:display-name="Text body" style:family="paragraph" style:parent-style-name="Standard" style:class="text">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0.247cm" style:contextual-spacing="false" fo:line-height="115%"/>
</style:style>
<style:style style:name="List" style:family="paragraph" style:parent-style-name="Text_20_body" style:class="list">
<style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/>
</style:style>
<style:style style:name="Caption" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties fo:margin-top="0.212cm" fo:margin-bottom="0.212cm" style:contextual-spacing="false" text:number-lines="false" text:line-number="0"/>
<style:text-properties fo:font-size="12pt" fo:font-style="italic" style:font-size-asian="12pt" style:font-style-asian="italic" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss" style:font-size-complex="12pt" style:font-style-complex="italic"/>
</style:style>
<style:style style:name="Index" style:family="paragraph" style:parent-style-name="Standard" style:class="index">
<style:paragraph-properties text:number-lines="false" text:line-number="0"/>
<style:text-properties style:font-size-asian="12pt" style:font-name-complex="Lucida Sans" style:font-family-complex="&apos;Lucida Sans&apos;" style:font-family-generic-complex="swiss"/>
</style:style>
<style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra">
<style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/>
</style:style>
<style:style style:name="Placeholder" style:family="text">
<style:text-properties fo:font-variant="small-caps" fo:color="#008080" loext:opacity="100%" style:text-underline-style="dotted" style:text-underline-width="auto" style:text-underline-color="font-color"/>
</style:style>
<text:outline-style style:name="Outline">
<text:outline-level-style text:level="1" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="2" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="3" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="4" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="5" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="6" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="7" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="8" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="9" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
<text:outline-level-style text:level="10" style:num-format="">
<style:list-level-properties text:list-level-position-and-space-mode="label-alignment">
<style:list-level-label-alignment text:label-followed-by="listtab"/>
</style:list-level-properties>
</text:outline-level-style>
</text:outline-style>
<text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/>
<text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/>
<text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/>
<loext:theme loext:name="Office Theme">
<loext:theme-colors loext:name="LibreOffice">
<loext:color loext:name="dark1" loext:color="#000000"/>
<loext:color loext:name="light1" loext:color="#ffffff"/>
<loext:color loext:name="dark2" loext:color="#000000"/>
<loext:color loext:name="light2" loext:color="#ffffff"/>
<loext:color loext:name="accent1" loext:color="#18a303"/>
<loext:color loext:name="accent2" loext:color="#0369a3"/>
<loext:color loext:name="accent3" loext:color="#a33e03"/>
<loext:color loext:name="accent4" loext:color="#8e03a3"/>
<loext:color loext:name="accent5" loext:color="#c99c00"/>
<loext:color loext:name="accent6" loext:color="#c9211e"/>
<loext:color loext:name="hyperlink" loext:color="#0000ee"/>
<loext:color loext:name="followed-hyperlink" loext:color="#551a8b"/>
</loext:theme-colors>
</loext:theme>
</office:styles>
<office:automatic-styles>
<style:style style:name="BillOfExchange" style:family="table">
<style:table-properties style:width="20.001cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="BillOfExchange.A" style:family="table-column">
<style:table-column-properties style:column-width="4.75cm"/>
</style:style>
<style:style style:name="BillOfExchange.B" style:family="table-column">
<style:table-column-properties style:column-width="15.251cm"/>
</style:style>
<style:style style:name="BillOfExchange.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="BillOfExchange.B1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.101cm" fo:border="0.5pt solid #000000"/>
</style:style>
<style:style style:name="Inner1" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner1.A" style:family="table-column">
<style:table-column-properties style:column-width="4.001cm"/>
</style:style>
<style:style style:name="Inner1.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner1.C" style:family="table-column">
<style:table-column-properties style:column-width="10.899cm"/>
</style:style>
<style:style style:name="Inner1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner1.C1" style:family="table-cell">
<style:table-cell-properties style:vertical-align="middle" fo:padding="0.101cm" fo:border="1.5pt solid #000000"/>
</style:style>
<style:style style:name="Inner2" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner2.A" style:family="table-column">
<style:table-column-properties style:column-width="4.5cm"/>
</style:style>
<style:style style:name="Inner2.B" style:family="table-column">
<style:table-column-properties style:column-width="13.899cm"/>
</style:style>
<style:style style:name="Inner2.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner2.B1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner3" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner3.A" style:family="table-column">
<style:table-column-properties style:column-width="18.399cm"/>
</style:style>
<style:style style:name="Inner3.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner4" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner4.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner4.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner4.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner4.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner5" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner5.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner5.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner5.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner5.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner6" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner6.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner6.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner6.F" style:family="table-column">
<style:table-column-properties style:column-width="3.902cm"/>
</style:style>
<style:style style:name="Inner6.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner6.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner1" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner1.A" style:family="table-column">
<style:table-column-properties style:column-width="4.001cm"/>
</style:style>
<style:style style:name="Inner1.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner1.C" style:family="table-column">
<style:table-column-properties style:column-width="10.899cm"/>
</style:style>
<style:style style:name="Inner1.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner1.C1" style:family="table-cell">
<style:table-cell-properties style:vertical-align="middle" fo:padding="0.101cm" fo:border="1.5pt solid #000000"/>
</style:style>
<style:style style:name="Inner2" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner2.A" style:family="table-column">
<style:table-column-properties style:column-width="4.5cm"/>
</style:style>
<style:style style:name="Inner2.B" style:family="table-column">
<style:table-column-properties style:column-width="13.899cm"/>
</style:style>
<style:style style:name="Inner2.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner2.B1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner3" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner3.A" style:family="table-column">
<style:table-column-properties style:column-width="18.399cm"/>
</style:style>
<style:style style:name="Inner3.A1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner4" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner4.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner4.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner4.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner4.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner5" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner5.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner5.B" style:family="table-column">
<style:table-column-properties style:column-width="15.9cm"/>
</style:style>
<style:style style:name="Inner5.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner5.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="Inner6" style:family="table">
<style:table-properties style:width="18.399cm" fo:margin-left="0cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left"/>
</style:style>
<style:style style:name="Inner6.A" style:family="table-column">
<style:table-column-properties style:column-width="2.499cm"/>
</style:style>
<style:style style:name="Inner6.B" style:family="table-column">
<style:table-column-properties style:column-width="3.5cm"/>
</style:style>
<style:style style:name="Inner6.F" style:family="table-column">
<style:table-column-properties style:column-width="3.902cm"/>
</style:style>
<style:style style:name="Inner6.A1" style:family="table-cell">
<style:table-cell-properties fo:padding="0.049cm" fo:border="none"/>
</style:style>
<style:style style:name="Inner6.B1" style:family="table-cell">
<style:table-cell-properties fo:padding-left="0.101cm" fo:padding-right="0.049cm" fo:padding-top="0.049cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.05pt solid #000000"/>
</style:style>
<style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
</style:style>
<style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="8pt" fo:font-weight="bold"/>
</style:style>
<style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
</style:style>
<style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="end" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="8pt"/>
</style:style>
<style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
</style:style>
<style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
</style:style>
<style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="9pt" fo:font-weight="bold"/>
</style:style>
<style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="7pt"/>
</style:style>
<style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard">
<style:paragraph-properties fo:margin-top="0cm" fo:margin-bottom="0cm" style:contextual-spacing="false" fo:text-align="center" style:justify-single-word="false"/>
<style:text-properties style:font-name="Arial" fo:font-size="7pt" officeooo:paragraph-rsid="001d1a93"/>
</style:style>
<style:page-layout style:name="pm1">
<style:page-layout-properties fo:page-width="21.001cm" fo:page-height="9.999cm" style:num-format="1" style:print-orientation="landscape" fo:margin-top="0.4cm" fo:margin-bottom="0.4cm" fo:margin-left="0.499cm" fo:margin-right="0.499cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm">
<style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
</style:page-layout-properties>
<style:header-style/>
<style:footer-style/>
</style:page-layout>
<style:style style:name="dp1" style:family="drawing-page">
<style:drawing-page-properties draw:background-size="full"/>
</style:style>
</office:automatic-styles>
<office:master-styles>
<style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/>
</office:master-styles>
<office:body>
<office:text>
<text:sequence-decls>
<text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>
<text:sequence-decl text:display-outline-level="0" text:name="Table"/>
<text:sequence-decl text:display-outline-level="0" text:name="Text"/>
<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>
<text:sequence-decl text:display-outline-level="0" text:name="Figure"/>
</text:sequence-decls>
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;for each=&quot;sale in records&quot;&gt;</text:placeholder></text:p>
<table:table table:name="BillOfExchange" table:style-name="BillOfExchange">
<table:table-column table:style-name="BillOfExchange.A"/>
<table:table-column table:style-name="BillOfExchange.B"/>
<table:table-row>
<table:table-cell table:style-name="BillOfExchange.A1" table:number-rows-spanned="2" office:value-type="string">
<text:p text:style-name="P6">Accepted by:</text:p>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P6"/>
<text:p text:style-name="P9">Per aval:</text:p>
</table:table-cell>
<table:table-cell table:style-name="BillOfExchange.B1" office:value-type="string">
<table:table table:name="Inner1" table:style-name="Inner1">
<table:table-column table:style-name="Inner1.A"/>
<table:table-column table:style-name="Inner1.B"/>
<table:table-column table:style-name="Inner1.C"/>
<table:table-row>
<table:table-cell table:style-name="Inner1.A1" office:value-type="string">
<text:p text:style-name="P1">Geneva, <text:placeholder text:placeholder-type="text">&lt;format_date(sale.sale_date, sale.party.lang)&gt;</text:placeholder></text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner1.A1" office:value-type="string">
<text:p text:style-name="P1">For</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner1.C1" office:value-type="string">
<text:p text:style-name="P7"><text:placeholder text:placeholder-type="text">&lt;format_currency(sale.lines[0].unit_price, sale.party.lang, sale.currency) if sale.lines else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
<table:table table:name="Inner2" table:style-name="Inner2">
<table:table-column table:style-name="Inner2.A"/>
<table:table-column table:style-name="Inner2.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner2.A1" office:value-type="string">
<text:p text:style-name="P1">At / on <text:placeholder text:placeholder-type="text">&lt;sale.payment_term.rec_name if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner2.B1" office:value-type="string">
<text:p text:style-name="P1">for value received, please pay against this sole Bill of Exchange</text:p>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P1">to our order of Melya S.A., Switzerland, the amount of</text:p>
<table:table table:name="Inner3" table:style-name="Inner3">
<table:table-column table:style-name="Inner3.A"/>
<table:table-row>
<table:table-cell table:style-name="Inner3.A1" office:value-type="string">
<text:p text:style-name="P1"> </text:p>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P5">effective payment to be made in <text:placeholder text:placeholder-type="text">&lt;sale.currency.symbol if sale.currency else &apos;&apos;&gt;</text:placeholder> only, without deduction for and free of any taxes, impost, levies or duties present or future of any nature under the laws of <text:placeholder text:placeholder-type="text">&lt;sale.party.addresses[0].country.name if sale.party and sale.party.addresses else &apos;&apos;&gt;</text:placeholder> or any political subdivision thereof or therein.</text:p>
<table:table table:name="Inner4" table:style-name="Inner4">
<table:table-column table:style-name="Inner4.A"/>
<table:table-column table:style-name="Inner4.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner4.A1" office:value-type="string">
<text:p text:style-name="P1">Payable at</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner4.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.party.addresses[0].city if sale.party and sale.party.addresses else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
<table:table table:name="Inner5" table:style-name="Inner5">
<table:table-column table:style-name="Inner5.A"/>
<table:table-column table:style-name="Inner5.B"/>
<table:table-row>
<table:table-cell table:style-name="Inner5.A1" office:value-type="string">
<text:p text:style-name="P1">Drawn on at</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner5.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.party.rec_name&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
<table:table table:name="Inner6" table:style-name="Inner6">
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.B"/>
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.B"/>
<table:table-column table:style-name="Inner6.A"/>
<table:table-column table:style-name="Inner6.F"/>
<table:table-row>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">No</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"> </text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">/ Invoice No</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.full_number&gt;</text:placeholder></text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.A1" office:value-type="string">
<text:p text:style-name="P1">/ D:</text:p>
</table:table-cell>
<table:table-cell table:style-name="Inner6.B1" office:value-type="string">
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;sale.reference if sale.reference else &apos;&apos;&gt;</text:placeholder></text:p>
</table:table-cell>
</table:table-row>
</table:table>
</table:table-cell>
</table:table-row>
<table:table-row>
<table:covered-table-cell table:style-name="BillOfExchange.A1"/>
<table:table-cell table:style-name="BillOfExchange.A1" office:value-type="string">
<text:p text:style-name="P6"/>
</table:table-cell>
</table:table-row>
</table:table>
<text:p text:style-name="P1"><text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder></text:p>
</office:text>
</office:body>
</office:document>

View File

@@ -422,6 +422,18 @@ this repository contains the full copyright notices and license terms. -->
<field name="action" ref="report_bill"/> <field name="action" ref="report_bill"/>
</record> </record>
<record model="ir.action.report" id="report_sale_final">
<field name="name">Sale (final)</field>
<field name="model">sale.sale</field>
<field name="report_name">sale.sale</field>
<field name="report">sale/sale_final.fodt</field>
</record>
<record model="ir.action.keyword" id="report_sale_final_keyword">
<field name="keyword">form_print</field>
<field name="model">sale.sale,-1</field>
<field name="action" ref="report_sale_final"/>
</record>
<record model="ir.ui.view" id="sale_line_view_form"> <record model="ir.ui.view" id="sale_line_view_form">
<field name="model">sale.line</field> <field name="model">sale.line</field>
<field name="type">form</field> <field name="type">form</field>

View File

@@ -4069,7 +4069,7 @@
<text:s /> <text:s />
<text:span text:style-name="T21">CROP </text:span> <text:span text:style-name="T21">CROP </text:span>
<text:span text:style-name="T21"> <text:span text:style-name="T21">
<text:placeholder text:placeholder-type="text">&lt;sale.report_crop_name&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;sale.crop.name&gt;</text:placeholder>
</text:span> </text:span>
</text:p> </text:p>
</table:table-cell> </table:table-cell>
@@ -4091,19 +4091,10 @@
<text:p text:style-name="P42" /> <text:p text:style-name="P42" />
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Table4.A1" office:value-type="string"> <table:table-cell table:style-name="Table4.A1" office:value-type="string">
<text:p text:style-name="P31">ABOUT <text:placeholder text:placeholder-type="text">&lt;sale.report_total_quantity&gt;</text:placeholder><text:s /><text:placeholder text:placeholder-type="text">&lt;sale.report_quantity_unit_upper&gt;</text:placeholder><text:s /><text:span text:style-name="T23">(</text:span><text:span text:style-name="T23"><text:placeholder text:placeholder-type="text">&lt;sale.report_qt&gt;</text:placeholder></text:span><text:span text:style-name="T23">) </text:span></text:p> <text:p text:style-name="P31">ABOUT <text:placeholder text:placeholder-type="text">&lt;sum(line.quantity for line in sale.lines)&gt;</text:placeholder><text:s /><text:placeholder text:placeholder-type="text">&lt;sale.lines[0].unit.rec_name.upper() if sale.lines and sale.lines[0].unit else ''&gt;</text:placeholder><text:s /><text:span text:style-name="T23">(</text:span><text:span text:style-name="T23"><text:placeholder text:placeholder-type="text">&lt;sale.report_qt&gt;</text:placeholder></text:span><text:span text:style-name="T23">) </text:span></text:p>
<text:p text:style-name="P39"> <text:p text:style-name="P39">
<text:placeholder text:placeholder-type="text">&lt;sale.report_nb_bale&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;sale.report_nb_bale&gt;</text:placeholder>
</text:p> </text:p>
<text:p text:style-name="P39">
<text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in sale.report_quantity_lines.splitlines()&quot;&gt;</text:placeholder>
</text:p>
<text:p text:style-name="P39">
<text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder>
</text:p>
<text:p text:style-name="P39">
<text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder>
</text:p>
<text:p text:style-name="P39" /> <text:p text:style-name="P39" />
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>
@@ -4119,13 +4110,27 @@
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Table5.A1" office:value-type="string"> <table:table-cell table:style-name="Table5.A1" office:value-type="string">
<text:p text:style-name="P56"> <text:p text:style-name="P56">
<text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in sale.report_price_lines.splitlines()&quot;&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;sale.lines[0].linked_currency.rec_name.upper() if sale.lines[0].linked_currency else sale.currency.rec_name.upper()&gt;</text:placeholder>
</text:p> <text:s />
<text:p text:style-name="P56"> <text:placeholder text:placeholder-type="text">&lt;sale.lines[0].linked_price if sale.lines[0].linked_price else sale.lines[0].unit_price&gt;</text:placeholder>
<text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder> <text:span text:style-name="T23">
</text:p> <text:s />
<text:p text:style-name="P56"> </text:span>
<text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder> <text:span text:style-name="T26">PER </text:span>
<text:span text:style-name="T26">
<text:placeholder text:placeholder-type="text">&lt;sale.lines[0].linked_unit.rec_name.upper() if sale.lines[0].linked_unit else sale.lines[0].unit.rec_name.upper()&gt;</text:placeholder>
</text:span>
<text:span text:style-name="T26">
<text:s />
</text:span>
<text:span text:style-name="T23">(</text:span>
<text:span text:style-name="T26">
<text:placeholder text:placeholder-type="text">&lt;sale.report_price&gt;</text:placeholder>
</text:span>
<text:span text:style-name="T23">) </text:span>
<text:span text:style-name="T23">
<text:placeholder text:placeholder-type="text">&lt;sale.lines[0].get_pricing_text&gt;</text:placeholder>
</text:span>
</text:p> </text:p>
<text:p text:style-name="P37" /> <text:p text:style-name="P37" />
</table:table-cell> </table:table-cell>
@@ -4194,18 +4199,12 @@
</text:p> </text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Table6.A1" office:value-type="string"> <table:table-cell table:style-name="Table6.A1" office:value-type="string">
<text:p text:style-name="P36">
<text:placeholder text:placeholder-type="text">&lt;for each=&quot;line in sale.report_shipment_periods.splitlines()&quot;&gt;</text:placeholder>
</text:p>
<text:p text:style-name="P36"> <text:p text:style-name="P36">
<text:s /> <text:s />
<text:span text:style-name="T24"> <text:span text:style-name="T24">
<text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder> <text:placeholder text:placeholder-type="text">&lt;sale.lines[0].del_period.description if sale.lines[0].del_period else ''&gt;</text:placeholder>
</text:span> </text:span>
</text:p> </text:p>
<text:p text:style-name="P36">
<text:placeholder text:placeholder-type="text">&lt;/for&gt;</text:placeholder>
</text:p>
<text:p text:style-name="P34" /> <text:p text:style-name="P34" />
</table:table-cell> </table:table-cell>
</table:table-row> </table:table-row>

View File

@@ -1763,8 +1763,8 @@
<text:p text:style-name="P25" loext:marker-style-name="T39"/> <text:p text:style-name="P25" loext:marker-style-name="T39"/>
<text:p text:style-name="P24" loext:marker-style-name="T39"/> <text:p text:style-name="P24" loext:marker-style-name="T39"/>
<text:p text:style-name="P24" loext:marker-style-name="T39"/> <text:p text:style-name="P24" loext:marker-style-name="T39"/>
<text:p text:style-name="P39" loext:marker-style-name="T26"><text:span text:style-name="T26"><text:s text:c="2"/></text:span><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.report_product_name or &apos;&apos;&gt;</text:placeholder></text:span></text:p> <text:p text:style-name="P39" loext:marker-style-name="T26"><text:span text:style-name="T26"><text:s text:c="2"/></text:span><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.lines[0].product.name if sale.lines and sale.lines[0].product else &apos;&apos;&gt;</text:placeholder></text:span></text:p>
<text:p text:style-name="P30" loext:marker-style-name="T26"><text:span text:style-name="T42"><text:placeholder text:placeholder-type="text">&lt;sale.report_product_description or &apos;&apos;&gt;</text:placeholder></text:span></text:p> <text:p text:style-name="P30" loext:marker-style-name="T26"/>
<text:p text:style-name="P27" loext:marker-style-name="T42"><text:span text:style-name="T42"><text:s/></text:span></text:p> <text:p text:style-name="P27" loext:marker-style-name="T42"><text:span text:style-name="T42"><text:s/></text:span></text:p>
</table:table-cell> </table:table-cell>
<table:table-cell table:style-name="Tableau1.B2" office:value-type="string"> <table:table-cell table:style-name="Tableau1.B2" office:value-type="string">
@@ -1791,7 +1791,7 @@
<text:p text:style-name="P9"/> <text:p text:style-name="P9"/>
<text:p text:style-name="P9"/> <text:p text:style-name="P9"/>
<text:p text:style-name="P9"/> <text:p text:style-name="P9"/>
<text:p text:style-name="P9"><text:span text:style-name="T51">SHIPMENT SCHEDULE</text:span>:<text:tab/><text:span text:style-name="T45"><text:placeholder text:placeholder-type="text">&lt;sale.report_delivery_period_description or &apos;&apos;&gt;</text:placeholder></text:span></text:p> <text:p text:style-name="P9"><text:span text:style-name="T51">SHIPMENT SCHEDULE</text:span>:<text:tab/><text:span text:style-name="T45"><text:placeholder text:placeholder-type="text">&lt;sale.lines[0].del_period.month_name if sale.lines and sale.lines[0].del_period else &apos;&apos;&gt;</text:placeholder></text:span></text:p>
<text:p text:style-name="P9"/> <text:p text:style-name="P9"/>
<text:p text:style-name="P6">TOLERANCE:<text:tab/><text:tab/>+/- <text:placeholder text:placeholder-type="text">&lt;sale.tol_min&gt;</text:placeholder><text:s/>%</text:p> <text:p text:style-name="P6">TOLERANCE:<text:tab/><text:tab/>+/- <text:placeholder text:placeholder-type="text">&lt;sale.tol_min&gt;</text:placeholder><text:s/>%</text:p>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
@@ -1803,13 +1803,6 @@
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P7">PAYMENT TERMS:<text:tab/><text:placeholder text:placeholder-type="text">&lt;sale.payment_term.description if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p> <text:p text:style-name="P7">PAYMENT TERMS:<text:tab/><text:placeholder text:placeholder-type="text">&lt;sale.payment_term.description if sale.payment_term else &apos;&apos;&gt;</text:placeholder></text:p>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P8">BANK: UBS SWITZERLAND AG</text:p>
<text:p text:style-name="P8">Case Postale</text:p>
<text:p text:style-name="P8">CH-1211 Geneve 2</text:p>
<text:p text:style-name="P2"/>
<text:p text:style-name="P8">IBAN : CH36 0021 5215 2487 7461 D</text:p>
<text:p text:style-name="P8">SwifT Code: UBSWCHZH80A</text:p>
<text:p text:style-name="P2"/>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>
<text:p text:style-name="P2">DELIVERY IS SUBJECT TO THE DELIVERY BY OUR SUPPLIER.</text:p> <text:p text:style-name="P2">DELIVERY IS SUBJECT TO THE DELIVERY BY OUR SUPPLIER.</text:p>
<text:p text:style-name="P2"/> <text:p text:style-name="P2"/>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool
from . import (
financing,
market,
valuation,
document,
template_execution,
counterparty,
fx,
operational,
facility,
constraint_type,
)
def register():
Pool.register(
financing.FinancingType,
financing.OperationalStatus,
market.MarketIndex,
market.MarketIndexRate,
market.IndexTerm,
market.InterestFormula,
valuation.ValuationMethod,
valuation.HaircutFormula,
valuation.CollateralType,
document.EvidenceType,
template_execution.TemplateSegment,
template_execution.ExecutionTemplate,
template_execution.ExecutionTemplateLine,
counterparty.ReceivableCategory,
counterparty.PaymentConditionType,
fx.FxFeeder,
operational.BlockingReason,
operational.ChargeType,
facility.FacilityStatus,
facility.Facility,
facility.FacilityCurrency,
facility.FacilityCovenant,
facility.FacilityLimit,
facility.FacilityLimitHaircut,
facility.FacilityLimitCurrency,
facility.FacilityLimitCost,
facility.FacilityLimitCostVariation,
facility.FacilityLimitOpStatus,
facility.FacilityLimitBankAccount,
facility.FacilityCap,
facility.FacilityCapHaircut,
facility.FacilityConstraint,
constraint_type.ConstraintType,
module='trade_finance', type_='model')
Pool.register(
fx.PriceCalendar,
module='price', type_='model')

View File

@@ -0,0 +1,54 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.transaction import Transaction
__all__ = ['ConstraintType']
class ConstraintType(ModelSQL, ModelView):
'Constraint Type'
__name__ = 'trade_finance.constraint_type'
_rec_name = 'name'
name = fields.Char('Type', required=True, size=50)
view_name = fields.Selection([], 'View')
value_field = fields.Selection(
'get_column_selection', 'Value Field',
selection_change_with=['view_name'])
label_field = fields.Selection(
'get_column_selection', 'Label Field',
selection_change_with=['view_name'])
@fields.depends('view_name')
def get_column_selection(self):
if not self.view_name:
return [('', '')]
cursor = Transaction().connection.cursor()
cursor.execute(
"SELECT column_name FROM information_schema.columns "
"WHERE table_schema = 'public' AND table_name = %s "
"ORDER BY ordinal_position",
(self.view_name,)
)
return [('', '')] + [(r[0], r[0]) for r in cursor.fetchall()]
@fields.depends('view_name')
def on_change_view_name(self):
self.value_field = None
self.label_field = None
@classmethod
def fields_get(cls, fields_names=None, level=0):
res = super().fields_get(fields_names, level)
if 'view_name' in res:
cursor = Transaction().connection.cursor()
cursor.execute(
"SELECT table_name FROM information_schema.views "
"WHERE table_schema = 'public' AND table_name LIKE 'vw_tf_const_%' "
"ORDER BY table_name"
)
res['view_name']['selection'] = (
[('', '')] + [(r[0], r[0]) for r in cursor.fetchall()])
return res

View File

@@ -0,0 +1,66 @@
<?xml version="1.0"?>
<tryton>
<data>
<!-- ================================================================ -->
<!-- CONSTRAINT TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="constraint_type_view_tree">
<field name="model">trade_finance.constraint_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">constraint_type_tree</field>
</record>
<record model="ir.ui.view" id="constraint_type_view_form">
<field name="model">trade_finance.constraint_type</field>
<field name="type">form</field>
<field name="name">constraint_type_form</field>
</record>
<record model="ir.action.act_window" id="act_constraint_type">
<field name="name">Constraint Types</field>
<field name="res_model">trade_finance.constraint_type</field>
</record>
<record model="ir.action.act_window.view" id="act_constraint_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="constraint_type_view_tree"/>
<field name="act_window" ref="act_constraint_type"/>
</record>
<record model="ir.action.act_window.view" id="act_constraint_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="constraint_type_view_form"/>
<field name="act_window" ref="act_constraint_type"/>
</record>
<menuitem
name="Constraint Types"
sequence="10"
id="menu_constraint_type"
parent="menu_trade_finance_configuration"
action="act_constraint_type"/>
<record model="ir.model.access" id="access_constraint_type">
<field name="model">trade_finance.constraint_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_constraint_type_user">
<field name="model">trade_finance.constraint_type</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_constraint_type_admin">
<field name="model">trade_finance.constraint_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,39 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['ReceivableCategory', 'PaymentConditionType']
class ReceivableCategory(ModelSQL, ModelView):
'Receivable Category'
__name__ = 'trade_finance.receivable_category'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class PaymentConditionType(ModelSQL, ModelView):
'Payment Condition Type'
__name__ = 'trade_finance.payment_condition_type'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
remaining_risk_pct = fields.Numeric(
'Remaining Risk (%)', digits=(16, 2),
help='Percentage of residual credit risk retained by the company '
'under this payment condition')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True

View File

@@ -0,0 +1,21 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['EvidenceType']
class EvidenceType(ModelSQL, ModelView):
'Evidence Type'
__name__ = 'trade_finance.evidence_type'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True

View File

@@ -0,0 +1,497 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.model import sequence_ordered
from trytond.pool import Pool
from trytond.pyson import Eval, Bool
from trytond.exceptions import UserError
__all__ = [
'FacilityStatus',
'Facility',
'FacilityCurrency',
'FacilityCovenant',
'FacilityLimit',
'FacilityLimitHaircut',
'FacilityLimitCurrency',
'FacilityLimitCost',
'FacilityLimitCostVariation',
'FacilityLimitOpStatus',
'FacilityLimitBankAccount',
'FacilityCap',
'FacilityCapHaircut',
'FacilityConstraint',
]
# ---------------------------------------------------------------------------
# Shared Selection lists
# ---------------------------------------------------------------------------
ATTRIBUTE_TYPES = [
('commodity', 'Commodity'),
('article', 'Article'),
('origin', 'Origin'),
('destination', 'Destination'),
('loading_place', 'Loading Place'),
('supplier', 'Supplier'),
('customer', 'Customer'),
('payment_condition_purchase', 'Payment Condition (Purchase)'),
('payment_condition_sale', 'Payment Condition (Sale)'),
('purchase_currency', 'Purchase Currency'),
('warehouse', 'Warehouse'),
('incoterm', 'Incoterm'),
('counterparty_rating', 'Counterparty Rating'),
('receivable_category', 'Receivable Category'),
]
# ---------------------------------------------------------------------------
# Facility Status (configurable reference)
# ---------------------------------------------------------------------------
class FacilityStatus(ModelSQL, ModelView):
'Facility Status'
__name__ = 'trade_finance.facility_status'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
# ---------------------------------------------------------------------------
# Facility Header
# ---------------------------------------------------------------------------
class Facility(ModelSQL, ModelView):
'TF Facility'
__name__ = 'trade_finance.facility'
_rec_name = 'name'
name = fields.Char('Name', required=True)
tfe = fields.Many2One('bank', 'Trade Finance Entity', required=True,
ondelete='RESTRICT',
help='Bank or fund providing this facility')
description = fields.Text('Description')
status = fields.Many2One('trade_finance.facility_status', 'Status',
ondelete='RESTRICT')
commitment_status = fields.Selection([
('uncommitted', 'Uncommitted'),
('committed', 'Committed'),
], 'Commitment Status', required=True)
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
currency = fields.Many2One('currency.currency', 'Facility Currency',
required=True, ondelete='RESTRICT')
fx_feeder = fields.Many2One('trade_finance.fx_feeder', 'FX Rate Feeder',
ondelete='RESTRICT')
fx_haircut_pct = fields.Numeric('FX Haircut (%)', digits=(16, 2))
is_tpa = fields.Boolean('TPA',
help='Third Party Account — broker managed structure')
broker = fields.Many2One('party.party', 'Broker',
states={'invisible': ~Bool(Eval('is_tpa'))},
depends=['is_tpa'], ondelete='RESTRICT')
broker_account = fields.Char('Broker Account',
states={'invisible': ~Bool(Eval('is_tpa'))},
depends=['is_tpa'])
limits = fields.One2Many('trade_finance.facility_limit', 'facility',
'Limits')
currencies = fields.One2Many('trade_finance.facility_currency', 'facility',
'Accepted Currencies')
caps = fields.One2Many('trade_finance.facility_cap', 'facility', 'Caps')
covenants = fields.One2Many('trade_finance.facility_covenant', 'facility',
'Covenants')
constraints = fields.One2Many('trade_finance.facility_constraint',
'facility', 'Facility Constraints',
domain=[('limit', '=', None)])
@classmethod
def default_status(cls):
pool = Pool()
FacilityStatus = pool.get('trade_finance.facility_status')
statuses = FacilityStatus.search([('code', '=', 'DRAFT')], limit=1)
if statuses:
return statuses[0].id
return None
@staticmethod
def default_commitment_status():
return 'uncommitted'
@staticmethod
def default_is_tpa():
return False
# ---------------------------------------------------------------------------
# Facility Accepted Currency
# ---------------------------------------------------------------------------
class FacilityCurrency(ModelSQL, ModelView):
'Facility Currency'
__name__ = 'trade_finance.facility_currency'
facility = fields.Many2One('trade_finance.facility', 'Facility',
required=True, ondelete='CASCADE')
currency = fields.Many2One('currency.currency', 'Currency',
required=True, ondelete='RESTRICT')
fx_haircut_formula = fields.Many2One('trade_finance.haircut_formula',
'FX Haircut Formula', ondelete='RESTRICT')
fx_feeder = fields.Many2One('trade_finance.fx_feeder', 'FX Rate Feeder',
ondelete='RESTRICT')
valuation_method = fields.Many2One('trade_finance.valuation_method',
'Valuation Method', ondelete='RESTRICT')
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
# ---------------------------------------------------------------------------
# Covenant
# ---------------------------------------------------------------------------
class FacilityCovenant(ModelSQL, ModelView):
'Facility Covenant'
__name__ = 'trade_finance.facility_covenant'
_rec_name = 'name'
facility = fields.Many2One('trade_finance.facility', 'Facility',
required=True, ondelete='CASCADE')
name = fields.Char('Covenant', required=True)
ratio_type = fields.Selection([
('leverage_ratio', 'Leverage Ratio'),
('dso', 'DSO'),
('interest_coverage', 'Interest Coverage Ratio'),
('current_ratio', 'Current Ratio'),
('other', 'Other'),
], 'Ratio Type', required=True)
threshold = fields.Numeric('Threshold', digits=(16, 4))
currency = fields.Many2One('currency.currency', 'Currency',
ondelete='RESTRICT')
notes = fields.Text('Notes')
# ---------------------------------------------------------------------------
# Facility Limit (Global Limit + Sub-Limits in one model)
# ---------------------------------------------------------------------------
class FacilityLimit(ModelSQL, ModelView):
'Facility Limit'
__name__ = 'trade_finance.facility_limit'
_rec_name = 'name'
facility = fields.Many2One('trade_finance.facility', 'Facility',
required=True, ondelete='CASCADE',
states={'readonly': Bool(Eval('parent'))},
depends=['parent'])
parent = fields.Many2One('trade_finance.facility_limit', 'Parent Limit',
ondelete='RESTRICT',
domain=[('facility', '=', Eval('facility'))],
depends=['facility'],
help='Leave empty for Global Limit (root node)')
children = fields.One2Many('trade_finance.facility_limit', 'parent',
'Sub-Limits')
name = fields.Char('Name', required=True)
alternative_name = fields.Char('Limit Alternative Name')
financing_type = fields.Many2One('trade_finance.financing_type',
'Financing Type', ondelete='RESTRICT')
amount = fields.Numeric('Amount', digits=(16, 2), required=True)
tenor = fields.Integer('Tenor (days)',
help='Maximum duration of financing from drawdown to repayment')
sequence = fields.Integer('Sequence')
_order = [('sequence', 'ASC'), ('id', 'ASC')]
haircuts = fields.One2Many('trade_finance.facility_limit_haircut', 'limit',
'Haircuts')
currencies = fields.One2Many('trade_finance.facility_limit_currency',
'limit', 'Accepted Currencies')
costs = fields.One2Many('trade_finance.facility_limit_cost', 'limit',
'Costs')
op_statuses = fields.One2Many('trade_finance.facility_limit_op_status',
'limit', 'Expected Operational Statuses')
bank_accounts = fields.One2Many('trade_finance.facility_limit_bank_account',
'limit', 'Bank Accounts')
constraints = fields.One2Many('trade_finance.facility_constraint', 'limit',
'Limit Constraints',
domain=[('facility', '=', None)])
@staticmethod
def default_sequence():
return 10
@classmethod
def create(cls, vlist):
vlist = [v.copy() for v in vlist]
for values in vlist:
if values.get('parent') and not values.get('facility'):
parent = cls(values['parent'])
values['facility'] = parent.facility.id
return super().create(vlist)
@classmethod
def validate(cls, limits):
super().validate(limits)
for limit in limits:
limit.check_single_root()
limit.check_amount_vs_parent()
limit.check_children_amounts()
def check_single_root(self):
if self.parent is None:
roots = self.__class__.search([
('facility', '=', self.facility.id),
('parent', '=', None),
('id', '!=', self.id),
])
if roots:
raise UserError(
f"Facility '{self.facility.name}' already has a Global "
f"Limit ('{roots[0].name}'). Only one root limit is "
f"allowed per facility.")
def check_amount_vs_parent(self):
if self.parent and self.amount > self.parent.amount:
raise UserError(
f"Sub-limit '{self.name}' amount ({self.amount}) "
f"cannot exceed parent limit '{self.parent.name}' "
f"amount ({self.parent.amount}).")
def check_children_amounts(self):
for child in self.children:
if child.amount > self.amount:
raise UserError(
f"Sub-limit '{child.name}' amount ({child.amount}) "
f"cannot exceed parent limit '{self.name}' "
f"amount ({self.amount}).")
# ---------------------------------------------------------------------------
# Limit Haircut
# ---------------------------------------------------------------------------
class FacilityLimitHaircut(ModelSQL, ModelView):
'Facility Limit Haircut'
__name__ = 'trade_finance.facility_limit_haircut'
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
required=True, ondelete='CASCADE')
attribute = fields.Selection(ATTRIBUTE_TYPES, 'Attribute Type',
required=True)
value = fields.Char('Value',
help='The specific attribute value this haircut applies to '
'(e.g. "Brazil", "Coffee", "USD")')
haircut_pct = fields.Numeric('Haircut (%)', digits=(16, 2), required=True)
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
# ---------------------------------------------------------------------------
# Limit Accepted Currency
# ---------------------------------------------------------------------------
class FacilityLimitCurrency(ModelSQL, ModelView):
'Facility Limit Currency'
__name__ = 'trade_finance.facility_limit_currency'
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
required=True, ondelete='CASCADE')
currency = fields.Many2One('currency.currency', 'Currency',
required=True, ondelete='RESTRICT')
haircut_pct = fields.Numeric('FX Haircut (%)', digits=(16, 2))
fx_feeder = fields.Many2One('trade_finance.fx_feeder', 'FX Rate Feeder',
ondelete='RESTRICT')
valuation_method = fields.Many2One('trade_finance.valuation_method',
'Valuation Method', ondelete='RESTRICT')
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
# ---------------------------------------------------------------------------
# Limit Cost
# ---------------------------------------------------------------------------
class FacilityLimitCost(ModelSQL, ModelView):
'Facility Limit Cost'
__name__ = 'trade_finance.facility_limit_cost'
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
required=True, ondelete='CASCADE')
cost_type = fields.Selection([
('interest', 'Interest-Based'),
('flat', 'Flat / Minimal Amount'),
], 'Cost Type', required=True)
# Interest-based fields
spread = fields.Numeric('Spread (%)', digits=(16, 4),
states={'invisible': Eval('cost_type') != 'interest'},
depends=['cost_type'])
index = fields.Many2One('trade_finance.market_index', 'Market Index',
ondelete='RESTRICT',
states={'invisible': Eval('cost_type') != 'interest'},
depends=['cost_type'])
index_term = fields.Many2One('trade_finance.index_term', 'Index Term',
ondelete='RESTRICT',
states={'invisible': Eval('cost_type') != 'interest'},
depends=['cost_type'])
interest_formula = fields.Many2One('trade_finance.interest_formula',
'Interest Formula', ondelete='RESTRICT',
states={'invisible': Eval('cost_type') != 'interest'},
depends=['cost_type'])
# Flat fields
flat_amount = fields.Numeric('Flat Amount', digits=(16, 2),
states={'invisible': Eval('cost_type') != 'flat'},
depends=['cost_type'])
flat_currency = fields.Many2One('currency.currency', 'Currency',
ondelete='RESTRICT',
states={'invisible': Eval('cost_type') != 'flat'},
depends=['cost_type'])
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
variations = fields.One2Many('trade_finance.facility_limit_cost_variation',
'cost', 'Cost Variations')
# ---------------------------------------------------------------------------
# Limit Cost Variation
# ---------------------------------------------------------------------------
class FacilityLimitCostVariation(ModelSQL, ModelView):
'Facility Limit Cost Variation'
__name__ = 'trade_finance.facility_limit_cost_variation'
cost = fields.Many2One('trade_finance.facility_limit_cost', 'Cost',
required=True, ondelete='CASCADE')
attribute = fields.Selection(ATTRIBUTE_TYPES, 'Attribute Type',
required=True)
value = fields.Char('Value')
variation_type = fields.Selection([
('pct', 'Percentage (+/-)'),
('flat', 'Flat Amount (+/-)'),
], 'Variation Type', required=True)
variation_value = fields.Numeric('Variation Value', digits=(16, 4),
required=True)
variation_currency = fields.Many2One('currency.currency', 'Currency',
ondelete='RESTRICT',
states={'invisible': Eval('variation_type') != 'flat'},
depends=['variation_type'])
# ---------------------------------------------------------------------------
# Limit Expected Operational Status
# ---------------------------------------------------------------------------
class FacilityLimitOpStatus(ModelSQL, ModelView):
'Facility Limit Operational Status'
__name__ = 'trade_finance.facility_limit_op_status'
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
required=True, ondelete='CASCADE')
operational_status = fields.Many2One('trade_finance.operational_status',
'Operational Status', required=True, ondelete='RESTRICT')
evidence_type = fields.Many2One('trade_finance.evidence_type',
'Required Evidence', ondelete='RESTRICT',
help='Evidence required when this operational status is reached')
# ---------------------------------------------------------------------------
# Limit Bank Account
# ---------------------------------------------------------------------------
class FacilityLimitBankAccount(ModelSQL, ModelView):
'Facility Limit Bank Account'
__name__ = 'trade_finance.facility_limit_bank_account'
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
required=True, ondelete='CASCADE')
bank_account = fields.Many2One('bank.account', 'Bank Account',
required=True, ondelete='RESTRICT')
currency = fields.Many2One('currency.currency', 'Currency',
required=True, ondelete='RESTRICT')
is_default = fields.Boolean('Default')
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
@staticmethod
def default_is_default():
return False
# ---------------------------------------------------------------------------
# Cap
# ---------------------------------------------------------------------------
class FacilityCap(ModelSQL, ModelView):
'Facility Cap'
__name__ = 'trade_finance.facility_cap'
_rec_name = 'name'
facility = fields.Many2One('trade_finance.facility', 'Facility',
required=True, ondelete='CASCADE')
name = fields.Char('Name', required=True)
amount = fields.Numeric('Cap Amount', digits=(16, 2), required=True)
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
haircuts = fields.One2Many('trade_finance.facility_cap_haircut', 'cap',
'Haircuts')
constraints = fields.One2Many('trade_finance.facility_constraint', 'cap',
'Cap Constraints')
# ---------------------------------------------------------------------------
# Cap Haircut
# ---------------------------------------------------------------------------
class FacilityCapHaircut(ModelSQL, ModelView):
'Facility Cap Haircut'
__name__ = 'trade_finance.facility_cap_haircut'
cap = fields.Many2One('trade_finance.facility_cap', 'Cap',
required=True, ondelete='CASCADE')
attribute = fields.Selection(ATTRIBUTE_TYPES, 'Attribute Type',
required=True)
value = fields.Char('Value')
haircut_pct = fields.Numeric('Haircut (%)', digits=(16, 2), required=True)
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
# ---------------------------------------------------------------------------
# Constraint (shared by Facility, Limit, Cap)
# ---------------------------------------------------------------------------
class FacilityConstraint(ModelSQL, ModelView):
'Facility Constraint'
__name__ = 'trade_finance.facility_constraint'
facility = fields.Many2One('trade_finance.facility', 'Facility',
ondelete='CASCADE')
limit = fields.Many2One('trade_finance.facility_limit', 'Limit',
ondelete='CASCADE')
cap = fields.Many2One('trade_finance.facility_cap', 'Cap',
ondelete='CASCADE')
constraint_type = fields.Many2One('trade_finance.constraint_type',
'Constraint Type', required=True, ondelete='RESTRICT')
is_exclusion = fields.Boolean('Exclusion',
help='Checked = Exclusion constraint, unchecked = Inclusion constraint')
date_from = fields.Date('Valid From')
date_to = fields.Date('Valid To')
@staticmethod
def default_is_exclusion():
return False

View File

@@ -0,0 +1,447 @@
<?xml version="1.0"?>
<tryton>
<data>
<!-- ================================================================ -->
<!-- ACCESS GROUP -->
<!-- ================================================================ -->
<record model="res.group" id="group_trade_finance_user">
<field name="name">Trade Finance</field>
</record>
<record model="res.user-res.group"
id="user_admin_group_trade_finance_user">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_trade_finance_user"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY STATUS — Reference Data -->
<!-- ================================================================ -->
<record model="trade_finance.facility_status" id="facility_status_draft">
<field name="code">DRAFT</field>
<field name="name">Draft</field>
<field name="active" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY STATUS -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_status_view_tree">
<field name="model">trade_finance.facility_status</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_status_tree</field>
</record>
<record model="ir.ui.view" id="facility_status_view_form">
<field name="model">trade_finance.facility_status</field>
<field name="type">form</field>
<field name="name">facility_status_form</field>
</record>
<record model="ir.action.act_window" id="act_facility_status">
<field name="name">Facility Statuses</field>
<field name="res_model">trade_finance.facility_status</field>
</record>
<record model="ir.action.act_window.view" id="act_facility_status_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="facility_status_view_tree"/>
<field name="act_window" ref="act_facility_status"/>
</record>
<record model="ir.action.act_window.view" id="act_facility_status_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="facility_status_view_form"/>
<field name="act_window" ref="act_facility_status"/>
</record>
<menuitem
name="Facility Statuses"
sequence="5"
id="menu_facility_status"
parent="menu_trade_finance_configuration"
action="act_facility_status"/>
<record model="ir.model.access" id="access_facility_status">
<field name="model">trade_finance.facility_status</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_status_user">
<field name="model">trade_finance.facility_status</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_status_admin">
<field name="model">trade_finance.facility_status</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_view_tree">
<field name="model">trade_finance.facility</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_tree</field>
</record>
<record model="ir.ui.view" id="facility_view_form">
<field name="model">trade_finance.facility</field>
<field name="type">form</field>
<field name="name">facility_form</field>
</record>
<record model="ir.action.act_window" id="act_facility">
<field name="name">TF Facilities</field>
<field name="res_model">trade_finance.facility</field>
</record>
<record model="ir.action.act_window.view" id="act_facility_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="facility_view_tree"/>
<field name="act_window" ref="act_facility"/>
</record>
<record model="ir.action.act_window.view" id="act_facility_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="facility_view_form"/>
<field name="act_window" ref="act_facility"/>
</record>
<menuitem
name="Facilities"
sequence="10"
id="menu_facility"
parent="menu_trade_finance"
action="act_facility"/>
<record model="ir.model.access" id="access_facility">
<field name="model">trade_finance.facility</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_user">
<field name="model">trade_finance.facility</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_admin">
<field name="model">trade_finance.facility</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY CURRENCY -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_currency_view_tree">
<field name="model">trade_finance.facility_currency</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_currency_tree</field>
</record>
<record model="ir.model.access" id="access_facility_currency">
<field name="model">trade_finance.facility_currency</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_currency_user">
<field name="model">trade_finance.facility_currency</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY COVENANT -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_covenant_view_tree">
<field name="model">trade_finance.facility_covenant</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_covenant_tree</field>
</record>
<record model="ir.model.access" id="access_facility_covenant">
<field name="model">trade_finance.facility_covenant</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_covenant_user">
<field name="model">trade_finance.facility_covenant</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY LIMIT -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_limit_view_tree">
<field name="model">trade_finance.facility_limit</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_tree</field>
</record>
<record model="ir.ui.view" id="facility_limit_view_form">
<field name="model">trade_finance.facility_limit</field>
<field name="type">form</field>
<field name="name">facility_limit_form</field>
</record>
<record model="ir.model.access" id="access_facility_limit">
<field name="model">trade_finance.facility_limit</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_user">
<field name="model">trade_finance.facility_limit</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY LIMIT CHILD TABLES -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_limit_haircut_view_tree">
<field name="model">trade_finance.facility_limit_haircut</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_haircut_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_haircut">
<field name="model">trade_finance.facility_limit_haircut</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_haircut_user">
<field name="model">trade_finance.facility_limit_haircut</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_limit_currency_view_tree">
<field name="model">trade_finance.facility_limit_currency</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_currency_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_currency">
<field name="model">trade_finance.facility_limit_currency</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_currency_user">
<field name="model">trade_finance.facility_limit_currency</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_limit_cost_view_tree">
<field name="model">trade_finance.facility_limit_cost</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_cost_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_cost">
<field name="model">trade_finance.facility_limit_cost</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_cost_user">
<field name="model">trade_finance.facility_limit_cost</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_limit_cost_variation_view_tree">
<field name="model">trade_finance.facility_limit_cost_variation</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_cost_variation_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_cost_variation">
<field name="model">trade_finance.facility_limit_cost_variation</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_cost_variation_user">
<field name="model">trade_finance.facility_limit_cost_variation</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_limit_op_status_view_tree">
<field name="model">trade_finance.facility_limit_op_status</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_op_status_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_op_status">
<field name="model">trade_finance.facility_limit_op_status</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_op_status_user">
<field name="model">trade_finance.facility_limit_op_status</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_limit_bank_account_view_tree">
<field name="model">trade_finance.facility_limit_bank_account</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_limit_bank_account_tree</field>
</record>
<record model="ir.model.access" id="access_facility_limit_bank_account">
<field name="model">trade_finance.facility_limit_bank_account</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_limit_bank_account_user">
<field name="model">trade_finance.facility_limit_bank_account</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY CAP -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_cap_view_tree">
<field name="model">trade_finance.facility_cap</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_cap_tree</field>
</record>
<record model="ir.model.access" id="access_facility_cap">
<field name="model">trade_finance.facility_cap</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_cap_user">
<field name="model">trade_finance.facility_cap</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<record model="ir.ui.view" id="facility_cap_haircut_view_tree">
<field name="model">trade_finance.facility_cap_haircut</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_cap_haircut_tree</field>
</record>
<record model="ir.model.access" id="access_facility_cap_haircut">
<field name="model">trade_finance.facility_cap_haircut</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_cap_haircut_user">
<field name="model">trade_finance.facility_cap_haircut</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FACILITY CONSTRAINT -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="facility_constraint_view_tree">
<field name="model">trade_finance.facility_constraint</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">facility_constraint_tree</field>
</record>
<record model="ir.ui.view" id="facility_constraint_view_form">
<field name="model">trade_finance.facility_constraint</field>
<field name="type">form</field>
<field name="name">facility_constraint_form</field>
</record>
<record model="ir.model.access" id="access_facility_constraint">
<field name="model">trade_finance.facility_constraint</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_facility_constraint_user">
<field name="model">trade_finance.facility_constraint</field>
<field name="group" ref="group_trade_finance_user"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,47 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['FinancingType', 'OperationalStatus']
class FinancingType(ModelSQL, ModelView):
'Financing Type'
__name__ = 'trade_finance.financing_type'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
sequence = fields.Integer('Sequence')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
@staticmethod
def default_sequence():
return 10
class OperationalStatus(ModelSQL, ModelView):
'Operational Status'
__name__ = 'trade_finance.operational_status'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
financing_type = fields.Many2One(
'trade_finance.financing_type', 'Default Financing Type',
ondelete='RESTRICT')
sequence = fields.Integer('Sequence')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
@staticmethod
def default_sequence():
return 10

View File

@@ -0,0 +1,37 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import PoolMeta
__all__ = ['FxFeeder', 'PriceCalendar']
class FxFeeder(ModelSQL, ModelView):
'FX Rate Feeder'
__name__ = 'trade_finance.fx_feeder'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
source_description = fields.Text(
'Source Description',
help='Description of the FX rate source / provider')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class PriceCalendar(metaclass=PoolMeta):
__name__ = 'price.calendar'
purpose = fields.Selection([
(None, ''),
('banking', 'Banking'),
('market', 'Market'),
('factoring', 'Factoring'),
], 'Purpose',
help='Use of this calendar: Banking days, Market trading days, '
'or Factoring program calendar')

View File

@@ -0,0 +1,64 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['MarketIndex', 'MarketIndexRate', 'IndexTerm', 'InterestFormula']
class MarketIndex(ModelSQL, ModelView):
'Market Index'
__name__ = 'trade_finance.market_index'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
rates = fields.One2Many(
'trade_finance.market_index_rate', 'index', 'Rates')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class MarketIndexRate(ModelSQL, ModelView):
'Market Index Rate'
__name__ = 'trade_finance.market_index_rate'
index = fields.Many2One(
'trade_finance.market_index', 'Index',
required=True, ondelete='CASCADE')
rate_date = fields.Date('Date', required=True)
rate = fields.Numeric('Rate (%)', digits=(16, 6), required=True)
class IndexTerm(ModelSQL, ModelView):
'Index Term'
__name__ = 'trade_finance.index_term'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
days = fields.Integer('Days', required=True,
help='Approximate number of days for this term (O/N=1, 1W=7, 1M=30, '
'3M=90, 6M=180, 1Y=365)')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class InterestFormula(ModelSQL, ModelView):
'Interest Calculation Formula'
__name__ = 'trade_finance.interest_formula'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True

View File

@@ -0,0 +1,35 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['BlockingReason', 'ChargeType']
class BlockingReason(ModelSQL, ModelView):
'Blocking Reason'
__name__ = 'trade_finance.blocking_reason'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class ChargeType(ModelSQL, ModelView):
'Charge Type'
__name__ = 'trade_finance.charge_type'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True

View File

@@ -0,0 +1,947 @@
<?xml version="1.0"?>
<tryton>
<data>
<!-- ================================================================ -->
<!-- ACCESS GROUPS -->
<!-- ================================================================ -->
<record model="res.group" id="group_trade_finance_admin">
<field name="name">Trade Finance Administration</field>
</record>
<record model="res.user-res.group"
id="user_admin_group_trade_finance_admin">
<field name="user" ref="res.user_admin"/>
<field name="group" ref="group_trade_finance_admin"/>
</record>
<!-- ================================================================ -->
<!-- TOP-LEVEL MENU -->
<!-- ================================================================ -->
<menuitem
name="Trade Finance"
sequence="70"
id="menu_trade_finance"/>
<menuitem
name="Configuration"
sequence="99"
id="menu_trade_finance_configuration"
parent="menu_trade_finance"/>
<menuitem
name="Market Data"
sequence="20"
id="menu_trade_finance_market_data"
parent="menu_trade_finance"/>
<!-- ================================================================ -->
<!-- FINANCING TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="financing_type_view_tree">
<field name="model">trade_finance.financing_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">financing_type_tree</field>
</record>
<record model="ir.ui.view" id="financing_type_view_form">
<field name="model">trade_finance.financing_type</field>
<field name="type">form</field>
<field name="name">financing_type_form</field>
</record>
<record model="ir.action.act_window" id="act_financing_type">
<field name="name">Financing Types</field>
<field name="res_model">trade_finance.financing_type</field>
</record>
<record model="ir.action.act_window.view" id="act_financing_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="financing_type_view_tree"/>
<field name="act_window" ref="act_financing_type"/>
</record>
<record model="ir.action.act_window.view" id="act_financing_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="financing_type_view_form"/>
<field name="act_window" ref="act_financing_type"/>
</record>
<menuitem
name="Financing Types"
sequence="10"
id="menu_financing_type"
parent="menu_trade_finance_configuration"
action="act_financing_type"/>
<record model="ir.model.access" id="access_financing_type">
<field name="model">trade_finance.financing_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_financing_type_admin">
<field name="model">trade_finance.financing_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- OPERATIONAL STATUS -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="operational_status_view_tree">
<field name="model">trade_finance.operational_status</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">operational_status_tree</field>
</record>
<record model="ir.ui.view" id="operational_status_view_form">
<field name="model">trade_finance.operational_status</field>
<field name="type">form</field>
<field name="name">operational_status_form</field>
</record>
<record model="ir.action.act_window" id="act_operational_status">
<field name="name">Operational Statuses</field>
<field name="res_model">trade_finance.operational_status</field>
</record>
<record model="ir.action.act_window.view" id="act_operational_status_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="operational_status_view_tree"/>
<field name="act_window" ref="act_operational_status"/>
</record>
<record model="ir.action.act_window.view" id="act_operational_status_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="operational_status_view_form"/>
<field name="act_window" ref="act_operational_status"/>
</record>
<menuitem
name="Operational Statuses"
sequence="20"
id="menu_operational_status"
parent="menu_trade_finance_configuration"
action="act_operational_status"/>
<record model="ir.model.access" id="access_operational_status">
<field name="model">trade_finance.operational_status</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_operational_status_admin">
<field name="model">trade_finance.operational_status</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- MARKET INDEX -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="market_index_view_tree">
<field name="model">trade_finance.market_index</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">market_index_tree</field>
</record>
<record model="ir.ui.view" id="market_index_view_form">
<field name="model">trade_finance.market_index</field>
<field name="type">form</field>
<field name="name">market_index_form</field>
</record>
<record model="ir.action.act_window" id="act_market_index">
<field name="name">Market Indexes</field>
<field name="res_model">trade_finance.market_index</field>
</record>
<record model="ir.action.act_window.view" id="act_market_index_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="market_index_view_tree"/>
<field name="act_window" ref="act_market_index"/>
</record>
<record model="ir.action.act_window.view" id="act_market_index_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="market_index_view_form"/>
<field name="act_window" ref="act_market_index"/>
</record>
<menuitem
name="Market Indexes"
sequence="10"
id="menu_market_index"
parent="menu_trade_finance_configuration"
action="act_market_index"/>
<record model="ir.model.access" id="access_market_index">
<field name="model">trade_finance.market_index</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_market_index_admin">
<field name="model">trade_finance.market_index</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- MARKET INDEX RATE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="market_index_rate_view_tree">
<field name="model">trade_finance.market_index_rate</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">market_index_rate_tree</field>
</record>
<record model="ir.ui.view" id="market_index_rate_view_form">
<field name="model">trade_finance.market_index_rate</field>
<field name="type">form</field>
<field name="name">market_index_rate_form</field>
</record>
<record model="ir.action.act_window" id="act_market_index_rate">
<field name="name">Market Index Rates</field>
<field name="res_model">trade_finance.market_index_rate</field>
</record>
<record model="ir.action.act_window.view" id="act_market_index_rate_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="market_index_rate_view_tree"/>
<field name="act_window" ref="act_market_index_rate"/>
</record>
<record model="ir.action.act_window.view" id="act_market_index_rate_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="market_index_rate_view_form"/>
<field name="act_window" ref="act_market_index_rate"/>
</record>
<menuitem
name="Market Index Rates"
sequence="10"
id="menu_market_index_rate"
parent="menu_trade_finance_market_data"
action="act_market_index_rate"/>
<record model="ir.model.access" id="access_market_index_rate">
<field name="model">trade_finance.market_index_rate</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_market_index_rate_admin">
<field name="model">trade_finance.market_index_rate</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- INDEX TERM -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="index_term_view_tree">
<field name="model">trade_finance.index_term</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">index_term_tree</field>
</record>
<record model="ir.ui.view" id="index_term_view_form">
<field name="model">trade_finance.index_term</field>
<field name="type">form</field>
<field name="name">index_term_form</field>
</record>
<record model="ir.action.act_window" id="act_index_term">
<field name="name">Index Terms</field>
<field name="res_model">trade_finance.index_term</field>
</record>
<record model="ir.action.act_window.view" id="act_index_term_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="index_term_view_tree"/>
<field name="act_window" ref="act_index_term"/>
</record>
<record model="ir.action.act_window.view" id="act_index_term_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="index_term_view_form"/>
<field name="act_window" ref="act_index_term"/>
</record>
<menuitem
name="Index Terms"
sequence="30"
id="menu_index_term"
parent="menu_trade_finance_configuration"
action="act_index_term"/>
<record model="ir.model.access" id="access_index_term">
<field name="model">trade_finance.index_term</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_index_term_admin">
<field name="model">trade_finance.index_term</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- INTEREST FORMULA -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="interest_formula_view_tree">
<field name="model">trade_finance.interest_formula</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">interest_formula_tree</field>
</record>
<record model="ir.ui.view" id="interest_formula_view_form">
<field name="model">trade_finance.interest_formula</field>
<field name="type">form</field>
<field name="name">interest_formula_form</field>
</record>
<record model="ir.action.act_window" id="act_interest_formula">
<field name="name">Interest Formulas</field>
<field name="res_model">trade_finance.interest_formula</field>
</record>
<record model="ir.action.act_window.view" id="act_interest_formula_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="interest_formula_view_tree"/>
<field name="act_window" ref="act_interest_formula"/>
</record>
<record model="ir.action.act_window.view" id="act_interest_formula_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="interest_formula_view_form"/>
<field name="act_window" ref="act_interest_formula"/>
</record>
<menuitem
name="Interest Formulas"
sequence="40"
id="menu_interest_formula"
parent="menu_trade_finance_configuration"
action="act_interest_formula"/>
<record model="ir.model.access" id="access_interest_formula">
<field name="model">trade_finance.interest_formula</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_interest_formula_admin">
<field name="model">trade_finance.interest_formula</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- HAIRCUT FORMULA -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="haircut_formula_view_tree">
<field name="model">trade_finance.haircut_formula</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">haircut_formula_tree</field>
</record>
<record model="ir.ui.view" id="haircut_formula_view_form">
<field name="model">trade_finance.haircut_formula</field>
<field name="type">form</field>
<field name="name">haircut_formula_form</field>
</record>
<record model="ir.action.act_window" id="act_haircut_formula">
<field name="name">Haircut Formulas</field>
<field name="res_model">trade_finance.haircut_formula</field>
</record>
<record model="ir.action.act_window.view" id="act_haircut_formula_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="haircut_formula_view_tree"/>
<field name="act_window" ref="act_haircut_formula"/>
</record>
<record model="ir.action.act_window.view" id="act_haircut_formula_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="haircut_formula_view_form"/>
<field name="act_window" ref="act_haircut_formula"/>
</record>
<menuitem
name="Haircut Formulas"
sequence="50"
id="menu_haircut_formula"
parent="menu_trade_finance_configuration"
action="act_haircut_formula"/>
<record model="ir.model.access" id="access_haircut_formula">
<field name="model">trade_finance.haircut_formula</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_haircut_formula_admin">
<field name="model">trade_finance.haircut_formula</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- VALUATION METHOD -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="valuation_method_view_tree">
<field name="model">trade_finance.valuation_method</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">valuation_method_tree</field>
</record>
<record model="ir.ui.view" id="valuation_method_view_form">
<field name="model">trade_finance.valuation_method</field>
<field name="type">form</field>
<field name="name">valuation_method_form</field>
</record>
<record model="ir.action.act_window" id="act_valuation_method">
<field name="name">Valuation Methods</field>
<field name="res_model">trade_finance.valuation_method</field>
</record>
<record model="ir.action.act_window.view" id="act_valuation_method_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="valuation_method_view_tree"/>
<field name="act_window" ref="act_valuation_method"/>
</record>
<record model="ir.action.act_window.view" id="act_valuation_method_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="valuation_method_view_form"/>
<field name="act_window" ref="act_valuation_method"/>
</record>
<menuitem
name="Valuation Methods"
sequence="60"
id="menu_valuation_method"
parent="menu_trade_finance_configuration"
action="act_valuation_method"/>
<record model="ir.model.access" id="access_valuation_method">
<field name="model">trade_finance.valuation_method</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_valuation_method_admin">
<field name="model">trade_finance.valuation_method</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- COLLATERAL TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="collateral_type_view_tree">
<field name="model">trade_finance.collateral_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">collateral_type_tree</field>
</record>
<record model="ir.ui.view" id="collateral_type_view_form">
<field name="model">trade_finance.collateral_type</field>
<field name="type">form</field>
<field name="name">collateral_type_form</field>
</record>
<record model="ir.action.act_window" id="act_collateral_type">
<field name="name">Collateral Types</field>
<field name="res_model">trade_finance.collateral_type</field>
</record>
<record model="ir.action.act_window.view" id="act_collateral_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="collateral_type_view_tree"/>
<field name="act_window" ref="act_collateral_type"/>
</record>
<record model="ir.action.act_window.view" id="act_collateral_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="collateral_type_view_form"/>
<field name="act_window" ref="act_collateral_type"/>
</record>
<menuitem
name="Collateral Types"
sequence="70"
id="menu_collateral_type"
parent="menu_trade_finance_configuration"
action="act_collateral_type"/>
<record model="ir.model.access" id="access_collateral_type">
<field name="model">trade_finance.collateral_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_collateral_type_admin">
<field name="model">trade_finance.collateral_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- EVIDENCE TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="evidence_type_view_tree">
<field name="model">trade_finance.evidence_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">evidence_type_tree</field>
</record>
<record model="ir.ui.view" id="evidence_type_view_form">
<field name="model">trade_finance.evidence_type</field>
<field name="type">form</field>
<field name="name">evidence_type_form</field>
</record>
<record model="ir.action.act_window" id="act_evidence_type">
<field name="name">Evidence Types</field>
<field name="res_model">trade_finance.evidence_type</field>
</record>
<record model="ir.action.act_window.view" id="act_evidence_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="evidence_type_view_tree"/>
<field name="act_window" ref="act_evidence_type"/>
</record>
<record model="ir.action.act_window.view" id="act_evidence_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="evidence_type_view_form"/>
<field name="act_window" ref="act_evidence_type"/>
</record>
<menuitem
name="Evidence Types"
sequence="80"
id="menu_evidence_type"
parent="menu_trade_finance_configuration"
action="act_evidence_type"/>
<record model="ir.model.access" id="access_evidence_type">
<field name="model">trade_finance.evidence_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_evidence_type_admin">
<field name="model">trade_finance.evidence_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- TEMPLATE SEGMENT -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="template_segment_view_tree">
<field name="model">trade_finance.template_segment</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">template_segment_tree</field>
</record>
<record model="ir.ui.view" id="template_segment_view_form">
<field name="model">trade_finance.template_segment</field>
<field name="type">form</field>
<field name="name">template_segment_form</field>
</record>
<record model="ir.action.act_window" id="act_template_segment">
<field name="name">Template Segments</field>
<field name="res_model">trade_finance.template_segment</field>
</record>
<record model="ir.action.act_window.view" id="act_template_segment_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="template_segment_view_tree"/>
<field name="act_window" ref="act_template_segment"/>
</record>
<record model="ir.action.act_window.view" id="act_template_segment_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="template_segment_view_form"/>
<field name="act_window" ref="act_template_segment"/>
</record>
<menuitem
name="Template Segments"
sequence="90"
id="menu_template_segment"
parent="menu_trade_finance_configuration"
action="act_template_segment"/>
<record model="ir.model.access" id="access_template_segment">
<field name="model">trade_finance.template_segment</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_template_segment_admin">
<field name="model">trade_finance.template_segment</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- EXECUTION TEMPLATE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="execution_template_view_tree">
<field name="model">trade_finance.execution_template</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">execution_template_tree</field>
</record>
<record model="ir.ui.view" id="execution_template_view_form">
<field name="model">trade_finance.execution_template</field>
<field name="type">form</field>
<field name="name">execution_template_form</field>
</record>
<record model="ir.action.act_window" id="act_execution_template">
<field name="name">Execution Templates</field>
<field name="res_model">trade_finance.execution_template</field>
</record>
<record model="ir.action.act_window.view" id="act_execution_template_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="execution_template_view_tree"/>
<field name="act_window" ref="act_execution_template"/>
</record>
<record model="ir.action.act_window.view" id="act_execution_template_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="execution_template_view_form"/>
<field name="act_window" ref="act_execution_template"/>
</record>
<menuitem
name="Execution Templates"
sequence="100"
id="menu_execution_template"
parent="menu_trade_finance_configuration"
action="act_execution_template"/>
<record model="ir.model.access" id="access_execution_template">
<field name="model">trade_finance.execution_template</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_execution_template_admin">
<field name="model">trade_finance.execution_template</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ExecutionTemplateLine — no separate menu (child of ExecutionTemplate) -->
<record model="ir.ui.view" id="execution_template_line_view_tree">
<field name="model">trade_finance.execution_template_line</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">execution_template_line_tree</field>
</record>
<record model="ir.model.access" id="access_execution_template_line">
<field name="model">trade_finance.execution_template_line</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_execution_template_line_admin">
<field name="model">trade_finance.execution_template_line</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- RECEIVABLE CATEGORY -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="receivable_category_view_tree">
<field name="model">trade_finance.receivable_category</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">receivable_category_tree</field>
</record>
<record model="ir.ui.view" id="receivable_category_view_form">
<field name="model">trade_finance.receivable_category</field>
<field name="type">form</field>
<field name="name">receivable_category_form</field>
</record>
<record model="ir.action.act_window" id="act_receivable_category">
<field name="name">Receivable Categories</field>
<field name="res_model">trade_finance.receivable_category</field>
</record>
<record model="ir.action.act_window.view" id="act_receivable_category_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="receivable_category_view_tree"/>
<field name="act_window" ref="act_receivable_category"/>
</record>
<record model="ir.action.act_window.view" id="act_receivable_category_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="receivable_category_view_form"/>
<field name="act_window" ref="act_receivable_category"/>
</record>
<menuitem
name="Receivable Categories"
sequence="110"
id="menu_receivable_category"
parent="menu_trade_finance_configuration"
action="act_receivable_category"/>
<record model="ir.model.access" id="access_receivable_category">
<field name="model">trade_finance.receivable_category</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_receivable_category_admin">
<field name="model">trade_finance.receivable_category</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- PAYMENT CONDITION TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="payment_condition_type_view_tree">
<field name="model">trade_finance.payment_condition_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">payment_condition_type_tree</field>
</record>
<record model="ir.ui.view" id="payment_condition_type_view_form">
<field name="model">trade_finance.payment_condition_type</field>
<field name="type">form</field>
<field name="name">payment_condition_type_form</field>
</record>
<record model="ir.action.act_window" id="act_payment_condition_type">
<field name="name">Payment Condition Types</field>
<field name="res_model">trade_finance.payment_condition_type</field>
</record>
<record model="ir.action.act_window.view" id="act_payment_condition_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="payment_condition_type_view_tree"/>
<field name="act_window" ref="act_payment_condition_type"/>
</record>
<record model="ir.action.act_window.view" id="act_payment_condition_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="payment_condition_type_view_form"/>
<field name="act_window" ref="act_payment_condition_type"/>
</record>
<menuitem
name="Payment Condition Types"
sequence="120"
id="menu_payment_condition_type"
parent="menu_trade_finance_configuration"
action="act_payment_condition_type"/>
<record model="ir.model.access" id="access_payment_condition_type">
<field name="model">trade_finance.payment_condition_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_payment_condition_type_admin">
<field name="model">trade_finance.payment_condition_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- FX FEEDER -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="fx_feeder_view_tree">
<field name="model">trade_finance.fx_feeder</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">fx_feeder_tree</field>
</record>
<record model="ir.ui.view" id="fx_feeder_view_form">
<field name="model">trade_finance.fx_feeder</field>
<field name="type">form</field>
<field name="name">fx_feeder_form</field>
</record>
<record model="ir.action.act_window" id="act_fx_feeder">
<field name="name">FX Rate Feeders</field>
<field name="res_model">trade_finance.fx_feeder</field>
</record>
<record model="ir.action.act_window.view" id="act_fx_feeder_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="fx_feeder_view_tree"/>
<field name="act_window" ref="act_fx_feeder"/>
</record>
<record model="ir.action.act_window.view" id="act_fx_feeder_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="fx_feeder_view_form"/>
<field name="act_window" ref="act_fx_feeder"/>
</record>
<menuitem
name="FX Rate Feeders"
sequence="130"
id="menu_fx_feeder"
parent="menu_trade_finance_configuration"
action="act_fx_feeder"/>
<record model="ir.model.access" id="access_fx_feeder">
<field name="model">trade_finance.fx_feeder</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_fx_feeder_admin">
<field name="model">trade_finance.fx_feeder</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- BLOCKING REASON -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="blocking_reason_view_tree">
<field name="model">trade_finance.blocking_reason</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">blocking_reason_tree</field>
</record>
<record model="ir.ui.view" id="blocking_reason_view_form">
<field name="model">trade_finance.blocking_reason</field>
<field name="type">form</field>
<field name="name">blocking_reason_form</field>
</record>
<record model="ir.action.act_window" id="act_blocking_reason">
<field name="name">Blocking Reasons</field>
<field name="res_model">trade_finance.blocking_reason</field>
</record>
<record model="ir.action.act_window.view" id="act_blocking_reason_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="blocking_reason_view_tree"/>
<field name="act_window" ref="act_blocking_reason"/>
</record>
<record model="ir.action.act_window.view" id="act_blocking_reason_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="blocking_reason_view_form"/>
<field name="act_window" ref="act_blocking_reason"/>
</record>
<menuitem
name="Blocking Reasons"
sequence="140"
id="menu_blocking_reason"
parent="menu_trade_finance_configuration"
action="act_blocking_reason"/>
<record model="ir.model.access" id="access_blocking_reason">
<field name="model">trade_finance.blocking_reason</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_blocking_reason_admin">
<field name="model">trade_finance.blocking_reason</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
<!-- ================================================================ -->
<!-- CHARGE TYPE -->
<!-- ================================================================ -->
<record model="ir.ui.view" id="charge_type_view_tree">
<field name="model">trade_finance.charge_type</field>
<field name="type">tree</field>
<field name="priority" eval="10"/>
<field name="name">charge_type_tree</field>
</record>
<record model="ir.ui.view" id="charge_type_view_form">
<field name="model">trade_finance.charge_type</field>
<field name="type">form</field>
<field name="name">charge_type_form</field>
</record>
<record model="ir.action.act_window" id="act_charge_type">
<field name="name">Charge Types</field>
<field name="res_model">trade_finance.charge_type</field>
</record>
<record model="ir.action.act_window.view" id="act_charge_type_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="charge_type_view_tree"/>
<field name="act_window" ref="act_charge_type"/>
</record>
<record model="ir.action.act_window.view" id="act_charge_type_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="charge_type_view_form"/>
<field name="act_window" ref="act_charge_type"/>
</record>
<menuitem
name="Charge Types"
sequence="150"
id="menu_charge_type"
parent="menu_trade_finance_configuration"
action="act_charge_type"/>
<record model="ir.model.access" id="access_charge_type">
<field name="model">trade_finance.charge_type</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.access" id="access_charge_type_admin">
<field name="model">trade_finance.charge_type</field>
<field name="group" ref="group_trade_finance_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,61 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields, sequence_ordered
__all__ = ['TemplateSegment', 'ExecutionTemplate', 'ExecutionTemplateLine']
class TemplateSegment(ModelSQL, ModelView):
'Template Segment'
__name__ = 'trade_finance.template_segment'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
from_place = fields.Many2One(
'stock.location', 'From Place',
help='Origin location / port of loading')
to_place = fields.Many2One(
'stock.location', 'To Place',
help='Destination location / port of discharge')
default_duration_days = fields.Integer(
'Default Duration (days)',
help='Default number of days for this segment')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class ExecutionTemplate(ModelSQL, ModelView):
'Execution Template'
__name__ = 'trade_finance.execution_template'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
lines = fields.One2Many(
'trade_finance.execution_template_line', 'template', 'Segments')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class ExecutionTemplateLine(sequence_ordered(), ModelSQL, ModelView):
'Execution Template Line'
__name__ = 'trade_finance.execution_template_line'
template = fields.Many2One(
'trade_finance.execution_template', 'Template',
required=True, ondelete='CASCADE')
segment = fields.Many2One(
'trade_finance.template_segment', 'Segment',
required=True, ondelete='RESTRICT')
duration_days = fields.Integer(
'Duration (days)',
help='Overrides the segment default duration for this template')

View File

@@ -0,0 +1,12 @@
[tryton]
version=7.2.7
depends:
ir
res
stock
price
bank
xml:
reference.xml
facility.xml
constraint_type.xml

View File

@@ -0,0 +1,50 @@
# This file is part of Tradon. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.model import ModelSQL, ModelView, fields
__all__ = ['ValuationMethod', 'HaircutFormula', 'CollateralType']
class ValuationMethod(ModelSQL, ModelView):
'Valuation Method'
__name__ = 'trade_finance.valuation_method'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class HaircutFormula(ModelSQL, ModelView):
'Haircut Formula'
__name__ = 'trade_finance.haircut_formula'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
description = fields.Text('Description')
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True
class CollateralType(ModelSQL, ModelView):
'Collateral Type'
__name__ = 'trade_finance.collateral_type'
_rec_name = 'name'
code = fields.Char('Code', required=True)
name = fields.Char('Name', required=True)
active = fields.Boolean('Active')
@staticmethod
def default_active():
return True

View File

@@ -0,0 +1,8 @@
<form col="4">
<label name="code"/>
<field name="code"/>
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
</form>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="code"/>
<field name="name"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,10 @@
<form col="4">
<label name="code"/>
<field name="code"/>
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
<label name="description"/>
<field name="description" colspan="4"/>
</form>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="code"/>
<field name="name"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,8 @@
<form col="4">
<label name="code"/>
<field name="code"/>
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
</form>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="code"/>
<field name="name"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,12 @@
<form col="4">
<group id="main" col="4" colspan="4">
<label name="name"/>
<field name="name" colspan="3"/>
<label name="view_name"/>
<field name="view_name" colspan="3"/>
<label name="value_field"/>
<field name="value_field" colspan="3"/>
<label name="label_field"/>
<field name="label_field" colspan="3"/>
</group>
</form>

View File

@@ -0,0 +1,3 @@
<tree>
<field name="name"/>
</tree>

View File

@@ -0,0 +1,10 @@
<form col="4">
<label name="code"/>
<field name="code"/>
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
<label name="description"/>
<field name="description" colspan="4"/>
</form>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="code"/>
<field name="name"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,12 @@
<form col="4">
<label name="code"/>
<field name="code"/>
<label name="name"/>
<field name="name"/>
<label name="active"/>
<field name="active"/>
<label name="description"/>
<field name="description" colspan="4"/>
<newline/>
<field name="lines" colspan="4"/>
</form>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="sequence"/>
<field name="segment"/>
<field name="duration_days"/>
</tree>

View File

@@ -0,0 +1,5 @@
<tree>
<field name="code"/>
<field name="name"/>
<field name="active"/>
</tree>

View File

@@ -0,0 +1,7 @@
<tree>
<field name="attribute"/>
<field name="value"/>
<field name="haircut_pct"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

View File

@@ -0,0 +1,6 @@
<tree>
<field name="name"/>
<field name="amount"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

View File

@@ -0,0 +1,10 @@
<form col="4">
<label name="constraint_type"/>
<field name="constraint_type" colspan="3"/>
<label name="date_from"/>
<field name="date_from"/>
<label name="date_to"/>
<field name="date_to"/>
<label name="is_exclusion"/>
<field name="is_exclusion"/>
</form>

View File

@@ -0,0 +1,6 @@
<tree>
<field name="constraint_type"/>
<field name="is_exclusion"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

View File

@@ -0,0 +1,6 @@
<tree>
<field name="name"/>
<field name="ratio_type"/>
<field name="threshold"/>
<field name="currency"/>
</tree>

View File

@@ -0,0 +1,8 @@
<tree>
<field name="currency"/>
<field name="valuation_method"/>
<field name="fx_haircut_formula"/>
<field name="fx_feeder"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

View File

@@ -0,0 +1,50 @@
<form col="6">
<group id="header" col="6" colspan="6">
<label name="name"/>
<field name="name" colspan="3"/>
<label name="status"/>
<field name="status" widget="selection"/>
<label name="tfe"/>
<field name="tfe" colspan="3"/>
<label name="commitment_status"/>
<field name="commitment_status"/>
<label name="currency"/>
<field name="currency"/>
<label name="fx_feeder"/>
<field name="fx_feeder"/>
<label name="fx_haircut_pct"/>
<field name="fx_haircut_pct"/>
<newline/>
<label name="date_from"/>
<field name="date_from"/>
<label name="date_to"/>
<field name="date_to"/>
<label name="is_tpa"/>
<field name="is_tpa"/>
<label name="broker"/>
<field name="broker"/>
<label name="broker_account"/>
<field name="broker_account" colspan="3"/>
<newline/>
<label name="description"/>
<field name="description" colspan="5"/>
</group>
<notebook colspan="6">
<page string="Limits" id="limits">
<field name="limits" colspan="6"
domain="[('parent', '=', None)]"/>
</page>
<page string="Currencies" id="currencies">
<field name="currencies" colspan="6"/>
</page>
<page string="Constraints" id="constraints">
<field name="constraints" colspan="6"/>
</page>
<page string="Caps" id="caps">
<field name="caps" colspan="6"/>
</page>
<page string="Covenants" id="covenants">
<field name="covenants" colspan="6"/>
</page>
</notebook>
</form>

View File

@@ -0,0 +1,7 @@
<tree>
<field name="bank_account"/>
<field name="currency"/>
<field name="is_default"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

View File

@@ -0,0 +1,11 @@
<tree>
<field name="cost_type"/>
<field name="spread"/>
<field name="index"/>
<field name="index_term"/>
<field name="interest_formula"/>
<field name="flat_amount"/>
<field name="flat_currency"/>
<field name="date_from"/>
<field name="date_to"/>
</tree>

Some files were not shown because too many files have changed in this diff Show More