From e8f97727810acd45390e9d73df44b57d8b73bcae Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 16 Jul 2025 20:31:29 +0200 Subject: [PATCH 1/3] [REF] sale_stock_available_to_promise_release: Add hook --- .../models/sale_order_line.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sale_stock_available_to_promise_release/models/sale_order_line.py b/sale_stock_available_to_promise_release/models/sale_order_line.py index dae1bec51b9..211057d5261 100644 --- a/sale_stock_available_to_promise_release/models/sale_order_line.py +++ b/sale_stock_available_to_promise_release/models/sale_order_line.py @@ -81,7 +81,7 @@ def _get_availability_data(self): availability_status = "partial" delayed_qty = self.product_uom_qty - available_qty # On order product - elif self.is_mto: + elif self._on_order_route(): availability_status = "on_order" # No stock elif float_is_zero(available_qty, precision_rounding=rounding): @@ -97,3 +97,7 @@ def _get_availability_data(self): "available_qty": available_qty, "delayed_qty": delayed_qty, } + + def _on_order_route(self): + self.ensure_one() + return self.is_mto From 72f6a35219c76dbfde9dfdb0fa0079ba01b73108 Mon Sep 17 00:00:00 2001 From: Thierry Ducrest Date: Mon, 18 Aug 2025 13:40:52 +0200 Subject: [PATCH 2/3] sale_stock_available_to_promise_release: add expected_date on report This is a forward port of the module `sale_stock_available_to_promise_release_cutoff` from the branch 14.0 of the wms repository. Because the module was wrongly named and the `sale_delivery_date` module is obsolete, this is added as a feature of this module --- .../models/sale_order.py | 21 ++++++++ .../reports/sale_order.xml | 26 ++++++++-- .../tests/__init__.py | 1 + .../tests/test_sale_ok_expected_date.py | 48 +++++++++++++++++++ 4 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 sale_stock_available_to_promise_release/tests/test_sale_ok_expected_date.py diff --git a/sale_stock_available_to_promise_release/models/sale_order.py b/sale_stock_available_to_promise_release/models/sale_order.py index 91e2019b39e..330cecc3ca6 100644 --- a/sale_stock_available_to_promise_release/models/sale_order.py +++ b/sale_stock_available_to_promise_release/models/sale_order.py @@ -10,6 +10,9 @@ class SaleOrder(models.Model): move_need_release_count = fields.Integer( string="Moves Need Release", compute="_compute_move_need_release_count" ) + is_ok_expected_delivery_date = fields.Boolean( + compute="_compute_is_ok_expected_delivery_date" + ) @api.depends("picking_ids.move_ids.need_release") def _compute_move_need_release_count(self): @@ -18,6 +21,24 @@ def _compute_move_need_release_count(self): sale.picking_ids.move_ids.filtered("need_release") ) + @api.depends("expected_date", "order_line.availability_status") + def _compute_is_ok_expected_delivery_date(self): + for sale in self: + if not (sale.commitment_date or sale.expected_date): + sale.is_ok_expected_delivery_date = False + continue + for line in sale.order_line: + if ( + not line.display_type + and not line.is_delivery + and not line.product_id.type == "service" + and line.availability_status in ("full", "partial", "on_order") + ): + sale.is_ok_expected_delivery_date = True + break + else: + sale.is_ok_expected_delivery_date = False + def action_open_move_need_release(self): self.ensure_one() if not self.move_need_release_count: diff --git a/sale_stock_available_to_promise_release/reports/sale_order.xml b/sale_stock_available_to_promise_release/reports/sale_order.xml index fa898f34cd1..6284390be89 100644 --- a/sale_stock_available_to_promise_release/reports/sale_order.xml +++ b/sale_stock_available_to_promise_release/reports/sale_order.xml @@ -52,9 +52,29 @@ t-elif="line.availability_status == 'no'" name="availability_status_no" >No - - - + + + + + +
+ Expected delivery +
+
+
+ diff --git a/sale_stock_available_to_promise_release/tests/__init__.py b/sale_stock_available_to_promise_release/tests/__init__.py index 4d37240cfe5..4bc4485983f 100644 --- a/sale_stock_available_to_promise_release/tests/__init__.py +++ b/sale_stock_available_to_promise_release/tests/__init__.py @@ -1 +1,2 @@ from . import test_sale_line_availability_status +from . import test_sale_ok_expected_date diff --git a/sale_stock_available_to_promise_release/tests/test_sale_ok_expected_date.py b/sale_stock_available_to_promise_release/tests/test_sale_ok_expected_date.py new file mode 100644 index 00000000000..686c690d8d9 --- /dev/null +++ b/sale_stock_available_to_promise_release/tests/test_sale_ok_expected_date.py @@ -0,0 +1,48 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + + +from .common import Common + + +class TestSaleOkExpectedDate(Common): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product_2 = cls.env["product.product"].create( + { + "name": "Test Storable Product Two", + "uom_id": cls.uom_unit.id, + "type": "product", + } + ) + # Have a line on the order that will not activate the feature + cls.line_2 = cls.env["sale.order.line"].create( + { + "order_id": cls.sale.id, + "product_id": cls.product_2.id, + "product_uom_qty": 100, + "product_uom": cls.uom_unit.id, + }, + ) + + def test_expected_date_ok(self): + self.sale.action_confirm() + self._set_stock(self.product, 100) + self.assertTrue(self.sale.is_ok_expected_delivery_date) + + def test_no_availability(self): + self.sale.action_confirm() + self.assertFalse(self.sale.is_ok_expected_delivery_date) + + def test_no_expected_date(self): + self.sale.action_confirm() + self.sale.expected_date = False + self.assertFalse(self.sale.commitment_date) + self.assertFalse(self.sale.is_ok_expected_delivery_date) + + def test_no_expected_date_for_service(self): + self.line.unlink() + self.product_2.type = "service" + self.sale.action_confirm() + self.assertFalse(self.sale.is_ok_expected_delivery_date) From 5d502f96c0ff8ef49a6f49ad515ad339cdd71887 Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Fri, 10 Oct 2025 22:53:35 +0200 Subject: [PATCH 3/3] sale_stock_available_to_promise_release: delivery date Drop sale_expected_date in favor of odoo standard date_deadline. A more accurate delivery date is also provided by stock_release_channel. --- .../models/__init__.py | 2 -- .../models/procurement_group.py | 24 ------------------- .../models/stock_move.py | 3 --- .../models/stock_picking.py | 12 ---------- .../views/stock_move_views.xml | 21 +++++++--------- .../views/stock_picking_views.xml | 13 ---------- 6 files changed, 9 insertions(+), 66 deletions(-) delete mode 100644 sale_stock_available_to_promise_release/models/procurement_group.py delete mode 100644 sale_stock_available_to_promise_release/models/stock_picking.py diff --git a/sale_stock_available_to_promise_release/models/__init__.py b/sale_stock_available_to_promise_release/models/__init__.py index 0e91254ec87..092584e3adf 100644 --- a/sale_stock_available_to_promise_release/models/__init__.py +++ b/sale_stock_available_to_promise_release/models/__init__.py @@ -1,8 +1,6 @@ from . import sale_order from . import sale_order_line from . import stock_move -from . import stock_picking -from . import procurement_group from . import product_product from . import res_config_settings from . import res_company diff --git a/sale_stock_available_to_promise_release/models/procurement_group.py b/sale_stock_available_to_promise_release/models/procurement_group.py deleted file mode 100644 index 78667ab5a8f..00000000000 --- a/sale_stock_available_to_promise_release/models/procurement_group.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2020 Camptocamp (https://www.camptocamp.com) -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). - -from odoo import api, fields, models - - -class ProcurementGroup(models.Model): - _inherit = "procurement.group" - - date_expected = fields.Date( - "Delivery Date", compute="_compute_date_expected", store="True" - ) - - @api.depends("sale_id") - def _compute_date_expected(self): - # expected_date is not stored on sale order but when we process - # procurement group it will never changed so we can store it on this - # level - for group in self: - so = group.sale_id - if so: - group.date_expected = so.commitment_date or so.expected_date - else: - group.date_expected = False diff --git a/sale_stock_available_to_promise_release/models/stock_move.py b/sale_stock_available_to_promise_release/models/stock_move.py index 91587a75114..edf4a478528 100644 --- a/sale_stock_available_to_promise_release/models/stock_move.py +++ b/sale_stock_available_to_promise_release/models/stock_move.py @@ -8,6 +8,3 @@ class StockMove(models.Model): _inherit = "stock.move" carrier_id = fields.Many2one(related="picking_id.carrier_id", store="True") - sale_date_expected = fields.Date( - "Delivery Date", related="group_id.date_expected", store="True" - ) diff --git a/sale_stock_available_to_promise_release/models/stock_picking.py b/sale_stock_available_to_promise_release/models/stock_picking.py deleted file mode 100644 index 8ca73cc86f4..00000000000 --- a/sale_stock_available_to_promise_release/models/stock_picking.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2020 Camptocamp (https://www.camptocamp.com) -# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). - -from odoo import fields, models - - -class StockPicking(models.Model): - _inherit = "stock.picking" - - sale_date_expected = fields.Date( - string="Delivery Date", related="group_id.date_expected", store=True - ) diff --git a/sale_stock_available_to_promise_release/views/stock_move_views.xml b/sale_stock_available_to_promise_release/views/stock_move_views.xml index 7b0a882330d..f1558b6ccda 100644 --- a/sale_stock_available_to_promise_release/views/stock_move_views.xml +++ b/sale_stock_available_to_promise_release/views/stock_move_views.xml @@ -17,9 +17,6 @@ 1 - - - @@ -33,9 +30,9 @@ 1 - - - + + 1 + @@ -50,26 +47,26 @@ diff --git a/sale_stock_available_to_promise_release/views/stock_picking_views.xml b/sale_stock_available_to_promise_release/views/stock_picking_views.xml index 16ebb924156..7c96f42cd67 100644 --- a/sale_stock_available_to_promise_release/views/stock_picking_views.xml +++ b/sale_stock_available_to_promise_release/views/stock_picking_views.xml @@ -1,18 +1,5 @@ - - stock.picking.release.tree - stock.picking - - - - - - - stock.picking.release.search stock.picking