Files
odoo_source/addons/maintenance/models/maintenance.py
T

371 lines
18 KiB
Python

# -*- coding: utf-8 -*-
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 MaintenanceStage(models.Model):
""" Model for case stages. This models the main stages of a Maintenance Request management flow. """
_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 Maintenance Pipe')
done = fields.Boolean('Request Done')
class MaintenanceEquipmentCategory(models.Model):
_name = 'maintenance.equipment.category'
_inherit = ['mail.alias.mixin', 'mail.thread']
_description = 'Asset Category'
@api.one
@api.depends('equipment_ids')
def _compute_fold(self):
self.fold = False if self.equipment_count else True
name = fields.Char('Category Name', required=True, translate=True)
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('maintenance.equipment', 'category_id', string='Equipments', copy=False)
equipment_count = fields.Integer(string="Equipment", compute='_compute_equipment_count')
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,
help="Email alias for this equipment category. New emails will automatically "
"create new maintenance request for this equipment category.")
fold = fields.Boolean(string='Folded in Maintenance Pipe', compute='_compute_fold', store=True)
@api.multi
def _compute_equipment_count(self):
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['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='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."))
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')
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'
@api.multi
def _track_subtype(self, init_values):
self.ensure_one()
if 'owner_user_id' in init_values and self.owner_user_id:
return 'maintenance.mt_mat_assign'
return super(MaintenanceEquipment, self)._track_subtype(init_values)
@api.multi
def name_get(self):
result = []
for record in self:
if record.name and record.serial_no:
result.append((record.id, record.name + '/' + record.serial_no))
if record.name and not record.serial_no:
result.append((record.id, record.name))
return result
@api.model
def name_search(self, name, args=None, operator='ilike', limit=100):
args = args or []
recs = self.browse()
if name:
recs = self.search([('name', '=', name)] + args, limit=limit)
if not recs:
recs = self.search([('name', operator, name)] + args, limit=limit)
return recs.name_get()
name = fields.Char('Equipment Name', required=True, translate=True)
active = fields.Boolean(default=True)
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('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')
model = fields.Char('Model')
serial_no = fields.Char('Serial Number', copy=False)
assign_date = fields.Date('Assigned Date', track_visibility='onchange')
cost = fields.Float('Cost')
note = fields.Text('Note')
warranty = fields.Date('Warranty')
color = fields.Integer('Color Index')
scrap_date = fields.Date('Scrap Date')
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')
def _compute_maintenance_count(self):
self.maintenance_count = len(self.maintenance_ids)
self.maintenance_open_count = len(self.maintenance_ids.filtered(lambda x: not x.stage_id.done))
@api.onchange('category_id')
def _onchange_category_id(self):
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!"),
]
@api.model
def create(self, vals):
equipment = super(MaintenanceEquipment, self).create(vals)
if equipment.owner_user_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(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['maintenance.equipment.category']
order = category_obj._order
access_rights_uid = access_rights_uid or self._uid
if read_group_order == 'category_id desc':
order = '%s desc' % order
category_ids = category_obj._search([], order=order, access_rights_uid=access_rights_uid)
result = [category.name_get()[0] for category in category_obj.browse(category_ids)]
# restore order of the search
result.sort(lambda x, y: cmp(category_ids.index(x[0]), category_ids.index(y[0])))
fold = {}
for category in category_obj.browse(category_ids):
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 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['maintenance.stage'].search([], limit=1)
@api.multi
def _track_subtype(self, init_values):
self.ensure_one()
if 'stage_id' in init_values and self.stage_id.sequence <= 1:
return 'maintenance.mt_req_created'
elif 'stage_id' in init_values and self.stage_id.sequence > 1:
return 'maintenance.mt_req_status'
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('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.")
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({'archive': True})
@api.multi
def reset_equipment_request(self):
""" 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):
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.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(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
def write(self, vals):
# Overridden to reset the kanban_state to normal whenever
# the stage (stage_id) of the Maintenance Request changes.
if vals and 'kanban_state' not in vals and 'stage_id' in vals:
vals['kanban_state'] = 'normal'
if vals.get('owner_user_id'):
self.message_subscribe_users(user_ids=[vals['owner_user_id']])
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['maintenance.stage']
order = stage_obj._order
access_rights_uid = access_rights_uid or self._uid
if read_group_order == 'stage_id desc':
order = '%s desc' % order
stage_ids = stage_obj._search([], order=order, access_rights_uid=access_rights_uid)
result = [stage.name_get()[0] for stage in stage_obj.browse(stage_ids)]
# restore order of the search
result.sort(lambda x, y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
fold = {}
for stage in stage_obj.browse(stage_ids):
fold[stage.id] = stage.fold or False
return result, fold
_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('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)