From 544c79d7d58a531219692ff93c767a1680d6f1dc Mon Sep 17 00:00:00 2001 From: Bernat Puig Font Date: Mon, 11 Oct 2021 11:16:10 +0200 Subject: [PATCH] [14.0][ADD] repair_type --- repair_type/__init__.py | 1 + repair_type/__manifest__.py | 21 +++ repair_type/models/__init__.py | 2 + repair_type/models/repair.py | 71 ++++++++ repair_type/models/repair_type.py | 41 +++++ repair_type/readme/CONFIGURE.rst | 1 + repair_type/readme/CONTRIBUTORS.rst | 3 + repair_type/readme/DESCRIPTION.rst | 1 + repair_type/readme/ROADMAP.rst | 5 + repair_type/readme/USAGE.rst | 1 + repair_type/security/ir.model.access.csv | 2 + repair_type/tests/__init__.py | 4 + repair_type/tests/test_repair_type.py | 199 ++++++++++++++++++++++ repair_type/views/repair.xml | 13 ++ repair_type/views/repair_type.xml | 59 +++++++ setup/repair_type/odoo/addons/repair_type | 1 + setup/repair_type/setup.py | 6 + 17 files changed, 431 insertions(+) create mode 100644 repair_type/__init__.py create mode 100644 repair_type/__manifest__.py create mode 100644 repair_type/models/__init__.py create mode 100644 repair_type/models/repair.py create mode 100644 repair_type/models/repair_type.py create mode 100644 repair_type/readme/CONFIGURE.rst create mode 100644 repair_type/readme/CONTRIBUTORS.rst create mode 100644 repair_type/readme/DESCRIPTION.rst create mode 100644 repair_type/readme/ROADMAP.rst create mode 100644 repair_type/readme/USAGE.rst create mode 100644 repair_type/security/ir.model.access.csv create mode 100644 repair_type/tests/__init__.py create mode 100644 repair_type/tests/test_repair_type.py create mode 100644 repair_type/views/repair.xml create mode 100644 repair_type/views/repair_type.xml create mode 120000 setup/repair_type/odoo/addons/repair_type create mode 100644 setup/repair_type/setup.py diff --git a/repair_type/__init__.py b/repair_type/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/repair_type/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/repair_type/__manifest__.py b/repair_type/__manifest__.py new file mode 100644 index 000000000..16feec452 --- /dev/null +++ b/repair_type/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2021 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Repair Type", + "version": "14.0.1.0.0", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/manufacture", + "summary": "Repair type", + "category": "Repair", + "depends": ["repair"], + "data": [ + "views/repair.xml", + "views/repair_type.xml", + "security/ir.model.access.csv", + ], + "installable": True, + "development_status": "Alpha", + "license": "AGPL-3", + "application": False, +} diff --git a/repair_type/models/__init__.py b/repair_type/models/__init__.py new file mode 100644 index 000000000..67781506c --- /dev/null +++ b/repair_type/models/__init__.py @@ -0,0 +1,2 @@ +from . import repair +from . import repair_type diff --git a/repair_type/models/repair.py b/repair_type/models/repair.py new file mode 100644 index 000000000..17c3c14ea --- /dev/null +++ b/repair_type/models/repair.py @@ -0,0 +1,71 @@ +# Copyright (C) 2021 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import api, fields, models + + +class Repair(models.Model): + _inherit = "repair.order" + + repair_type_id = fields.Many2one(comodel_name="repair.type") + location_id = fields.Many2one( + compute="_compute_location_id", store=True, readonly=False + ) + + @api.depends("repair_type_id") + def _compute_location_id(self): + for rec in self: + if rec.repair_type_id.source_location_id: + rec.location_id = rec.repair_type_id.source_location_id + + +class RepairLine(models.Model): + _inherit = "repair.line" + + location_id = fields.Many2one( + compute="_compute_location_id", store=True, readonly=False + ) + location_dest_id = fields.Many2one( + compute="_compute_location_id", store=True, readonly=False + ) + + @api.depends("type", "repair_id.repair_type_id") + def _compute_location_id(self): + for rec in self: + if ( + rec.type == "add" + and rec.repair_id.repair_type_id.source_location_add_part_id + ): + rec.location_id = ( + rec.repair_id.repair_type_id.source_location_add_part_id + ) + if ( + rec.type == "add" + and rec.repair_id.repair_type_id.destination_location_add_part_id + ): + rec.location_dest_id = ( + rec.repair_id.repair_type_id.destination_location_add_part_id + ) + if ( + rec.type == "remove" + and rec.repair_id.repair_type_id.source_location_remove_part_id + ): + rec.location_id = ( + rec.repair_id.repair_type_id.source_location_remove_part_id + ) + if ( + rec.type == "remove" + and rec.repair_id.repair_type_id.destination_location_remove_part_id + ): + rec.location_dest_id = ( + rec.repair_id.repair_type_id.destination_location_remove_part_id + ) + + @api.onchange("type") + def onchange_operation_type(self): + # this onchange was overriding the changes from the compute + # method `_compute_location_id`, we ensure that the locations + # in the types have more priority by explicit calling the compute. + res = super().onchange_operation_type() + self._compute_location_id() + return res diff --git a/repair_type/models/repair_type.py b/repair_type/models/repair_type.py new file mode 100644 index 000000000..318298486 --- /dev/null +++ b/repair_type/models/repair_type.py @@ -0,0 +1,41 @@ +# Copyright (C) 2021 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo import fields, models + + +class RepairType(models.Model): + _name = "repair.type" + _description = "Repair Type" + + name = fields.Char("Repair Type Name", copy=False, required=True) + source_location_id = fields.Many2one( + "stock.location", + "Source Location", + help="This is the location where the product to repair is located.", + ) + destination_location_id = fields.Many2one( + "stock.location", + "Destination Location", + help="This is the location where the product repaired will be located.", + ) + source_location_add_part_id = fields.Many2one( + "stock.location", + "Source Location Add Component", + help="This is the location where the part of the product to add is located.", + ) + destination_location_add_part_id = fields.Many2one( + "stock.location", + "Destination Location Add Component", + help="This is the location where the part of the product to add is located.", + ) + source_location_remove_part_id = fields.Many2one( + "stock.location", + "Source Location Remove Component", + help="This is the location where the part of the product to remove is located.", + ) + destination_location_remove_part_id = fields.Many2one( + "stock.location", + "Destination Location Remove Component", + help="This is the location where the part of the product to remove is located.", + ) diff --git a/repair_type/readme/CONFIGURE.rst b/repair_type/readme/CONFIGURE.rst new file mode 100644 index 000000000..029bb402b --- /dev/null +++ b/repair_type/readme/CONFIGURE.rst @@ -0,0 +1 @@ +No configuration needed for this module. diff --git a/repair_type/readme/CONTRIBUTORS.rst b/repair_type/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..be2871269 --- /dev/null +++ b/repair_type/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `ForgeFlow `_: + + * Bernat Puig diff --git a/repair_type/readme/DESCRIPTION.rst b/repair_type/readme/DESCRIPTION.rst new file mode 100644 index 000000000..f84b78a71 --- /dev/null +++ b/repair_type/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module adds the type to a repair order. If we select a type on a Repair Order, Odoo will automatically fill some fields of the order. diff --git a/repair_type/readme/ROADMAP.rst b/repair_type/readme/ROADMAP.rst new file mode 100644 index 000000000..15259cfc3 --- /dev/null +++ b/repair_type/readme/ROADMAP.rst @@ -0,0 +1,5 @@ +Possible improvements for future versions: + +* Destination Location of the product to repair is not used currently, + so that's why is invisible. We still save the field for future new + module implementations. diff --git a/repair_type/readme/USAGE.rst b/repair_type/readme/USAGE.rst new file mode 100644 index 000000000..f5c98f6f7 --- /dev/null +++ b/repair_type/readme/USAGE.rst @@ -0,0 +1 @@ +Go to Configuration>Repair Types and create a new repair type. Afterwards selecting a type on a Repair Order will automatically fill some fields. diff --git a/repair_type/security/ir.model.access.csv b/repair_type/security/ir.model.access.csv new file mode 100644 index 000000000..edf093528 --- /dev/null +++ b/repair_type/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +type_repair.stock_manager,type_repair.stock_manager,model_repair_type,stock.group_stock_manager,1,1,1,1 diff --git a/repair_type/tests/__init__.py b/repair_type/tests/__init__.py new file mode 100644 index 000000000..8e6b33343 --- /dev/null +++ b/repair_type/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2021 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from . import test_repair_type diff --git a/repair_type/tests/test_repair_type.py b/repair_type/tests/test_repair_type.py new file mode 100644 index 000000000..a6f8e57d4 --- /dev/null +++ b/repair_type/tests/test_repair_type.py @@ -0,0 +1,199 @@ +# Copyright (C) 2021 ForgeFlow S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.tests.common import TransactionCase + + +class TestRepairType(TransactionCase): + def setUp(self, *args, **kwargs): + super(TestRepairType, self).setUp(*args, **kwargs) + + # First of all we create a repair to work with + self.repair_r1 = self.env.ref("repair.repair_r1") + + # Now we will create a location scrap for the destination location of removed components + stock_location_locations_virtual = self.env["stock.location"].create( + {"name": "Virtual Locations", "usage": "view", "posz": 1} + ) + self.scrapped_location = self.env["stock.location"].create( + { + "name": "Scrapped", + "location_id": stock_location_locations_virtual.id, + "scrap_location": True, + "usage": "inventory", + } + ) + + # Then, we create a repair type to know the source and destination locations + self.repair_type_1 = self.env["repair.type"].create( + { + "name": "Repairings Office 1", + "source_location_id": self.env.ref("stock.stock_location_stock").id, + "destination_location_id": self.env.ref( + "stock.stock_location_customers" + ).id, + "source_location_add_part_id": self.env.ref( + "stock.stock_location_components" + ).id, + "destination_location_add_part_id": self.env.ref( + "stock.stock_location_customers" + ).id, + "source_location_remove_part_id": self.env.ref( + "stock.stock_location_stock" + ).id, + "destination_location_remove_part_id": self.scrapped_location.id, + } + ) + self.repair_type_2 = self.env["repair.type"].create( + { + "name": "Repairings Office 2", + "source_location_id": self.env.ref( + "stock.stock_location_components" + ).id, + "destination_location_id": self.env.ref( + "stock.stock_location_stock" + ).id, + "source_location_add_part_id": self.env.ref( + "stock.location_refrigerator_small" + ).id, + "destination_location_add_part_id": self.env.ref( + "stock.stock_location_14" + ).id, + "source_location_remove_part_id": self.env.ref( + "stock.stock_location_stock" + ).id, + "destination_location_remove_part_id": self.scrapped_location.id, + } + ) + + # Finally we add two line components to the repair order, + # one adding a component and the other one removing + self.add_component = self.env["repair.line"].create( + { + "name": "Add Component 1", + "repair_id": 1, + "price_unit": 2.0, + "type": "add", + "product_id": self.env.ref("product.product_product_3").id, + "product_uom": self.env.ref("product.product_product_3").uom_id.id, + "product_uom_qty": 1.0, + "location_id": self.env.ref("stock.stock_location_14").id, + "location_dest_id": self.env.ref( + "product.product_product_3" + ).property_stock_production.id, + "company_id": self.env.company.id, + } + ) + self.remove_component = self.env["repair.line"].create( + { + "name": "Add Component 2", + "repair_id": 1, + "price_unit": 2.0, + "type": "remove", + "product_id": self.env.ref("product.product_product_11").id, + "product_uom": self.env.ref("product.product_product_11").uom_id.id, + "product_uom_qty": 1.0, + "location_id": self.env.ref("stock.stock_location_14").id, + "location_dest_id": self.env.ref( + "product.product_product_11" + ).property_stock_production.id, + "company_id": self.env.company.id, + } + ) + self.repair_r1.operations |= self.add_component + self.repair_r1.operations |= self.remove_component + + def test_compute_location_id(self): + # First we associate the repair with the repair type + self.repair_r1.repair_type_id = self.repair_type_1 + + # Afterwards we will assert the source and + # destination of the product in the repair order + self.assertEqual( + self.repair_r1.location_id, self.repair_type_1.source_location_id + ) + + # Next we assert if the source and destination locations of the components are correct + self.assertEqual( + self.repair_r1.operations[0].location_id, + self.repair_type_1.source_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[0].location_dest_id, + self.repair_type_1.destination_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[1].location_id, + self.repair_type_1.source_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[1].location_dest_id, + self.repair_type_1.destination_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[2].location_id, + self.repair_type_1.source_location_remove_part_id, + ) + self.assertEqual( + self.repair_r1.operations[2].location_dest_id, + self.repair_type_1.destination_location_remove_part_id, + ) + + # We change the repair type to repair_type_2 and check if all the locations changed + self.repair_r1.repair_type_id = self.repair_type_2 + + self.assertEqual( + self.repair_r1.location_id, self.repair_type_2.source_location_id + ) + + self.assertEqual( + self.repair_r1.operations[0].location_id, + self.repair_type_2.source_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[0].location_dest_id, + self.repair_type_2.destination_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[1].location_id, + self.repair_type_2.source_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[1].location_dest_id, + self.repair_type_2.destination_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[2].location_id, + self.repair_type_2.source_location_remove_part_id, + ) + self.assertEqual( + self.repair_r1.operations[2].location_dest_id, + self.repair_type_2.destination_location_remove_part_id, + ) + + def test_compute_location_id_2(self): + # First we will assert the source and destination + # of the component product in the repair order + self.repair_r1.repair_type_id = self.repair_type_1 + + self.assertEqual( + self.repair_r1.operations[0].location_id, + self.repair_type_1.source_location_add_part_id, + ) + self.assertEqual( + self.repair_r1.operations[0].location_dest_id, + self.repair_type_1.destination_location_add_part_id, + ) + + # Then we change the type of operation + self.repair_r1.operations[0].type = "remove" + + # And finally we assert that the locations of that operation changed + self.assertEqual( + self.repair_r1.operations[0].location_id, + self.repair_type_1.source_location_remove_part_id, + ) + self.assertEqual( + self.repair_r1.operations[0].location_dest_id, + self.repair_type_1.destination_location_remove_part_id, + ) diff --git a/repair_type/views/repair.xml b/repair_type/views/repair.xml new file mode 100644 index 000000000..a23e7dfe8 --- /dev/null +++ b/repair_type/views/repair.xml @@ -0,0 +1,13 @@ + + + + repair.type.inherit + repair.order + + + + + + + + diff --git a/repair_type/views/repair_type.xml b/repair_type/views/repair_type.xml new file mode 100644 index 000000000..6feeb1220 --- /dev/null +++ b/repair_type/views/repair_type.xml @@ -0,0 +1,59 @@ + + + + Repair Types + repair.type + tree,form + + + + + + Repair Types Form + repair.type + +
+ + +
+
+
+ + + Repair Types List + repair.type + + + + + + + + + + + + +
diff --git a/setup/repair_type/odoo/addons/repair_type b/setup/repair_type/odoo/addons/repair_type new file mode 120000 index 000000000..45adaa43d --- /dev/null +++ b/setup/repair_type/odoo/addons/repair_type @@ -0,0 +1 @@ +../../../../repair_type \ No newline at end of file diff --git a/setup/repair_type/setup.py b/setup/repair_type/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/repair_type/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)