diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 248ac58e562..a262e1eaeed 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -368,13 +368,10 @@ class MrpProduction(models.Model): any_quantity_done = any([m.quantity_done > 0 for m in order.move_raw_ids]) order.unreserve_visible = not any_quantity_done and already_reserved - @api.depends('move_raw_ids.quantity_done', 'move_finished_ids.quantity_done', 'is_locked') + @api.depends('move_finished_ids.quantity_done', 'move_finished_ids.state', 'is_locked') def _compute_post_visible(self): for order in self: - if order.product_tmpl_id._is_cost_method_standard(): - order.post_visible = order.is_locked and any((x.quantity_done > 0 and x.state not in ['done', 'cancel']) for x in order.move_raw_ids | order.move_finished_ids) - else: - order.post_visible = order.is_locked and any((x.quantity_done > 0 and x.state not in ['done', 'cancel']) for x in order.move_finished_ids) + order.post_visible = order.is_locked and any((x.quantity_done > 0 and x.state not in ['done', 'cancel']) for x in order.move_finished_ids) @api.depends('workorder_ids.state', 'move_finished_ids', 'move_finished_ids.quantity_done', 'is_locked') def _get_produced_qty(self): diff --git a/addons/mrp_account/tests/__init__.py b/addons/mrp_account/tests/__init__.py index 349bd9d4fed..832146f1555 100644 --- a/addons/mrp_account/tests/__init__.py +++ b/addons/mrp_account/tests/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import test_mrp_account from . import test_bom_price +from . import test_valuation_layers diff --git a/addons/mrp_account/tests/test_valuation_layers.py b/addons/mrp_account/tests/test_valuation_layers.py new file mode 100644 index 00000000000..bf50edf042b --- /dev/null +++ b/addons/mrp_account/tests/test_valuation_layers.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +""" Implementation of "INVENTORY VALUATION TESTS (With valuation layers)" spreadsheet. """ + +from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon +from odoo.tests import Form + + +class TestMrpValuationCommon(TestStockValuationCommon): + @classmethod + def setUpClass(cls): + super(TestMrpValuationCommon, cls).setUpClass() + cls.component_category = cls.env['product.category'].create( + {'name': 'category2'} + ) + cls.component = cls.env['product.product'].create({ + 'name': 'component1', + 'type': 'product', + 'categ_id': cls.component_category.id, + }) + cls.bom = cls.env['mrp.bom'].create({ + 'product_id': cls.product1.id, + 'product_tmpl_id': cls.product1.product_tmpl_id.id, + 'product_uom_id': cls.uom_unit.id, + 'product_qty': 1.0, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': cls.component.id, 'product_qty': 1}) + ]}) + + def _make_mo(self, bom, quantity=1): + mo_form = Form(self.env['mrp.production']) + mo_form.product_id = bom.product_id + mo_form.bom_id = bom + mo_form.product_qty = quantity + mo = mo_form.save() + mo.action_confirm() + return mo + + def _produce(self, mo, quantity=0): + produce_form = Form(self.env['mrp.product.produce'].with_context({ + 'active_id': mo.id, + 'active_ids': [mo.id], + })) + if quantity: + produce_form.qty_producing = quantity + product_produce = produce_form.save() + product_produce.do_produce() + + +class TestMrpValuationStandard(TestMrpValuationCommon): + def test_fifo_fifo_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 20) + self.assertEqual(self.product1.value_svl, 10) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_fifo_fifo_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'fifo' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 15) + + def test_fifo_avco_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 20) + self.assertEqual(self.product1.value_svl, 10) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_fifo_avco_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 15) + + def test_fifo_std_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.standard_price = 8.8 + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 20) + self.assertEqual(self.product1.value_svl, 8.8) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 8.8 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_fifo_std_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'fifo' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.standard_price = 8.8 + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 8.8 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 8.8) + + def test_std_avco_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + self.component.standard_price = 8.8 + + self._make_in_move(self.component, 1) + self._make_in_move(self.component, 1) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 8.8) + self.assertEqual(self.product1.value_svl, 8.8) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 8.8 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_std_avco_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + self.component.standard_price = 8.8 + + self._make_in_move(self.component, 1) + self._make_in_move(self.component, 1) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 8.8 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 8.8) + + def test_std_std_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.component.standard_price = 8.8 + self.product1.standard_price = 7.2 + + self._make_in_move(self.component, 1) + self._make_in_move(self.component, 1) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 8.8) + self.assertEqual(self.product1.value_svl, 7.2) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 7.2 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_std_std_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'standard' + self.component.standard_price = 8.8 + self.product1.standard_price = 7.2 + + self._make_in_move(self.component, 1) + self._make_in_move(self.component, 1) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 7.2 * 2) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 7.2) + + def test_avco_avco_1(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'average' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo, 1) + mo.post_inventory() + self.assertEqual(self.component.value_svl, 15) + self.assertEqual(self.product1.value_svl, 15) + self.assertEqual(self.component.quantity_svl, 1) + self.assertEqual(self.product1.quantity_svl, 1) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + + def test_avco_avco_2(self): + self.component.product_tmpl_id.categ_id.property_cost_method = 'average' + self.product1.product_tmpl_id.categ_id.property_cost_method = 'average' + + self._make_in_move(self.component, 1, 10) + self._make_in_move(self.component, 1, 20) + mo = self._make_mo(self.bom, 2) + self._produce(mo) + mo.button_mark_done() + self.assertEqual(self.component.value_svl, 0) + self.assertEqual(self.product1.value_svl, 30) + self.assertEqual(self.component.quantity_svl, 0) + self.assertEqual(self.product1.quantity_svl, 2) + self._make_out_move(self.product1, 1) + self.assertEqual(self.product1.value_svl, 15) diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index aa9202d996c..f5056f25894 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -580,9 +580,6 @@ class ProductTemplate(models.Model): relation="stock.location.route", string="Category Routes", related='categ_id.total_route_ids', readonly=False) - def _is_cost_method_standard(self): - return True - @api.depends( 'product_variant_ids', 'product_variant_ids.stock_move_ids.product_qty', diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index e5bb309e0b5..49d5018ddb8 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -64,9 +64,6 @@ class ProductTemplate(models.Model): # ------------------------------------------------------------------------- # Misc. # ------------------------------------------------------------------------- - def _is_cost_method_standard(self): - return self.categ_id.property_cost_method == 'standard' - def _get_product_accounts(self): """ Add the stock accounts related to product to the result of super() @return: dictionary which contains information regarding stock accounts and super (income+expense accounts)