Add physical + Link
This commit is contained in:
@@ -372,6 +372,22 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'planned_to_location': 20,
|
||||
})
|
||||
|
||||
def test_lot_shipping_defaults_purchase_locations_without_plan(self):
|
||||
'link to transport falls back to purchase locations without a plan'
|
||||
wizard = lot_module.LotShipping()
|
||||
wizard.records = [Mock(
|
||||
r_planned_from_location=None,
|
||||
r_planned_to_location=None,
|
||||
r_purchase=Mock(
|
||||
from_location=Mock(id=10),
|
||||
to_location=Mock(id=20)),
|
||||
)]
|
||||
|
||||
self.assertEqual(wizard.default_ship(None), {
|
||||
'planned_from_location': 10,
|
||||
'planned_to_location': 20,
|
||||
})
|
||||
|
||||
def test_lot_shipping_defaults_uniform_planned_locations(self):
|
||||
'link to transport carries uniform planned locations from selection'
|
||||
wizard = lot_module.LotShipping()
|
||||
@@ -509,6 +525,47 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
Lot.assert_lines_quantity_consistency.assert_called_once_with([
|
||||
lot.line])
|
||||
|
||||
def test_lot_shipping_open_quantity_uses_shared_transport_link(self):
|
||||
'standalone link action keeps linking open lot.qt quantities'
|
||||
wizard = lot_module.LotShipping()
|
||||
shipment = Mock(id=40)
|
||||
wizard.ship = Mock(
|
||||
shipment='in',
|
||||
shipment_in=shipment,
|
||||
shipment_out=None,
|
||||
shipment_internal=None,
|
||||
create_new_shipment=False,
|
||||
quantity=None,
|
||||
)
|
||||
wizard.records = [Mock(
|
||||
id=10000007,
|
||||
r_lot_shipment_in=None,
|
||||
r_lot_quantity=Decimal('125'),
|
||||
r_lot_matched=Decimal('0'),
|
||||
)]
|
||||
purchase_line = Mock()
|
||||
source = Mock(
|
||||
lot_p=Mock(line=purchase_line),
|
||||
lot_s=None,
|
||||
)
|
||||
Lot = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__enter__ = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__exit__ = Mock()
|
||||
LotQt = Mock(return_value=source)
|
||||
Move = Mock()
|
||||
pool = Mock()
|
||||
pool.get.side_effect = [Lot, LotQt, Move]
|
||||
|
||||
with patch('trytond.modules.purchase_trade.lot.Pool',
|
||||
return_value=pool):
|
||||
state = wizard.transition_shipping()
|
||||
|
||||
self.assertEqual(state, 'end')
|
||||
LotQt.link_to_transport.assert_called_once_with(
|
||||
source, Decimal('125.00000'), 'stock.shipment.in,40')
|
||||
Lot.assert_lines_quantity_consistency.assert_called_once_with([
|
||||
purchase_line])
|
||||
|
||||
def test_lot_unship_restores_planned_open_quantity(self):
|
||||
'unlinking a planned scheduled lot.qt returns it to planned'
|
||||
wizard = lot_module.LotUnship()
|
||||
@@ -648,14 +705,10 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
|
||||
def test_lot_shipping_scheduled_lotqt_keeps_planned_locations(self):
|
||||
'scheduled lot.qt keeps the planned from and to locations'
|
||||
wizard = lot_module.LotShipping()
|
||||
wizard.ship = Mock(
|
||||
shipment='in',
|
||||
shipment_in=Mock(id=40),
|
||||
shipment_out=None,
|
||||
shipment_internal=None,
|
||||
)
|
||||
LotQt = Pool().get('lot.qt')
|
||||
linked = Mock()
|
||||
lqt = Mock(
|
||||
lot_quantity=Decimal('125'),
|
||||
lot_p=Mock(id=1),
|
||||
lot_s=Mock(id=2),
|
||||
lot_unit=Mock(id=3),
|
||||
@@ -669,11 +722,15 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
planned_to_date=datetime.date(2026, 7, 5),
|
||||
planned_note='POL to POD',
|
||||
)
|
||||
LotQt = Mock()
|
||||
lqt.is_planned_transport.return_value = True
|
||||
|
||||
wizard._create_scheduled_lotqt(LotQt, lqt, Decimal('125'))
|
||||
with patch.object(
|
||||
LotQt, 'create', return_value=[linked]) as create, \
|
||||
patch.object(LotQt, 'save') as save:
|
||||
result = LotQt.link_to_transport(
|
||||
lqt, Decimal('125'), 'stock.shipment.in,40')
|
||||
|
||||
LotQt.create.assert_called_once_with([{
|
||||
create.assert_called_once_with([{
|
||||
'lot_p': 1,
|
||||
'lot_s': 2,
|
||||
'lot_quantity': Decimal('125'),
|
||||
@@ -689,6 +746,124 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
'planned_note': 'POL to POD',
|
||||
'lot_shipment_in': 40,
|
||||
}])
|
||||
save.assert_called_once_with([lqt])
|
||||
self.assertEqual(lqt.lot_quantity, 0)
|
||||
self.assertIs(result, linked)
|
||||
|
||||
def test_add_physical_lot_defaults_transport_from_purchase(self):
|
||||
'add physical lot proposes shipment creation from purchase values'
|
||||
wizard = lot_module.LotAdding()
|
||||
purchase = Mock(
|
||||
party=Mock(id=30),
|
||||
from_location=Mock(id=10),
|
||||
to_location=Mock(id=20),
|
||||
)
|
||||
lqt = Mock(
|
||||
lot_p=Mock(line=Mock(
|
||||
purchase=purchase,
|
||||
unit=Mock(id=3))),
|
||||
lot_quantity=Decimal('125'),
|
||||
lot_shipment_in=None,
|
||||
lot_shipment_internal=None,
|
||||
lot_shipment_out=None,
|
||||
planned_from_location=None,
|
||||
planned_to_location=None,
|
||||
)
|
||||
lqt.lot_p.lot_unit_line = Mock(id=3)
|
||||
LotQt = Mock(return_value=lqt)
|
||||
pool = Mock()
|
||||
pool.get.side_effect = [Mock(), LotQt]
|
||||
|
||||
with patch('trytond.modules.purchase_trade.lot.Pool',
|
||||
return_value=pool), patch(
|
||||
'trytond.modules.purchase_trade.lot.Transaction'
|
||||
) as TransactionMock:
|
||||
TransactionMock.return_value.context = {
|
||||
'active_ids': [10000007]}
|
||||
values = wizard.default_add(None)
|
||||
|
||||
self.assertTrue(values['transport_missing'])
|
||||
self.assertEqual(values['shipment_supplier'], 30)
|
||||
self.assertEqual(values['transport_from_location'], 10)
|
||||
self.assertEqual(values['transport_to_location'], 20)
|
||||
|
||||
def test_add_physical_lot_links_existing_shipment_before_add(self):
|
||||
'add physical lot can link an existing shipment in one transaction'
|
||||
wizard = lot_module.LotAdding()
|
||||
shipment = Mock(id=40)
|
||||
source = Mock(lot_quantity=Decimal('125'))
|
||||
source.has_shipment.return_value = False
|
||||
linked = Mock()
|
||||
LotQt = Mock(return_value=source)
|
||||
LotQt.link_to_transport.return_value = linked
|
||||
Lot = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__enter__ = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__exit__ = Mock()
|
||||
pool = Mock()
|
||||
pool.get.side_effect = [LotQt, Lot]
|
||||
wizard.records = [Mock(id=10000007)]
|
||||
wizard.add = Mock(
|
||||
shipment_in=shipment,
|
||||
create_new_shipment=False,
|
||||
lots=[Mock()],
|
||||
unlink_remainder=True,
|
||||
)
|
||||
|
||||
with patch('trytond.modules.purchase_trade.lot.Pool',
|
||||
return_value=pool):
|
||||
state = wizard.transition_adding()
|
||||
|
||||
self.assertEqual(state, 'end')
|
||||
LotQt.link_to_transport.assert_called_once_with(
|
||||
source, Decimal('125'), 'stock.shipment.in,40')
|
||||
LotQt.add_physical_lots.assert_called_once_with(
|
||||
linked, wizard.add.lots, True)
|
||||
|
||||
def test_add_physical_lot_creates_shipment_with_optional_bl(self):
|
||||
'add physical lot creates and links a shipment with optional BL data'
|
||||
wizard = lot_module.LotAdding()
|
||||
shipment = Mock(id=40)
|
||||
source = Mock(lot_quantity=Decimal('125'))
|
||||
source.has_shipment.return_value = False
|
||||
linked = Mock()
|
||||
LotQt = Mock(return_value=source)
|
||||
LotQt.link_to_transport.return_value = linked
|
||||
ShipmentIn = Mock()
|
||||
ShipmentIn.create.return_value = [shipment]
|
||||
Lot = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__enter__ = Mock()
|
||||
Lot.skip_quantity_consistency.return_value.__exit__ = Mock()
|
||||
pool = Mock()
|
||||
pool.get.side_effect = [LotQt, ShipmentIn, Lot]
|
||||
wizard.records = [Mock(id=10000007)]
|
||||
wizard.add = Mock(
|
||||
shipment_in=None,
|
||||
create_new_shipment=True,
|
||||
shipment_supplier=Mock(id=30),
|
||||
transport_from_location=Mock(id=10),
|
||||
transport_to_location=Mock(id=20),
|
||||
shipment_bl_number='BL-2026-01',
|
||||
shipment_bl_date=datetime.date(2026, 6, 22),
|
||||
lots=[Mock()],
|
||||
unlink_remainder=True,
|
||||
)
|
||||
|
||||
with patch('trytond.modules.purchase_trade.lot.Pool',
|
||||
return_value=pool):
|
||||
state = wizard.transition_adding()
|
||||
|
||||
self.assertEqual(state, 'end')
|
||||
ShipmentIn.create.assert_called_once_with([{
|
||||
'supplier': 30,
|
||||
'from_location': 10,
|
||||
'to_location': 20,
|
||||
'bl_number': 'BL-2026-01',
|
||||
'bl_date': datetime.date(2026, 6, 22),
|
||||
}])
|
||||
LotQt.link_to_transport.assert_called_once_with(
|
||||
source, Decimal('125'), 'stock.shipment.in,40')
|
||||
LotQt.add_physical_lots.assert_called_once_with(
|
||||
linked, wizard.add.lots, True)
|
||||
|
||||
@with_transaction()
|
||||
def test_get_mtm_applies_component_ratio_as_percentage(self):
|
||||
@@ -2604,6 +2779,18 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
|
||||
self.assertEqual(shipment.get_shipment_type(), 'inbound')
|
||||
|
||||
@with_transaction()
|
||||
def test_shipment_in_location_domains_follow_trade_direction(self):
|
||||
'shipment locations exclude invalid trade counterpart directions'
|
||||
ShipmentIn = Pool().get('stock.shipment.in')
|
||||
|
||||
self.assertEqual(
|
||||
ShipmentIn.from_location.domain,
|
||||
[('type', '!=', 'customer')])
|
||||
self.assertEqual(
|
||||
ShipmentIn.to_location.domain,
|
||||
[('type', '!=', 'supplier')])
|
||||
|
||||
@with_transaction()
|
||||
def test_lot_report_shipment_type_uses_linked_shipment(self):
|
||||
'lot report shipment type mirrors the linked shipment_in'
|
||||
|
||||
Reference in New Issue
Block a user