From 3841c5c1aeecda4b553a364eab0843239bd27fc0 Mon Sep 17 00:00:00 2001 From: Michael Tietz Date: Wed, 17 Jan 2024 17:15:15 +0100 Subject: [PATCH] [IMP] stock_available_to_promise_release: Own field for release policy Currently if sale_stock_available_to_promise_release is installed we are not able to change the release policy anymore. Therefor we need a separate field, which will be set from the procurement.group's move_type. For Example we can now keep the shipping_policy on the transfer but release only partially. --- .../__manifest__.py | 2 +- .../migrations/16.0.3.1.0/post-migrate.py | 17 +++++++++++++++ .../models/stock_move.py | 13 ++++++++---- .../models/stock_picking.py | 15 +++++++------ .../readme/CONTRIBUTORS.rst | 1 + .../tests/test_reservation.py | 21 +++++++++++++++++++ .../views/stock_picking_views.xml | 6 ++++++ 7 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 stock_available_to_promise_release/migrations/16.0.3.1.0/post-migrate.py diff --git a/stock_available_to_promise_release/__manifest__.py b/stock_available_to_promise_release/__manifest__.py index 8fc84d8db7..836b3db18d 100644 --- a/stock_available_to_promise_release/__manifest__.py +++ b/stock_available_to_promise_release/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Stock Available to Promise Release", - "version": "16.0.3.0.0", + "version": "16.0.3.1.0", "summary": "Release Operations based on available to promise", "author": "Camptocamp, BCIM, Odoo Community Association (OCA)", "website": "https://github.com/OCA/wms", diff --git a/stock_available_to_promise_release/migrations/16.0.3.1.0/post-migrate.py b/stock_available_to_promise_release/migrations/16.0.3.1.0/post-migrate.py new file mode 100644 index 0000000000..97b60041a4 --- /dev/null +++ b/stock_available_to_promise_release/migrations/16.0.3.1.0/post-migrate.py @@ -0,0 +1,17 @@ +# Copyright 2024 Michael Tietz (MT Software) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +def migrate(cr, version): + cr.execute( + """ + UPDATE + stock_picking + SET + release_policy = procurement_group.move_type + FROM + procurement_group + WHERE + stock_picking.group_id = procurement_group.id + """ + ) diff --git a/stock_available_to_promise_release/models/stock_move.py b/stock_available_to_promise_release/models/stock_move.py index f1fdae85e4..3d9abd0dd1 100644 --- a/stock_available_to_promise_release/models/stock_move.py +++ b/stock_available_to_promise_release/models/stock_move.py @@ -283,12 +283,12 @@ def _is_release_ready(self): self.ensure_one() if not self._is_release_needed() or self.state == "draft": return False - shipping_policy = self.picking_id._get_shipping_policy() + release_policy = self.picking_id.release_policy rounding = self.product_id.uom_id.rounding # computed field has no depends set, invalidate cache before reading self.invalidate_recordset(["ordered_available_to_promise_qty"]) ordered_available_to_promise_qty = self.ordered_available_to_promise_qty - if shipping_policy == "one": + if release_policy == "one": return ( float_compare( ordered_available_to_promise_qty, @@ -306,7 +306,7 @@ def _is_release_ready(self): @api.depends( "ordered_available_to_promise_qty", - "picking_id.move_type", + "picking_id.release_policy", "picking_id.move_ids", "need_release", "state", @@ -314,7 +314,7 @@ def _is_release_ready(self): def _compute_release_ready(self): for move in self: release_ready = move._is_release_ready() - if release_ready and move.picking_id._get_shipping_policy() == "one": + if release_ready and move.picking_id.release_policy == "one": release_ready = move.picking_id.release_ready move.release_ready = release_ready @@ -696,3 +696,8 @@ def _search_picking_for_assignation_domain(self): if self.picking_type_id.prevent_new_move_after_release: domain = expression.AND([domain, [("last_release_date", "=", False)]]) return domain + + def _get_new_picking_values(self): + values = super()._get_new_picking_values() + values["release_policy"] = values["move_type"] + return values diff --git a/stock_available_to_promise_release/models/stock_picking.py b/stock_available_to_promise_release/models/stock_picking.py index 76506efad6..12d269453d 100644 --- a/stock_available_to_promise_release/models/stock_picking.py +++ b/stock_available_to_promise_release/models/stock_picking.py @@ -28,6 +28,13 @@ class StockPicking(models.Model): "Used to calculate the ordered available to promise.", ) last_release_date = fields.Datetime() + release_policy = fields.Selection( + [("direct", "As soon as possible"), ("one", "When all products are ready")], + "Release Policy", + default="direct", + required=True, + help="It specifies how to release a transfer partially or all at once", + ) @api.depends("move_ids.need_release") def _compute_need_release(self): @@ -63,14 +70,10 @@ def _search_need_release(self, operator, value): picking_ids = [group["picking_id"][0] for group in groups] return [("id", in_operator, picking_ids)] - def _get_shipping_policy(self): - """Hook returning the related shipping policy.""" - self.ensure_one() - return self.move_type - # move_ids.ordered_available_to_promise_qty has no depends, so we need to # invalidate cache before accessing this release_ready computed value @api.depends( + "release_policy", "move_type", "move_ids.ordered_available_to_promise_qty", "move_ids.need_release", @@ -82,7 +85,7 @@ def _compute_release_ready(self): release_ready = False release_ready_count = sum(1 for move in moves if move._is_release_ready()) if moves: - if picking._get_shipping_policy() == "one": + if picking.release_policy == "one": release_ready = release_ready_count == len(moves) else: release_ready = bool(release_ready_count) diff --git a/stock_available_to_promise_release/readme/CONTRIBUTORS.rst b/stock_available_to_promise_release/readme/CONTRIBUTORS.rst index ff18ba1ceb..137e8a2d97 100644 --- a/stock_available_to_promise_release/readme/CONTRIBUTORS.rst +++ b/stock_available_to_promise_release/readme/CONTRIBUTORS.rst @@ -3,3 +3,4 @@ * Jacques-Etienne Baudoux * Dung Tran * Laurent Mignon +* Michael Tietz (MT Software) diff --git a/stock_available_to_promise_release/tests/test_reservation.py b/stock_available_to_promise_release/tests/test_reservation.py index e2a345b382..30b44327c8 100644 --- a/stock_available_to_promise_release/tests/test_reservation.py +++ b/stock_available_to_promise_release/tests/test_reservation.py @@ -1192,3 +1192,24 @@ def test_multiple_warehouses(self): self.assertEqual(picking_wh1_2.move_ids.previous_promised_qty, 4) self.assertEqual(picking_wh2_2.move_ids.ordered_available_to_promise_qty, 0) self.assertEqual(picking_wh2_2.move_ids.previous_promised_qty, 4) + + def test_release_policy(self): + self.wh.delivery_route_id.write( + {"available_to_promise_defer_pull": True, "no_backorder_at_release": True} + ) + picking = self._out_picking( + self._create_picking_chain( + self.wh, + [(self.product1, 10), (self.product2, 10)], + date=datetime(2019, 9, 2, 16, 0), + move_type="one", + ) + ) + self.assertEqual(picking.move_type, "one") + self._update_qty_in_location(self.loc_bin1, self.product1, 10.0) + self.assertFalse(picking.release_ready) + picking.release_policy = "direct" + self.assertTrue(picking.release_ready) + picking.release_available_to_promise() + new_picking = self._pickings_in_group(picking.group_id) - picking + self.assertEqual(new_picking.move_type, "one") diff --git a/stock_available_to_promise_release/views/stock_picking_views.xml b/stock_available_to_promise_release/views/stock_picking_views.xml index ad710cc9be..fc0decf357 100644 --- a/stock_available_to_promise_release/views/stock_picking_views.xml +++ b/stock_available_to_promise_release/views/stock_picking_views.xml @@ -55,6 +55,12 @@ + + +