This commit is contained in:
2026-04-02 13:09:04 +02:00
parent a99efcfc5b
commit 6d52317804
3 changed files with 84 additions and 3 deletions

View File

@@ -3999,7 +3999,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_positive_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"><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"/>

View File

@@ -31,6 +31,14 @@ class Invoice(metaclass=PoolMeta):
]
return lines or list(self.lines or [])
@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):
purchases = list(self.purchases or [])
return purchases[0] if purchases else None
@@ -141,7 +149,7 @@ class Invoice(metaclass=PoolMeta):
@property
def report_description_upper(self):
if self.lines:
return (self.lines[0].description or '').upper()
return self._clean_report_description(self.lines[0].description)
return ''
@property
@@ -259,6 +267,40 @@ class Invoice(metaclass=PoolMeta):
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
def report_payment_date(self):
trade = self._get_report_trade()
@@ -287,6 +329,12 @@ class Invoice(metaclass=PoolMeta):
@property
def report_nb_bale(self):
unit = self.report_weight_unit_upper
net = self.report_net
if net != '' and unit == 'MT':
quantity = abs(Decimal(str(net or 0))).quantize(Decimal('1'))
if quantity:
return 'NB BALES: ' + str(int(quantity))
sale = self._get_report_sale()
if sale and sale.report_nb_bale:
return sale.report_nb_bale
@@ -473,7 +521,7 @@ class InvoiceLine(metaclass=PoolMeta):
@property
def report_description_upper(self):
return (self.description or '').upper()
return Invoice._clean_report_description(self.description)
@property
def report_rate_currency_upper(self):

View File

@@ -333,6 +333,37 @@ class PurchaseTradeTestCase(ModuleTestCase):
self.assertEqual(invoice.report_net, Decimal('800'))
def test_invoice_report_nb_bale_uses_abs_mt_difference(self):
'invoice final note displays bale count as rounded MT differential'
Invoice = Pool().get('account.invoice')
line = Mock(type='line', quantity=Decimal('-15'))
line.unit = Mock(rec_name='MT')
invoice = Invoice()
invoice.lines = [line]
self.assertEqual(invoice.report_nb_bale, 'NB BALES: 15')
def test_invoice_report_positive_rate_lines_keep_positive_components(self):
'invoice final note pricing section keeps only positive component lines'
Invoice = Pool().get('account.invoice')
sale = Mock()
sale.report_price_lines = (
'USC 8.3000 PER POUND (EIGHT USC AND THIRTY CENTS) ON ICE Cotton #2 MARCH 2026\n'
'USC 8.3000 PER POUND (EIGHT USC AND THIRTY CENTS) ON ICE Cotton #2 MAY 2026'
)
invoice = Invoice()
invoice.sales = [sale]
invoice.lines = []
self.assertEqual(
invoice.report_positive_rate_lines.splitlines(),
[
'USC 8.3000 PER POUND (EIGHT USC AND THIRTY CENTS) ON ICE Cotton #2 MARCH 2026',
'USC 8.3000 PER POUND (EIGHT USC AND THIRTY CENTS) ON ICE Cotton #2 MAY 2026',
])
def test_lot_invoice_sale_uses_sale_invoice_line_reference(self):
'sale invoicing must resolve the generated invoice from sale invoice links'
sale_invoice = Mock()