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/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/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
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/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)
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