Create mirror action

This commit is contained in:
2026-07-27 20:24:44 +02:00
parent 9429f7d2e3
commit 0ffd43149b
13 changed files with 710 additions and 38 deletions

View File

@@ -8344,6 +8344,45 @@ description</t></is></c>
self.assertEqual(invoice.report_contract_number, 'P-12/S-34')
def test_sale_melya_incoterm_uses_destination_for_cost_incoterms(self):
'sale_melya incoterm uses sale destination only for CIF/CFR/CIP'
Sale = Pool().get('sale.sale')
sale = Sale()
sale.incoterm = SimpleNamespace(code='CFR')
sale.incoterm_location = SimpleNamespace(
party_name='Ignored Port',
country=SimpleNamespace(name='Ignored Country'))
sale.to_location = SimpleNamespace(
rec_name='Mejillones',
country=SimpleNamespace(name='Chile'))
self.assertEqual(sale.report_melya_incoterm, 'CFR Mejillones Chile')
sale.incoterm = SimpleNamespace(code='FOB')
self.assertEqual(sale.report_melya_incoterm, 'FOB')
def test_invoice_melya_incoterm_uses_destination_for_cost_incoterms(self):
'invoice_melya incoterm uses sale destination only for CIF/CFR/CIP'
Invoice = Pool().get('account.invoice')
invoice = Invoice()
trade = SimpleNamespace(
incoterm=SimpleNamespace(code='CIP'),
incoterm_location=SimpleNamespace(party_name='Ignored Port'),
to_location=SimpleNamespace(
rec_name='Rotterdam',
country=SimpleNamespace(name='Netherlands')))
invoice._get_report_trade = Mock(return_value=trade)
self.assertEqual(
invoice.report_incoterm, 'CIP Rotterdam Netherlands')
trade.incoterm = SimpleNamespace(code='FCA')
self.assertEqual(invoice.report_incoterm, 'FCA')
def test_invoice_melya_bank_uses_sale_our_bank_account(self):
'invoice_melya bank block uses the sale company bank account'
Invoice = Pool().get('account.invoice')
@@ -8628,6 +8667,146 @@ description</t></is></c>
self.assertIsNone(
ContractFactory._get_shipment_origin(ContractsStartMock()))
def test_contract_factory_create_mirror_keeps_product_per_line(self):
'create mirror builds one opposite contract with one line per source'
product_a = Mock(id=10)
product_b = Mock(id=20)
unit_a = Mock(id=30)
unit_b = Mock(id=40)
purchase = Mock(
currency=Mock(id=1),
crop=None,
tol_min=Decimal('0'),
tol_max=Decimal('0'),
payment_term=Mock(),
reference='PUR-1',
from_location=Mock(type='supplier'),
to_location=Mock(type='storage'),
wb=None,
association=None,
certif=None,
incoterm=Mock(),
product_origin=None)
purchase_line_a = Mock(
product=product_a, unit=unit_a, purchase=purchase)
purchase_line_b = Mock(
product=product_b, unit=unit_b, purchase=purchase)
lot_a = Mock(
id=101, lot_type='virtual', line=purchase_line_a)
lot_b = Mock(
id=102, lot_type='virtual', line=purchase_line_b)
lqt_a = Mock(
id=201, lot_p=lot_a, lot_s=None,
lot_quantity=Decimal('100'),
lot_shipment_origin=None)
lqt_b = Mock(
id=202, lot_p=lot_b, lot_s=None,
lot_quantity=Decimal('200'),
lot_shipment_origin=None)
header = Mock(
selected_source_count=2,
selected_source_ids='201,202',
party=Mock(addresses=[]),
currency=Mock(id=1),
crop=None,
tol_min=Decimal('0'),
tol_max=Decimal('0'),
payment_term=Mock(),
reference='MIRROR',
from_location=None,
to_location=None,
incoterm=Mock())
mirror_lines = [
Mock(
source_lqt=lqt_a,
product=product_a,
unit=unit_a,
quantity=Decimal('100'),
price_type='priced',
price=Decimal('10'),
premium=Decimal('1'),
currency_unit='1_30',
del_period=None,
from_del=None,
to_del=None),
Mock(
source_lqt=lqt_b,
product=product_b,
unit=unit_b,
quantity=Decimal('200'),
price_type='priced',
price=Decimal('20'),
premium=Decimal('2'),
currency_unit='1_40',
del_period=None,
from_del=None,
to_del=None),
]
created_contracts = []
created_lines = []
def new_sale():
sale = Mock(id=301)
sale.save = Mock()
created_contracts.append(sale)
return sale
def new_sale_line():
line = Mock()
line.save = Mock()
created_lines.append(line)
return line
sale_model = Mock(side_effect=new_sale)
sale_line_model = Mock(side_effect=new_sale_line)
purchase_model = Mock()
purchase_line_model = Mock()
lot_model = Mock()
date_model = Mock()
date_model.today.return_value = '2026-07-27'
def get_model(name):
return {
'sale.sale': sale_model,
'purchase.purchase': purchase_model,
'sale.line': sale_line_model,
'purchase.line': purchase_line_model,
'lot.lot': lot_model,
'ir.date': date_model,
}[name]
with patch('trytond.modules.purchase_trade.service.Pool') as PoolMock, \
patch.object(
ContractFactory, '_create_lot') as create_lot:
PoolMock.return_value.get.side_effect = get_model
created = ContractFactory.create_mirror_contract(
header, mirror_lines, type_='Sale')
self.assertEqual(created, created_contracts[0])
self.assertEqual(len(created_contracts), 1)
self.assertEqual(len(created_lines), 2)
self.assertEqual(
[line.product for line in created_lines],
[product_a, product_b])
self.assertEqual(
[line.quantity for line in created_lines],
[Decimal('100.00000'), Decimal('200.00000')])
self.assertEqual(
[line.sale for line in created_lines],
[301, 301])
self.assertEqual(create_lot.call_count, 2)
lot_model.assert_lines_quantity_consistency.assert_called_once()
def test_contract_factory_create_mirror_rejects_removed_line(self):
'create mirror must keep one wizard line per selected open quantity'
header = Mock(selected_source_count=2, selected_source_ids='1,2')
line = Mock()
with self.assertRaises(UserError):
ContractFactory.create_mirror_contract(
header, [line], type_='Sale')
def test_custom_duplicate_resets_finished_line(self):
'custom duplicate keeps duplicated lots visible in lots management'
line = Mock(