This commit is contained in:
2026-04-02 11:16:26 +02:00
parent b644aea007
commit 346a34951d
6 changed files with 129 additions and 2 deletions

View File

@@ -3931,9 +3931,14 @@
</table:table-cell>
<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;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:placeholder text:placeholder-type="text">&lt;for each=&quot;line in invoice.report_quantity_lines.splitlines()&quot;&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"><text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder></text:p>
<text:p text:style-name="P26"><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;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_attributes_name&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="P18"><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="P18">At <text:placeholder text:placeholder-type="text">&lt;line&gt;</text:placeholder></text:p>
<text:p text:style-name="P18"><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="P32"><text:placeholder text:placeholder-type="text">&lt;invoice.report_incoterm&gt;</text:placeholder></text:p>
@@ -4009,7 +4014,9 @@
<table:table-column table:style-name="Tableau8.B"/>
<table:table-row table:style-name="Tableau8.1">
<table:table-cell table:style-name="Tableau8.A1" office:value-type="string">
<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"><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;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">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"/>

View File

@@ -94,6 +94,10 @@ Source code: `modules/purchase_trade/invoice.py`
- 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`
@@ -116,6 +120,10 @@ Source code: `modules/purchase_trade/invoice.py`
- 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`
@@ -245,6 +253,7 @@ Source code: `modules/purchase_trade/sale.py`
- `report_qt`
- `report_total_quantity`
- `report_quantity_unit_upper`
- `report_quantity_lines`
- `report_nb_bale`
- `report_deal`
- `report_packing`

View File

@@ -6,12 +6,30 @@ from trytond.pool import Pool, PoolMeta
class Invoice(metaclass=PoolMeta):
__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'
def _get_report_invoice_line(self):
for line in self.lines or []:
if getattr(line, 'type', None) == 'line':
return line
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 [])
def _get_report_purchase(self):
purchases = list(self.purchases or [])
return purchases[0] if purchases else None
@@ -146,6 +164,32 @@ class Invoice(metaclass=PoolMeta):
return trade.report_price
return ''
@property
def report_quantity_lines(self):
sale = self._get_report_sale()
if sale and getattr(sale, 'report_quantity_lines', None):
return sale.report_quantity_lines
details = []
for line in self._get_report_invoice_lines():
quantity = getattr(line, 'report_net', '')
if quantity == '':
quantity = getattr(line, 'quantity', '')
if quantity == '':
continue
quantity_text = self._format_report_number(
quantity, keep_trailing_decimal=True)
unit = getattr(line, 'unit', None)
unit_name = unit.rec_name.upper() if unit and unit.rec_name else ''
lbs = getattr(line, 'report_lbs', '')
parts = [quantity_text, unit_name]
if lbs != '':
parts.append(
f"({self._format_report_number(lbs, digits='0.01')} LBS)")
detail = ' '.join(part for part in parts if part)
if detail:
details.append(detail)
return '\n'.join(details)
@property
def report_rate_currency_upper(self):
line = self._get_report_invoice_line()
@@ -181,6 +225,35 @@ class Invoice(metaclass=PoolMeta):
return line.report_rate_pricing_text
return ''
@property
def report_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():
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_payment_date(self):
trade = self._get_report_trade()

View File

@@ -408,6 +408,29 @@ class Sale(metaclass=PoolMeta):
total = sum(Decimal(str(line.quantity or 0)) for line in lines)
return quantity_to_words(total)
return ''
@property
def report_quantity_lines(self):
lines = self._get_report_lines()
if not lines:
return ''
details = []
for line in lines:
quantity = self._format_report_number(
line.quantity, keep_trailing_decimal=True)
unit = line.unit.rec_name.upper() if line.unit and line.unit.rec_name else ''
words = quantity_to_words(Decimal(str(line.quantity or 0)))
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
def report_nb_bale(self):

View File

@@ -185,6 +185,12 @@ class PurchaseTradeTestCase(ModuleTestCase):
self.assertEqual(sale.report_quantity_unit_upper, 'MT')
self.assertEqual(sale.report_qt, 'TWO THOUSAND METRIC TONS')
self.assertEqual(sale.report_nb_bale, '')
self.assertEqual(
sale.report_quantity_lines.splitlines(),
[
'1000.0 MT (ONE THOUSAND METRIC TONS) - MARCH 2026',
'1000.0 MT (ONE THOUSAND METRIC TONS) - MAY 2026',
])
self.assertEqual(
sale.report_shipment_periods.splitlines(),
['MARCH 2026', 'MAY 2026'])

View File

@@ -4095,6 +4095,15 @@
<text:p text:style-name="P39">
<text:placeholder text:placeholder-type="text">&lt;sale.report_nb_bale&gt;</text:placeholder>
</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" />
</table:table-cell>
</table:table-row>