From f99c6b0f5cb17eb6e27599380349bc4972daa341 Mon Sep 17 00:00:00 2001 From: Mourad Date: Mon, 3 Feb 2025 14:52:12 +0100 Subject: [PATCH 1/8] [IMP] product_stock_state: Add on demand state --- product_stock_state/i18n/fr.po | 12 ++++++++++++ product_stock_state/i18n/product_stock_state.pot | 6 ++++++ product_stock_state/models/product_product.py | 5 +++++ product_stock_state/models/product_template.py | 3 +++ product_stock_state/views/product_template_view.xml | 1 + 5 files changed, 27 insertions(+) diff --git a/product_stock_state/i18n/fr.po b/product_stock_state/i18n/fr.po index 59f2e3a9416..3f47e0ccc2b 100644 --- a/product_stock_state/i18n/fr.po +++ b/product_stock_state/i18n/fr.po @@ -90,6 +90,12 @@ msgstr "" msgid "Manual Stock State Threshold" msgstr "Seuil pour l'état du stock manuel" +#. module: product_stock_state +#: model:ir.model.fields,field_description:product_stock_state.field_product_product__on_demand +#: model:ir.model.fields,field_description:product_stock_state.field_product_template__on_demand +msgid "On Demand" +msgstr "A la demande" + #. module: product_stock_state #: model:ir.model,name:product_stock_state.model_product_product msgid "Product" @@ -174,6 +180,12 @@ msgstr "" "elle n'est pas définie, Odoo utilisera le seuil défini au niveau de " "l'entreprise." +#. module: product_stock_state +#: model:ir.model.fields,help:product_stock_state.field_product_product__on_demand +#: model:ir.model.fields,help:product_stock_state.field_product_template__on_demand +msgid "This field allows you to force the stock state to the on-demand value" +msgstr "Ce champs vous permet de forcer l'état du stock à 'A la demande'" + #. module: product_stock_state #: model:product.product,uom_name:product_stock_state.product_setting_by_company #: model:product.product,uom_name:product_stock_state.product_setting_by_product diff --git a/product_stock_state/i18n/product_stock_state.pot b/product_stock_state/i18n/product_stock_state.pot index f46218e7062..85d86d6d15e 100644 --- a/product_stock_state/i18n/product_stock_state.pot +++ b/product_stock_state/i18n/product_stock_state.pot @@ -79,6 +79,12 @@ msgstr "" msgid "Manual Stock State Threshold" msgstr "" +#. module: product_stock_state +#: model:ir.model.fields,field_description:product_stock_state.field_product_product__on_demand +#: model:ir.model.fields,field_description:product_stock_state.field_product_template__on_demand +msgid "On Demand" +msgstr "" + #. module: product_stock_state #: model:ir.model,name:product_stock_state.model_product_product msgid "Product" diff --git a/product_stock_state/models/product_product.py b/product_stock_state/models/product_product.py index 39960a0428e..31e33b37dbc 100644 --- a/product_stock_state/models/product_product.py +++ b/product_stock_state/models/product_product.py @@ -16,6 +16,7 @@ class ProductProduct(models.Model): _inherit = "product.product" _STOCK_STATE_SELECTION = [ + ("on_demand", "On Demand"), ("in_stock", "In Stock"), ("in_limited_stock", "In Limited Stock"), ("resupplying", "Resupplying"), @@ -57,6 +58,9 @@ def _stock_state_check_resupplying(self, qty, precision): def _stock_state_check_out_of_stock(self, qty, precision): return True + def _stock_state_check_on_demand(self, qty, precision): + return self.on_demand + def _available_states(self): return [x[0] for x in self._selection_stock_state()] @@ -65,6 +69,7 @@ def _available_states(self): "incoming_qty", "stock_state_threshold", "company_id.stock_state_threshold", + "on_demand", ) def _compute_stock_state(self): precision = self.env["decimal.precision"].precision_get("Stock Threshold") diff --git a/product_stock_state/models/product_template.py b/product_stock_state/models/product_template.py index 2ba49b7c45f..0644e5d3590 100644 --- a/product_stock_state/models/product_template.py +++ b/product_stock_state/models/product_template.py @@ -24,6 +24,9 @@ class ProductTemplate(models.Model): ) manual_stock_state_threshold = fields.Float(digits="Stock Threshold") + on_demand = fields.Boolean( + help="This field allows you to force the stock state to the on-demand value" + ) @api.depends("categ_id.stock_state_threshold", "manual_stock_state_threshold") def _compute_stock_state_threshold(self): diff --git a/product_stock_state/views/product_template_view.xml b/product_stock_state/views/product_template_view.xml index 913dd7e6036..07409af63a0 100644 --- a/product_stock_state/views/product_template_view.xml +++ b/product_stock_state/views/product_template_view.xml @@ -8,6 +8,7 @@ + From d689dd127b1cc214eff88fe750b2d04a35ef16a7 Mon Sep 17 00:00:00 2001 From: mathieu_mpv Date: Wed, 19 Feb 2025 11:27:20 +0100 Subject: [PATCH 2/8] [UPD] Updated 'on demand' feature display in product view --- product_stock_state/i18n/fr.po | 7 ++++++- product_stock_state/i18n/product_stock_state.pot | 5 +++++ product_stock_state/models/product_product.py | 5 +++++ product_stock_state/models/product_template.py | 2 ++ .../views/product_template_view.xml | 15 +++++++++++---- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/product_stock_state/i18n/fr.po b/product_stock_state/i18n/fr.po index 3f47e0ccc2b..ea77c376900 100644 --- a/product_stock_state/i18n/fr.po +++ b/product_stock_state/i18n/fr.po @@ -94,7 +94,12 @@ msgstr "Seuil pour l'état du stock manuel" #: model:ir.model.fields,field_description:product_stock_state.field_product_product__on_demand #: model:ir.model.fields,field_description:product_stock_state.field_product_template__on_demand msgid "On Demand" -msgstr "A la demande" +msgstr "Sur demande" + +#. module: product_stock_state +#: model:ir.model.fields,help:product_stock_state.field_product_template_on_demand +msgid "This field allows you to force the stock state to the on-demand value" +msgstr "Ce champ vous permet de forcer l'état du stock à 'À la demande'" #. module: product_stock_state #: model:ir.model,name:product_stock_state.model_product_product diff --git a/product_stock_state/i18n/product_stock_state.pot b/product_stock_state/i18n/product_stock_state.pot index 85d86d6d15e..cc952e744f5 100644 --- a/product_stock_state/i18n/product_stock_state.pot +++ b/product_stock_state/i18n/product_stock_state.pot @@ -85,6 +85,11 @@ msgstr "" msgid "On Demand" msgstr "" +#. module: product_stock_state +#: model:ir.model.fields,help:product_stock_state.field_product_template__on_demand +msgid "This field allows you to force the stock state to the on-demand value" +msgstr "" + #. module: product_stock_state #: model:ir.model,name:product_stock_state.model_product_product msgid "Product" diff --git a/product_stock_state/models/product_product.py b/product_stock_state/models/product_product.py index 31e33b37dbc..16995ad32b2 100644 --- a/product_stock_state/models/product_product.py +++ b/product_stock_state/models/product_product.py @@ -72,6 +72,11 @@ def _available_states(self): "on_demand", ) def _compute_stock_state(self): + """ + This method updates {stock_state} of each triggered {product}. + {stock_state} = first {state} where {product}_stock_state_check_{state} is True + {state} ordering is insured by _available_states method + """ precision = self.env["decimal.precision"].precision_get("Stock Threshold") for product in self: qty_available = product._get_qty_available_for_stock_state() diff --git a/product_stock_state/models/product_template.py b/product_stock_state/models/product_template.py index 0644e5d3590..e33cbbefd8a 100644 --- a/product_stock_state/models/product_template.py +++ b/product_stock_state/models/product_template.py @@ -24,7 +24,9 @@ class ProductTemplate(models.Model): ) manual_stock_state_threshold = fields.Float(digits="Stock Threshold") + on_demand = fields.Boolean( + default=False, help="This field allows you to force the stock state to the on-demand value" ) diff --git a/product_stock_state/views/product_template_view.xml b/product_stock_state/views/product_template_view.xml index 07409af63a0..db1452e064f 100644 --- a/product_stock_state/views/product_template_view.xml +++ b/product_stock_state/views/product_template_view.xml @@ -4,11 +4,18 @@ product.template + + +
+ +
+
+ - - - - + + +
From 54a3981a7d4d3cfbd2fa5b703f6c7164ee430870 Mon Sep 17 00:00:00 2001 From: mathieu_mpv Date: Wed, 19 Feb 2025 15:55:23 +0100 Subject: [PATCH 3/8] [UPD] on_demand tests --- .../tests/test_product_stock_state.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/product_stock_state/tests/test_product_stock_state.py b/product_stock_state/tests/test_product_stock_state.py index 4fed84ba0a8..f78ba1ea2de 100644 --- a/product_stock_state/tests/test_product_stock_state.py +++ b/product_stock_state/tests/test_product_stock_state.py @@ -53,3 +53,28 @@ def test_04_category_setting_inherit(self): def test_05_state_out_of_stock(self): """Test Stock State computation""" self.assertEqual(self.product_threshold_on_product.stock_state, "out_of_stock") + + # on_demand tests + + def test_06_state_on_demand_default_value(self): + """Test default value of on_demand""" + self.assertFalse(self.product_threshold_on_product.on_demand) + + def test_07_on_demand_inherit(self): + """Test on_demand Setting (Setting on a product unique template)""" + self.assertEqual( + self.product_threshold_on_product._stock_state_check_on_demand(), + self.product_threshold_on_product.on_demand, + ) + + def test_08_state_on_demand_computation(self): + """Test on_demand = True Stock State computation + stock_state is set to 'on_demand' regardless of the previous state""" + + self.product_threshold_on_product.on_demand = True + states = self.product_threshold_on_product._available_states() + + for state in states: + self.product_threshold_on_product.stock_state = state + self.product_threshold_on_product._compute_stock_state() + self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') \ No newline at end of file From c447ee35f1fe2ff31eb02836b28018c07d9e9c89 Mon Sep 17 00:00:00 2001 From: mathieu_mpv Date: Wed, 19 Feb 2025 17:16:34 +0100 Subject: [PATCH 4/8] [UPD] manifest --- product_stock_state/__manifest__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/product_stock_state/__manifest__.py b/product_stock_state/__manifest__.py index e70622f7ad9..d928bea3f92 100644 --- a/product_stock_state/__manifest__.py +++ b/product_stock_state/__manifest__.py @@ -7,8 +7,11 @@ { "name": "Product Stock State", - "summary": "Compute the state of a product's stock" - "the stock level and sale_ok field", + "summary": """Compute the state of a product's stock + Offers 'sale ok' field + Tracks the stock level and manage the following product's stock states based on rules : + 'on demand' 'in_stock' 'limited stock' 'resupplying' 'out of stock' + """, "version": "14.0.1.0.1", "website": "https://github.com/OCA/product-attribute", "author": " Akretion, GRAP, Odoo Community Association (OCA)", From f890f87e2d3d63b8919d96126cfffbba04b3a1ea Mon Sep 17 00:00:00 2001 From: mathieu_mpv Date: Thu, 20 Feb 2025 11:01:01 +0100 Subject: [PATCH 5/8] [UI] place 'on_demand' within 'stock' > 'stock thershold' group --- .../views/product_template_view.xml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/product_stock_state/views/product_template_view.xml b/product_stock_state/views/product_template_view.xml index db1452e064f..e4ecacc9c87 100644 --- a/product_stock_state/views/product_template_view.xml +++ b/product_stock_state/views/product_template_view.xml @@ -4,18 +4,14 @@ product.template - - -
- -
-
- - - - + + + +
From 8084075da3653d9d50f70bc1b33ee794ef956ac6 Mon Sep 17 00:00:00 2001 From: mpv <2486vigouroux@gmail.com> Date: Thu, 20 Feb 2025 12:58:43 +0100 Subject: [PATCH 6/8] Update test_product_stock_state.py --- .../tests/test_product_stock_state.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/product_stock_state/tests/test_product_stock_state.py b/product_stock_state/tests/test_product_stock_state.py index f78ba1ea2de..ecc6e281637 100644 --- a/product_stock_state/tests/test_product_stock_state.py +++ b/product_stock_state/tests/test_product_stock_state.py @@ -54,20 +54,7 @@ def test_05_state_out_of_stock(self): """Test Stock State computation""" self.assertEqual(self.product_threshold_on_product.stock_state, "out_of_stock") - # on_demand tests - - def test_06_state_on_demand_default_value(self): - """Test default value of on_demand""" - self.assertFalse(self.product_threshold_on_product.on_demand) - - def test_07_on_demand_inherit(self): - """Test on_demand Setting (Setting on a product unique template)""" - self.assertEqual( - self.product_threshold_on_product._stock_state_check_on_demand(), - self.product_threshold_on_product.on_demand, - ) - - def test_08_state_on_demand_computation(self): + def test_06_state_on_demand_computation(self): """Test on_demand = True Stock State computation stock_state is set to 'on_demand' regardless of the previous state""" @@ -77,4 +64,4 @@ def test_08_state_on_demand_computation(self): for state in states: self.product_threshold_on_product.stock_state = state self.product_threshold_on_product._compute_stock_state() - self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') \ No newline at end of file + self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') From 57bba804ea4e7397404b049f9b39596bf34cdf71 Mon Sep 17 00:00:00 2001 From: mpv <2486vigouroux@gmail.com> Date: Wed, 5 Mar 2025 16:11:21 +0100 Subject: [PATCH 7/8] [UPD] test relative value of threshold vs qty --- .../tests/test_product_stock_state.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/product_stock_state/tests/test_product_stock_state.py b/product_stock_state/tests/test_product_stock_state.py index ecc6e281637..95e55994194 100644 --- a/product_stock_state/tests/test_product_stock_state.py +++ b/product_stock_state/tests/test_product_stock_state.py @@ -56,12 +56,20 @@ def test_05_state_out_of_stock(self): def test_06_state_on_demand_computation(self): """Test on_demand = True Stock State computation - stock_state is set to 'on_demand' regardless of the previous state""" + stock_state is set to 'on_demand' : + - regardless of the previous state + - regardless of the relative value of stock_state_threshold vs qty_available""" self.product_threshold_on_product.on_demand = True states = self.product_threshold_on_product._available_states() - for state in states: - self.product_threshold_on_product.stock_state = state - self.product_threshold_on_product._compute_stock_state() - self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') + stock_state_threshold = 30 + self.product_threshold_on_product.stock_state_threshold = stock_state_threshold + + for qty in [stock_state_threshold + 1, stock_state_threshold - 1]: + self.product_threshold_on_product.qty_available = qty + + for state in states: + self.product_threshold_on_product.stock_state = state + self.product_threshold_on_product._compute_stock_state() + self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') From 65e7f8c3ab5a2223a31f150e2582b97d280fb660 Mon Sep 17 00:00:00 2001 From: Hpar Date: Mon, 24 Mar 2025 11:09:45 +0100 Subject: [PATCH 8/8] Update test_product_stock_state.py --- product_stock_state/tests/test_product_stock_state.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/product_stock_state/tests/test_product_stock_state.py b/product_stock_state/tests/test_product_stock_state.py index 95e55994194..0ab889a3f35 100644 --- a/product_stock_state/tests/test_product_stock_state.py +++ b/product_stock_state/tests/test_product_stock_state.py @@ -60,16 +60,10 @@ def test_06_state_on_demand_computation(self): - regardless of the previous state - regardless of the relative value of stock_state_threshold vs qty_available""" - self.product_threshold_on_product.on_demand = True - states = self.product_threshold_on_product._available_states() - stock_state_threshold = 30 self.product_threshold_on_product.stock_state_threshold = stock_state_threshold + self.product_threshold_on_product.on_demand = True for qty in [stock_state_threshold + 1, stock_state_threshold - 1]: self.product_threshold_on_product.qty_available = qty - - for state in states: - self.product_threshold_on_product.stock_state = state - self.product_threshold_on_product._compute_stock_state() - self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand') + self.assertEqual(self.product_threshold_on_product.stock_state, 'on_demand')