Bug pnl fee
This commit is contained in:
@@ -586,6 +586,103 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
self.assertEqual(values[0]['sale'], sale.id)
|
||||
self.assertEqual(values[0]['sale_line'], sale_line.id)
|
||||
|
||||
def test_purchase_pnl_fee_deduplicates_sale_lot_seen_twice(self):
|
||||
'purchase-side fee pnl does not duplicate a sale lot already in matching'
|
||||
Valuation = Pool().get('valuation.valuation')
|
||||
currency = Mock(id=1)
|
||||
unit = Mock(id=2)
|
||||
product = Mock(id=3, name='Broker commission')
|
||||
supplier = Mock(id=4)
|
||||
sale = Mock(id=5)
|
||||
sale_line = Mock(id=6, sale=sale, finished=False)
|
||||
sale_lot = Mock(id=7, sale_line=sale_line, lot_type='virtual')
|
||||
sale_lot.get_current_quantity_converted.return_value = Decimal('2')
|
||||
fee = Mock(
|
||||
product=product,
|
||||
supplier=supplier,
|
||||
type='budgeted',
|
||||
p_r='pay',
|
||||
mode='lumpsum',
|
||||
price=Decimal('10'),
|
||||
currency=currency,
|
||||
shipment_in=None,
|
||||
sale_line=sale_line,
|
||||
unit=unit,
|
||||
)
|
||||
line = Mock(
|
||||
id=9,
|
||||
finished=False,
|
||||
lots=[sale_lot],
|
||||
get_matched_lines=Mock(return_value=[Mock(lot_s=sale_lot)]),
|
||||
purchase=Mock(id=10, currency=currency),
|
||||
unit=unit,
|
||||
)
|
||||
fee_lots = Mock()
|
||||
fee_lots.search.return_value = [Mock(fee=fee)]
|
||||
|
||||
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, 5, 14))),
|
||||
'currency.currency': Mock(),
|
||||
'fee.lots': fee_lots,
|
||||
'lot.qt': Mock(),
|
||||
}[name]
|
||||
|
||||
values = Valuation.create_pnl_fee_from_line(line)
|
||||
|
||||
self.assertEqual(len(values), 1)
|
||||
self.assertEqual(values[0]['type'], 'sale fee')
|
||||
self.assertEqual(values[0]['lot'], sale_lot.id)
|
||||
|
||||
def test_snapshot_identity_prefers_sale_line_over_purchase_line(self):
|
||||
'valuation snapshot identity ignores purchase line when sale line exists'
|
||||
Valuation = Pool().get('valuation.valuation')
|
||||
base = {
|
||||
'purchase': 1,
|
||||
'line': 2,
|
||||
'sale': 3,
|
||||
'sale_line': 4,
|
||||
'lot': 5,
|
||||
'type': 'sale fee',
|
||||
'reference': 'Broker/Open',
|
||||
'counterparty': 6,
|
||||
'product': 7,
|
||||
'state': 'budgeted',
|
||||
'strategy': None,
|
||||
'price': Decimal('10'),
|
||||
'quantity': Decimal('2'),
|
||||
'amount': Decimal('-20'),
|
||||
}
|
||||
regenerated = base.copy()
|
||||
regenerated.update({
|
||||
'purchase': None,
|
||||
'line': None,
|
||||
'price': Decimal('12'),
|
||||
'quantity': Decimal('3'),
|
||||
'amount': Decimal('-36'),
|
||||
})
|
||||
|
||||
self.assertEqual(
|
||||
Valuation._value_key(base),
|
||||
Valuation._value_key(regenerated))
|
||||
|
||||
def test_generate_from_matched_sale_line_does_not_create_snapshot(self):
|
||||
'matched sale line pnl is owned by the matched purchase line'
|
||||
Valuation = Pool().get('valuation.valuation')
|
||||
purchase_line = Mock(id=10)
|
||||
sale_line = Mock()
|
||||
sale_line.get_matched_lines.return_value = [
|
||||
Mock(lot_p=Mock(line=purchase_line))]
|
||||
|
||||
with patch.object(Valuation, '_delete_existing_sale_line') as delete_existing, patch.object(
|
||||
Valuation, 'create_pnl_fee_from_sale_line') as create_fees, patch.object(
|
||||
Valuation, 'generate') as generate:
|
||||
Valuation.generate_from_sale_line(sale_line, valuation_type='fees')
|
||||
|
||||
generate.assert_called_once_with(purchase_line, valuation_type='fees')
|
||||
delete_existing.assert_not_called()
|
||||
create_fees.assert_not_called()
|
||||
|
||||
def test_purchase_open_pnl_fee_skips_zero_virtual_lot(self):
|
||||
'purchase-side fee pnl ignores open virtual lots with no quantity'
|
||||
Valuation = Pool().get('valuation.valuation')
|
||||
|
||||
Reference in New Issue
Block a user