Price composition

This commit is contained in:
2026-05-20 14:40:25 +02:00
parent ea3cb65d7d
commit 27e081228f
3 changed files with 38 additions and 6 deletions

View File

@@ -1662,10 +1662,10 @@
</table:table-row>
<table:table-row>
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P12"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T8"><text:placeholder text:placeholder-type="text">&lt;pc[&apos;label&apos;]&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P12"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:placeholder text:placeholder-type="text">&lt;pc[&apos;label&apos;]&gt;</text:placeholder></text:span></text:span></text:p>
</table:table-cell>
<table:table-cell table:style-name="Tableau3.A1" office:value-type="string">
<text:p text:style-name="P13"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T8"><text:placeholder text:placeholder-type="text">&lt;format_currency(pc[&apos;amount&apos;], invoice.party.lang, invoice.currency) if pc[&apos;amount&apos;] is not None else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
<text:p text:style-name="P13"><text:span text:style-name="Police_20_par_20_défaut"><text:span text:style-name="T9"><text:placeholder text:placeholder-type="text">&lt;format_number(pc[&apos;amount&apos;], invoice.party.lang) if pc[&apos;amount&apos;] is not None else &apos;&apos;&gt;</text:placeholder></text:span></text:span></text:p>
</table:table-cell>
</table:table-row>
<table:table-row>

View File

@@ -859,11 +859,27 @@ class Sale(metaclass=PoolMeta):
currency_name = (
currency.rec_name.upper()
if currency and currency.rec_name else '')
for composition in getattr(line, 'price_composition', []) or []:
compositions = list(getattr(line, 'price_composition', []) or [])
missing = [
composition for composition in compositions
if getattr(composition, 'price', None) in (None, '')]
known_total = sum(
Decimal(str(getattr(composition, 'price', 0) or 0))
for composition in compositions
if getattr(composition, 'price', None) not in (None, ''))
residual = None
if len(missing) == 1:
residual = (
self._get_report_price_composition_line_amount(line)
- known_total)
for composition in compositions:
component = getattr(composition, 'component', '') or ''
price = getattr(composition, 'price', None)
if price in (None, ''):
continue
if composition is missing[0] and residual is not None:
price = residual
else:
continue
label = ' '.join(
part for part in [
component,
@@ -877,6 +893,18 @@ class Sale(metaclass=PoolMeta):
})
return lines
@staticmethod
def _get_report_price_composition_line_amount(line):
amount = getattr(line, 'amount', None)
if amount not in (None, ''):
return Decimal(str(amount or 0))
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
unit_price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
premium_getter = getattr(line, '_get_premium_price', None)
premium = premium_getter() if premium_getter else getattr(
line, 'premium', 0)
return quantity * (unit_price + Decimal(str(premium or 0)))
@property
def report_trade_blocks(self):
lines = self._get_report_lines()

View File

@@ -2600,9 +2600,10 @@ class PurchaseTradeTestCase(ModuleTestCase):
line.linked_unit = None
line.unit = Mock(rec_name='MT')
line.unit_price = Decimal('2525')
line.amount = Decimal('62493.75')
line.price_composition = [
Mock(component='FOB', price=Decimal('2500')),
Mock(component='FREIGHT', price=Decimal('25')),
Mock(component='FREIGHT', price=None),
]
sale = Sale()
@@ -2619,7 +2620,10 @@ class PurchaseTradeTestCase(ModuleTestCase):
sale.report_price_composition_rows,
[
{'label': 'FOB value in EUR', 'amount': Decimal('2500')},
{'label': 'FREIGHT value in EUR', 'amount': Decimal('25')},
{
'label': 'FREIGHT value in EUR',
'amount': Decimal('59993.75'),
},
])
def test_invoice_report_rate_lines_prefers_sale_price_composition(self):