mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[14.0][ADD] repair_type
This commit is contained in:
1
repair_type/__init__.py
Normal file
1
repair_type/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
21
repair_type/__manifest__.py
Normal file
21
repair_type/__manifest__.py
Normal file
@@ -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,
|
||||||
|
}
|
||||||
2
repair_type/models/__init__.py
Normal file
2
repair_type/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import repair
|
||||||
|
from . import repair_type
|
||||||
71
repair_type/models/repair.py
Normal file
71
repair_type/models/repair.py
Normal file
@@ -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
|
||||||
41
repair_type/models/repair_type.py
Normal file
41
repair_type/models/repair_type.py
Normal file
@@ -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.",
|
||||||
|
)
|
||||||
1
repair_type/readme/CONFIGURE.rst
Normal file
1
repair_type/readme/CONFIGURE.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
No configuration needed for this module.
|
||||||
3
repair_type/readme/CONTRIBUTORS.rst
Normal file
3
repair_type/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
* `ForgeFlow <https://forgeflow.com>`_:
|
||||||
|
|
||||||
|
* Bernat Puig <bernat.puig@forgeflow.com>
|
||||||
1
repair_type/readme/DESCRIPTION.rst
Normal file
1
repair_type/readme/DESCRIPTION.rst
Normal file
@@ -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.
|
||||||
5
repair_type/readme/ROADMAP.rst
Normal file
5
repair_type/readme/ROADMAP.rst
Normal file
@@ -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.
|
||||||
1
repair_type/readme/USAGE.rst
Normal file
1
repair_type/readme/USAGE.rst
Normal file
@@ -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.
|
||||||
2
repair_type/security/ir.model.access.csv
Normal file
2
repair_type/security/ir.model.access.csv
Normal file
@@ -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
|
||||||
|
4
repair_type/tests/__init__.py
Normal file
4
repair_type/tests/__init__.py
Normal file
@@ -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
|
||||||
199
repair_type/tests/test_repair_type.py
Normal file
199
repair_type/tests/test_repair_type.py
Normal file
@@ -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,
|
||||||
|
)
|
||||||
13
repair_type/views/repair.xml
Normal file
13
repair_type/views/repair.xml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record id="repair_type_form_inherit" model="ir.ui.view">
|
||||||
|
<field name="name">repair.type.inherit</field>
|
||||||
|
<field name="model">repair.order</field>
|
||||||
|
<field name="inherit_id" ref="repair.view_repair_order_form" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<field name="product_id" position="after">
|
||||||
|
<field name="repair_type_id" />
|
||||||
|
</field>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
59
repair_type/views/repair_type.xml
Normal file
59
repair_type/views/repair_type.xml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record id='repair_type_action' model='ir.actions.act_window'>
|
||||||
|
<field name="name">Repair Types</field>
|
||||||
|
<field name="res_model">repair.type</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem
|
||||||
|
name="Repair Types"
|
||||||
|
id="repair_type_menu"
|
||||||
|
parent="repair.repair_menu_config"
|
||||||
|
action="repair_type_action"
|
||||||
|
groups="stock.group_stock_manager"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<record id="repair_type_view_form" model="ir.ui.view">
|
||||||
|
<field name="name">Repair Types Form</field>
|
||||||
|
<field name="model">repair.type</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<sheet string="Repair types">
|
||||||
|
<label for="name" />
|
||||||
|
<h1>
|
||||||
|
<field name="name" />
|
||||||
|
</h1>
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="source_location_id" />
|
||||||
|
<field name="destination_location_id" />
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="source_location_add_part_id" />
|
||||||
|
<field name="destination_location_add_part_id" />
|
||||||
|
<field name="source_location_remove_part_id" />
|
||||||
|
<field name="destination_location_remove_part_id" />
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="repair_type_view_tree" model="ir.ui.view">
|
||||||
|
<field name="name">Repair Types List</field>
|
||||||
|
<field name="model">repair.type</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree>
|
||||||
|
<field name="name" />
|
||||||
|
<field name="source_location_id" />
|
||||||
|
<field name="destination_location_id" invisible="1" />
|
||||||
|
<field name="source_location_add_part_id" />
|
||||||
|
<field name="destination_location_add_part_id" />
|
||||||
|
<field name="source_location_remove_part_id" />
|
||||||
|
<field name="destination_location_remove_part_id" />
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
1
setup/repair_type/odoo/addons/repair_type
Symbolic link
1
setup/repair_type/odoo/addons/repair_type
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../../repair_type
|
||||||
6
setup/repair_type/setup.py
Normal file
6
setup/repair_type/setup.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import setuptools
|
||||||
|
|
||||||
|
setuptools.setup(
|
||||||
|
setup_requires=['setuptools-odoo'],
|
||||||
|
odoo_addon=True,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user