From 62f363dd037b9be53634c642cc8990c42dccc020 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Tue, 24 Apr 2018 10:02:21 -0700 Subject: [PATCH 1/4] Initial commit `maintenance_repair` for 11.0 --- maintenance_repair/__init__.py | 1 + maintenance_repair/__manifest__.py | 25 ++++ maintenance_repair/models/__init__.py | 1 + maintenance_repair/models/maintenance.py | 141 ++++++++++++++++++ .../security/ir.model.access.csv | 2 + maintenance_repair/tests/__init__.py | 1 + .../tests/test_maintenance_repair.py | 37 +++++ .../views/maintenance_views.xml | 81 ++++++++++ 8 files changed, 289 insertions(+) create mode 100644 maintenance_repair/__init__.py create mode 100644 maintenance_repair/__manifest__.py create mode 100644 maintenance_repair/models/__init__.py create mode 100644 maintenance_repair/models/maintenance.py create mode 100644 maintenance_repair/security/ir.model.access.csv create mode 100644 maintenance_repair/tests/__init__.py create mode 100644 maintenance_repair/tests/test_maintenance_repair.py create mode 100644 maintenance_repair/views/maintenance_views.xml diff --git a/maintenance_repair/__init__.py b/maintenance_repair/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/maintenance_repair/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/maintenance_repair/__manifest__.py b/maintenance_repair/__manifest__.py new file mode 100644 index 00000000..e05f64b7 --- /dev/null +++ b/maintenance_repair/__manifest__.py @@ -0,0 +1,25 @@ +{ + 'name': 'Equipment Repair', + 'version': '11.0.1.0.0', + 'author': 'Hibou Corp. ', + 'category': 'Human Resources', + 'summary': 'Consume products on Maintenance Requests', + 'description': """ +Equipment Repair +================ + +Keep track of parts required to repair equipment. +""", + 'website': 'https://hibou.io/', + 'depends': [ + 'stock', + 'maintenance_notebook', + 'hr_department_project', + ], + 'data': [ + 'security/ir.model.access.csv', + 'views/maintenance_views.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/maintenance_repair/models/__init__.py b/maintenance_repair/models/__init__.py new file mode 100644 index 00000000..12bf298f --- /dev/null +++ b/maintenance_repair/models/__init__.py @@ -0,0 +1 @@ +from . import maintenance diff --git a/maintenance_repair/models/maintenance.py b/maintenance_repair/models/maintenance.py new file mode 100644 index 00000000..2a1b0603 --- /dev/null +++ b/maintenance_repair/models/maintenance.py @@ -0,0 +1,141 @@ +from odoo import api, fields, models, _ +from odoo.addons import decimal_precision as dp +from odoo.exceptions import UserError, ValidationError + + +class StockMove(models.Model): + _inherit = 'stock.move' + + maintenance_request_id = fields.Many2one('maintenance.request') + + +class MaintenanceTeam(models.Model): + _inherit = 'maintenance.team' + + repair_location_id = fields.Many2one('stock.location', string='Default Repair Parts Source') + repair_location_dest_id = fields.Many2one('stock.location', string='Default Repair Parts Destination') + + +class MaintenanceRequest(models.Model): + _inherit = 'maintenance.request' + + maintenance_type = fields.Selection(selection_add=[('negligence', 'Negligence')]) + repair_line_ids = fields.One2many('maintenance.request.repair.line', 'request_id', 'Parts', copy=True) + repair_status = fields.Selection([ + ('repaired', 'Repaired'), + ('to repair', 'To Repair'), + ('no', 'Nothing to Repair') + ], string='Repair Status', compute='_get_repaired', store=True, readonly=True) + repair_location_id = fields.Many2one('stock.location', string='Source Location') + repair_location_dest_id = fields.Many2one('stock.location', string='Destination Location') + total_lst_price = fields.Float(string='Total Price', compute='_compute_repair_totals', stored=True) + total_standard_price = fields.Float(string='Total Est. Cost', compute='_compute_repair_totals', stored=True) + total_cost = fields.Float(string='Total Cost', compute='_compute_repair_totals', stored=True) + + @api.depends('repair_line_ids.lst_price', 'repair_line_ids.standard_price', 'repair_line_ids.cost') + def _compute_repair_totals(self): + for repair in self: + repair.total_lst_price = sum(l.lst_price for l in repair.repair_line_ids) + repair.total_standard_price = sum(l.standard_price for l in repair.repair_line_ids) + repair.total_cost = sum(l.cost for l in repair.repair_line_ids) + + @api.depends('repair_line_ids.state') + def _get_repaired(self): + for request in self: + if not request.repair_line_ids: + request.repair_status = 'no' + elif request.repair_line_ids.filtered(lambda l: l.state != 'done'): + request.repair_status = 'to repair' + else: + request.repair_status = 'repaired' + + @api.onchange('maintenance_team_id') + def _onchange_maintenance_team(self): + for request in self: + if request.maintenance_team_id: + request.repair_location_id = request.maintenance_team_id.repair_location_id + request.repair_location_dest_id = request.maintenance_team_id.repair_location_dest_id + + + def action_complete_repair(self): + for request in self.filtered(lambda r: r.repair_status == 'to repair'): + request.repair_line_ids.action_complete() + return True + + +class MaintenanceRequestRepairLine(models.Model): + _name = 'maintenance.request.repair.line' + + request_id = fields.Many2one('maintenance.request', copy=False) + product_id = fields.Many2one('product.product', 'Product', required=True, + states={'done': [('readonly', True)]}) + product_uom_qty = fields.Float('Quantity', default=1.0, + digits=dp.get_precision('Product Unit of Measure'), required=True, + states={'done': [('readonly', True)]}) + product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure', required=True, + states={'done': [('readonly', True)]}) + state = fields.Selection([ + ('draft', 'Draft'), + ('done', 'Done'), + ], string='State', copy=False, default='draft') + move_id = fields.Many2one('stock.move', string='Stock Move') + lst_price = fields.Float(string='Sale Price', states={'done': [('readonly', True)]}) + standard_price = fields.Float(string='Est. Cost', states={'done': [('readonly', True)]}) + cost = fields.Float(string='Cost', compute='_compute_actual_cost', stored=True) + + @api.multi + def unlink(self): + if self.filtered(lambda l: l.state == 'done'): + raise UserError(_('Only draft lines can be deleted.')) + return super(MaintenanceRequestRepairLine, self).unlink() + + @api.onchange('product_id', 'product_uom_qty') + def onchange_product_id(self): + if self.product_id: + self.product_uom_id = self.product_id.uom_id + self.lst_price = self.product_id.lst_price * self.product_uom_qty + self.standard_price = self.product_id.standard_price * self.product_uom_qty + + @api.depends('product_id', 'move_id') + def _compute_actual_cost(self): + for line in self: + if line.move_id: + line.cost = sum(abs(m.amount) for m in line.move_id.account_move_ids) + else: + line.cost = 0.0 + + @api.multi + def action_complete(self): + # Create stock movements. - Inspired by mrp_repair + MoveObj = self.env['stock.move'] + for line in self.filtered(lambda l: not l.state == 'done'): + request = line.request_id + + # Optional hooks to `maintenance_timesheet` and `stock_analytic` + analytic_account_id = False + if getattr(request, 'project_id', False): + analytic_account_id = request.project_id.analytic_account_id.id + + move = MoveObj.create({ + 'name': request.name, + 'product_id': line.product_id.id, + 'product_uom_qty': line.product_uom_qty, + 'product_uom': line.product_uom_id.id, + 'location_id': request.repair_location_id.id, + 'location_dest_id': request.repair_location_dest_id.id, + 'maintenance_request_id': request.id, + 'origin': request.name, + 'analytic_account_id': analytic_account_id, + }) + move._action_confirm() + move._action_assign() + if move.state != 'assigned': + raise ValidationError(_('Unable to reserve inventory.')) + + move.quantity_done = line.product_uom_qty + move._action_done() + if move.state != 'done': + raise ValidationError(_('Unable to move inventory.')) + + line.write({'move_id': move.id, 'state': 'done'}) + return True diff --git a/maintenance_repair/security/ir.model.access.csv b/maintenance_repair/security/ir.model.access.csv new file mode 100644 index 00000000..26e989ac --- /dev/null +++ b/maintenance_repair/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" +"access_maintenance_request_repair_line","access maintenance.request.repair.line","model_maintenance_request_repair_line","base.group_user",1,1,1,1 \ No newline at end of file diff --git a/maintenance_repair/tests/__init__.py b/maintenance_repair/tests/__init__.py new file mode 100644 index 00000000..3820c3df --- /dev/null +++ b/maintenance_repair/tests/__init__.py @@ -0,0 +1 @@ +from . import test_maintenance_repair diff --git a/maintenance_repair/tests/test_maintenance_repair.py b/maintenance_repair/tests/test_maintenance_repair.py new file mode 100644 index 00000000..00e93754 --- /dev/null +++ b/maintenance_repair/tests/test_maintenance_repair.py @@ -0,0 +1,37 @@ +from odoo.tests import common + + +class TestMaintenanceRepair(common.TransactionCase): + """Tests for repairs + """ + + def test_create(self): + equipment = self.env['maintenance.equipment'].create({ + 'name': 'Monitor', + }) + + loc_from = self.env.ref('stock.stock_location_stock') + loc_to = self.env.ref('stock.location_inventory') + request = self.env['maintenance.request'].create({ + 'name': 'Repair Monitor', + 'equipment_id': equipment.id, + 'repair_location_id': loc_from.id, + 'repair_location_dest_id': loc_to.id, + }) + self.assertEqual(request.repair_status, 'no') + + product_to_repair = self.env.ref('product.product_product_24_product_template') + line = self.env['maintenance.request.repair.line'].create({ + 'request_id': request.id, + 'product_id': product_to_repair.id, + 'product_uom_id': product_to_repair.uom_id.id, + }) + + self.assertEqual(request.repair_status, 'to repair') + line.action_complete() + self.assertEqual(request.repair_status, 'repaired') + self.assertEqual(line.state, 'done') + self.assertTrue(line.move_id, 'Expect a stock move to be done.') + + + diff --git a/maintenance_repair/views/maintenance_views.xml b/maintenance_repair/views/maintenance_views.xml new file mode 100644 index 00000000..4fdf6daf --- /dev/null +++ b/maintenance_repair/views/maintenance_views.xml @@ -0,0 +1,81 @@ + + + + maintenance.team.form.inherited + maintenance.team + + + + + + + + + + + equipment.request.form.inherited + maintenance.request + + + + +