19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:43 +01:00
parent 4607ccbd2e
commit 825ff6514e
487 changed files with 184979 additions and 195262 deletions

View file

@ -1,13 +1,10 @@
# -*- coding: utf-8 -*-
import ast
from datetime import date, datetime, timedelta
from odoo import api, fields, models, SUPERUSER_ID, _
from dateutil.relativedelta import relativedelta
from odoo.exceptions import ValidationError
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv import expression
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
class MaintenanceStage(models.Model):
@ -25,7 +22,6 @@ class MaintenanceStage(models.Model):
class MaintenanceEquipmentCategory(models.Model):
_name = 'maintenance.equipment.category'
_inherit = ['mail.alias.mixin', 'mail.thread']
_description = 'Maintenance Equipment Category'
@api.depends('equipment_ids')
@ -39,49 +35,81 @@ class MaintenanceEquipmentCategory(models.Model):
name = fields.Char('Category Name', required=True, translate=True)
company_id = fields.Many2one('res.company', string='Company',
default=lambda self: self.env.company)
technician_user_id = fields.Many2one('res.users', 'Responsible', tracking=True, default=lambda self: self.env.uid)
technician_user_id = fields.Many2one('res.users', 'Responsible', default=lambda self: self.env.uid)
color = fields.Integer('Color Index')
note = fields.Html('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')
equipment_ids = fields.One2many('maintenance.equipment', 'category_id', string='Equipment', copy=False)
equipment_count = fields.Integer(string="Equipment Count", compute='_compute_equipment_count')
maintenance_ids = fields.One2many('maintenance.request', 'category_id', copy=False)
maintenance_count = fields.Integer(string="Maintenance Count", compute='_compute_maintenance_count')
alias_id = fields.Many2one(
'mail.alias', 'Alias', ondelete='restrict', required=True,
help="Email alias for this equipment category. New emails will automatically "
"create a new equipment under this category.")
maintenance_open_count = fields.Integer(string="Current Maintenance", compute='_compute_maintenance_count')
fold = fields.Boolean(string='Folded in Maintenance Pipe', compute='_compute_fold', store=True)
equipment_properties_definition = fields.PropertiesDefinition('Equipment Properties')
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])
equipment_data = self.env['maintenance.equipment']._read_group([('category_id', 'in', self.ids)], ['category_id'], ['__count'])
mapped_data = {category.id: count for category, count in equipment_data}
for category in self:
category.equipment_count = mapped_data.get(category.id, 0)
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])
maintenance_data = self.env['maintenance.request']._read_group([('category_id', 'in', self.ids)], ['category_id', 'archive'], ['__count'])
mapped_data = {(category.id, archive): count for category, archive, count in maintenance_data}
for category in self:
category.maintenance_count = mapped_data.get(category.id, 0)
category.maintenance_open_count = mapped_data.get((category.id, False), 0)
category.maintenance_count = category.maintenance_open_count + mapped_data.get((category.id, True), 0)
@api.ondelete(at_uninstall=False)
def _unlink_except_contains_maintenance_requests(self):
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."))
raise UserError(_("You cant delete an equipment category if some equipment or maintenance requests are linked to it."))
def _alias_get_creation_values(self):
values = super(MaintenanceEquipmentCategory, self)._alias_get_creation_values()
values['alias_model_id'] = self.env['ir.model']._get('maintenance.request').id
if self.id:
values['alias_defaults'] = defaults = ast.literal_eval(self.alias_defaults or "{}")
defaults['category_id'] = self.id
return values
class MaintenanceMixin(models.AbstractModel):
_name = 'maintenance.mixin'
_check_company_auto = True
_description = 'Maintenance Maintained Item'
company_id = fields.Many2one('res.company', string='Company',
default=lambda self: self.env.company)
effective_date = fields.Date('Effective Date', default=fields.Date.context_today, required=True, help="This date will be used to compute the Mean Time Between Failure.")
maintenance_team_id = fields.Many2one('maintenance.team', string='Maintenance Team', compute='_compute_maintenance_team_id', store=True, readonly=False, check_company=True, index='btree_not_null')
technician_user_id = fields.Many2one('res.users', string='Technician', tracking=True)
maintenance_ids = fields.One2many('maintenance.request') # needs to be extended in order to specify inverse_name !
maintenance_count = fields.Integer(compute='_compute_maintenance_count', string="Maintenance Count", store=True)
maintenance_open_count = fields.Integer(compute='_compute_maintenance_count', string="Current Maintenance", store=True)
expected_mtbf = fields.Integer(string='Expected MTBF', help='Expected Mean Time Between Failure')
mtbf = fields.Integer(compute='_compute_maintenance_request', string='MTBF', help='Mean Time Between Failure, computed based on done corrective maintenances.')
mttr = fields.Integer(compute='_compute_maintenance_request', string='MTTR', help='Mean Time To Repair')
estimated_next_failure = fields.Date(compute='_compute_maintenance_request', string='Estimated time before next failure (in days)', help='Computed as Latest Failure Date + MTBF')
latest_failure_date = fields.Date(compute='_compute_maintenance_request', string='Latest Failure Date')
@api.depends('company_id')
def _compute_maintenance_team_id(self):
for record in self:
if record.maintenance_team_id.company_id and record.maintenance_team_id.company_id.id != record.company_id.id:
record.maintenance_team_id = False
@api.depends('effective_date', 'maintenance_ids.stage_id', 'maintenance_ids.close_date', 'maintenance_ids.request_date')
def _compute_maintenance_request(self):
for record in self:
maintenance_requests = record.maintenance_ids.filtered(lambda mr: mr.maintenance_type == 'corrective' and mr.stage_id.done)
record.mttr = len(maintenance_requests) and (sum(int((request.close_date - request.request_date).days) if request.close_date and request.request_date else 0 for request in maintenance_requests) / len(maintenance_requests)) or 0
record.latest_failure_date = max((request.request_date for request in maintenance_requests), default=False)
record.mtbf = record.latest_failure_date and (record.latest_failure_date - record.effective_date).days / len(maintenance_requests) or 0
record.estimated_next_failure = record.mtbf and record.latest_failure_date + relativedelta(days=record.mtbf) or False
@api.depends('maintenance_ids.stage_id.done', 'maintenance_ids.archive')
def _compute_maintenance_count(self):
for record in self:
record.maintenance_count = len(record.maintenance_ids)
record.maintenance_open_count = len(record.maintenance_ids.filtered(lambda mr: not mr.stage_id.done and not mr.archive))
class MaintenanceEquipment(models.Model):
_name = 'maintenance.equipment'
_inherit = ['mail.thread', 'mail.activity.mixin']
_inherit = ['mail.thread', 'mail.activity.mixin', 'maintenance.mixin']
_description = 'Maintenance Equipment'
_check_company_auto = True
@ -91,113 +119,40 @@ class MaintenanceEquipment(models.Model):
return self.env.ref('maintenance.mt_mat_assign')
return super(MaintenanceEquipment, self)._track_subtype(init_values)
def name_get(self):
result = []
@api.depends('serial_no')
def _compute_display_name(self):
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, name_get_uid=None):
args = args or []
equipment_ids = []
if name and operator not in expression.NEGATIVE_TERM_OPERATORS and operator != '=':
equipment_ids = self._search([('name', '=', name)] + args, limit=limit, access_rights_uid=name_get_uid)
return equipment_ids or super()._name_search(name, args, operator, limit, name_get_uid)
if record.serial_no:
record.display_name = (record.name or '') + '/' + record.serial_no
else:
record.display_name = record.name
name = fields.Char('Equipment Name', required=True, translate=True)
company_id = fields.Many2one('res.company', string='Company',
default=lambda self: self.env.company)
active = fields.Boolean(default=True)
technician_user_id = fields.Many2one('res.users', string='Technician', tracking=True)
owner_user_id = fields.Many2one('res.users', string='Owner', tracking=True)
owner_user_id = fields.Many2one('res.users', string='Owner', tracking=True, index='btree_not_null')
category_id = fields.Many2one('maintenance.equipment.category', string='Equipment Category',
tracking=True, group_expand='_read_group_category_ids')
tracking=True, group_expand='_read_group_category_ids', index='btree_not_null')
partner_id = fields.Many2one('res.partner', string='Vendor', check_company=True)
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', tracking=True)
effective_date = fields.Date('Effective Date', default=fields.Date.context_today, required=True, help="Date at which the equipment became effective. This date will be used to compute the Mean Time Between Failure.")
cost = fields.Float('Cost')
note = fields.Html('Note')
warranty_date = fields.Date('Warranty Expiration Date')
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 Count", 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', check_company=True, ondelete="restrict")
maintenance_duration = fields.Float(help="Maintenance Duration in hours.")
@api.depends('effective_date', 'period', 'maintenance_ids.request_date', 'maintenance_ids.close_date')
def _compute_next_maintenance(self):
date_now = fields.Date.context_today(self)
equipments = self.filtered(lambda x: x.period > 0)
for equipment in equipments:
next_maintenance_todo = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'),
('stage_id.done', '!=', True),
('close_date', '=', False)], order="request_date asc", limit=1)
last_maintenance_done = self.env['maintenance.request'].search([
('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'),
('stage_id.done', '=', True),
('close_date', '!=', False)], order="close_date desc", limit=1)
if next_maintenance_todo and last_maintenance_done:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - last_maintenance_done.close_date
# If the gap between the last_maintenance_done and the next_maintenance_todo one is bigger than 2 times the period and next request is in the future
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(days=equipment.period) * 2 and next_maintenance_todo.request_date > date_now:
# If the new date still in the past, we set it for today
if last_maintenance_done.close_date + timedelta(days=equipment.period) < date_now:
next_date = date_now
else:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.period)
elif next_maintenance_todo:
next_date = next_maintenance_todo.request_date
date_gap = next_maintenance_todo.request_date - date_now
# If next maintenance to do is in the future, and in more than 2 times the period, we insert an new request
# We use 2 times the period to avoid creation too closed request from a manually one created
if date_gap > timedelta(0) and date_gap > timedelta(days=equipment.period) * 2:
next_date = date_now + timedelta(days=equipment.period)
elif last_maintenance_done:
next_date = last_maintenance_done.close_date + timedelta(days=equipment.period)
# If when we add the period to the last maintenance done and we still in past, we plan it for today
if next_date < date_now:
next_date = date_now
else:
next_date = equipment.effective_date + timedelta(days=equipment.period)
equipment.next_action_date = next_date
(self - equipments).next_action_date = False
@api.depends('maintenance_ids.stage_id.done')
def _compute_maintenance_count(self):
for equipment in self:
equipment.maintenance_count = len(equipment.maintenance_ids)
equipment.maintenance_open_count = len(equipment.maintenance_ids.filtered(lambda x: not x.stage_id.done))
@api.onchange('company_id')
def _onchange_company_id(self):
if self.company_id and self.maintenance_team_id:
if self.maintenance_team_id.company_id and not self.maintenance_team_id.company_id.id == self.company_id.id:
self.maintenance_team_id = False
equipment_properties = fields.Properties('Properties', definition='category_id.equipment_properties_definition', copy=True)
@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!"),
]
_serial_no = models.Constraint(
'unique(serial_no)',
'Another asset already exists with this serial number!',
)
@api.model_create_multi
def create(self, vals_list):
@ -213,48 +168,15 @@ class MaintenanceEquipment(models.Model):
return super(MaintenanceEquipment, self).write(vals)
@api.model
def _read_group_category_ids(self, categories, domain, order):
def _read_group_category_ids(self, categories, domain):
""" Read group customization in order to display all the categories in
the kanban view, even if they are empty.
"""
category_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
# bypass ir.model.access checks, but search with ir.rules
search_domain = self.env['ir.rule']._compute_domain(categories._name)
category_ids = categories.sudo()._search(search_domain, order=categories._order)
return categories.browse(category_ids)
def _prepare_maintenance_request_vals(self, date):
self.ensure_one()
return {
'name': _('Preventive Maintenance - %s', self.name),
'request_date': date,
'schedule_date': date,
'category_id': self.category_id.id,
'equipment_id': self.id,
'maintenance_type': 'preventive',
'owner_user_id': self.owner_user_id.id,
'user_id': self.technician_user_id.id,
'maintenance_team_id': self.maintenance_team_id.id,
'duration': self.maintenance_duration,
'company_id': self.company_id.id or self.env.company.id
}
def _create_new_request(self, date):
self.ensure_one()
vals = self._prepare_maintenance_request_vals(date)
maintenance_requests = self.env['maintenance.request'].create(vals)
return maintenance_requests
@api.model
def _cron_generate_requests(self):
"""
Generates maintenance request on the next_action_date or today if none exists
"""
for equipment in self.search([('period', '>', 0)]):
next_requests = self.env['maintenance.request'].search([('stage_id.done', '=', False),
('equipment_id', '=', equipment.id),
('maintenance_type', '=', 'preventive'),
('request_date', '=', equipment.next_action_date)])
if not next_requests:
equipment._create_new_request(equipment.next_action_date)
class MaintenanceRequest(models.Model):
_name = 'maintenance.request'
@ -263,7 +185,6 @@ class MaintenanceRequest(models.Model):
_order = "id desc"
_check_company_auto = True
@api.returns('self')
def _default_stage(self):
return self.env['maintenance.stage'].search([], limit=1)
@ -284,16 +205,16 @@ class MaintenanceRequest(models.Model):
return team.id
name = fields.Char('Subjects', required=True)
company_id = fields.Many2one('res.company', string='Company',
company_id = fields.Many2one('res.company', string='Company', required=True,
default=lambda self: self.env.company)
description = fields.Html('Description')
request_date = fields.Date('Request Date', tracking=True, default=fields.Date.context_today,
help="Date requested for the maintenance to happen")
owner_user_id = fields.Many2one('res.users', string='Created by User', default=lambda s: s.env.uid)
category_id = fields.Many2one('maintenance.equipment.category', related='equipment_id.category_id', string='Category', store=True, readonly=True)
category_id = fields.Many2one('maintenance.equipment.category', related='equipment_id.category_id', string='Category', store=True, readonly=True, index='btree_not_null')
equipment_id = fields.Many2one('maintenance.equipment', string='Equipment',
ondelete='restrict', index=True, check_company=True)
user_id = fields.Many2one('res.users', string='Technician', tracking=True)
user_id = fields.Many2one('res.users', string='Technician', compute='_compute_user_id', store=True, readonly=False, tracking=True)
stage_id = fields.Many2one('maintenance.stage', string='Stage', ondelete='restrict', tracking=True,
group_expand='_read_group_stage_ids', default=_default_stage, copy=False)
priority = fields.Selection([('0', 'Very Low'), ('1', 'Low'), ('2', 'Normal'), ('3', 'High')], string='Priority')
@ -305,12 +226,37 @@ class MaintenanceRequest(models.Model):
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', help="Date the maintenance team plans the maintenance. It should not differ much from the Request Date. ")
maintenance_team_id = fields.Many2one('maintenance.team', string='Team', required=True, default=_get_default_team_id, check_company=True)
duration = fields.Float(help="Duration in hours.")
schedule_end = fields.Datetime(
string="Scheduled End", compute='_compute_schedule_end',
help="Expected completion date and time of the maintenance request.",
readonly=False, store=True)
maintenance_team_id = fields.Many2one('maintenance.team', string='Team', required=True, index=True, default=_get_default_team_id,
compute='_compute_maintenance_team_id', store=True, readonly=False, check_company=True)
duration = fields.Float(help="Duration in hours.", compute='_compute_duration', store=True)
done = fields.Boolean(related='stage_id.done')
instruction_type = fields.Selection([
('pdf', 'PDF'), ('google_slide', 'Google Slide'), ('text', 'Text')],
string="Instruction", default="text"
)
instruction_pdf = fields.Binary('PDF')
instruction_google_slide = fields.Char('Google Slide', help="Paste the url of your Google Slide. Make sure the access to the document is public.")
instruction_text = fields.Html('Text')
recurring_maintenance = fields.Boolean(string="Recurrent", compute='_compute_recurring_maintenance', store=True, readonly=False)
repeat_interval = fields.Integer(string='Repeat Every', default=1)
repeat_unit = fields.Selection([
('day', 'Days'),
('week', 'Weeks'),
('month', 'Months'),
('year', 'Years'),
], default='week')
repeat_type = fields.Selection([
('forever', 'Forever'),
('until', 'Until'),
], default="forever", string="Until")
repeat_until = fields.Date(string="End Date")
def archive_equipment_request(self):
self.write({'archive': True})
self.write({'archive': True, 'recurring_maintenance': False})
def reset_equipment_request(self):
""" Reinsert the maintenance request into the maintenance pipe in the first stage"""
@ -318,24 +264,53 @@ class MaintenanceRequest(models.Model):
# self.write({'active': True, 'stage_id': first_stage_obj.id})
self.write({'archive': False, 'stage_id': first_stage_obj.id})
@api.onchange('company_id')
def _onchange_company_id(self):
if self.company_id and self.maintenance_team_id:
if self.maintenance_team_id.company_id and not self.maintenance_team_id.company_id.id == self.company_id.id:
self.maintenance_team_id = False
@api.constrains('schedule_end')
def _check_schedule_end(self):
for request in self:
if request.schedule_date and request.schedule_end and request.schedule_date > request.schedule_end:
raise ValidationError(self.env._("End date cannot be earlier than start date."))
@api.onchange('equipment_id')
def onchange_equipment_id(self):
if self.equipment_id:
self.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.depends('schedule_date')
def _compute_schedule_end(self):
for request in self:
request.schedule_end = request.schedule_date and request.schedule_date + relativedelta(hours=1)
@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.technician_user_id):
self.user_id = self.category_id.technician_user_id
@api.depends('schedule_date', 'schedule_end')
def _compute_duration(self):
for request in self:
if request.schedule_date and request.schedule_end:
duration = (request.schedule_end - request.schedule_date).total_seconds() / 3600
request.duration = round(duration, 2)
else:
request.duration = 0
@api.constrains('repeat_interval')
def _check_repeat_interval(self):
for record in self:
if record.repeat_interval < 1:
raise ValidationError(self.env._("The repeat interval cannot be less than 1."))
@api.depends('company_id', 'equipment_id')
def _compute_maintenance_team_id(self):
for request in self:
if request.equipment_id and request.equipment_id.maintenance_team_id:
request.maintenance_team_id = request.equipment_id.maintenance_team_id.id
if request.maintenance_team_id.company_id and request.maintenance_team_id.company_id.id != request.company_id.id:
request.maintenance_team_id = False
@api.depends('company_id', 'equipment_id')
def _compute_user_id(self):
for request in self:
if request.equipment_id:
request.user_id = request.equipment_id.technician_user_id or request.equipment_id.category_id.technician_user_id
if request.user_id and request.company_id.id not in request.user_id.company_ids.ids:
request.user_id = False
@api.depends('maintenance_type')
def _compute_recurring_maintenance(self):
for request in self:
if request.maintenance_type != 'preventive':
request.recurring_maintenance = False
@api.model_create_multi
def create(self, vals_list):
@ -345,7 +320,7 @@ class MaintenanceRequest(models.Model):
if request.owner_user_id or request.user_id:
request._add_followers()
if request.equipment_id and not request.maintenance_team_id:
request.maintenance_team_id = request.equipment_id.maintenance_team_id
request.maintenance_team_id = request.maintenance_team_id
if request.close_date and not request.stage_id.done:
request.close_date = False
if not request.close_date and request.stage_id.done:
@ -358,6 +333,20 @@ class MaintenanceRequest(models.Model):
# 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'
now = fields.Datetime.now()
if 'stage_id' in vals and self.env['maintenance.stage'].browse(vals['stage_id']).done:
for request in self:
if request.maintenance_type != 'preventive' or not request.recurring_maintenance:
continue
schedule_date = request.schedule_date or now
schedule_date += relativedelta(**{f"{request.repeat_unit}s": request.repeat_interval})
schedule_end = schedule_date + relativedelta(hours=request.duration or 1)
if request.repeat_type == 'forever' or schedule_date.date() <= request.repeat_until:
request.copy({
'schedule_date': schedule_date,
'schedule_end': schedule_end,
'stage_id': request._default_stage().id,
})
res = super(MaintenanceRequest, self).write(vals)
if vals.get('owner_user_id') or vals.get('user_id'):
self._add_followers()
@ -368,12 +357,21 @@ class MaintenanceRequest(models.Model):
self.activity_update()
if vals.get('user_id') or vals.get('schedule_date'):
self.activity_update()
if vals.get('equipment_id'):
if self._need_new_activity(vals):
# need to change description of activity also so unlink old and create new activity
self.activity_unlink(['maintenance.mail_act_maintenance_request'])
self.activity_update()
return res
def _need_new_activity(self, vals):
return vals.get('equipment_id')
def _get_activity_note(self):
self.ensure_one()
if self.equipment_id:
return _('Request planned for %s', self.equipment_id._get_html_link())
return False
def activity_update(self):
""" Update maintenance activities based on current record set state.
It reschedule, unlink or create maintenance request activities. """
@ -385,13 +383,7 @@ class MaintenanceRequest(models.Model):
date_deadline=date_dl,
new_user_id=request.user_id.id or request.owner_user_id.id or self.env.uid)
if not updated:
if request.equipment_id:
note = _(
'Request planned for %s',
request.equipment_id._get_html_link()
)
else:
note = False
note = request._get_activity_note()
request.activity_schedule(
'maintenance.mail_act_maintenance_request',
fields.Datetime.from_string(request.schedule_date).date(),
@ -403,16 +395,17 @@ class MaintenanceRequest(models.Model):
request.message_subscribe(partner_ids=partner_ids)
@api.model
def _read_group_stage_ids(self, stages, domain, order):
def _read_group_stage_ids(self, stages, domain):
""" Read group customization in order to display all the stages in the
kanban view, even if they are empty
"""
stage_ids = stages._search([], order=order, access_rights_uid=SUPERUSER_ID)
stage_ids = stages.sudo()._search([], order=stages._order)
return stages.browse(stage_ids)
class MaintenanceTeam(models.Model):
_name = 'maintenance.team'
_inherit = ['mail.alias.mixin', 'mail.thread']
_description = 'Maintenance Teams'
name = fields.Char('Team Name', required=True, translate=True)
@ -433,18 +426,32 @@ class MaintenanceTeam(models.Model):
todo_request_count_high_priority = fields.Integer(string="Number of Requests in High Priority", compute='_compute_todo_requests')
todo_request_count_block = fields.Integer(string="Number of Requests Blocked", compute='_compute_todo_requests')
todo_request_count_unscheduled = fields.Integer(string="Number of Requests Unscheduled", compute='_compute_todo_requests')
alias_id = fields.Many2one(help="Email alias for this maintenance team.")
@api.depends('request_ids.stage_id.done')
def _compute_todo_requests(self):
for team in self:
team.todo_request_ids = self.env['maintenance.request'].search([('maintenance_team_id', '=', team.id), ('stage_id.done', '=', False)])
team.todo_request_count = len(team.todo_request_ids)
team.todo_request_count_date = self.env['maintenance.request'].search_count([('maintenance_team_id', '=', team.id), ('schedule_date', '!=', False)])
team.todo_request_count_high_priority = self.env['maintenance.request'].search_count([('maintenance_team_id', '=', team.id), ('priority', '=', '3')])
team.todo_request_count_block = self.env['maintenance.request'].search_count([('maintenance_team_id', '=', team.id), ('kanban_state', '=', 'blocked')])
team.todo_request_count_unscheduled = self.env['maintenance.request'].search_count([('maintenance_team_id', '=', team.id), ('schedule_date', '=', False)])
team.todo_request_ids = self.env['maintenance.request'].search([('maintenance_team_id', '=', team.id), ('stage_id.done', '=', False), ('archive', '=', False)])
data = self.env['maintenance.request']._read_group(
[('maintenance_team_id', '=', team.id), ('stage_id.done', '=', False), ('archive', '=', False)],
['schedule_date:year', 'priority', 'kanban_state'],
['__count']
)
team.todo_request_count = sum(count for (_, _, _, count) in data)
team.todo_request_count_date = sum(count for (schedule_date, _, _, count) in data if schedule_date)
team.todo_request_count_high_priority = sum(count for (_, priority, _, count) in data if priority == '3')
team.todo_request_count_block = sum(count for (_, _, kanban_state, count) in data if kanban_state == 'blocked')
team.todo_request_count_unscheduled = team.todo_request_count - team.todo_request_count_date
@api.depends('equipment_ids')
def _compute_equipment(self):
for team in self:
team.equipment_count = len(team.equipment_ids)
def _alias_get_creation_values(self):
values = super()._alias_get_creation_values()
values['alias_model_id'] = self.env['ir.model']._get('maintenance.request').id
if self.id:
values['alias_defaults'] = defaults = ast.literal_eval(self.alias_defaults or "{}")
defaults['maintenance_team_id'] = self.id
return values