From b3b780331387901091ebf176061b832116af53b5 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sun, 7 Jun 2026 07:23:32 +0200 Subject: [PATCH] Link to transport --- modules/purchase_trade/lot.py | 56 ++++++++++++++++++--- modules/purchase_trade/tests/test_module.py | 27 ++++++++++ 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/modules/purchase_trade/lot.py b/modules/purchase_trade/lot.py index 975ae5c..06c21ff 100755 --- a/modules/purchase_trade/lot.py +++ b/modules/purchase_trade/lot.py @@ -2954,14 +2954,16 @@ class LotShipping(Wizard): start = StateTransition() - ship = StateView( - 'lot.shipping.start', - 'purchase_trade.shipping_view_form', [ - Button("Cancel", 'end', 'tryton-cancel'), - Button("Link", 'shipping', 'tryton-ok', default=True), - ]) - - shipping = StateTransition() + ship = StateView( + 'lot.shipping.start', + 'purchase_trade.shipping_view_form', [ + Button("Cancel", 'end', 'tryton-cancel'), + Button("Create shipment", 'create_shipment', 'tryton-add'), + Button("Link", 'shipping', 'tryton-ok', default=True), + ]) + + create_shipment = StateTransition() + shipping = StateTransition() def transition_start(self): if self.model.__name__ == 'lot.report': @@ -2980,6 +2982,44 @@ class LotShipping(Wizard): values['planned_to_location'] = record.r_planned_to_location.id return values + @staticmethod + def _record_id(record): + return record.id if record else None + + def _unique_supplier(self): + suppliers = {} + for record in self.records: + supplier = getattr(record, 'r_supplier', None) + if supplier: + suppliers[supplier.id] = supplier + if len(suppliers) == 1: + return next(iter(suppliers.values())) + if not suppliers: + raise UserError("Supplier is required to create a shipment.") + raise UserError( + "Please select lots with the same supplier to create a shipment.") + + def _shipment_in_create_values(self): + if self.ship.shipment != 'in': + raise UserError("Shipment creation is only available for Shipment In.") + supplier = self._unique_supplier() + values = { + 'supplier': self._record_id(supplier), + } + if self.ship.planned_from_location: + values['from_location'] = self.ship.planned_from_location.id + if self.ship.planned_to_location: + values['to_location'] = self.ship.planned_to_location.id + return values + + def transition_create_shipment(self): + ShipmentIn = Pool().get('stock.shipment.in') + if self.ship.shipment_in: + return 'ship' + shipment, = ShipmentIn.create([self._shipment_in_create_values()]) + self.ship.shipment_in = shipment + return 'ship' + def transition_shipping(self): Lot = Pool().get('lot.lot') LotQt = Pool().get('lot.qt') diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index a4c57c7..5e5b1f4 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -219,6 +219,33 @@ class PurchaseTradeTestCase(ModuleTestCase): 'planned_to_location': 20, }) + def test_lot_shipping_create_shipment_uses_planned_locations(self): + 'link to transport creates shipment in from planned locations' + wizard = lot_module.LotShipping() + supplier = Mock(id=30) + created_shipment = Mock() + ShipmentIn = Mock() + ShipmentIn.create.return_value = [created_shipment] + wizard.records = [Mock(r_supplier=supplier)] + wizard.ship = Mock( + shipment='in', + shipment_in=None, + planned_from_location=Mock(id=10), + planned_to_location=Mock(id=20), + ) + + with patch('trytond.modules.purchase_trade.lot.Pool') as PoolMock: + PoolMock.return_value.get.return_value = ShipmentIn + state = wizard.transition_create_shipment() + + self.assertEqual(state, 'ship') + ShipmentIn.create.assert_called_once_with([{ + 'supplier': 30, + 'from_location': 10, + 'to_location': 20, + }]) + self.assertEqual(wizard.ship.shipment_in, created_shipment) + @with_transaction() def test_get_mtm_applies_component_ratio_as_percentage(self): 'get_mtm treats component ratio as a percentage'