From 9dc7835cf62302ce05db822dcc1db9e5b577338f Mon Sep 17 00:00:00 2001
From: mafo-odoo <mafo@odoo.com>
Date: Thu, 18 Aug 2022 10:54:45 +0000
Subject: [PATCH] [FIX] stock_account, purchase_stock: no stock account in
 manual valuation

Issues:
1) When the inventory valuation is Manual the stock accounts field of the
product category should be empty and they should be set when the
inventory valuation is Automated.
2) For the moment at installation all the categories have the Manual default
value and the comapy account default values for the stock accounts (not
respecting condition 1)

Solutions:
For issue 1 we add checks on the write and create functions of the product
category model so that after creation/modification the instance respect the
condition
For issue 2 we add at the end of the post_hook script some code to set an
empty stock account property for every product category.

opw-2746384

closes odoo/odoo#98379

Signed-off-by: William Henrotin (whe) <whe@odoo.com>
---
 .../tests/test_stockvaluation.py              |  5 +--
 addons/stock_account/__init__.py              | 21 +++++++-----
 addons/stock_account/models/product.py        | 32 ++++++++++++++++++-
 .../test_stock_valuation_layer_revaluation.py |  1 +
 .../tests/test_stockvaluationlayer.py         |  3 +-
 5 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py
index c8aee9707714..047ae0418ac1 100644
--- a/addons/purchase_stock/tests/test_stockvaluation.py
+++ b/addons/purchase_stock/tests/test_stockvaluation.py
@@ -349,6 +349,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
             'type': 'general',
         })
         cls.product1.categ_id.write({
+            'property_valuation': 'real_time',
             'property_stock_account_input_categ_id': cls.stock_input_account.id,
             'property_stock_account_output_categ_id': cls.stock_output_account.id,
             'property_stock_valuation_account_id': cls.stock_valuation_account.id,
@@ -779,14 +780,14 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon):
         inv.action_post()
 
         move_lines = inv.line_ids
-        self.assertEqual(len(move_lines), 2)
+        self.assertEqual(len(move_lines), 4)
 
         payable_line = move_lines.filtered(lambda l: l.account_id.internal_type == 'payable')
 
         self.assertEqual(payable_line.amount_currency, -100.0)
         self.assertAlmostEqual(payable_line.balance, -66.67)
 
-        stock_line = move_lines.filtered(lambda l: l.account_id == self.stock_input_account)
+        stock_line = move_lines.filtered(lambda l: l.account_id == self.stock_input_account and l.balance > 0)
         self.assertEqual(stock_line.amount_currency, 100.0)
         self.assertAlmostEqual(stock_line.balance, 66.67)
 
diff --git a/addons/stock_account/__init__.py b/addons/stock_account/__init__.py
index fd3f4a2eddbe..99d699ac408b 100644
--- a/addons/stock_account/__init__.py
+++ b/addons/stock_account/__init__.py
@@ -14,7 +14,12 @@ def _configure_journals(cr, registry):
 
     # if we already have a coa installed, create journal and set property field
     company_ids = env['res.company'].search([('chart_template_id', '!=', False)])
-
+    todo_list = [
+        'property_stock_account_input_categ_id',
+        'property_stock_account_output_categ_id',
+        'property_stock_valuation_account_id',
+    ]
+    # Property Stock Accounts
     for company_id in company_ids:
         # Check if property exists for stock account journal exists
         field = env['ir.model.fields']._get("product.category", "property_stock_journal")
@@ -43,13 +48,6 @@ def _configure_journals(cr, registry):
                 company_id,
             )
 
-        # Property Stock Accounts
-        todo_list = [
-            'property_stock_account_input_categ_id',
-            'property_stock_account_output_categ_id',
-            'property_stock_valuation_account_id',
-        ]
-
         for name in todo_list:
             account = getattr(company_id, name)
             if account:
@@ -59,3 +57,10 @@ def _configure_journals(cr, registry):
                     account,
                     company_id,
                 )
+    for name in todo_list:
+        env['ir.property']._set_multi(
+            name,
+            'product.category',
+            {category.id: False for category in env['product.category'].search([])},
+            True
+        )
diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py
index 64a565107608..2ecf3b887817 100644
--- a/addons/stock_account/models/product.py
+++ b/addons/stock_account/models/product.py
@@ -783,8 +783,23 @@ class ProductCategory(models.Model):
             new_cost_method = vals.get('property_cost_method')
             new_valuation = vals.get('property_valuation')
 
-
             for product_category in self:
+                property_stock_fields = ['property_stock_account_input_categ_id', 'property_stock_account_output_categ_id', 'property_stock_valuation_account_id']
+                if 'property_valuation' in vals and vals['property_valuation'] == 'manual_periodic' and product_category.property_valuation != 'manual_periodic':
+                    for stock_property in property_stock_fields:
+                        vals[stock_property] = False
+                elif 'property_valuation' in vals and vals['property_valuation'] == 'real_time' and product_category.property_valuation != 'real_time':
+                    company_id = self.env.company
+                    for stock_property in property_stock_fields:
+                        vals[stock_property] = vals.get(stock_property, False) or company_id[stock_property]
+                elif product_category.property_valuation == 'manual_periodic':
+                    for stock_property in property_stock_fields:
+                        if stock_property in vals:
+                            vals.pop(stock_property)
+                else:
+                    for stock_property in property_stock_fields:
+                        if stock_property in vals and vals[stock_property] is False:
+                            vals.pop(stock_property)
                 valuation_impacted = False
                 if new_cost_method and new_cost_method != product_category.property_cost_method:
                     valuation_impacted = True
@@ -825,6 +840,21 @@ class ProductCategory(models.Model):
             account_moves._post()
         return res
 
+
+    @api.model
+    def create(self, vals):
+        if 'property_valuation' not in vals or vals['property_valuation'] == 'manual_periodic':
+            vals['property_stock_account_input_categ_id'] = False
+            vals['property_stock_account_output_categ_id'] = False
+            vals['property_stock_valuation_account_id'] = False
+        if 'property_valuation' in vals and vals['property_valuation'] == 'real_time':
+            company_id = self.env.company
+            vals['property_stock_account_input_categ_id'] = vals.get('property_stock_account_input_categ_id', False) or company_id.property_stock_account_input_categ_id
+            vals['property_stock_account_output_categ_id'] = vals.get('property_stock_account_output_categ_id', False) or company_id.property_stock_account_output_categ_id
+            vals['property_stock_valuation_account_id'] = vals.get('property_stock_valuation_account_id', False) or company_id.property_stock_valuation_account_id
+
+        return super().create(vals)
+
     @api.onchange('property_valuation')
     def onchange_property_valuation(self):
         # Remove or set the account stock properties if necessary
diff --git a/addons/stock_account/tests/test_stock_valuation_layer_revaluation.py b/addons/stock_account/tests/test_stock_valuation_layer_revaluation.py
index 7ae51f263db1..91abfba9e803 100644
--- a/addons/stock_account/tests/test_stock_valuation_layer_revaluation.py
+++ b/addons/stock_account/tests/test_stock_valuation_layer_revaluation.py
@@ -16,6 +16,7 @@ class TestStockValuationLayerRevaluation(TestStockValuationCommon):
             'property_account_expense_id': cls.expense_account.id,
         })
         cls.product1.categ_id.write({
+            'property_valuation': 'real_time',
             'property_stock_account_input_categ_id': cls.stock_input_account.id,
             'property_stock_account_output_categ_id': cls.stock_output_account.id,
             'property_stock_valuation_account_id': cls.stock_valuation_account.id,
diff --git a/addons/stock_account/tests/test_stockvaluationlayer.py b/addons/stock_account/tests/test_stockvaluationlayer.py
index 8f880ebe4c18..20887ea0182b 100644
--- a/addons/stock_account/tests/test_stockvaluationlayer.py
+++ b/addons/stock_account/tests/test_stockvaluationlayer.py
@@ -757,7 +757,6 @@ class TestStockValuationFIFO(TestStockValuationCommon):
         finally:
             self.env.user.company_id = old_company
 
-
 class TestStockValuationChangeCostMethod(TestStockValuationCommon):
     def test_standard_to_fifo_1(self):
         """ The accounting impact of this cost method change is neutral.
@@ -870,7 +869,7 @@ class TestStockValuationChangeCostMethod(TestStockValuationCommon):
         self.assertEqual(self.product1.value_svl, 190)
         self.assertEqual(self.product1.quantity_svl, 19)
 
-
+@tagged('post_install', '-at_install')
 class TestStockValuationChangeValuation(TestStockValuationCommon):
     @classmethod
     def setUpClass(cls):
-- 
GitLab