Price composition + Pnl open matched

This commit is contained in:
2026-06-30 18:27:40 +02:00
parent c0ac8fac68
commit 99d5d2a849
6 changed files with 765 additions and 23 deletions

View File

@@ -2554,6 +2554,90 @@ class PurchaseTradeTestCase(ModuleTestCase):
self.assertEqual(values[0]['type'], 'sale fee')
self.assertEqual(values[0]['lot'], sale_lot.id)
def test_purchase_open_fee_pnl_splits_by_matched_sale_lotqt(self):
'purchase open fee pnl keeps one segment per matched sale lot.qt'
Valuation = Pool().get('valuation.valuation')
currency = Mock(id=1)
unit = Mock(id=2)
product = Mock(id=3, name='Broker commission')
supplier = Mock(id=4)
purchase = Mock(id=5, currency=currency, company=Mock(currency=currency))
line = Mock(id=6, purchase=purchase, unit=unit, finished=False)
purchase_lot = Mock(id=7, sale_line=None, lot_type='virtual')
purchase_lot.get_current_quantity_converted.return_value = Decimal('60')
line.lots = [purchase_lot]
line.get_matched_lines.return_value = []
sales = [Mock(id=20 + index) for index in range(3)]
sale_lines = [
Mock(id=30 + index, sale=sales[index], finished=False)
for index in range(3)]
sale_lots = [
Mock(id=40 + index, sale_line=sale_lines[index])
for index in range(3)]
lot_qts = [
Mock(
id=50,
lot_s=sale_lots[0],
lot_quantity=Decimal('10'),
lot_unit=unit,
lot_shipment_in=None),
Mock(
id=51,
lot_s=sale_lots[1],
lot_quantity=Decimal('20'),
lot_unit=unit,
lot_shipment_in=None),
Mock(
id=52,
lot_s=sale_lots[2],
lot_quantity=Decimal('30'),
lot_unit=unit,
lot_shipment_in=None),
]
fee = Mock(
id=60,
line=line,
sale_line=None,
shipment_in=None,
shipment_out=None,
shipment_internal=None,
product=product,
supplier=supplier,
type='budgeted',
p_r='pay',
mode='perqt',
price=Decimal('2'),
currency=currency,
unit=unit,
)
fee.get_price_per_qt.return_value = Decimal('2')
fee_lots = Mock()
fee_lots.search.return_value = [Mock(fee=fee)]
lot_qt_model = Mock()
lot_qt_model.search.return_value = lot_qts
with patch('trytond.modules.purchase_trade.valuation.Pool') as PoolMock:
PoolMock.return_value.get.side_effect = lambda name: {
'ir.date': Mock(today=Mock(return_value=datetime.date(2026, 6, 30))),
'currency.currency': Mock(),
'fee.lots': fee_lots,
'lot.qt': lot_qt_model,
}[name]
values = Valuation.create_pnl_fee_from_line(line)
self.assertEqual(len(values), 3)
self.assertEqual(
[value['sale_line'] for value in values],
[sale_line.id for sale_line in sale_lines])
self.assertEqual(
[value['quantity'] for value in values],
[Decimal('10.00000'), Decimal('20.00000'), Decimal('30.00000')])
self.assertEqual(
[value['amount'] for value in values],
[Decimal('-20.00'), Decimal('-40.00'), Decimal('-60.00')])
self.assertEqual(len(Valuation._dedupe_values(values)), 3)
def test_sale_open_fee_pnl_splits_by_shipment_lotqt(self):
'sale open fee pnl is split between shipped and unshipped lot.qt'
Valuation = Pool().get('valuation.valuation')
@@ -6345,8 +6429,10 @@ class PurchaseTradeTestCase(ModuleTestCase):
line.linked_currency = None
line.linked_unit = None
line.unit = Mock(rec_name='MT')
line.quantity = Decimal('25')
line.unit_price = Decimal('2525')
line.amount = Decimal('62493.75')
line.amount = Decimal('63750')
line.lots = []
line.price_composition = [
Mock(component='FOB', price=Decimal('2500')),
Mock(component='FREIGHT', price=None),
@@ -6367,13 +6453,55 @@ class PurchaseTradeTestCase(ModuleTestCase):
[
{
'label': 'FOB value in EUR',
'amount': Decimal('2500'),
'amount_text': '2,500.00',
'amount': Decimal('62500'),
'amount_text': '62,500.00',
},
{
'label': 'FREIGHT value in EUR',
'amount': Decimal('59993.75'),
'amount_text': '59,993.75',
'amount': Decimal('1250'),
'amount_text': '1,250.00',
},
])
def test_invoice_report_melya_price_composition_uses_invoice_quantity(self):
'invoice_melya price composition applies the invoiced quantity'
Invoice = Pool().get('account.invoice')
unit = Mock(id=1, rec_name='MT')
sale = Mock(currency=Mock(rec_name='EUR'), lines=[])
sale_line = Mock(
sale=sale,
unit=unit,
amount=Decimal('63750'),
price_composition=[
Mock(component='FOB', price=Decimal('2500')),
Mock(component='FREIGHT', price=None),
])
invoice_line = Mock(
type='line',
origin=sale_line,
unit=unit,
quantity=Decimal('20'),
amount=Decimal('51000'),
currency=Mock(rec_name='EUR'),
invoice=None,
lot=None,
lot_weight_snapshots=[])
invoice = Invoice()
invoice.lines = [invoice_line]
invoice.sales = [sale]
self.assertEqual(
invoice.report_melya_rate_rows,
[
{
'label': 'FOB value in EUR',
'amount': Decimal('50000'),
'amount_text': '50,000.00',
},
{
'label': 'FREIGHT value in EUR',
'amount': Decimal('1000'),
'amount_text': '1,000.00',
},
])