diff --git a/addons/hr_maintenance/__openerp__.py b/addons/hr_maintenance/__openerp__.py index 8f736028d31..5c1e83e2345 100644 --- a/addons/hr_maintenance/__openerp__.py +++ b/addons/hr_maintenance/__openerp__.py @@ -9,6 +9,7 @@ 'depends': ['hr', 'maintenance'], 'summary': 'Equipments, Assets, Internal Hardware, Allocation Tracking', 'data': [ + 'security/equipment.xml', 'views/maintenance_views.xml', ], 'demo': [], diff --git a/addons/hr_maintenance/models/equipment.py b/addons/hr_maintenance/models/equipment.py index 31c84064bf6..66757b26331 100644 --- a/addons/hr_maintenance/models/equipment.py +++ b/addons/hr_maintenance/models/equipment.py @@ -3,16 +3,26 @@ from odoo import api, fields, models, tools -class HrEquipment(models.Model): - _inherit = 'hr.equipment' +class MaintenanceEquipment(models.Model): + _inherit = 'maintenance.equipment' employee_id = fields.Many2one('hr.employee', string='Assigned to Employee', track_visibility='onchange') department_id = fields.Many2one('hr.department', string='Assigned to Department', track_visibility='onchange') equipment_assign_to = fields.Selection( - [('department', 'Department'), ('employee', 'Employee')], + [('department', 'Department'), ('employee', 'Employee') ,('other', 'Other')], string='Used By', required=True, default='employee') + owner_user_id = fields.Many2one(compute='_compute_owner') + + @api.one + @api.depends('employee_id', 'department_id', 'equipment_assign_to') + def _compute_owner(self): + self.owner_user_id = self.env.user.id + if self.equipment_assign_to == 'employee': + self.owner_user_id = self.employee_id.user_id.id + elif self.equipment_assign_to == 'department': + self.owner_user_id = self.department_id.manager_id.user_id.id @api.onchange('equipment_assign_to') def _onchange_equipment_assign_to(self): @@ -24,7 +34,7 @@ class HrEquipment(models.Model): @api.model def create(self, vals): - equipment = super(HrEquipment, self).create(vals) + equipment = super(MaintenanceEquipment, self).create(vals) # subscribe employee or department manager when equipment assign to him. user_ids = [] if equipment.employee_id and equipment.employee_id.user_id: @@ -49,18 +59,18 @@ class HrEquipment(models.Model): user_ids.append(department.manager_id.user_id.id) if user_ids: self.message_subscribe_users(user_ids=user_ids) - return super(HrEquipment, self).write(vals) + return super(MaintenanceEquipment, self).write(vals) @api.multi def _track_subtype(self, init_values): self.ensure_one() if ('employee_id' in init_values and self.employee_id) or ('department_id' in init_values and self.department_id): return 'maintenance.mt_mat_assign' - return super(HrEquipment, self)._track_subtype(init_values) + return super(MaintenanceEquipment, self)._track_subtype(init_values) -class HrEquipmentRequest(models.Model): - _inherit = 'hr.equipment.request' +class MaintenanceRequest(models.Model): + _inherit = 'maintenance.request' @api.returns('self') def _default_employee_get(self): @@ -68,6 +78,14 @@ class HrEquipmentRequest(models.Model): employee_id = fields.Many2one('hr.employee', string='Employee', default=_default_employee_get) department_id = fields.Many2one('hr.department', string='Department') + owner_user_id = fields.Many2one(compute='_compute_owner', store=True) + + @api.depends('employee_id', 'department_id') + def _compute_owner(self): + if self.equipment_id.equipment_assign_to == 'employee': + self.owner_user_id = self.employee_id.user_id.id + elif self.equipment_id.equipment_assign_to == 'department': + self.owner_user_id = self.department_id.manager_id.user_id.id @api.onchange('employee_id', 'department_id') def onchange_department_or_employee_id(self): @@ -78,27 +96,25 @@ class HrEquipmentRequest(models.Model): domain = ['|'] + domain if self.employee_id: domain = domain + ['|', ('employee_id', '=', self.employee_id.id), ('employee_id', '=', None)] - equipment = self.env['hr.equipment'].search(domain, limit=2) + equipment = self.env['maintenance.equipment'].search(domain, limit=2) if len(equipment) == 1: self.equipment_id = equipment return {'domain': {'equipment_id': domain}} @api.model def create(self, vals): - result = super(HrEquipmentRequest, self).create(vals) + result = super(MaintenanceRequest, self).create(vals) if result.employee_id.user_id: result.message_subscribe_users(user_ids=[result.employee_id.user_id.id]) return result @api.multi def write(self, vals): - # Overridden to reset the kanban_state to normal whenever - # the stage (stage_id) of the Maintenance Request changes. if vals.get('employee_id'): employee = self.env['hr.employee'].browse(vals['employee_id']) if employee and employee.user_id: self.message_subscribe_users(user_ids=[employee.user_id.id]) - return super(HrEquipmentRequest, self).write(vals) + return super(MaintenanceRequest, self).write(vals) @api.model def message_new(self, msg, custom_values=None): @@ -114,4 +130,4 @@ class HrEquipmentRequest(models.Model): employee = self.env['hr.employee'].search([('user_id', '=', user.id)], limit=1) if employee: custom_values['employee_id'] = employee and employee[0].id - return super(HrEquipmentRequest, self).message_new(msg, custom_values=custom_values) + return super(MaintenanceRequest, self).message_new(msg, custom_values=custom_values) diff --git a/addons/hr_maintenance/security/equipment.xml b/addons/hr_maintenance/security/equipment.xml new file mode 100644 index 00000000000..1c5d4470b55 --- /dev/null +++ b/addons/hr_maintenance/security/equipment.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/addons/hr_maintenance/views/maintenance_views.xml b/addons/hr_maintenance/views/maintenance_views.xml index 07c19cc9e4b..58dec50bc2f 100644 --- a/addons/hr_maintenance/views/maintenance_views.xml +++ b/addons/hr_maintenance/views/maintenance_views.xml @@ -2,12 +2,12 @@ - - hr.equipment.request.view.search.inherit.hr - hr.equipment.request + + maintenance.request.view.search.inherit.hr + maintenance.request - + @@ -19,9 +19,9 @@ - - hr.equipment.request.view.form.inherit.hr - hr.equipment.request + + maintenance.request.view.form.inherit.hr + maintenance.request @@ -30,9 +30,9 @@ - - hr.equipment.request.view.kanban.inherit.hr - hr.equipment.request + + maintenance.request.view.kanban.inherit.hr + maintenance.request @@ -42,9 +42,9 @@ - - hr.equipment.request.view.tree.inherit.hr - hr.equipment.request + + maintenance.request.view.tree.inherit.hr + maintenance.request @@ -54,9 +54,9 @@ - - hr.equipment.view.form.inherit.hr - hr.equipment + + maintenance.equipment.view.form.inherit.hr + maintenance.equipment @@ -67,12 +67,12 @@ - - hr.equipment.view.kanban.inherit.hr - hr.equipment + + maintenance.equipment.view.kanban.inherit.hr + maintenance.equipment - + @@ -82,9 +82,9 @@ - - hr.equipment.view.tree.inherit.hr - hr.equipment + + maintenance.equipment.view.tree.inherit.hr + maintenance.equipment diff --git a/addons/maintenance/__openerp__.py b/addons/maintenance/__openerp__.py index f2c12cc3302..b30f3bd2d73 100644 --- a/addons/maintenance/__openerp__.py +++ b/addons/maintenance/__openerp__.py @@ -6,15 +6,15 @@ 'sequence': 125, 'category': 'Human Resources', 'description': """ - Track employees' equipment and manage maintenance requests.""", + Track equipment and manage maintenance requests.""", 'depends': ['mail'], 'summary': 'Equipments, Assets, Internal Hardware, Allocation Tracking', 'data': [ 'security/maintenance.xml', 'security/ir.model.access.csv', 'data/maintenance_data.xml', - 'views/maintenance_config_settings_views.xml', 'views/maintenance_views.xml', + 'views/maintenance_templates.xml', ], 'demo': ['data/maintenance_demo.xml'], 'installable': True, diff --git a/addons/maintenance/data/maintenance_cron.xml b/addons/maintenance/data/maintenance_cron.xml new file mode 100644 index 00000000000..141ae9757c3 --- /dev/null +++ b/addons/maintenance/data/maintenance_cron.xml @@ -0,0 +1,13 @@ + + + + Generate preventive maintenance requests + 1 + days + -1 + + + + + + \ No newline at end of file diff --git a/addons/maintenance/data/maintenance_data.xml b/addons/maintenance/data/maintenance_data.xml index 4048e864a90..70a40c84a96 100644 --- a/addons/maintenance/data/maintenance_data.xml +++ b/addons/maintenance/data/maintenance_data.xml @@ -1,25 +1,25 @@ - + - + New Request - + In Progress - + Repaired - + Scrap @@ -29,20 +29,20 @@ helpdesk - + Request Created - hr.equipment.request + equipment.request Maintenance Request created Status Changed - hr.equipment.request + maintenance.request Status changed @@ -50,35 +50,49 @@ Equipment Assigned - hr.equipment + maintenance.equipment Equipment Assigned Maintenance Request Created - hr.equipment.category + maintenance.equipment.category category_id Equipment Assigned - hr.equipment.category + maintenance.equipment.category category_id - + Computers + - + Software + - + Printers + + + Internal Maintenance + + + + Metrology + + + + Subcontractor + diff --git a/addons/maintenance/data/maintenance_demo.xml b/addons/maintenance/data/maintenance_demo.xml index 915cc979982..1abdeb31c83 100644 --- a/addons/maintenance/data/maintenance_demo.xml +++ b/addons/maintenance/data/maintenance_demo.xml @@ -3,129 +3,131 @@ - + Monitors - + 3 + - + Phones - + + - + Samsung Monitor 15" - + - + MT/122/11112222 NP300E5X - + Samsung Monitor 15" - + - + MT/125/22778837 NP355E5X - + Samsung Monitor 15" - + - + MT/127/18291018 NP355E5X 3 - + Acer Laptop - + - + LP/203/19281928 NE56R - + Acer Laptop - + - + LP/205/12928291 V5131 - + HP Laptop - + - + LP/303/28292090 17-j059nr - + HP Laptop - + - + LP/305/17281718 - + HP Inkjet printer - - + + PR/011/2928191889 - + Resolution is bad - + - - + 7 + - + Some keys are not working - + - - + + - + Motherboard failed - + - - + + - + Battery drains fast - + - - + + - + Touchpad not working - + - - + + diff --git a/addons/maintenance/models/__init__.py b/addons/maintenance/models/__init__.py index 427d3df6a82..3641d220dbc 100644 --- a/addons/maintenance/models/__init__.py +++ b/addons/maintenance/models/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- import maintenance -import maintenance_config_settings diff --git a/addons/maintenance/models/maintenance.py b/addons/maintenance/models/maintenance.py index 52eb6321d5e..007a67a1f9f 100644 --- a/addons/maintenance/models/maintenance.py +++ b/addons/maintenance/models/maintenance.py @@ -1,27 +1,28 @@ # -*- coding: utf-8 -*- -from openerp import api, fields, models, fields -from openerp import _, tools -from openerp.exceptions import UserError +from datetime import date, datetime, timedelta + +from odoo import api, fields, models, _ +from odoo.exceptions import UserError +from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT -class HrEquipmentStage(models.Model): +class MaintenanceStage(models.Model): """ Model for case stages. This models the main stages of a Maintenance Request management flow. """ - _name = 'hr.equipment.stage' + _name = 'maintenance.stage' _description = 'Maintenance Stage' _order = 'sequence, id' name = fields.Char('Name', required=True, translate=True) sequence = fields.Integer('Sequence', default=20) - fold = fields.Boolean('Folded in Recruitment Pipe') + fold = fields.Boolean('Folded in Maintenance Pipe') done = fields.Boolean('Request Done') -class HrEquipmentCategory(models.Model): - _name = 'hr.equipment.category' - _inherits = {"mail.alias": "alias_id"} - _inherit = ['mail.thread'] +class MaintenanceEquipmentCategory(models.Model): + _name = 'maintenance.equipment.category' + _inherit = ['mail.alias.mixin', 'mail.thread'] _description = 'Asset Category' @api.one @@ -30,12 +31,12 @@ class HrEquipmentCategory(models.Model): self.fold = False if self.equipment_count else True name = fields.Char('Category Name', required=True, translate=True) - user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.uid) + technician_user_id = fields.Many2one('res.users', 'Responsible', track_visibility='onchange', default=lambda self: self.env.uid, oldname='user_id') color = fields.Integer('Color Index') note = fields.Text('Comments', translate=True) - equipment_ids = fields.One2many('hr.equipment', 'category_id', string='Equipments', copy=False) + equipment_ids = fields.One2many('maintenance.equipment', 'category_id', string='Equipments', copy=False) equipment_count = fields.Integer(string="Equipment", compute='_compute_equipment_count') - maintenance_ids = fields.One2many('hr.equipment.request', 'category_id', copy=False) + maintenance_ids = fields.One2many('maintenance.request', 'category_id', copy=False) maintenance_count = fields.Integer(string="Maintenance", compute='_compute_maintenance_count') alias_id = fields.Many2one( 'mail.alias', 'Alias', ondelete='cascade', required=True, @@ -45,36 +46,49 @@ class HrEquipmentCategory(models.Model): @api.multi def _compute_equipment_count(self): - equipment_data = self.env['hr.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id']) + equipment_data = self.env['maintenance.equipment'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id']) mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in equipment_data]) for category in self: category.equipment_count = mapped_data.get(category.id, 0) @api.multi def _compute_maintenance_count(self): - maintenance_data = self.env['hr.equipment.request'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id']) + maintenance_data = self.env['maintenance.request'].read_group([('category_id', 'in', self.ids)], ['category_id'], ['category_id']) mapped_data = dict([(m['category_id'][0], m['category_id_count']) for m in maintenance_data]) for category in self: category.maintenance_count = mapped_data.get(category.id, 0) @api.model def create(self, vals): - self = self.with_context(alias_model_name='hr.equipment.request', alias_parent_model_name=self._name) - category_id = super(HrEquipmentCategory, self).create(vals) + self = self.with_context(alias_model_name='maintenance.request', alias_parent_model_name=self._name) + if not vals.get('alias_name'): + vals['alias_name'] = vals.get('name') + category_id = super(MaintenanceEquipmentCategory, self).create(vals) category_id.alias_id.write({'alias_parent_thread_id': category_id.id, 'alias_defaults': {'category_id': category_id.id}}) return category_id @api.multi def unlink(self): + MailAlias = self.env['mail.alias'] for category in self: if category.equipment_ids or category.maintenance_ids: raise UserError(_("You cannot delete an equipment category containing equipments or maintenance requests.")) - res = super(HrEquipmentCategory, self).unlink() + MailAlias += category.alias_id + res = super(MaintenanceEquipmentCategory, self).unlink() + MailAlias.unlink() return res + def get_alias_model_name(self, vals): + return vals.get('alias_model', 'maintenance.equipment') -class HrEquipment(models.Model): - _name = 'hr.equipment' + def get_alias_values(self): + values = super(MaintenanceEquipmentCategory, self).get_alias_values() + values['alias_defaults'] = {'category_id': self.id} + return values + + +class MaintenanceEquipment(models.Model): + _name = 'maintenance.equipment' _inherit = ['mail.thread'] _description = 'Equipment' @@ -83,7 +97,7 @@ class HrEquipment(models.Model): self.ensure_one() if 'owner_user_id' in init_values and self.owner_user_id: return 'maintenance.mt_mat_assign' - return super(HrEquipment, self)._track_subtype(init_values) + return super(MaintenanceEquipment, self)._track_subtype(init_values) @api.multi def name_get(self): @@ -105,11 +119,11 @@ class HrEquipment(models.Model): recs = self.search([('name', operator, name)] + args, limit=limit) return recs.name_get() - name = fields.Char('Asset Name', required=True, translate=True) + name = fields.Char('Equipment Name', required=True, translate=True) active = fields.Boolean(default=True) - user_id = fields.Many2one('res.users', string='Technician', track_visibility='onchange') + technician_user_id = fields.Many2one('res.users', string='Technician', track_visibility='onchange', oldname='user_id') owner_user_id = fields.Many2one('res.users', string='Owner', track_visibility='onchange') - category_id = fields.Many2one('hr.equipment.category', string='Asset Category', track_visibility='onchange') + category_id = fields.Many2one('maintenance.equipment.category', string='Equipment Category', track_visibility='onchange') partner_id = fields.Many2one('res.partner', string='Vendor', domain="[('supplier', '=', 1)]") partner_ref = fields.Char('Vendor Reference') location = fields.Char('Location') @@ -121,9 +135,24 @@ class HrEquipment(models.Model): warranty = fields.Date('Warranty') color = fields.Integer('Color Index') scrap_date = fields.Date('Scrap Date') - maintenance_ids = fields.One2many('hr.equipment.request', 'equipment_id') + maintenance_ids = fields.One2many('maintenance.request', 'equipment_id') maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Maintenance", store=True) maintenance_open_count = fields.Integer(compute='_compute_maintenance_count', string="Current Maintenance", store=True) + period = fields.Integer('Days between each preventive maintenance') + next_action_date = fields.Date(compute='_compute_next_maintenance', string='Date of the next preventive maintenance', store=True) + maintenance_team_id = fields.Many2one('maintenance.team', string='Maintenance Team') + maintenance_duration = fields.Float(help="Maintenance Duration in minutes and seconds.") + + @api.depends('period', 'maintenance_open_count', 'maintenance_ids.request_date') + def _compute_next_maintenance(self): + for equipment in self: + create_date = equipment.create_date and datetime.strptime(equipment.create_date, DEFAULT_SERVER_DATETIME_FORMAT) + if equipment.period: + next_date = create_date + if equipment.maintenance_ids: + maintenance = equipment.maintenance_ids.sorted(lambda x: x.request_date)[0] + next_date = maintenance.request_date and datetime.strptime(maintenance.request_date, DEFAULT_SERVER_DATE_FORMAT) or create_date + equipment.next_action_date = next_date and (next_date + timedelta(days=equipment.period)).strftime(DEFAULT_SERVER_DATE_FORMAT) @api.one @api.depends('maintenance_ids.stage_id.done') @@ -133,7 +162,7 @@ class HrEquipment(models.Model): @api.onchange('category_id') def _onchange_category_id(self): - self.user_id = self.category_id.user_id + self.technician_user_id = self.category_id.technician_user_id _sql_constraints = [ ('serial_no', 'unique(serial_no)', "Another asset already exists with this serial number!"), @@ -141,23 +170,23 @@ class HrEquipment(models.Model): @api.model def create(self, vals): - equipment = super(HrEquipment, self).create(vals) + equipment = super(MaintenanceEquipment, self).create(vals) if equipment.owner_user_id: - equipment.message_subscribe_users(user_ids=equipment.owner_user_id.id) + equipment.message_subscribe_users(user_ids=[equipment.owner_user_id.id]) return equipment @api.multi def write(self, vals): if vals.get('owner_user_id'): self.message_subscribe_users(user_ids=[vals['owner_user_id']]) - return super(HrEquipment, self).write(vals) + return super(MaintenanceEquipment, self).write(vals) @api.multi def _read_group_category_ids(self, domain, read_group_order=None, access_rights_uid=None): """ Read group customization in order to display all the category in the kanban view, even if they are empty """ - category_obj = self.env['hr.equipment.category'] + category_obj = self.env['maintenance.equipment.category'] order = category_obj._order access_rights_uid = access_rights_uid or self._uid if read_group_order == 'category_id desc': @@ -173,20 +202,32 @@ class HrEquipment(models.Model): fold[category.id] = category.fold return result, fold + @api.model + def _cron_generate_requests(self): + for equipment in self.search([]): + if equipment.period and equipment.next_action_date == date.today().strftime(DEFAULT_SERVER_DATE_FORMAT): + self.env['maintenance.request'].create({ + 'name': _('Preventive Maintenance - %s' % equipment.next_action_date), + 'request_date': equipment.next_action_date, + 'category_id': equipment.category_id.id, + 'equipment_id': equipment.id, + 'maintenance_type': 'preventive', + }) + _group_by_full = { 'category_id': _read_group_category_ids } -class HrEquipmentRequest(models.Model): - _name = 'hr.equipment.request' +class MaintenanceRequest(models.Model): + _name = 'maintenance.request' _inherit = ['mail.thread'] _description = 'Maintenance Requests' _order = "id desc" @api.returns('self') def _default_stage(self): - return self.env['hr.equipment.stage'].search([], limit=1) + return self.env['maintenance.stage'].search([], limit=1) @api.multi def _track_subtype(self, init_values): @@ -195,50 +236,65 @@ class HrEquipmentRequest(models.Model): return 'maintenance.mt_req_created' elif 'stage_id' in init_values and self.stage_id.sequence > 1: return 'maintenance.mt_req_status' - return super(HrEquipmentRequest, self)._track_subtype(init_values) + return super(MaintenanceRequest, self)._track_subtype(init_values) + + def _get_default_team_id(self): + return self.env.ref('maintenance.equipment_team_maintenance', raise_if_not_found=False) name = fields.Char('Subjects', required=True) description = fields.Text('Description') request_date = fields.Date('Request Date', track_visibility='onchange', default=fields.Date.context_today) + owner_user_id = fields.Many2one('res.users', string='Created by', default=lambda s: s.env.uid) - category_id = fields.Many2one('hr.equipment.category', string='Category') - equipment_id = fields.Many2one('hr.equipment', string='Asset', select=True) - user_id = fields.Many2one('res.users', string='Assigned to', track_visibility='onchange') - stage_id = fields.Many2one('hr.equipment.stage', string='Stage', track_visibility='onchange', default=_default_stage) + category_id = fields.Many2one('maintenance.equipment.category', related='equipment_id.category_id', string='Category', store=True, readonly=True) + equipment_id = fields.Many2one('maintenance.equipment', string='Equipment', select=True) + technician_user_id = fields.Many2one('res.users', string='Owner', track_visibility='onchange', oldname='user_id') + stage_id = fields.Many2one('maintenance.stage', string='Stage', track_visibility='onchange', default=_default_stage) priority = fields.Selection([('0', 'Very Low'), ('1', 'Low'), ('2', 'Normal'), ('3', 'High')], string='Priority') color = fields.Integer('Color Index') close_date = fields.Date('Close Date') kanban_state = fields.Selection([('normal', 'In Progress'), ('blocked', 'Blocked'), ('done', 'Ready for next stage')], string='Kanban State', required=True, default='normal', track_visibility='onchange') - active = fields.Boolean(default=True, help="Set active to false to hide the maintenance request without deleting it.") + # active = fields.Boolean(default=True, help="Set active to false to hide the maintenance request without deleting it.") + archive = fields.Boolean(default=False, help="Set archive to true to hide the maintenance request without deleting it.") + maintenance_type = fields.Selection([('corrective', 'Corrective'), ('preventive', 'Preventive')], string='Maintenance Type', default="corrective") + schedule_date = fields.Datetime('Scheduled Date') + maintenance_team_id = fields.Many2one('maintenance.team', string='Team', required=True, default=_get_default_team_id) + duration = fields.Float(help="Duration in minutes and seconds.") @api.multi def archive_equipment_request(self): - self.write({'active': False}) + self.write({'archive': True}) @api.multi def reset_equipment_request(self): - """ Reinsert the equipment request into the maintenance pipe in the first stage""" - first_stage_obj = self.env['hr.equipment.stage'].search([], order="sequence asc", limit=1) - self.write({'active': True, 'stage_id': first_stage_obj.id}) + """ Reinsert the maintenance request into the maintenance pipe in the first stage""" + first_stage_obj = self.env['maintenance.stage'].search([], order="sequence asc", limit=1) + # self.write({'active': True, 'stage_id': first_stage_obj.id}) + self.write({'archive': False, 'stage_id': first_stage_obj.id}) @api.onchange('equipment_id') def onchange_equipment_id(self): - self.user_id = self.equipment_id.user_id if self.equipment_id.user_id else self.equipment_id.category_id.user_id - self.category_id = self.equipment_id.category_id + if self.equipment_id: + self.technician_user_id = self.equipment_id.technician_user_id if self.equipment_id.technician_user_id else self.equipment_id.category_id.technician_user_id + self.category_id = self.equipment_id.category_id + if self.equipment_id.maintenance_team_id: + self.maintenance_team_id = self.equipment_id.maintenance_team_id.id @api.onchange('category_id') def onchange_category_id(self): - if not self.user_id or not self.equipment_id or (self.user_id and not self.equipment_id.user_id): - self.user_id = self.category_id.user_id + if not self.technician_user_id or not self.equipment_id or (self.technician_user_id and not self.equipment_id.technician_user_id): + self.technician_user_id = self.category_id.technician_user_id @api.model def create(self, vals): # context: no_log, because subtype already handle this self = self.with_context(mail_create_nolog=True) - request = super(HrEquipmentRequest, self).create(vals) + request = super(MaintenanceRequest, self).create(vals) if request.owner_user_id: request.message_subscribe_users(user_ids=[request.owner_user_id.id]) + if request.equipment_id and not request.maintenance_team_id: + request.maintenance_team_id = request.equipment_id.maintenance_team_id return request @api.multi @@ -249,14 +305,17 @@ class HrEquipmentRequest(models.Model): vals['kanban_state'] = 'normal' if vals.get('owner_user_id'): self.message_subscribe_users(user_ids=[vals['owner_user_id']]) - return super(HrEquipmentRequest, self).write(vals) + res = super(MaintenanceRequest, self).write(vals) + if self.stage_id.done and 'stage_id' in vals: + self.write({'close_date': fields.Date.today()}) + return res @api.multi def _read_group_stage_ids(self, domain, read_group_order=None, access_rights_uid=None): """ Read group customization in order to display all the stages in the kanban view, even if they are empty """ - stage_obj = self.env['hr.equipment.stage'] + stage_obj = self.env['maintenance.stage'] order = stage_obj._order access_rights_uid = access_rights_uid or self._uid @@ -277,3 +336,35 @@ class HrEquipmentRequest(models.Model): _group_by_full = { 'stage_id': _read_group_stage_ids } + + +class MaintenanceTeam(models.Model): + _name = 'maintenance.team' + _description = 'Maintenance Teams' + + name = fields.Char(required=True) + partner_id = fields.Many2one('res.partner', string='Subcontracting Partner') + color = fields.Integer(default=0) + request_ids = fields.One2many('maintenance.request', 'maintenance_team_id', copy=False) + equipment_ids = fields.One2many('maintenance.equipment', 'maintenance_team_id', copy=False) + + # For the dashboard only + todo_request_ids = fields.One2many('maintenance.request', copy=False, compute='_compute_todo_requests') + todo_request_count = fields.Integer(compute='_compute_todo_requests') + todo_request_count_date = fields.Integer(compute='_compute_todo_requests') + todo_request_count_high_priority = fields.Integer(compute='_compute_todo_requests') + todo_request_count_block = fields.Integer(compute='_compute_todo_requests') + + @api.one + @api.depends('todo_request_ids.stage_id.done') + def _compute_todo_requests(self): + self.todo_request_ids = self.request_ids.filtered(lambda e: e.stage_id.done==False) + self.todo_request_count = len(self.todo_request_ids) + self.todo_request_count_date = len(self.todo_request_ids.filtered(lambda e: e.schedule_date != False)) + self.todo_request_count_high_priority = len(self.todo_request_ids.filtered(lambda e: e.priority == '3')) + self.todo_request_count_block = len(self.todo_request_ids.filtered(lambda e: e.kanban_state == 'blocked')) + + @api.one + @api.depends('equipment_ids') + def _compute_equipment(self): + self.equipment_count = len(self.equipment_ids) diff --git a/addons/maintenance/models/maintenance_config_settings.py b/addons/maintenance/models/maintenance_config_settings.py deleted file mode 100644 index a029e45eab7..00000000000 --- a/addons/maintenance/models/maintenance_config_settings.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -from urlparse import urlsplit -from openerp import api, fields, models - - -class HrEquipmentConfigSettings(models.TransientModel): - _name = 'hr.equipment.config.settings' - _inherit = 'res.config.settings' - - equipment_alias_prefix = fields.Char('Use the following alias to report internal equipment issue') - alias_domain = fields.Char("Alias Domain") - - @api.model - def get_default_alias_equipment(self, fields): - alias_name = False - alias_id = self.env.ref('hr_equipment.mail_alias_equipment') - if alias_id: - alias_name = alias_id.alias_name - return {'equipment_alias_prefix': alias_name} - - @api.multi - def set_default_alias_equipment(self): - for record in self: - default_equipment_alias_prefix = record.get_default_alias_equipment()['equipment_alias_prefix'] - if record.equipment_alias_prefix != default_equipment_alias_prefix: - alias_id = self.env.ref('hr_equipment.mail_alias_equipment') - if alias_id: - alias_id.write({'alias_name': record.equipment_alias_prefix}) - return True - - @api.model - def get_default_alias_domain(self, fields): - alias_domain = self.env['ir.config_parameter'].get_param("mail.catchall.domain") - if not alias_domain: - domain = self.env["ir.config_parameter"].get_param("web.base.url") - try: - alias_domain = urlsplit(domain).netloc.split(':')[0] - except Exception: - pass - return {'alias_domain': alias_domain} - diff --git a/addons/maintenance/security/ir.model.access.csv b/addons/maintenance/security/ir.model.access.csv index 3748c9f79bb..8788384fa4f 100644 --- a/addons/maintenance/security/ir.model.access.csv +++ b/addons/maintenance/security/ir.model.access.csv @@ -1,10 +1,9 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_hr_equipment_user,hr.equipment.user,model_hr_equipment,base.group_hr_user,1,1,1,1 -access_hr_equipment_emp,hr.equipment.emp,model_hr_equipment,base.group_user,1,0,0,0 -access_hr_equipment_admin_user,hr.equipment.admin.user,model_hr_equipment,base.group_equipment_manager,1,1,1,1 -access_hr_maintenance_user,hr.equipment.request user,model_hr_equipment_request,base.group_hr_user,1,1,1,1 -access_hr_maintenance_system_user,hr.equipment.request system user,model_hr_equipment_request,base.group_user,1,1,1,1 -access_hr_equipment_category_user,hr.equipment.category.user,model_hr_equipment_category,base.group_hr_user,1,1,1,1 -access_maintenance_request_stage_user,hr.equipment.stage.user,model_hr_equipment_stage,base.group_hr_user,1,1,1,1 -access_hr_equipment_category_employee,hr.equipment.category.employee,model_hr_equipment_category,base.group_user,1,0,0,0 -access_maintenance_request_stage_employee,hr.equipment.stage.employee,model_hr_equipment_stage,base.group_user,1,0,0,0 +access_equipment_user,equipment.user,model_maintenance_equipment,base.group_user,1,0,0,0 +access_equipment_admin_user,equipment.admin.user,model_maintenance_equipment,base.group_equipment_manager,1,1,1,1 +access_maintenance_system_user,equipment.request system user,model_maintenance_request,base.group_user,1,1,1,1 +access_equipment_category_user,equipment.category.user,model_maintenance_equipment_category,base.group_user,1,0,0,0 +access_equipment_category_admin_user,equipment.category system user,model_maintenance_equipment_category,base.group_equipment_manager,1,1,1,1 +access_maintenance_stage_user,maintenance.stage.user,model_maintenance_stage,base.group_user,1,0,0,0 +access_maintenance_stage_admin_user,equipment.request.stage system user,model_maintenance_stage,base.group_equipment_manager,1,1,1,1 +access_maintenance_team_user,maintenance.team.user,model_maintenance_team,base.group_user,1,0,0,0 \ No newline at end of file diff --git a/addons/maintenance/security/maintenance.xml b/addons/maintenance/security/maintenance.xml index b52aebd5346..313548b8a17 100644 --- a/addons/maintenance/security/maintenance.xml +++ b/addons/maintenance/security/maintenance.xml @@ -1,9 +1,6 @@ - + Equipment Manager @@ -11,36 +8,31 @@ The user will be able to manage equipments. - - - - - - - Employees are allowed to access their own maintenance requests - - ['|', ('user_id.id', '=', user.id), ('employee_id.user_id.id', '=', user.id)] + + Users are allowed to access their own maintenance requests + + ['|', ('owner_user_id.id', '=', user.id), ('technician_user_id.id', '=', user.id)] - - Employees are allowed to access their own equipments - - [('employee_id.user_id.id', '=', user.id)] + + Users are allowed to access their own equipments + + [('owner_user_id.id', '=', user.id)] - + Administrator of maintenance requests - + [(1, '=', 1)] - + Equipments administrator - + [(1, '=', 1)] diff --git a/addons/maintenance/static/src/less/maintenance_team_dashboard.less b/addons/maintenance/static/src/less/maintenance_team_dashboard.less new file mode 100644 index 00000000000..36ce517166f --- /dev/null +++ b/addons/maintenance/static/src/less/maintenance_team_dashboard.less @@ -0,0 +1,8 @@ +.o_kanban_view.o_kanban_dashboard.o_maintenance_team_kanban { + .o_kanban_record { + min-height: 250px; + @media (min-width: @screen-sm-min) { + min-width: 420px; + } + } +} \ No newline at end of file diff --git a/addons/maintenance/tests/test_maintenance.py b/addons/maintenance/tests/test_maintenance.py index 6660260ac90..5935b012996 100644 --- a/addons/maintenance/tests/test_maintenance.py +++ b/addons/maintenance/tests/test_maintenance.py @@ -4,45 +4,44 @@ from openerp.tests.common import TransactionCase import time -class TestHrEquipment(TransactionCase): +class TestEquipment(TransactionCase): """ Test used to check that when doing equipment/maintenance_request/equipment_category creation.""" def setUp(self): - super(TestHrEquipment, self).setUp() - self.equipment = self.env['hr.equipment'] - self.maintenance_request = self.env['hr.equipment.request'] - self.user = self.env['res.users'] + super(TestEquipment, self).setUp() + self.equipment = self.env['maintenance.equipment'] + self.maintenance_request = self.env['maintenance.request'] + self.res_users = self.env['res.users'] self.main_company = self.env.ref('base.main_company') - res_hr_user = self.env.ref('base.group_user') - res_hr_manager = self.env.ref('base.group_hr_manager') + res_user = self.env.ref('base.group_user') + res_manager = self.env.ref('base.group_equipment_manager') - self.hr_user = self.user.create(dict( + self.user = self.res_users.create(dict( name="Normal User/Employee", company_id=self.main_company.id, login="emp", password="emp", email="empuser@yourcompany.example.com", - groups_id=[(6, 0, [res_hr_user.id])] + groups_id=[(6, 0, [res_user.id])] )) - self.env.ref('hr.employee_qdp').write({'user_id': self.hr_user.id}) - self.hr_manager = self.user.create(dict( - name="HR Manager", + self.manager = self.res_users.create(dict( + name="Equipment Manager", company_id=self.main_company.id, login="hm", password="hm", - email="hrmanager@yourcompany.example.com", - groups_id=[(6, 0, [res_hr_manager.id])] + email="eqmanager@yourcompany.example.com", + groups_id=[(6, 0, [res_manager.id])] )) - def test_hr_equipment_request_category(self): + def test_equipment_request_category(self): # Create a new equipment - equipment_01 = self.equipment.sudo(self.hr_manager).create({ + equipment_01 = self.equipment.sudo(self.manager).create({ 'name': 'Samsung Monitor "15', - 'category_id': self.ref('hr_equipment.hr_equipment_monitor'), - 'employee_id': self.ref('hr.employee_qdp'), - 'user_id': self.ref('base.user_root'), + 'category_id': self.ref('maintenance.equipment_monitor'), + 'technician_user_id': self.ref('base.user_root'), + 'owner_user_id': self.user.id, 'assign_date': time.strftime('%Y-%m-%d'), 'serial_no': 'MT/127/18291015', 'model': 'NP355E5X', @@ -53,24 +52,24 @@ class TestHrEquipment(TransactionCase): assert equipment_01, "Equipment not created" # Create new maintenance request - maintenance_request_01 = self.maintenance_request.sudo(self.hr_user).create({ + maintenance_request_01 = self.maintenance_request.sudo(self.user).create({ 'name': 'Resolution is bad', - 'user_id': self.hr_user.id, - 'employee_id': self.ref('hr.employee_qdp'), + 'technician_user_id': self.user.id, + 'owner_user_id': self.user.id, 'equipment_id': equipment_01.id, - 'category_id': self.ref('hr_equipment.hr_equipment_monitor'), 'color': 7, - 'stage_id': self.ref('hr_equipment.stage_0') + 'stage_id': self.ref('maintenance.stage_0'), + 'maintenance_team_id': self.ref('maintenance.equipment_team_maintenance') }) # I check that maintenance_request is created or not assert maintenance_request_01, "Maintenance Request not created" # I check that Initially maintenance request is in the "New Request" stage - self.assertEquals(maintenance_request_01.stage_id.id, self.ref('hr_equipment.stage_0')) + self.assertEquals(maintenance_request_01.stage_id.id, self.ref('maintenance.stage_0')) # I check that change the maintenance_request stage on click statusbar - maintenance_request_01.sudo(self.hr_user).write({'stage_id': self.ref('hr_equipment.stage_1')}) + maintenance_request_01.sudo(self.user).write({'stage_id': self.ref('maintenance.stage_1')}) # I check that maintenance request is in the "In Progress" stage - self.assertEquals(maintenance_request_01.stage_id.id, self.ref('hr_equipment.stage_1')) + self.assertEquals(maintenance_request_01.stage_id.id, self.ref('maintenance.stage_1')) diff --git a/addons/maintenance/views/maintenance_config_settings_views.xml b/addons/maintenance/views/maintenance_config_settings_views.xml deleted file mode 100644 index 5b61b8b536d..00000000000 --- a/addons/maintenance/views/maintenance_config_settings_views.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - hr.equipment.config.settings - hr.equipment.config.settings - -
-
-
- - -
-
-
- - - Configure Equipments - hr.equipment.config.settings - - form - inline - -
diff --git a/addons/maintenance/views/maintenance_templates.xml b/addons/maintenance/views/maintenance_templates.xml new file mode 100644 index 00000000000..09b86b5af4e --- /dev/null +++ b/addons/maintenance/views/maintenance_templates.xml @@ -0,0 +1,8 @@ + + + + diff --git a/addons/maintenance/views/maintenance_views.xml b/addons/maintenance/views/maintenance_views.xml index f4b8adb4498..26071d62091 100644 --- a/addons/maintenance/views/maintenance_views.xml +++ b/addons/maintenance/views/maintenance_views.xml @@ -1,18 +1,27 @@ - + - hr.equipment.request.search - hr.equipment.request + equipment.request.search + maintenance.request - + + + + + + + + + + @@ -20,7 +29,7 @@ - + @@ -30,22 +39,22 @@ - hr.equipment.request.form - hr.equipment.request + equipment.request.form + maintenance.request
-
-
- +
+ Canceled +
+
+
-
@@ -319,17 +404,17 @@ - hr.equipment.tree - hr.equipment + equipment.tree + maintenance.equipment - + - + - + @@ -337,8 +422,8 @@ - hr.equipment.search - hr.equipment + equipment.search + maintenance.equipment @@ -353,9 +438,9 @@ - + - + @@ -366,7 +451,7 @@ Equipments - hr.equipment + maintenance.equipment kanban,tree,form @@ -381,10 +466,10 @@ - + Equipments - hr.equipment + maintenance.equipment kanban,tree,form @@ -403,10 +488,10 @@ - + - hr.equipment.category.form - hr.equipment.category + equipment.category.form + maintenance.equipment.category @@ -432,7 +517,7 @@ - + - hr.equipment.category.tree - hr.equipment.category + equipment.category.tree + maintenance.equipment.category - + - + - hr.equipment.category.search - hr.equipment.category + equipment.category.search + maintenance.equipment.category - + - + Equipment Categories - hr.equipment.category + maintenance.equipment.category tree,form @@ -491,10 +576,10 @@ - + - hr.equipment.stage.search - hr.equipment.stage + equipment.stage.search + maintenance.stage @@ -503,8 +588,8 @@ - hr.equipment.stage.tree - hr.equipment.stage + equipment.stage.tree + maintenance.stage @@ -515,10 +600,10 @@ - + Stages - hr.equipment.stage + maintenance.stage tree form @@ -529,59 +614,263 @@ + + + maintenance.team.form + maintenance.team + + + +
+
+ +
+ +
+
+ + + maintenance.team.tree + maintenance.team + + + + + + + + + maintenance.team.kanban + maintenance.team + + + + + + + + + + + +
+
+
+
+
+
+ More +
+
+
+
+
+ +
+
+
+ +
+ +
+ +
+ +
+ +
+ +
+
+
+
+
+
+
+
+ View +
+ + + + +
+
+
+ Reports +
+
+
+
+
+
    +
+
+ Settings +
+
+
+
+
+
+
+
+
+ + + + Teams + maintenance.team + tree + form + + +

+ Click to add a team in the maintenance request. +

+
+
+ + + Maintenance Teams + maintenance.team + kanban,form + form + +

+ Click to add a stage in the maintenance request. +

+
+
+ + id="menu_m_dashboard" + name="Dashboard" + parent="menu_maintenance_title" + groups="base.group_equipment_manager,base.group_user" + action="maintenance_dashboard_action" + sequence="0"/> + + + + + + + + + id="menu_m_reports_losses" + name="Losses Analysis" + parent="menu_m_reports" + groups="base.group_equipment_manager,base.group_user" + sequence="2"/> + + + + + sequence="2"/> + sequence="3" />