From ab9335fa929543c06651762dbd7d48fe2f6005d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 12 May 2016 12:20:36 +0200 Subject: [PATCH] [TESTS] mrp: yml to new API unit tests --- addons/mrp/__openerp__.py | 8 +- .../test/bom_with_service_type_product.yml | 63 ------ addons/mrp/test/cancel_order.yml | 26 --- addons/mrp/test/mrp_users.yml | 29 --- addons/mrp/test/order_demo.yml | 17 -- addons/mrp/test/order_process.yml | 190 ------------------ addons/mrp/tests/__init__.py | 5 + addons/mrp/tests/common.py | 47 +++++ addons/mrp/tests/test_bom.py | 35 ++++ addons/mrp/tests/test_order.py | 27 +++ addons/mrp/tests/test_order_process.py | 190 ++++++++++++++++++ 11 files changed, 305 insertions(+), 332 deletions(-) delete mode 100644 addons/mrp/test/bom_with_service_type_product.yml delete mode 100644 addons/mrp/test/cancel_order.yml delete mode 100644 addons/mrp/test/mrp_users.yml delete mode 100644 addons/mrp/test/order_demo.yml delete mode 100644 addons/mrp/test/order_process.yml create mode 100644 addons/mrp/tests/__init__.py create mode 100644 addons/mrp/tests/common.py create mode 100644 addons/mrp/tests/test_bom.py create mode 100644 addons/mrp/tests/test_order.py create mode 100644 addons/mrp/tests/test_order_process.py diff --git a/addons/mrp/__openerp__.py b/addons/mrp/__openerp__.py index 1d0da4f18bf..34407c80661 100644 --- a/addons/mrp/__openerp__.py +++ b/addons/mrp/__openerp__.py @@ -58,13 +58,7 @@ Dashboard / Reports for MRP will include: 'report/mrp_bom_templates.xml', ], 'demo': ['data/mrp_demo.xml'], - 'test': [ - 'test/bom_with_service_type_product.yml', - 'test/mrp_users.yml', - 'test/order_demo.yml', - 'test/order_process.yml', - 'test/cancel_order.yml', - ], + 'test': [], 'installable': True, 'application': True, 'auto_install': False, diff --git a/addons/mrp/test/bom_with_service_type_product.yml b/addons/mrp/test/bom_with_service_type_product.yml deleted file mode 100644 index 7fd715970e7..00000000000 --- a/addons/mrp/test/bom_with_service_type_product.yml +++ /dev/null @@ -1,63 +0,0 @@ -- - I create Bill of Materials with one service type product and one consumable product. -- - !record {model: mrp.bom, id: mrp_bom_test1}: - company_id: base.main_company - product_tmpl_id: product.product_product_3_product_template - product_id: product.product_product_3 - product_uom: product.product_uom_unit - product_qty: 1.0 - type: normal - bom_line_ids: - - product_id: product.product_product_2 - product_uom: product.product_uom_unit - product_qty: 1.0 - - product_id: product.consu_delivery_01 - product_uom: product.product_uom_unit - product_qty: 1.0 -- - I make the production order using BoM having one service type product and one consumable product. -- - !record {model: mrp.production, id: mrp_production_servicetype_mo1}: - name: 'MO-Test' - product_id: product.product_product_3 - product_qty: 1.0 - bom_id: mrp_bom_test1 - date_planned: !eval time.strftime('%Y-%m-%d %H:%M:%S') -- - I compute the data of production order. -- - !python {model: mrp.production}: | - self.action_compute(cr, uid, [ref("mrp_production_servicetype_mo1")], {"lang": "en_US", "tz": False, "search_default_Current": 1, - "active_model": "ir.ui.menu", "active_ids": [ref("mrp.menu_mrp_production_action")], - "active_id": ref("mrp.menu_mrp_production_action"), }) -- - I confirm the production order. -- - !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_servicetype_mo1} -- - I reserved the product. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_servicetype_mo1")) - assert order.state == 'confirmed', "Production order should be confirmed." - self.force_production(cr, uid, [order.id]) - -- - I produce product. -- - !python {model: mrp.product.produce}: | - context.update({'active_id': ref('mrp_production_servicetype_mo1')}) -- - !record {model: mrp.product.produce, id: mrp_product_produce_1, view: mrp.view_mrp_product_produce_wizard}: - mode: 'consume_produce' -- - !python {model: mrp.product.produce}: | - self.on_change_qty(cr, uid, [ref('mrp_product_produce_1')], context=context) - self.do_produce(cr, uid, [ref('mrp_product_produce_1')], context=context) -- - I check production order after produced. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_servicetype_mo1")) - assert order.state == 'done', "Production order should be closed." diff --git a/addons/mrp/test/cancel_order.yml b/addons/mrp/test/cancel_order.yml deleted file mode 100644 index 17905906e3b..00000000000 --- a/addons/mrp/test/cancel_order.yml +++ /dev/null @@ -1,26 +0,0 @@ -- - MRP user can cancelled Production Order, so let's check data with giving the access rights of user. -- - !context - uid: 'res_users_mrp_user' -- - I first confirm order for PC Assemble SC349. -- - !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_test1} -- - Now I cancel the production order. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1"), context=context) - order.action_cancel(context=context) -- - Now I check that the production order is cancelled. -- - !assert {model: mrp.production, id: mrp_production_test1}: - - state == 'cancel' -- - I remove cancelled production order. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1"), context=context) - self.unlink(cr, uid, [order.id]) diff --git a/addons/mrp/test/mrp_users.yml b/addons/mrp/test/mrp_users.yml deleted file mode 100644 index 414610feb19..00000000000 --- a/addons/mrp/test/mrp_users.yml +++ /dev/null @@ -1,29 +0,0 @@ -- - Create a user as 'MRP Manager' -- - !record {model: res.users, id: res_users_mrp_manager, view: False}: - company_id: base.main_company - name: MRP Manager - login: mam - email: mrp_manager@yourcompany.com -- - I added groups for MRP Manager. -- - !record {model: res.users, id: res_users_mrp_manager}: - groups_id: - - mrp.group_mrp_manager - - account.group_account_user -- - Create a user as 'MRP User' -- - !record {model: res.users, id: res_users_mrp_user, view: False}: - company_id: base.main_company - name: MRP User - login: mau - email: mrp_user@yourcompany.com -- - I added groups for MRP User. -- - !record {model: res.users, id: res_users_mrp_user}: - groups_id: - - mrp.group_mrp_user diff --git a/addons/mrp/test/order_demo.yml b/addons/mrp/test/order_demo.yml deleted file mode 100644 index ec8b2dcc6ae..00000000000 --- a/addons/mrp/test/order_demo.yml +++ /dev/null @@ -1,17 +0,0 @@ -- - MRP user can create Production Order, so let's check data with giving the access rights of user. -- - !context - uid: 'res_users_mrp_user' -- - I create Production Order of Computer SC234 to produce 5.0 Unit. -- - !record {model: mrp.production, id: mrp_production_test1}: - product_id: product.product_product_3 - product_qty: 5.0 - location_src_id: stock.stock_location_14 - location_dest_id: stock.stock_location_output - bom_id: mrp_bom_kit - routing_id: mrp.mrp_routing_1 - - diff --git a/addons/mrp/test/order_process.yml b/addons/mrp/test/order_process.yml deleted file mode 100644 index 7c1b9f4e502..00000000000 --- a/addons/mrp/test/order_process.yml +++ /dev/null @@ -1,190 +0,0 @@ -- - MRP user can doing all process related to Production Order, so let's check data with giving the access rights of user. -- - !context - uid: 'res_users_mrp_user' -- - I compute the production order. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1"), context=context) - order.action_compute() -- - I check production lines after compute. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1"), context=context) - assert len(order.product_lines) == 7, "Production lines are not generated proper." -- - Now I check workcenter lines. -- - !python {model: mrp.production}: | - from openerp.tools import float_compare - def assert_equals(value1, value2, msg, float_compare=float_compare): - assert float_compare(value1, value2, precision_digits=2) == 0, msg - order = self.browse(cr, uid, ref("mrp_production_test1"), context=context) - assert len(order.workcenter_lines), "Workcenter lines are not generated proper." -- - I confirm the Production Order. -- - !workflow {model: mrp.production, action: button_confirm, ref: mrp_production_test1} - -- - I check details of Produce Move of Production Order to trace Final Product. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - assert order.state == 'confirmed', "Production order should be confirmed." - assert order.move_created_ids, "Trace Record is not created for Final Product." - move = order.move_created_ids[0] - source_location_id = order.product_id.property_stock_production.id - assert move.date == order.date_planned, "Planned date is not correspond." - assert move.product_id.id == order.product_id.id, "Product does not correspond." - assert move.product_uom.id == order.product_uom.id, "UOM does not correspond." - assert move.product_qty == order.product_qty, "Qty does not correspond." - assert move.location_id.id == source_location_id, "Source Location does not correspond." - assert move.location_dest_id.id == order.location_dest_id.id, "Destination Location does not correspond." - routing_loc = None - if order.bom_id.routing_id and order.bom_id.routing_id.location_id: - routing_loc = order.bom_id.routing_id.location_id.id - date_planned = order.date_planned - for move_line in order.move_lines: - for order_line in order.product_lines: - if move_line.product_id.type not in ('product', 'consu'): - continue - if move_line.product_id.id == order_line.product_id.id: - assert move_line.date == date_planned, "Planned date does not correspond in 'To consume line'." - assert move_line.product_qty == order_line.product_qty, "Qty does not correspond in 'To consume line'." - assert move_line.product_uom.id == order_line.product_uom.id, "UOM does not correspond in 'To consume line'." - assert move_line.location_id.id == routing_loc or order.location_src_id.id, "Source location is not correspond in 'To consume line'." - assert move_line.location_dest_id.id == source_location_id, "Destination Location is not correspond in 'To consume line'." -- - I consume raw materials and put one material in scrap location due to waste it. -- - !python {model: mrp.production}: | - scrap_location_ids = self.pool.get('stock.location').search(cr, uid, [('scrap_location','=',True)]) - scrap_location_id = scrap_location_ids[0] - order = self.browse(cr, uid, ref("mrp_production_test1")) - for move in order.move_lines: - if move.product_id.id == ref("product.product_product_6"): - move.action_scrap(5.0, scrap_location_id) -- - I check procurements have been generated for every consume line -- - !python {model: procurement.order}: | - order = self.pool.get("mrp.production").browse(cr, uid, ref("mrp_production_test1")) - move_line_ids = [x.id for x in order.move_lines] - procurements = self.search(cr, uid, [('move_dest_id', 'in', move_line_ids)]) - for proc in self.browse(cr, uid, procurements): - for order_line in order.product_lines: - date_planned = order.date_planned - if proc.product_id.type not in ('product', 'consu'): - continue - if proc.product_id.id == order_line.product_id.id: - assert proc.date_planned == date_planned, "Planned date does not correspond" - assert proc.product_qty == order_line.product_qty, "Qty does not correspond" - assert proc.location_id.id == order.location_src_id.id, "Input location and procurement location do not correspond" - assert proc.product_uom.id == order_line.product_uom.id, "UOM does not correspond in procurement." - # procurement state should be `confirmed` at this stage, except if procurement_jit is installed, in which - # case it could already be in `running` or `exception` state (not enough stock) - expected_states = ('confirmed', 'running', 'exception') - assert proc.state in expected_states, 'Procurement state is `%s` for %s, expected one of %s' % \ - (proc.state, proc.product_id.name, expected_states) -- - I change production qty with 3 PC Assemble SC349. -- - !python {model: change.production.qty}: | - context.update({'active_id': ref('mrp_production_test1')}) -- - !record {model: change.production.qty, id: mrp_production_qty}: - product_qty: 3.0 -- - !python {model: change.production.qty}: | - self.change_prod_qty(cr, uid, [ref("mrp_production_qty")], context=context) -- - I check qty after changed in production order. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - assert order.product_qty == 3, "Qty is not changed in order." - move = order.move_created_ids[0] - assert move.product_qty == order.product_qty, "Qty is not changed in move line." -- - I run scheduler. -- - !python {model: procurement.order}: | - self.run_scheduler(cr, uid) -- - The production order is Waiting Goods, will force production which should set consume lines as available -- - !python {model: mrp.production}: | - self.force_production(cr, uid, [ref("mrp_production_test1")]) -- - I check that production order in ready state after forcing production. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - assert order.state == 'ready', 'Production order should be in Ready State.' -- - Now I start production. -- - !workflow {model: mrp.production, action: button_produce, ref: mrp_production_test1} -- - I check that production order in production state after start production. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - assert order.state == 'in_production', 'Production order should be in production State.' -- - I produce product. -- - !python {model: mrp.product.produce}: | - context.update({'active_id': ref('mrp_production_test1')}) -- - !record {model: mrp.product.produce, id: mrp_product_produce1}: - mode: 'consume_produce' -- - !python {model: mrp.product.produce}: | - self.on_change_qty(cr, uid, [ref('mrp_product_produce1')], context=context) - self.do_produce(cr, uid, [ref('mrp_product_produce1')], context=context) -- - I check production order after produced. -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - assert order.state == 'done', "Production order should be closed." -- - I check Total Costs at End of Production as a manager. -- - !context - uid: 'res_users_mrp_manager' -- - !python {model: mrp.production}: | - order = self.browse(cr, uid, ref("mrp_production_test1")) - account_analytic_line = self.pool.get('account.analytic.line') - def rounding(f, r): - import math - if not r: - return f - return math.ceil(f / r) * r - - for wc_line in order.workcenter_lines: - wc = wc_line.workcenter_id - accounts = [wc.costs_hour_account_id, wc.costs_cycle_account_id] - cost_per_cyle = wc_line.cycle * wc.costs_cycle - cost_per_hours = wc_line.hour * wc.costs_hour - if accounts and wc.costs_general_account_id and (cost_per_cyle or cost_per_hours): - line_ids = account_analytic_line.search(cr, uid, [('name','ilike',wc_line.name)]) - assert line_ids, 'Costs lines are not generated.' - for line in account_analytic_line.browse(cr, uid, line_ids, context=context): - if wc.costs_hour_account_id and line.account_id.id == wc.costs_hour_account_id.id: - assert rounding(line.unit_amount, 3) == rounding(wc_line.hour, 3), "Cost Unit Amount is not correspond." - assert rounding(line.amount, 3) == rounding(cost_per_hours, 3), "Cost amount is not correspond." - elif wc.costs_cycle_account_id and line.account_id.id == wc.costs_cycle_account_id.id: - assert rounding(line.unit_amount, 3) == rounding(wc_line.cycle, 3), "Cost Unit Amount is not correspond." - assert rounding(line.amount, 3) == rounding(cost_per_cyle, 3), "Cost Amount is not correspond." - else: - raise AssertionError('unknown cost line: %s' % line) - assert line.general_account_id.id == wc.costs_general_account_id.id, "General Account is not correspond." - assert line.product_id.id == wc.product_id.id, "Product does not correspond." - assert line.product_uom_id.id == wc.product_id.uom_id.id, "UOM does not correspond." diff --git a/addons/mrp/tests/__init__.py b/addons/mrp/tests/__init__.py new file mode 100644 index 00000000000..4114b35a1c9 --- /dev/null +++ b/addons/mrp/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +import test_bom +import test_order +import test_order_process \ No newline at end of file diff --git a/addons/mrp/tests/common.py b/addons/mrp/tests/common.py new file mode 100644 index 00000000000..0eb610db89f --- /dev/null +++ b/addons/mrp/tests/common.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +from odoo.addons.stock.tests import common2 + + +class TestMrpCommon(common2.TestStockCommon): + + @classmethod + def setUpClass(cls): + super(TestMrpCommon, cls).setUpClass() + + # Fetch mrp-related user groups + user_group_mrp_user = cls.env.ref('mrp.group_mrp_user') + user_group_mrp_manager = cls.env.ref('mrp.group_mrp_manager') + + # User Data: stock user and stock manager + Users = cls.env['res.users'].with_context({'no_reset_password': True, 'mail_create_nosubscribe': True}) + cls.user_mrp_user = Users.create({ + 'name': 'Hilda Ferachwal', + 'login': 'hilda', + 'email': 'h.h@example.com', + 'notify_email': 'none', + 'groups_id': [(6, 0, [user_group_mrp_user.id])]}) + cls.user_mrp_manager = Users.create({ + 'name': 'Gary Youngwomen', + 'login': 'gary', + 'email': 'g.g@example.com', + 'notify_email': 'none', + 'groups_id': [(6, 0, [user_group_mrp_manager.id])]}) + + cls.bom_1 = cls.env['mrp.bom'].create({ + 'product_id': cls.product_1.id, + 'product_tmpl_id': cls.product_1.product_tmpl_id.id, + 'product_uom': cls.product_1.uom_id.id, + 'product_qty': 1.0, + 'type': 'normal', + 'bom_line_ids': [ + (0, 0, {'product_id': cls.product_2.id}), + (0, 0, {'product_id': cls.product_3.id}) + ]}) + + cls.production_1 = cls.env['mrp.production'].create({ + 'name': 'MO-Test', + 'product_id': cls.product_1.id, + 'product_qty': 1.0, + 'bom_id': cls.bom_1.id, + }) diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py new file mode 100644 index 00000000000..1b149ea8ebc --- /dev/null +++ b/addons/mrp/tests/test_bom.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mrp.tests.common import TestMrpCommon + + +class TestBoM(TestMrpCommon): + + def test_basic(self): + # make the production order + production = self.production_1 + + # compute production order data + production.action_compute() + + # confirm production + production.signal_workflow('button_confirm') + self.assertEqual(production.state, 'confirmed') + + # reserve product + production.force_production() + + # produce product + produce_wizard = self.env['mrp.product.produce'].with_context({ + 'active_id': production.id, + 'active_ids': [production.id], + }).create({ + 'mode': 'consume_produce', + 'product_qty': 1.0, + }) + produce_wizard.on_change_qty() + produce_wizard.do_produce() + + # check production + self.assertEqual(production.state, 'done') diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py new file mode 100644 index 00000000000..35b7ceb9a51 --- /dev/null +++ b/addons/mrp/tests/test_order.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mrp.tests.common import TestMrpCommon + + +class TestMrpOrder(TestMrpCommon): + + def test_access_rights_manager(self): + production = self.production_1.sudo(self.user_mrp_manager) + production.action_compute() + production.signal_workflow('button_confirm') + production.action_cancel() + self.assertEqual(production.state, 'cancel') + production.unlink() + + def test_access_rights_user(self): + production = self.production_1.sudo(self.user_mrp_user) + production.action_compute() + production.signal_workflow('button_confirm') + production.action_cancel() + self.assertEqual(production.state, 'cancel') + production.unlink() + + def test_flow(self): + production = self.production_1.sudo(self.user_mrp_user) + production.action_compute() diff --git a/addons/mrp/tests/test_order_process.py b/addons/mrp/tests/test_order_process.py new file mode 100644 index 00000000000..44e7f0f163f --- /dev/null +++ b/addons/mrp/tests/test_order_process.py @@ -0,0 +1,190 @@ + +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from openerp.tests import common + + +class TestOrderProcess(common.TransactionCase): + + def test_00_order_process(self): + self.res_users_mrp_manager = self.env.ref('mrp.group_mrp_manager') + self.group_account_user = self.env.ref('account.group_account_user') + self.main_company = self.env.ref('base.main_company') + self.group_mrp_user = self.env.ref('mrp.group_mrp_user') + + self.res_users_mrp_manager = self.env['res.users'].create({ + 'company_id': self.main_company.id, + 'name': 'MRP Manager', + 'login': 'mam', + 'password': 'mam', + 'email': 'mrp_manager@yourcompany.com', + 'groups_id': [(6, 0, [self.res_users_mrp_manager.id, self.group_account_user.id])] + }) + + # Create a user as 'MRP User' + # I added groups for MRP User. + self.res_users_mrp_user = self.env['res.users'].create({ + 'company_id': self.main_company.id, + 'name': 'MRP User', + 'login': 'mau', + 'password': 'mau', + 'email': 'mrp_user@yourcompany.com', + 'groups_id': [(6, 0, [self.group_mrp_user.id])] + }) + + self.mrp_production_test1 = self.env['mrp.production'].sudo(self.res_users_mrp_user.id).create({ + 'product_id': self.env.ref('product.product_product_3').id, + 'product_qty': 5.0, + 'location_src_id': self.env.ref('stock.stock_location_14').id, + 'location_dest_id': self.env.ref('stock.stock_location_output').id, + 'bom_id': self.env.ref('mrp.mrp_bom_kit').id, + 'routing_id': self.env.ref('mrp.mrp_routing_1').id + }) + + # I compute the production order. + self.mrp_production_test1.action_compute() + + # I check production lines after compute. + self.assertEqual(len(self.mrp_production_test1.product_lines), 7) + + # Now I check workcenter lines. + from openerp.tools import float_compare + + def assert_equals(value1, value2, msg, float_compare=float_compare): + assert float_compare(value1, value2, precision_digits=2) == 0, msg + self.assertTrue(len(self.mrp_production_test1.workcenter_lines)) + + # I confirm the Production Order. + self.mrp_production_test1.signal_workflow('button_confirm') + + + # I check details of Produce Move of Production Order to trace Final Product. + + self.assertEqual(self.mrp_production_test1.state, 'confirmed', "Production order should be confirmed.") + self.assertTrue(self.mrp_production_test1.move_created_ids, "Trace Record is not created for Final Product.") + move = self.mrp_production_test1.move_created_ids[0] + source_location_id = self.mrp_production_test1.product_id.property_stock_production.id + self.assertEqual(move.date, self.mrp_production_test1.date_planned, "Planned date is not correspond.") + self.assertEqual(move.product_id.id, self.mrp_production_test1.product_id.id, "Product does not correspond.") + self.assertEqual(move.product_uom.id, self.mrp_production_test1.product_uom.id, "UOM does not correspond.") + self.assertEqual(move.product_qty, self.mrp_production_test1.product_qty, "Qty does not correspond.") + self.assertEqual(move.location_id.id, source_location_id, "Source Location does not correspond.") + self.assertEqual(move.location_dest_id.id, self.mrp_production_test1.location_dest_id.id, "Destination Location does not correspond.") + routing_loc = None + if self.mrp_production_test1.bom_id.routing_id and self.mrp_production_test1.bom_id.routing_id.location_id: + routing_loc = self.mrp_production_test1.routing_id.location_id.id + date_planned = self.mrp_production_test1.date_planned + for move_line in self.mrp_production_test1.move_lines: + for order_line in self.mrp_production_test1.product_lines: + if move_line.product_id.type not in ('product', 'consu'): + continue + if move_line.product_id.id == order_line.product_id.id: + self.assertEqual(move_line.date, date_planned, "Planned date does not correspond in 'To consume line'.") + self.assertEqual(move_line.product_qty, order_line.product_qty, "Qty does not correspond in 'To consume line'.") + self.assertEqual(move_line.product_uom.id, order_line.product_uom.id, "UOM does not correspond in 'To consume line'.") + self.assertEqual(move_line.location_id.id, routing_loc or self.mrp_production_test1.location_src_id.id, "Source location is not correspond in 'To consume line'.") + self.assertEqual(move_line.location_dest_id.id, source_location_id, "Destination Location is not correspond in 'To consume line'.") + + # I consume raw materials and put one material in scrap location due to waste it. + scrap_location_ids = self.env['stock.location'].search([('scrap_location', '=', True)]) + scrap_location_id = scrap_location_ids[0] + for move in self.mrp_production_test1.move_lines: + if move.product_id.id == self.env.ref("product.product_product_6").id: + move.action_scrap(5.0, scrap_location_id) + + # I check procurements have been generated for every consume line + + # order = self.env["mrp.production"].browse(self.env.ref("mrp_production_test1")) + move_line_ids = [x.id for x in self.mrp_production_test1.move_lines] + procurements = self.env['procurement.order'].search([('move_dest_id', 'in', move_line_ids)]) + for proc in self.env['procurement.order'].browse(procurements): + for order_line in self.mrp_production_test1.product_lines: + date_planned = self.mrp_production_test1.date_planned + if proc.product_id.type not in ('product', 'consu'): + continue + if proc.product_id.id == order_line.product_id.id: + self.assertEqual(proc.date_planned, date_planned, "Planned date does not correspond") + self.assertEqual(proc.product_qty, order_line.product_qty, "Qty does not correspond") + self.assertEqual(proc.location_id.id, self.mrp_production_test1.location_src_id.id, "Input location and procurement location do not correspond") + self.assertEqual(proc.product_uom_id.id, order_line.product_uom.id, "UOM does not correspond in procurement.") + # procurement state should be `confirmed` at this stage, except if procurement_jit is installed, in which + # case it could already be in `running` or `exception` state (not enough stock) + expected_states = ('confirmed', 'running', 'exception') + self.assertEqual(proc.state in expected_states, 'Procurement state is `%s` for %s, expected one of %s' % (proc.state, proc.product_id.name, expected_states)) + + # I change production qty with 3 PC Assemble SC349. + ctx = dict(self.env.context) + ctx.update({'active_id': self.mrp_production_test1.id}) + + self.mrp_production_qty = self.env['change.production.qty'].with_context(ctx).create({ + 'product_qty': 3.0 + }) + + self.mrp_production_qty.change_prod_qty() + + # I check qty after changed in production order. + self.assertEqual(self.mrp_production_test1.product_qty, 3, "Qty is not changed in order.") + move = self.mrp_production_test1.move_created_ids[0] + self.assertEqual(move.product_qty, self.mrp_production_test1.product_qty, "Qty is not changed in move line.") + + # I run scheduler. + self.env['procurement.order'].run_scheduler() + + # The production order is Waiting Goods, will force production which should set consume lines as available + self.mrp_production_test1.force_production() + + # I check that production order in ready state after forcing production. + + self.assertEqual(self.mrp_production_test1.state, 'ready', 'Production order should be in Ready State.') + + # Now I start production. + self.mrp_production_test1.signal_workflow('button_produce') + + # I check that production order in production state after start production. + self.assertEqual(self.mrp_production_test1.state, 'in_production', 'Production order should be in production State.') + + # I produce product. + ctx.update({'active_id': self.mrp_production_test1.id}) + + self.mrp_product_produce1 = self.env['mrp.product.produce'].with_context(ctx).create({ + 'mode': 'consume_produce' + }) + + qty = self.mrp_product_produce1.product_qty + self.mrp_product_produce1.on_change_qty() + self.mrp_product_produce1.do_produce() + + # I check production order after produced. + self.assertEqual(self.mrp_production_test1.state, 'done', "Production order should be closed.") + + # I check Total Costs at End of Production as a manager. + account_analytic_line = self.env['account.analytic.line'] + + def rounding(f, r): + import math + if not r: + return f + return math.ceil(f / r) * r + + for workcenter_line in self.mrp_production_test1.workcenter_lines: + workcenter = workcenter_line.workcenter_id + accounts = [workcenter.costs_hour_account_id, workcenter.costs_cycle_account_id] + cost_per_cyle = workcenter_line.cycle * workcenter.costs_cycle + cost_per_hours = workcenter_line.hour * workcenter.costs_hour + if accounts and workcenter.costs_general_account_id and (cost_per_cyle or cost_per_hours): + line_ids = account_analytic_line.search([('name', 'ilike', workcenter_line.name)]) + self.assertTrue(line_ids, 'Costs lines are not generated.') + for line in account_analytic_line.browse(line_ids): + if workcenter.costs_hour_account_id and line.account_id.id == workcenter.costs_hour_account_id.id: + self.assertEqual(rounding(line.unit_amount, 3), rounding(workcenter_line.hour, 3), "Cost Unit Amount is not correspond.") + self.assertEqual(rounding(line.amount, 3), rounding(cost_per_hours, 3), "Cost amount is not correspond.") + elif workcenter.costs_cycle_account_id and line.account_id.id == workcenter.costs_cycle_account_id.id: + self.assertEqual(rounding(line.unit_amount, 3), rounding(workcenter_line.cycle, 3), "Cost Unit Amount is not correspond.") + self.assertEqual(rounding(line.amount, 3), rounding(cost_per_cyle, 3), "Cost Amount is not correspond.") + else: + raise AssertionError('unknown cost line: %s' % line) + self.assertEqual(line.general_account_id.id, workcenter.costs_general_account_id.id, "General Account is not correspond.") + self.assertEqual(line.journal_id.id, workcenter.costs_journal_id.id, "Account Journal is not correspond.") + self.assertEqual(line.product_id.id, workcenter.product_id.id, "Product does not correspond.") + self.assertEqual(line.product_uom.id, workcenter.product_id.uom_id.id, "UOM does not correspond.") \ No newline at end of file