Duplicate from LM
This commit is contained in:
@@ -39,6 +39,8 @@ class TradeCustomDuplicateStart(ModelView):
|
||||
('sale.sale', 'Sale'),
|
||||
], readonly=True)
|
||||
duplicated_record_id = fields.Integer("Duplicated Record ID", readonly=True)
|
||||
duplicate_pair_available = fields.Boolean(
|
||||
"Duplicate Pair Available", readonly=True)
|
||||
party = fields.Many2One('party.party', "Counterparty", required=True)
|
||||
currency = fields.Many2One('currency.currency', "Currency", required=True)
|
||||
payment_term = fields.Many2One(
|
||||
@@ -56,6 +58,7 @@ class TradeCustomDuplicateStart(ModelView):
|
||||
states={
|
||||
'invisible': ~Bool(Eval('create_matched_mirror')),
|
||||
'required': Bool(Eval('create_matched_mirror')),
|
||||
'readonly': ~Bool(Eval('duplicate_pair_available')),
|
||||
})
|
||||
mirror_party = fields.Many2One('party.party', "Mirror Counterparty",
|
||||
states={
|
||||
@@ -161,6 +164,33 @@ class TradeCustomDuplicate(Wizard):
|
||||
def _opposite_type(source_model):
|
||||
return 'Sale' if source_model == 'purchase.purchase' else 'Purchase'
|
||||
|
||||
@staticmethod
|
||||
def _record_from_lot_report(record):
|
||||
if getattr(record, '__name__', None) != 'lot.report':
|
||||
return record
|
||||
if getattr(record, 'r_purchase', None):
|
||||
return record.r_purchase
|
||||
if getattr(record, 'r_sale', None):
|
||||
return record.r_sale
|
||||
lot = (
|
||||
getattr(record, 'r_lot_p', None)
|
||||
or getattr(record, 'r_lot_s', None)
|
||||
or getattr(record, 'r_lot_himself', None))
|
||||
if lot:
|
||||
line = getattr(lot, 'line', None)
|
||||
if line and getattr(line, 'purchase', None):
|
||||
return line.purchase
|
||||
sale_line = getattr(lot, 'sale_line', None)
|
||||
if sale_line and getattr(sale_line, 'sale', None):
|
||||
return sale_line.sale
|
||||
raise UserError(
|
||||
"Custom duplicate could not find a purchase or sale from this "
|
||||
"Lots Management line.")
|
||||
|
||||
@staticmethod
|
||||
def _source_record(record):
|
||||
return TradeCustomDuplicate._record_from_lot_report(record)
|
||||
|
||||
@staticmethod
|
||||
def _reference_record(reference):
|
||||
if not reference:
|
||||
@@ -172,15 +202,18 @@ class TradeCustomDuplicate(Wizard):
|
||||
|
||||
def default_start(self, fields):
|
||||
if len(self.records) != 1:
|
||||
raise UserError("Please select a single purchase or sale.")
|
||||
raise UserError(
|
||||
"Please select a single purchase, sale, or Lots Management "
|
||||
"line.")
|
||||
|
||||
record = self.records[0]
|
||||
record = self._source_record(self.records[0])
|
||||
source_model = self._source_model(record)
|
||||
line = self._trade_line(record)
|
||||
if not line:
|
||||
raise UserError("The selected contract has no trade line to duplicate.")
|
||||
matched_record = self._matched_counterpart_record(
|
||||
record, line, strict=False)
|
||||
duplicate_pair_available = bool(matched_record)
|
||||
mirror_mode = 'duplicate_pair' if matched_record else 'new_mirror'
|
||||
mirror_defaults = self._mirror_defaults(
|
||||
record, line, mirror_mode, strict=False)
|
||||
@@ -202,6 +235,7 @@ class TradeCustomDuplicate(Wizard):
|
||||
'clear_fees': False,
|
||||
'clear_pricing_components': False,
|
||||
'create_matched_mirror': False,
|
||||
'duplicate_pair_available': duplicate_pair_available,
|
||||
'mirror_mode': mirror_mode,
|
||||
**mirror_defaults,
|
||||
}
|
||||
@@ -748,7 +782,7 @@ class TradeCustomDuplicate(Wizard):
|
||||
ContractFactory.create_contracts([detail], type_=mirror_type, ct=ct)
|
||||
|
||||
def transition_duplicate(self):
|
||||
record = self.records[0]
|
||||
record = self._source_record(self.records[0])
|
||||
options = self.start
|
||||
new_record = self._copy_contract(record, options)
|
||||
new_line = self._apply_line_options(new_record, options)
|
||||
|
||||
@@ -148,9 +148,19 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<field name="model">lot.report,-1</field>
|
||||
<field name="action" ref="act_plan_transport"/>
|
||||
</record>
|
||||
<record model="ir.action.wizard" id="act_lot_report_custom_duplicate">
|
||||
<field name="name">Custom Duplicate</field>
|
||||
<field name="wiz_name">trade.custom_duplicate</field>
|
||||
<field name="model">lot.report</field>
|
||||
</record>
|
||||
<record model="ir.action.keyword" id="act_lot_report_custom_duplicate_keyword">
|
||||
<field name="keyword">form_action</field>
|
||||
<field name="model">lot.report,-1</field>
|
||||
<field name="action" ref="act_lot_report_custom_duplicate"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="add_lot_view_form">
|
||||
<field name="model">lot.add.lot</field>
|
||||
<field name="model">lot.add.lot</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">lot_add_start_form</field>
|
||||
</record>
|
||||
|
||||
@@ -6324,6 +6324,123 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
self.assertEqual(values['mirror_unit_price'], Decimal('25'))
|
||||
self.assertEqual(values['mirror_price_type'], 'priced')
|
||||
|
||||
def test_custom_duplicate_starts_from_lot_report_purchase(self):
|
||||
'custom duplicate can resolve a Lots Management row to its purchase'
|
||||
purchase_party = SimpleNamespace(id=1)
|
||||
purchase_currency = SimpleNamespace(id=4)
|
||||
purchase_payment_term = SimpleNamespace(id=5)
|
||||
purchase_incoterm = SimpleNamespace(id=6)
|
||||
unit = SimpleNamespace(id=3)
|
||||
line = SimpleNamespace(
|
||||
__name__='purchase.line',
|
||||
id=11,
|
||||
type='line',
|
||||
product=Mock(),
|
||||
lots=[],
|
||||
unit=unit,
|
||||
quantity=Decimal('100'),
|
||||
quantity_theorical=Decimal('100'),
|
||||
unit_price=Decimal('25'),
|
||||
price_type='priced',
|
||||
)
|
||||
purchase = SimpleNamespace(
|
||||
__name__='purchase.purchase',
|
||||
id=12,
|
||||
lines=[line],
|
||||
party=purchase_party,
|
||||
currency=purchase_currency,
|
||||
payment_term=purchase_payment_term,
|
||||
incoterm=purchase_incoterm,
|
||||
btb=None,
|
||||
)
|
||||
line.purchase = purchase
|
||||
lot_report = SimpleNamespace(
|
||||
__name__='lot.report',
|
||||
r_purchase=purchase,
|
||||
r_sale=None,
|
||||
r_lot_p=None,
|
||||
r_lot_s=None,
|
||||
r_lot_himself=None,
|
||||
)
|
||||
wizard = duplicate_module.TradeCustomDuplicate()
|
||||
wizard.records = [lot_report]
|
||||
|
||||
values = wizard.default_start(None)
|
||||
|
||||
self.assertEqual(values['source_model'], 'purchase.purchase')
|
||||
self.assertEqual(values['source'], 'purchase.purchase,12')
|
||||
self.assertFalse(values['duplicate_pair_available'])
|
||||
self.assertEqual(values['mirror_mode'], 'new_mirror')
|
||||
|
||||
def test_custom_duplicate_lot_report_marks_pair_available(self):
|
||||
'Lots Management custom duplicate enables pair mode when matched'
|
||||
purchase_party = SimpleNamespace(id=1)
|
||||
sale_party = SimpleNamespace(id=2)
|
||||
unit = SimpleNamespace(id=3)
|
||||
sale = SimpleNamespace(
|
||||
party=sale_party,
|
||||
currency=SimpleNamespace(id=30),
|
||||
payment_term=SimpleNamespace(id=31),
|
||||
incoterm=SimpleNamespace(id=32))
|
||||
sale_line = SimpleNamespace(
|
||||
id=20,
|
||||
sale=sale,
|
||||
unit=unit,
|
||||
quantity=Decimal('100'),
|
||||
quantity_theorical=Decimal('100'),
|
||||
unit_price=Decimal('50'),
|
||||
price_type='priced')
|
||||
physical_lot = SimpleNamespace(
|
||||
id=10,
|
||||
lot_type='physic',
|
||||
sale_line=sale_line)
|
||||
line = SimpleNamespace(
|
||||
__name__='purchase.line',
|
||||
id=11,
|
||||
type='line',
|
||||
product=Mock(),
|
||||
lots=[physical_lot],
|
||||
unit=unit,
|
||||
quantity=Decimal('100'),
|
||||
quantity_theorical=Decimal('100'),
|
||||
unit_price=Decimal('25'),
|
||||
price_type='priced',
|
||||
)
|
||||
purchase = SimpleNamespace(
|
||||
__name__='purchase.purchase',
|
||||
id=12,
|
||||
lines=[line],
|
||||
party=purchase_party,
|
||||
currency=SimpleNamespace(id=4),
|
||||
payment_term=SimpleNamespace(id=5),
|
||||
incoterm=SimpleNamespace(id=6),
|
||||
)
|
||||
lot_report = SimpleNamespace(
|
||||
__name__='lot.report',
|
||||
r_purchase=purchase,
|
||||
r_sale=None,
|
||||
r_lot_p=physical_lot,
|
||||
r_lot_s=None,
|
||||
r_lot_himself=None,
|
||||
)
|
||||
|
||||
class FakeLotQt:
|
||||
@classmethod
|
||||
def search(cls, domain):
|
||||
return []
|
||||
|
||||
pool = Mock()
|
||||
pool.get.side_effect = lambda name: {'lot.qt': FakeLotQt}[name]
|
||||
wizard = duplicate_module.TradeCustomDuplicate()
|
||||
wizard.records = [lot_report]
|
||||
|
||||
with patch.object(duplicate_module, 'Pool', return_value=pool):
|
||||
values = wizard.default_start(None)
|
||||
|
||||
self.assertTrue(values['duplicate_pair_available'])
|
||||
self.assertEqual(values['mirror_mode'], 'duplicate_pair')
|
||||
self.assertEqual(values['mirror_party'], sale_party.id)
|
||||
|
||||
def test_custom_duplicate_mirror_mode_change_refreshes_source_defaults(self):
|
||||
'changing mirror mode refreshes mirror fields from the source contract'
|
||||
purchase_party = SimpleNamespace(id=1)
|
||||
|
||||
@@ -48,4 +48,5 @@
|
||||
<field name="mirror_clear_pricing_components"/>
|
||||
<field name="source" invisible="1"/>
|
||||
<field name="duplicated_record_id" invisible="1"/>
|
||||
<field name="duplicate_pair_available" invisible="1"/>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user