From 2d7adda6b93027d5e36a33ee3be900eb07714454 Mon Sep 17 00:00:00 2001 From: Mikel Arregi Date: Wed, 16 Dec 2020 17:35:14 +0100 Subject: [PATCH 1/4] [ADD] mrp_workoder_production_lot_force_name --- .../README.rst | 43 +++++++++ .../__init__.py | 1 + .../__manifest__.py | 20 +++++ .../models/__init__.py | 2 + .../models/mrp_workorder.py | 24 +++++ .../models/product_category.py | 9 ++ .../tests/__init__.py | 1 + ...mrp_workorder_production_lot_force_name.py | 87 +++++++++++++++++++ .../views/mrp_workorder_view.xml | 14 +++ .../views/product_category_view.xml | 15 ++++ 10 files changed, 216 insertions(+) create mode 100644 mrp_workorder_production_lot_force_name/README.rst create mode 100644 mrp_workorder_production_lot_force_name/__init__.py create mode 100644 mrp_workorder_production_lot_force_name/__manifest__.py create mode 100644 mrp_workorder_production_lot_force_name/models/__init__.py create mode 100644 mrp_workorder_production_lot_force_name/models/mrp_workorder.py create mode 100644 mrp_workorder_production_lot_force_name/models/product_category.py create mode 100644 mrp_workorder_production_lot_force_name/tests/__init__.py create mode 100644 mrp_workorder_production_lot_force_name/tests/test_mrp_workorder_production_lot_force_name.py create mode 100644 mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml create mode 100644 mrp_workorder_production_lot_force_name/views/product_category_view.xml diff --git a/mrp_workorder_production_lot_force_name/README.rst b/mrp_workorder_production_lot_force_name/README.rst new file mode 100644 index 000000000..742005a85 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/README.rst @@ -0,0 +1,43 @@ +=========================== +Force lot name in Workorder +=========================== + +A checkbox in product category activates a field to force lot name when the workorder is executed. + +.. |badge1| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +|badge1| + +Adds a new level in products with the custom values specified in a order +line, manufacturing order or a lot. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* AvanzOSC + +Contributors +~~~~~~~~~~~~ + +* Mikel Arregi +* Ana Juaristi diff --git a/mrp_workorder_production_lot_force_name/__init__.py b/mrp_workorder_production_lot_force_name/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/mrp_workorder_production_lot_force_name/__manifest__.py b/mrp_workorder_production_lot_force_name/__manifest__.py new file mode 100644 index 000000000..1fb4ce3e7 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2020 Mikel Arregi Etxaniz - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +{ + "name": "force lot name in workorders", + "version": "12.0.1.0.0", + "license": "AGPL-3", + "depends": [ + "mrp", + ], + "author": "AvanzOSC", + "website": "http://www.avanzosc.es", + "category": "Tools", + "data": [ + 'views/product_category_view.xml', + 'views/mrp_workorder_view.xml', + ], + 'demo': [], + 'installable': True, + 'auto_install': False, +} diff --git a/mrp_workorder_production_lot_force_name/models/__init__.py b/mrp_workorder_production_lot_force_name/models/__init__.py new file mode 100644 index 000000000..9ee598bb6 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/models/__init__.py @@ -0,0 +1,2 @@ +from . import mrp_workorder +from . import product_category diff --git a/mrp_workorder_production_lot_force_name/models/mrp_workorder.py b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py new file mode 100644 index 000000000..0b8a31bd9 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py @@ -0,0 +1,24 @@ +# Copyright 2020 Mikel Arregi Etxaniz - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, fields, models + + +class MrpWorkorder(models.Model): + _inherit = "mrp.workorder" + + force_lot_name = fields.Char("Lot Name") + display_force_name = fields.Boolean(compute="_compute_force_field") + + @api.depends('force_lot_name') + def _compute_force_field(self): + for order in self: + product = order.product_id + order.display_force_name = product.categ_id.force_lot_name \ + and product.tracking != 'none' + + def record_production(self): + for order in self: + if order.display_force_name: + order.final_lot_id.name = order.force_lot_name + order.force_lot_name = "" + return super().record_production() diff --git a/mrp_workorder_production_lot_force_name/models/product_category.py b/mrp_workorder_production_lot_force_name/models/product_category.py new file mode 100644 index 000000000..5f9c4a6ca --- /dev/null +++ b/mrp_workorder_production_lot_force_name/models/product_category.py @@ -0,0 +1,9 @@ +# Copyright 2020 Mikel Arregi Etxaniz - AvanzOSC +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + force_lot_name = fields.Boolean("Force Workorder Lot Name") diff --git a/mrp_workorder_production_lot_force_name/tests/__init__.py b/mrp_workorder_production_lot_force_name/tests/__init__.py new file mode 100644 index 000000000..c4a36e133 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mrp_workorder_production_lot_force_name diff --git a/mrp_workorder_production_lot_force_name/tests/test_mrp_workorder_production_lot_force_name.py b/mrp_workorder_production_lot_force_name/tests/test_mrp_workorder_production_lot_force_name.py new file mode 100644 index 000000000..2aeefcb2f --- /dev/null +++ b/mrp_workorder_production_lot_force_name/tests/test_mrp_workorder_production_lot_force_name.py @@ -0,0 +1,87 @@ +# Copyright 2020 Mikel Arregi - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo.tests import common + + +@common.at_install(False) +@common.post_install(True) +class TestMrpWorkorder(common.SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestMrpWorkorder, cls).setUpClass() + cls.mrp_production_model = cls.env['mrp.production'] + cls.bom_model = cls.env['mrp.bom'] + cls.product_model = cls.env['product.product'] + cls.product_categ_model = cls.env['product.category'] + cls.lot_model = cls.env['stock.production.lot'] + cls.route_model = cls.env['mrp.routing'] + cls.workcenter_model = cls.env['mrp.workcenter'] + cls.operation_model = cls.env['mrp.routing.workcenter'] + unit_id = cls.env.ref('uom.product_uom_unit').id + cls.product_categ = cls.product_categ_model.create({ + 'name': 'Product Category', + 'force_lot_name': True, + }) + cls.bom_product = cls.product_model.create({ + 'name': 'BoM product', + 'uom_id': unit_id, + 'tracking': 'serial', + 'categ_id': cls.product_categ.id, + }) + cls.lot = cls.lot_model.create({ + 'name': 'lot', + 'product_id': cls.bom_product.id + }) + cls.component1 = cls.product_model.create({ + 'name': 'Component1', + 'uom_id': unit_id, + }) + cls.component2 = cls.product_model.create({ + 'name': 'Component2', + 'uom_id': unit_id, + }) + cls.workcenter = cls.workcenter_model.create({ + 'name': 'wc1', + 'resource_calendar_id': cls.env.ref( + 'resource.resource_calendar_std').id, + }) + cls.route = cls.route_model.create({ + 'name': 'route', + 'resource_calendar_id': cls.env.ref( + 'resource.resource_calendar_std').id, + 'operation_ids': + [(0, 0, {'name': 'op1', + 'workcenter_id': cls.workcenter.id, + })] + }) + vals = { + 'product_tmpl_id': cls.bom_product.product_tmpl_id.id, + 'product_id': cls.bom_product.id, + 'routing_id': cls.route.id, + 'bom_line_ids': + [(0, 0, {'product_id': cls.component1.id, + 'product_qty': 1, + 'operation_id': cls.route.operation_ids[0].id}), + (0, 0, {'product_id': cls.component2.id, + 'product_qty': 1})], + } + cls.mrp_bom = cls.bom_model.create(vals) + cls.production = cls.mrp_production_model.create({ + 'product_id': cls.bom_product.id, + 'product_uom_id': cls.bom_product.uom_id.id, + 'bom_id': cls.mrp_bom.id, + 'routiog_id': cls.route.id, + }) + + def test_force_lot_name(self): + self.production.button_plan() + workorder = self.env['mrp.workorder'].search([])[0] + workorder.button_start() + workorder.final_lot_id = self.lot.id + self.assertTrue(workorder.display_force_name) + self.assertEqual(workorder.final_lot_id.name, 'lot') + workorder.force_lot_name = 'changed_lot' + workorder.record_production() + self.assertEqual(self.lot.name, 'changed_lot') diff --git a/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml b/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml new file mode 100644 index 000000000..0119808aa --- /dev/null +++ b/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml @@ -0,0 +1,14 @@ + + + + mrp.workoder.force.lot.name.form + mrp.workorder + + + + + + + + + \ No newline at end of file diff --git a/mrp_workorder_production_lot_force_name/views/product_category_view.xml b/mrp_workorder_production_lot_force_name/views/product_category_view.xml new file mode 100644 index 000000000..a0c1ae3a2 --- /dev/null +++ b/mrp_workorder_production_lot_force_name/views/product_category_view.xml @@ -0,0 +1,15 @@ + + + + product.category.force.lot.name.form + product.category + + + + + + + + + + \ No newline at end of file From 8b6a104e21919c859b6125e2418de09e286a91e3 Mon Sep 17 00:00:00 2001 From: Mikel Arregi Date: Wed, 16 Dec 2020 18:26:51 +0100 Subject: [PATCH 2/4] [FIX] mrp_workorder_production_lot_force_name: lot name is mandatory when state is progress --- .../views/mrp_workorder_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml b/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml index 0119808aa..325d6027c 100644 --- a/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml +++ b/mrp_workorder_production_lot_force_name/views/mrp_workorder_view.xml @@ -7,7 +7,7 @@ - + From acf33af380ffe51a8e9f60c658bd892618415230 Mon Sep 17 00:00:00 2001 From: Mikel Arregi Date: Thu, 17 Dec 2020 18:10:36 +0100 Subject: [PATCH 3/4] [FIX] mrp_workorder_production_lot_force_name --- mrp_workorder_production_lot_force_name/models/mrp_workorder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrp_workorder_production_lot_force_name/models/mrp_workorder.py b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py index 0b8a31bd9..84c0b8bed 100644 --- a/mrp_workorder_production_lot_force_name/models/mrp_workorder.py +++ b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py @@ -18,7 +18,7 @@ def _compute_force_field(self): def record_production(self): for order in self: - if order.display_force_name: + if order.display_force_name and order.final_lot_id: order.final_lot_id.name = order.force_lot_name order.force_lot_name = "" return super().record_production() From 6f55e33eb920f38265c252689d4d93a0c275f5aa Mon Sep 17 00:00:00 2001 From: mikelarre Date: Sat, 19 Dec 2020 17:39:46 +0100 Subject: [PATCH 4/4] mrp_workorder_production_lot_force_name: force_name field only when workorder has moves --- mrp_workorder_production_lot_force_name/models/mrp_workorder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mrp_workorder_production_lot_force_name/models/mrp_workorder.py b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py index 84c0b8bed..d38e25c10 100644 --- a/mrp_workorder_production_lot_force_name/models/mrp_workorder.py +++ b/mrp_workorder_production_lot_force_name/models/mrp_workorder.py @@ -14,7 +14,7 @@ def _compute_force_field(self): for order in self: product = order.product_id order.display_force_name = product.categ_id.force_lot_name \ - and product.tracking != 'none' + and product.tracking != 'none' and self.move_raw_ids def record_production(self): for order in self: