From 016fc52fabb19f2da2a77ea13ffd2f3e33c6c0fe Mon Sep 17 00:00:00 2001 From: Michael Tietz Date: Tue, 9 Jul 2024 17:39:16 +0200 Subject: [PATCH 1/3] [IMP] shipment_advice: Refactor Unittest common --- shipment_advice/tests/common.py | 39 +++++++++-------- shipment_advice/tests/test_shipment_advice.py | 42 +++++++++---------- .../tests/test_shipment_advice_load.py | 22 +++++----- .../test_shipment_advice_picking_values.py | 4 +- .../tests/test_shipment_advice_plan.py | 4 +- .../tests/test_shipment_advice_stock_user.py | 6 +-- .../tests/test_shipment_advice_to_load.py | 10 ++--- .../tests/test_shipment_advice_unload.py | 16 +++---- ...test_shipment_advice_bill_auto_complete.py | 12 +++--- ..._shipment_advice_bill_auto_complete_mrp.py | 8 ++-- .../test_shipment_advice_reception_planner.py | 2 +- 11 files changed, 85 insertions(+), 80 deletions(-) diff --git a/shipment_advice/tests/common.py b/shipment_advice/tests/common.py index 818e4788f..c91c0d38c 100644 --- a/shipment_advice/tests/common.py +++ b/shipment_advice/tests/common.py @@ -1,4 +1,5 @@ # Copyright 2021 Camptocamp SA +# Copyright 2024 Michael Tietz (MT Software) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields @@ -118,32 +119,33 @@ def _create_move(cls, picking_type, product, quantity, group=False): move.picking_id.action_assign() return move - def _confirm_shipment_advice(self, shipment_advice, arrival_date=None): + @classmethod + def confirm_shipment_advice(cls, shipment_advice, arrival_date=None): if shipment_advice.state != "draft": return if arrival_date is None: arrival_date = fields.Datetime.now() shipment_advice.arrival_date = arrival_date shipment_advice.action_confirm() - self.assertEqual(shipment_advice.state, "confirmed") - def _in_progress_shipment_advice(self, shipment_advice, dock=None): - self._confirm_shipment_advice(shipment_advice) + @classmethod + def progress_shipment_advice(cls, shipment_advice, dock=None): + cls.confirm_shipment_advice(shipment_advice) if shipment_advice.state != "confirmed": return - shipment_advice.dock_id = dock or self.dock + shipment_advice.dock_id = dock or cls.dock shipment_advice.action_in_progress() - self.assertEqual(shipment_advice.state, "in_progress") - def _cancel_shipment_advice(self, shipment_advice, dock=None): - self._confirm_shipment_advice(shipment_advice) + @classmethod + def cancel_shipment_advice(cls, shipment_advice, dock=None): + cls.confirm_shipment_advice(shipment_advice) if shipment_advice.state != "confirmed": return shipment_advice.action_cancel() - self.assertEqual(shipment_advice.state, "cancel") - def _plan_records_in_shipment(self, shipment_advice, records, user=None): - wiz_model = self.env["wizard.plan.shipment"].with_context( + @classmethod + def plan_records_in_shipment(cls, shipment_advice, records, user=None): + wiz_model = cls.env["wizard.plan.shipment"].with_context( active_model=records._name, active_ids=records.ids, ) @@ -153,8 +155,9 @@ def _plan_records_in_shipment(self, shipment_advice, records, user=None): wiz.action_plan() return wiz - def _unplan_records_from_shipment(self, records, user=None): - wiz_model = self.env["wizard.unplan.shipment"].with_context( + @classmethod + def unplan_records_from_shipment(cls, records, user=None): + wiz_model = cls.env["wizard.unplan.shipment"].with_context( active_model=records._name, active_ids=records.ids, ) @@ -164,9 +167,10 @@ def _unplan_records_from_shipment(self, records, user=None): wiz.action_unplan() return wiz - def _load_records_in_shipment(self, shipment_advice, records, user=None): + @classmethod + def load_records_in_shipment(cls, shipment_advice, records, user=None): """Load pickings, move lines or package levels in the givent shipment.""" - wiz_model = self.env["wizard.load.shipment"].with_context( + wiz_model = cls.env["wizard.load.shipment"].with_context( active_model=records._name, active_ids=records.ids, ) @@ -176,9 +180,10 @@ def _load_records_in_shipment(self, shipment_advice, records, user=None): wiz.action_load() return wiz - def _unload_records_from_shipment(self, shipment_advice, records): + @classmethod + def unload_records_from_shipment(cls, shipment_advice, records): """Unload pickings, move lines or package levels from the givent shipment.""" - wiz_model = self.env["wizard.unload.shipment"].with_context( + wiz_model = cls.env["wizard.unload.shipment"].with_context( active_model=records._name, active_ids=records.ids, ) diff --git a/shipment_advice/tests/test_shipment_advice.py b/shipment_advice/tests/test_shipment_advice.py index 6e6ad581e..12ba01e7b 100644 --- a/shipment_advice/tests/test_shipment_advice.py +++ b/shipment_advice/tests/test_shipment_advice.py @@ -48,7 +48,7 @@ def test_shipment_advice_confirm(self): self.assertEqual(self.shipment_advice_out.state, "confirmed") def test_shipment_advice_in_progress(self): - self._confirm_shipment_advice(self.shipment_advice_out) + self.confirm_shipment_advice(self.shipment_advice_out) with self.assertRaises(UserError): self.shipment_advice_out.action_in_progress() self.shipment_advice_out.dock_id = self.dock @@ -60,8 +60,8 @@ def test_shipment_advice_incoming_done_full(self): transfers. Here the planned transfers have been fully received. """ picking = self.move_product_in1.picking_id - self._plan_records_in_shipment(self.shipment_advice_in, picking) - self._in_progress_shipment_advice(self.shipment_advice_in) + self.plan_records_in_shipment(self.shipment_advice_in, picking) + self.progress_shipment_advice(self.shipment_advice_in) for ml in picking.move_line_ids: ml.qty_done = ml.product_uom_qty picking._action_done() @@ -81,8 +81,8 @@ def test_shipment_advice_incoming_done_partial(self): """ picking = self.move_product_in1.picking_id # Plan a move - self._plan_records_in_shipment(self.shipment_advice_in, self.move_product_in1) - self._in_progress_shipment_advice(self.shipment_advice_in) + self.plan_records_in_shipment(self.shipment_advice_in, self.move_product_in1) + self.progress_shipment_advice(self.shipment_advice_in) # Receive it (making its related transfer partially received) for ml in self.move_product_in1.move_line_ids: ml.qty_done = ml.product_uom_qty @@ -103,8 +103,8 @@ def test_shipment_advice_done_full(self): to only one in progress shipment. """ picking = self.move_product_out1.picking_id - self._in_progress_shipment_advice(self.shipment_advice_out) - self._load_records_in_shipment(self.shipment_advice_out, picking) + self.progress_shipment_advice(self.shipment_advice_out) + self.load_records_in_shipment(self.shipment_advice_out, picking) self.shipment_advice_out.action_done() self.assertEqual(self.shipment_advice_out.state, "done") self.assertTrue( @@ -124,8 +124,8 @@ def test_shipment_advice_done_backorder_policy_disabled(self): company.shipment_advice_outgoing_backorder_policy = "leave_open" # Load a transfer partially (here a package) package_level = self.move_product_out2.move_line_ids.package_level_id - self._in_progress_shipment_advice(self.shipment_advice_out) - self._load_records_in_shipment(self.shipment_advice_out, package_level) + self.progress_shipment_advice(self.shipment_advice_out) + self.load_records_in_shipment(self.shipment_advice_out, package_level) # Validate the shipment => the transfer is still open self.shipment_advice_out.action_done() picking = package_level.picking_id @@ -160,16 +160,16 @@ def test_multi_shipment_advice_done_backorder_policy_disabled(self): line1, line2 = picking.move_line_ids # Load first package in the first shipment advice pl1 = line1.package_level_id - self._in_progress_shipment_advice(self.shipment_advice_out) - self._load_records_in_shipment(self.shipment_advice_out, pl1) + self.progress_shipment_advice(self.shipment_advice_out) + self.load_records_in_shipment(self.shipment_advice_out, pl1) # Validate the first shipment advice: delivery order hasn't been validated self.shipment_advice_out.action_done() self.assertEqual(self.shipment_advice_out.state, "done") self.assertEqual(picking.state, "assigned") # Load second package in the second shipment advice pl2 = line2.package_level_id - self._in_progress_shipment_advice(shipment_advice_out2) - self._load_records_in_shipment(shipment_advice_out2, pl2) + self.progress_shipment_advice(shipment_advice_out2) + self.load_records_in_shipment(shipment_advice_out2, pl2) # Validate the second shipment advice: delivery order has now been validated shipment_advice_out2.action_done() self.assertEqual(shipment_advice_out2.state, "done") @@ -184,8 +184,8 @@ def test_shipment_advice_done_backorder_policy_enabled(self): company.shipment_advice_outgoing_backorder_policy = "create_backorder" # Load a transfer partially (here a package) package_level = self.move_product_out2.move_line_ids.package_level_id - self._in_progress_shipment_advice(self.shipment_advice_out) - self._load_records_in_shipment(self.shipment_advice_out, package_level) + self.progress_shipment_advice(self.shipment_advice_out) + self.load_records_in_shipment(self.shipment_advice_out, package_level) self.assertEqual(package_level.picking_id, self.move_product_out1.picking_id) # Validate the shipment => the transfer is validated, creating a backorder self.shipment_advice_out.action_done() @@ -219,11 +219,11 @@ def test_assign_lines_to_multiple_shipment_advices(self): line1, line2 = picking.move_line_ids # Load packages in different shipment advices pl1 = line1.package_level_id - self._in_progress_shipment_advice(self.shipment_advice_out) - self._load_records_in_shipment(self.shipment_advice_out, pl1) + self.progress_shipment_advice(self.shipment_advice_out) + self.load_records_in_shipment(self.shipment_advice_out, pl1) pl2 = line2.package_level_id - self._in_progress_shipment_advice(shipment_advice_out2) - self._load_records_in_shipment(shipment_advice_out2, pl2) + self.progress_shipment_advice(shipment_advice_out2) + self.load_records_in_shipment(shipment_advice_out2, pl2) # Validate the first shipment advice: delivery order hasn't been validated self.shipment_advice_out.action_done() self.assertEqual(self.shipment_advice_out.state, "done") @@ -234,12 +234,12 @@ def test_assign_lines_to_multiple_shipment_advices(self): self.assertEqual(picking.state, "done") def test_shipment_advice_cancel(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) self.shipment_advice_out.action_cancel() self.assertEqual(self.shipment_advice_out.state, "cancel") def test_shipment_advice_draft(self): - self._cancel_shipment_advice(self.shipment_advice_out) + self.cancel_shipment_advice(self.shipment_advice_out) self.shipment_advice_out.action_draft() self.assertEqual(self.shipment_advice_out.state, "draft") diff --git a/shipment_advice/tests/test_shipment_advice_load.py b/shipment_advice/tests/test_shipment_advice_load.py index 558339e4c..42fdd7d2e 100644 --- a/shipment_advice/tests/test_shipment_advice_load.py +++ b/shipment_advice/tests/test_shipment_advice_load.py @@ -8,7 +8,7 @@ class TestShipmentAdviceLoad(Common): def test_shipment_advice_load_picking_not_planned(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) picking = self.move_product_out1.picking_id wiz_model = self.env["wizard.load.shipment"].with_context( active_model=picking._name, @@ -42,9 +42,9 @@ def test_shipment_advice_load_picking_not_planned(self): def test_shipment_advice_load_picking_already_planned(self): picking = self.move_product_out1.picking_id - self._plan_records_in_shipment(self.shipment_advice_out, picking) - self._in_progress_shipment_advice(self.shipment_advice_out) - wiz = self._load_records_in_shipment(self.shipment_advice_out, picking) + self.plan_records_in_shipment(self.shipment_advice_out, picking) + self.progress_shipment_advice(self.shipment_advice_out) + wiz = self.load_records_in_shipment(self.shipment_advice_out, picking) self.assertEqual(wiz.picking_ids, picking) self.assertFalse(wiz.move_line_ids) # Check planned entries @@ -73,7 +73,7 @@ def test_shipment_advice_load_picking_already_planned(self): self.assertEqual(wiz.shipment_advice_id.loaded_package_ids, self.package) def test_shipment_advice_load_move_line_not_planned(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) move = self.move_product_out1 wiz_model = self.env["wizard.load.shipment"].with_context( active_model=move.move_line_ids._name, @@ -101,9 +101,9 @@ def test_shipment_advice_load_move_line_not_planned(self): def test_shipment_advice_load_move_line_already_planned(self): move = self.move_product_out1 - self._plan_records_in_shipment(self.shipment_advice_out, move) - self._in_progress_shipment_advice(self.shipment_advice_out) - wiz = self._load_records_in_shipment( + self.plan_records_in_shipment(self.shipment_advice_out, move) + self.progress_shipment_advice(self.shipment_advice_out) + wiz = self.load_records_in_shipment( self.shipment_advice_out, move.move_line_ids ) self.assertEqual(wiz.move_line_ids, move.move_line_ids) @@ -127,12 +127,12 @@ def test_shipment_advice_load_move_line_already_planned(self): def test_shipment_advice_already_planned_load_move_line_not_planned(self): # Plan the first move move1 = self.move_product_out1 - self._plan_records_in_shipment(self.shipment_advice_out, move1) + self.plan_records_in_shipment(self.shipment_advice_out, move1) # But load something else => error package_level = self.move_product_out2.move_line_ids.package_level_id - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) with self.assertRaisesRegex(UserError, "planned already"): - self._load_records_in_shipment( + self.load_records_in_shipment( self.shipment_advice_out, package_level, ) diff --git a/shipment_advice/tests/test_shipment_advice_picking_values.py b/shipment_advice/tests/test_shipment_advice_picking_values.py index c9ba6b968..3e4986425 100644 --- a/shipment_advice/tests/test_shipment_advice_picking_values.py +++ b/shipment_advice/tests/test_shipment_advice_picking_values.py @@ -8,7 +8,7 @@ class TestShipmentPickingValues(Common): def test_picking_loaded_waiting_quantity_no(self): move = self.move_product_out1 picking = move.picking_id - self._load_records_in_shipment(self.shipment_advice_out, picking) + self.load_records_in_shipment(self.shipment_advice_out, picking) self.assertEqual(picking.loaded_waiting_quantity, 0) def test_picking_loaded_waiting_quantity_yes(self): @@ -16,5 +16,5 @@ def test_picking_loaded_waiting_quantity_yes(self): picking = move.picking_id quantity = move.product_qty move.move_line_ids.product_uom_qty = quantity - 3 - self._load_records_in_shipment(self.shipment_advice_out, picking) + self.load_records_in_shipment(self.shipment_advice_out, picking) self.assertEqual(picking.loaded_waiting_quantity, 3) diff --git a/shipment_advice/tests/test_shipment_advice_plan.py b/shipment_advice/tests/test_shipment_advice_plan.py index 1a02eb534..32817e649 100644 --- a/shipment_advice/tests/test_shipment_advice_plan.py +++ b/shipment_advice/tests/test_shipment_advice_plan.py @@ -7,7 +7,7 @@ class TestShipmentAdvicePlan(Common): def test_shipment_advice_plan_picking(self): picking = self.move_product_out1.picking_id - wiz = self._plan_records_in_shipment(self.shipment_advice_out, picking) + wiz = self.plan_records_in_shipment(self.shipment_advice_out, picking) self.assertEqual(wiz.picking_ids, picking) self.assertFalse(wiz.move_ids) self.assertEqual(wiz.shipment_advice_id, self.shipment_advice_out) @@ -18,7 +18,7 @@ def test_shipment_advice_plan_picking(self): def test_shipment_advice_plan_move(self): picking = self.move_product_out1.picking_id - wiz = self._plan_records_in_shipment( + wiz = self.plan_records_in_shipment( self.shipment_advice_out, self.move_product_out1 ) self.assertEqual(wiz.move_ids, self.move_product_out1) diff --git a/shipment_advice/tests/test_shipment_advice_stock_user.py b/shipment_advice/tests/test_shipment_advice_stock_user.py index b970d4dcf..75176115a 100644 --- a/shipment_advice/tests/test_shipment_advice_stock_user.py +++ b/shipment_advice/tests/test_shipment_advice_stock_user.py @@ -75,13 +75,13 @@ def test_stock_package_level_button_load_in_shipment(self): def test_wizard_plan_and_load_shipment(self): move = self.move_product_out1 - self._plan_records_in_shipment( + self.plan_records_in_shipment( self.shipment_advice_out, move, user=self.stock_user, ) - self._in_progress_shipment_advice(self.shipment_advice_out) - wiz = self._load_records_in_shipment( + self.progress_shipment_advice(self.shipment_advice_out) + wiz = self.load_records_in_shipment( self.shipment_advice_out, move.move_line_ids, user=self.stock_user, diff --git a/shipment_advice/tests/test_shipment_advice_to_load.py b/shipment_advice/tests/test_shipment_advice_to_load.py index 53dc33a05..b49be9d51 100644 --- a/shipment_advice/tests/test_shipment_advice_to_load.py +++ b/shipment_advice/tests/test_shipment_advice_to_load.py @@ -7,9 +7,9 @@ class TestShipmentAdviceToLoad(Common): def test_shipment_advice_not_planned_lines_to_load(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) # Load a transfer partially - self._load_records_in_shipment( + self.load_records_in_shipment( self.shipment_advice_out, self.move_product_out1.move_line_ids ) self.assertEqual( @@ -24,17 +24,17 @@ def test_shipment_advice_not_planned_lines_to_load(self): self.assertEqual(self.shipment_advice_out.line_to_load_ids, lines_to_load) def test_shipment_advice_planned_lines_to_load(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) # Plan a transfer in the shipment advice picking = self.move_product_out2.picking_id - self._plan_records_in_shipment(self.shipment_advice_out, picking) + self.plan_records_in_shipment(self.shipment_advice_out, picking) # Check the lines computed by the shipment advice that could be loaded # (= all the lines of the planned transfer) lines_to_load = picking.move_line_ids self.assertFalse(lines_to_load.shipment_advice_id) self.assertEqual(self.shipment_advice_out.line_to_load_ids, lines_to_load) # Load some goods from the planned transfer - self._load_records_in_shipment( + self.load_records_in_shipment( self.shipment_advice_out, self.move_product_out1.move_line_ids ) self.assertEqual( diff --git a/shipment_advice/tests/test_shipment_advice_unload.py b/shipment_advice/tests/test_shipment_advice_unload.py index d89f98a26..7f71905ef 100644 --- a/shipment_advice/tests/test_shipment_advice_unload.py +++ b/shipment_advice/tests/test_shipment_advice_unload.py @@ -6,10 +6,10 @@ class TestShipmentAdviceUnload(Common): def test_shipment_advice_unload_picking(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) # Load picking picking = self.move_product_out1.picking_id - self._load_records_in_shipment(self.shipment_advice_out, picking) + self.load_records_in_shipment(self.shipment_advice_out, picking) self.assertEqual(self.shipment_advice_out.loaded_picking_ids, picking) self.assertEqual( self.shipment_advice_out.loaded_move_line_ids, @@ -18,29 +18,29 @@ def test_shipment_advice_unload_picking(self): | self.move_product_out3.move_line_ids, ) # Unload it - self._unload_records_from_shipment(self.shipment_advice_out, picking) + self.unload_records_from_shipment(self.shipment_advice_out, picking) self.assertFalse(self.shipment_advice_out.loaded_picking_ids) self.assertFalse(self.shipment_advice_out.loaded_move_line_ids) def test_shipment_advice_unload_move_line(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) # Load move line move_line = self.move_product_out1.move_line_ids - self._load_records_in_shipment(self.shipment_advice_out, move_line) + self.load_records_in_shipment(self.shipment_advice_out, move_line) self.assertEqual(move_line.qty_done, 20) self.assertEqual( self.shipment_advice_out.loaded_move_line_without_package_ids, move_line ) # Unload it - self._unload_records_from_shipment(self.shipment_advice_out, move_line) + self.unload_records_from_shipment(self.shipment_advice_out, move_line) self.assertFalse(move_line.qty_done) self.assertFalse(self.shipment_advice_out.loaded_move_line_without_package_ids) def test_shipment_advice_unload_package_level(self): - self._in_progress_shipment_advice(self.shipment_advice_out) + self.progress_shipment_advice(self.shipment_advice_out) # Load package level package_level = self.move_product_out2.move_line_ids.package_level_id - self._load_records_in_shipment(self.shipment_advice_out, package_level) + self.load_records_in_shipment(self.shipment_advice_out, package_level) self.assertTrue(package_level.is_done) self.assertEqual(self.move_product_out2.move_line_ids.qty_done, 10) self.assertEqual(self.move_product_out3.move_line_ids.qty_done, 10) diff --git a/shipment_advice_bill_auto_complete/tests/test_shipment_advice_bill_auto_complete.py b/shipment_advice_bill_auto_complete/tests/test_shipment_advice_bill_auto_complete.py index a940eb51e..9072384bd 100644 --- a/shipment_advice_bill_auto_complete/tests/test_shipment_advice_bill_auto_complete.py +++ b/shipment_advice_bill_auto_complete/tests/test_shipment_advice_bill_auto_complete.py @@ -79,8 +79,8 @@ def _check_invoiced_lines(self, invoice, pickings): def test_select_shipment_with_different_supplier(self): """Check shipment selected has not the same supplier than the invoice.""" - self._plan_records_in_shipment(self.shipment, self.purchase_1.picking_ids) - self._in_progress_shipment_advice(self.shipment) + self.plan_records_in_shipment(self.shipment, self.purchase_1.picking_ids) + self.progress_shipment_advice(self.shipment) self._receive_goods(self.purchase_1.picking_ids) self.shipment.action_done() # Invoice the shipment @@ -94,8 +94,8 @@ def test_select_shipment_with_different_supplier(self): def test_select_shipment_with_one_supplier(self): """Check invoicing shipment with one supplier.""" - self._plan_records_in_shipment(self.shipment, self.purchase_1.picking_ids) - self._in_progress_shipment_advice(self.shipment) + self.plan_records_in_shipment(self.shipment, self.purchase_1.picking_ids) + self.progress_shipment_advice(self.shipment) self._receive_goods(self.purchase_1.picking_ids) self.shipment.action_done() # Invoice the shipment @@ -109,8 +109,8 @@ def test_select_shipment_with_one_supplier(self): def test_select_shipment_with_goods_partially_received(self): pickings = self.purchase_1.picking_ids - self._plan_records_in_shipment(self.shipment, pickings) - self._in_progress_shipment_advice(self.shipment) + self.plan_records_in_shipment(self.shipment, pickings) + self.progress_shipment_advice(self.shipment) # Partially receive the goods for line in pickings.move_line_ids: line.qty_done = line.product_uom_qty - 1 diff --git a/shipment_advice_bill_auto_complete_mrp/tests/test_shipment_advice_bill_auto_complete_mrp.py b/shipment_advice_bill_auto_complete_mrp/tests/test_shipment_advice_bill_auto_complete_mrp.py index 0f6887528..0052ef883 100644 --- a/shipment_advice_bill_auto_complete_mrp/tests/test_shipment_advice_bill_auto_complete_mrp.py +++ b/shipment_advice_bill_auto_complete_mrp/tests/test_shipment_advice_bill_auto_complete_mrp.py @@ -37,8 +37,8 @@ def _get_vendor_bill_form(self): def test_select_shipment_with_one_supplier(self): """""" - self._plan_records_in_shipment(self.shipment, self.purchase.picking_ids) - self._in_progress_shipment_advice(self.shipment) + self.plan_records_in_shipment(self.shipment, self.purchase.picking_ids) + self.progress_shipment_advice(self.shipment) self._receive_goods(self.purchase.picking_ids) self.shipment.action_done() # Invoice the shipment @@ -56,8 +56,8 @@ def test_select_shipment_with_one_supplier(self): def test_select_shipment_with_goods_partially_received(self): pickings = self.purchase.picking_ids - self._plan_records_in_shipment(self.shipment, pickings) - self._in_progress_shipment_advice(self.shipment) + self.plan_records_in_shipment(self.shipment, pickings) + self.progress_shipment_advice(self.shipment) # Partially receive the goods for line in pickings.move_line_ids: line.qty_done = line.product_uom_qty - 1 diff --git a/shipment_advice_reception_planner/tests/test_shipment_advice_reception_planner.py b/shipment_advice_reception_planner/tests/test_shipment_advice_reception_planner.py index d5edbb4da..bf2d0f7f6 100644 --- a/shipment_advice_reception_planner/tests/test_shipment_advice_reception_planner.py +++ b/shipment_advice_reception_planner/tests/test_shipment_advice_reception_planner.py @@ -98,7 +98,7 @@ def test_shipment_advice_reception_split_move(self): self.assertEqual(new_split_move.state, "assigned") # Unplanning the previously planned move, should merge them back. - self._unplan_records_from_shipment(new_split_move) + self.unplan_records_from_shipment(new_split_move) move = self.picking.move_lines.filtered( lambda move: move.product_id == self.product1 ) From 509b38955958800523404acbcf0482edb16902d0 Mon Sep 17 00:00:00 2001 From: Michael Tietz Date: Fri, 12 Jul 2024 11:52:36 +0200 Subject: [PATCH 2/3] [IMP] shipment_advice: Auto close incoming advice If a move is processed the related incoming shipment advice will be set to done if all planned moves are done or canceled --- shipment_advice/models/res_company.py | 9 ++++ shipment_advice/models/res_config_settings.py | 4 ++ shipment_advice/models/shipment_advice.py | 30 +++++++++++- shipment_advice/models/stock_move.py | 11 +++++ shipment_advice/readme/CONTRIBUTORS.rst | 1 + shipment_advice/tests/__init__.py | 1 + shipment_advice/tests/common.py | 16 ++++++- .../tests/test_shipment_advice_auto_close.py | 46 +++++++++++++++++++ shipment_advice/views/res_config_settings.xml | 14 ++++++ 9 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 shipment_advice/tests/test_shipment_advice_auto_close.py diff --git a/shipment_advice/models/res_company.py b/shipment_advice/models/res_company.py index df8c1ad04..f09dc183f 100644 --- a/shipment_advice/models/res_company.py +++ b/shipment_advice/models/res_company.py @@ -1,4 +1,5 @@ # Copyright 2021 Camptocamp SA +# Copyright 2024 Michael Tietz (MT Software) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields, models @@ -23,3 +24,11 @@ class ResCompany(models.Model): "deliveries will be shipped by several trucks." ), ) + shipment_advice_auto_close_incoming = fields.Boolean( + string="Shipment Advice: Auto Close Incoming Advices", + help=( + "This flag indicates if an incoming shipment advice " + "will be automatically set to done " + "if all related moves are done or canceled" + ), + ) diff --git a/shipment_advice/models/res_config_settings.py b/shipment_advice/models/res_config_settings.py index 1bb6a2417..67bf99a8d 100644 --- a/shipment_advice/models/res_config_settings.py +++ b/shipment_advice/models/res_config_settings.py @@ -1,4 +1,5 @@ # Copyright 2021 Camptocamp SA +# Copyright 2024 Michael Tietz (MT Software) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields, models @@ -10,3 +11,6 @@ class ResConfigSettings(models.TransientModel): shipment_advice_outgoing_backorder_policy = fields.Selection( related="company_id.shipment_advice_outgoing_backorder_policy", readonly=False ) + shipment_advice_auto_close_incoming = fields.Boolean( + related="company_id.shipment_advice_auto_close_incoming", readonly=False + ) diff --git a/shipment_advice/models/shipment_advice.py b/shipment_advice/models/shipment_advice.py index bfa8f368e..013522339 100644 --- a/shipment_advice/models/shipment_advice.py +++ b/shipment_advice/models/shipment_advice.py @@ -1,4 +1,5 @@ # Copyright 2021 Camptocamp SA +# Copyright 2024 Michael Tietz (MT Software) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import _, api, fields, models @@ -381,6 +382,8 @@ def _lock_records(self, records): def action_done(self): wiz_model = self.env["stock.backorder.confirmation"] + shipment_advice_ids_to_validate = [] + self = self.with_context(shipment_advice_ignore_auto_close=True) for shipment in self: if shipment.state != "in_progress": raise UserError( @@ -432,10 +435,33 @@ def action_done(self): lambda m: m.state not in ("cancel", "done") and not m.quantity_done ) moves_to_unplan.shipment_advice_id = False - shipment.departure_date = fields.Datetime.now() - shipment.state = "done" + shipment_advice_ids_to_validate.append(shipment.id) + if shipment_advice_ids_to_validate: + self.browse(shipment_advice_ids_to_validate)._action_done() return True + def _action_done(self): + self.write({"departure_date": fields.Datetime.now(), "state": "done"}) + + def auto_close_incoming_shipment_advices(self): + """Set incoming shipment advice to done when all planned moves are processed""" + if self.env.context.get("shipment_advice_ignore_auto_close"): + return + shipment_ids_to_close = [] + for shipment in self: + if ( + shipment.shipment_type != "incoming" + or not shipment.company_id.shipment_advice_auto_close_incoming + or any( + move.state not in ("cancel", "done") + for move in shipment.planned_move_ids + ) + ): + continue + shipment_ids_to_close.append(shipment.id) + if shipment_ids_to_close: + self.browse(shipment_ids_to_close)._action_done() + def action_cancel(self): for shipment in self: if shipment.state not in ("confirmed", "in_progress"): diff --git a/shipment_advice/models/stock_move.py b/shipment_advice/models/stock_move.py index 0fe033d64..942a6ce67 100644 --- a/shipment_advice/models/stock_move.py +++ b/shipment_advice/models/stock_move.py @@ -1,4 +1,5 @@ # Copyright 2021 Camptocamp SA +# Copyright 2024 Michael Tietz (MT Software) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields, models @@ -23,3 +24,13 @@ def _prepare_merge_moves_distinct_fields(self): # Avoid having stock move assign to different shipment merged together res.append("shipment_advice_id") return res + + def _action_done(self, cancel_backorder=False): + res = super()._action_done(cancel_backorder=cancel_backorder) + res.shipment_advice_id.auto_close_incoming_shipment_advices() + return res + + def _action_cancel(self): + res = super()._action_cancel() + self.shipment_advice_id.auto_close_incoming_shipment_advices() + return res diff --git a/shipment_advice/readme/CONTRIBUTORS.rst b/shipment_advice/readme/CONTRIBUTORS.rst index 09f87c8c8..67ff68bce 100644 --- a/shipment_advice/readme/CONTRIBUTORS.rst +++ b/shipment_advice/readme/CONTRIBUTORS.rst @@ -3,6 +3,7 @@ * Simone Orsi * `Trobz `_: * Dung Tran +* Michael Tietz (MT Software) Design ~~~~~~ diff --git a/shipment_advice/tests/__init__.py b/shipment_advice/tests/__init__.py index 197236b61..6152d14fa 100644 --- a/shipment_advice/tests/__init__.py +++ b/shipment_advice/tests/__init__.py @@ -5,3 +5,4 @@ from . import test_shipment_advice_picking_values from . import test_shipment_advice_unload from . import test_shipment_advice_stock_user +from . import test_shipment_advice_auto_close diff --git a/shipment_advice/tests/common.py b/shipment_advice/tests/common.py index c91c0d38c..c60ba50a2 100644 --- a/shipment_advice/tests/common.py +++ b/shipment_advice/tests/common.py @@ -3,7 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) from odoo import fields -from odoo.tests.common import SavepointCase, new_test_user +from odoo.tests.common import Form, SavepointCase, new_test_user class Common(SavepointCase): @@ -190,3 +190,17 @@ def unload_records_from_shipment(cls, shipment_advice, records): wiz = wiz_model.create({}) wiz.action_unload() return wiz + + @classmethod + def validate_picking(cls, picking, qty_done=None): + picking.ensure_one() + for ml in picking.move_line_ids: + ml.qty_done = qty_done or ml.product_uom_qty + action_data = picking.button_validate() + if action_data is True: + return cls.env["stock.picking"] + backorder_wizard = Form( + cls.env["stock.backorder.confirmation"].with_context(action_data["context"]) + ).save() + backorder_wizard.process() + return cls.env["stock.picking"].search([("backorder_id", "=", picking.id)]) diff --git a/shipment_advice/tests/test_shipment_advice_auto_close.py b/shipment_advice/tests/test_shipment_advice_auto_close.py new file mode 100644 index 000000000..b7b1674dc --- /dev/null +++ b/shipment_advice/tests/test_shipment_advice_auto_close.py @@ -0,0 +1,46 @@ +# Copyright 2024 Michael Tietz (MT Software) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from .common import Common + + +class TestShipmentAdviceAutoClose(Common): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.shipment_advice_in.company_id.shipment_advice_auto_close_incoming = True + cls.picking1 = cls.move_product_in1.picking_id + group = cls.env["procurement.group"].create({}) + cls.move_product_in21 = cls._create_move( + cls.picking_type_in, cls.product_in, 5, group + ) + cls.picking2 = cls.move_product_in21.picking_id + cls.pickings = cls.picking1 | cls.picking2 + cls.plan_records_in_shipment(cls.shipment_advice_in, cls.pickings) + cls.progress_shipment_advice(cls.shipment_advice_in) + + def test_auto_close_incoming_on_done(self): + self.validate_picking(self.picking1) + self.assertEqual(self.shipment_advice_in.state, "in_progress") + self.validate_picking(self.picking2) + self.assertEqual(self.shipment_advice_in.state, "done") + + def test_auto_close_incoming_on_cancel(self): + self.validate_picking(self.picking1) + self.assertEqual(self.shipment_advice_in.state, "in_progress") + self.picking2.action_cancel() + self.assertEqual(self.shipment_advice_in.state, "done") + + def test_no_auto_close_on_outgoing(self): + picking = self.move_product_out1.picking_id + self.plan_records_in_shipment(self.shipment_advice_out, picking) + self.progress_shipment_advice(self.shipment_advice_out) + self.validate_picking(picking) + self.assertEqual(picking.state, "done") + self.assertEqual(self.shipment_advice_out.state, "in_progress") + + def test_no_auto_close_context(self): + pickings = self.pickings.with_context(shipment_advice_ignore_auto_close=True) + for picking in pickings: + self.validate_picking(picking) + self.assertEqual(self.shipment_advice_in.state, "in_progress") diff --git a/shipment_advice/views/res_config_settings.xml b/shipment_advice/views/res_config_settings.xml index 2b747f386..0eaddbe3d 100644 --- a/shipment_advice/views/res_config_settings.xml +++ b/shipment_advice/views/res_config_settings.xml @@ -1,5 +1,6 @@ @@ -27,6 +28,19 @@ +
+
+ +
+
+
+
From 2224ba29992f9c133dd9691dd987ecca44beb773 Mon Sep 17 00:00:00 2001 From: Michael Tietz Date: Thu, 11 Jul 2024 13:50:33 +0200 Subject: [PATCH 3/3] [FIX] shipment_advice: Refactor action_done use just one record instead of the recordset --- shipment_advice/models/shipment_advice.py | 83 +++++++++++------------ 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/shipment_advice/models/shipment_advice.py b/shipment_advice/models/shipment_advice.py index 013522339..205219ed6 100644 --- a/shipment_advice/models/shipment_advice.py +++ b/shipment_advice/models/shipment_advice.py @@ -380,8 +380,42 @@ def _lock_records(self, records): sql = "SELECT id FROM %s WHERE ID IN %%s FOR UPDATE" % records._table self.env.cr.execute(sql, (tuple(records.ids),), log_exceptions=False) - def action_done(self): + def _close_pickings(self): + """Validate transfers (create backorders for unprocessed lines)""" + self.ensure_one() wiz_model = self.env["stock.backorder.confirmation"] + pickings = self.env["stock.picking"] + create_backorder = True + if self.shipment_type == "incoming": + self._lock_records(self.planned_picking_ids) + pickings = self.planned_picking_ids + else: + self._lock_records(self.loaded_picking_ids) + pickings = self.to_validate_picking_ids + create_backorder = ( + self.company_id.shipment_advice_outgoing_backorder_policy + == "create_backorder" + ) + for picking in pickings: + if picking.state in ("cancel", "done"): + continue + if picking._check_backorder(): + if not create_backorder: + continue + wiz = wiz_model.create({}) + wiz.pick_ids = picking + wiz.with_context(button_validate_picking_ids=picking.ids).process() + else: + picking._action_done() + + def _unplan_loaded_moves(self): + """Unplan moves that were not loaded and validated""" + moves_to_unplan = self.loaded_move_line_ids.move_id.filtered( + lambda m: m.state not in ("cancel", "done") and not m.quantity_done + ) + moves_to_unplan.shipment_advice_id = False + + def action_done(self): shipment_advice_ids_to_validate = [] self = self.with_context(shipment_advice_ignore_auto_close=True) for shipment in self: @@ -391,50 +425,9 @@ def action_done(self): shipment.name ) ) - # Validate transfers (create backorders for unprocessed lines) - if shipment.shipment_type == "incoming": - self._lock_records(self.planned_picking_ids) - for picking in self.planned_picking_ids: - if picking.state in ("cancel", "done"): - continue - if picking._check_backorder(): - wiz = wiz_model.create({}) - wiz.pick_ids = picking - wiz.with_context( - button_validate_picking_ids=picking.ids - ).process() - else: - picking._action_done() - else: - backorder_policy = ( - shipment.company_id.shipment_advice_outgoing_backorder_policy - ) - self._lock_records(self.loaded_picking_ids) - if backorder_policy == "create_backorder": - for picking in self.to_validate_picking_ids: - if picking.state in ("cancel", "done"): - continue - if picking._check_backorder(): - wiz = wiz_model.create({}) - wiz.pick_ids = picking - wiz.with_context( - button_validate_picking_ids=picking.ids - ).process() - else: - picking._action_done() - else: - for picking in self.to_validate_picking_ids: - if picking.state in ("cancel", "done"): - continue - if not picking._check_backorder(): - # no backorder needed means that all qty_done are - # set to fullfill the need => validate - picking._action_done() - # Unplan moves that were not loaded and validated - moves_to_unplan = self.loaded_move_line_ids.move_id.filtered( - lambda m: m.state not in ("cancel", "done") and not m.quantity_done - ) - moves_to_unplan.shipment_advice_id = False + shipment._close_pickings() + if shipment.shipment_type == "outgoing": + shipment._unplan_loaded_moves() shipment_advice_ids_to_validate.append(shipment.id) if shipment_advice_ids_to_validate: self.browse(shipment_advice_ids_to_validate)._action_done()