Files
enterprise-addons/planning/models/planning_planning.py
T

122 lines
5.8 KiB
Python

# Part of Odoo. See LICENSE file for full copyright and licensing details.
import uuid
import pytz
from odoo import api, fields, models
class PlanningPlanning(models.Model):
_name = 'planning.planning'
_description = 'Schedule'
@api.model
def _default_access_token(self):
return str(uuid.uuid4())
start_datetime = fields.Datetime("Start Date", required=True)
end_datetime = fields.Datetime("Stop Date", required=True)
include_unassigned = fields.Boolean("Includes Open Shifts", default=True)
access_token = fields.Char("Security Token", default=_default_access_token, required=True, copy=False, readonly=True)
company_id = fields.Many2one('res.company', string="Company", required=True, default=lambda self: self.env.company,
help="Company linked to the material resource. Leave empty for the resource to be available in every company.")
date_start = fields.Date('Date Start', compute='_compute_dates')
date_end = fields.Date('Date End', compute='_compute_dates')
allow_self_unassign = fields.Boolean('Let Employee Unassign Themselves', compute='_compute_allow_self_unassign')
self_unassign_days_before = fields.Integer("Days before shift for unassignment", related="company_id.planning_self_unassign_days_before", export_string_translation=False)
is_planning_preview = fields.Boolean(string="Is Planning Preview")
@api.depends('start_datetime', 'end_datetime')
@api.depends_context('uid')
def _compute_dates(self):
tz = pytz.timezone(self.env.user.tz or 'UTC')
for planning in self:
planning.date_start = pytz.utc.localize(planning.start_datetime).astimezone(tz).replace(tzinfo=None)
planning.date_end = pytz.utc.localize(planning.end_datetime).astimezone(tz).replace(tzinfo=None)
def _compute_display_name(self):
""" This override is need to have a human readable string in the email light layout header (`message.record_name`) """
self.display_name = self.env._('Planning')
def _compute_allow_self_unassign(self):
self.allow_self_unassign = self.company_id.planning_employee_unavailabilities == "unassign"
# ----------------------------------------------------
# Business Methods
# ----------------------------------------------------
def _is_slot_in_planning(self, slot_sudo):
return (
self
and slot_sudo.start_datetime >= self.start_datetime
and slot_sudo.end_datetime <= self.end_datetime
and slot_sudo.state == "published"
)
def _get_ics_file(self, calendar, employee):
self.ensure_one()
slots_in_planning = self.env['planning.slot'].search([
('start_datetime', '>=', self.start_datetime),
('end_datetime', '<=', self.end_datetime),
('state', '=', 'published'),
('employee_id', '=', employee.id),
])
slots_in_planning._get_ics_file(calendar, employee.tz)
return calendar
def _send_planning(self, slots, message=None, employees=False):
email_from = self.env.user.email or self.env.user.company_id.email or ''
# extract planning URLs
employees_sudo = employees.sudo()
employee_url_map = employees_sudo._planning_get_url(self.date_start, self.date_end, self.access_token)
ics_url_per_employee_id = {e.id: f'/planning/{self.access_token}/{e.employee_token}.ics' for e in employees_sudo}
# send planning email template with custom domain per employee
template = self.env.ref('planning.email_template_planning_planning', raise_if_not_found=False)
template_context = {
'slot_unassigned': self.include_unassigned,
'message': message,
}
if template:
# /!\ For security reason, we only given the public employee to render mail template
for employee in self.env['hr.employee.public'].browse(employees.ids):
if employee.work_email:
assigned_new_shift = bool(slots.filtered(lambda slot: slot.employee_id.id == employee.id))
template_context['employee'] = employee
template_context['start_datetime'] = self.date_start
template_context['end_datetime'] = self.date_end
template_context['planning_url'] = employee_url_map[employee.id]
template_context['planning_url_ics'] = ics_url_per_employee_id[employee.id] if assigned_new_shift else False
template_context['assigned_new_shift'] = assigned_new_shift
template.with_context(**template_context).send_mail(self.id, email_values={'email_to': employee.work_email, 'email_from': email_from}, email_layout_xmlid='mail.mail_notification_light')
# mark as sent
slots.write({
'state': 'published',
'publication_warning': False,
})
return True
def _get_preview_planning(self, start_datetime, end_datetime, include_unassigned):
Planning = self.env['planning.planning']
planning = Planning.search([
('start_datetime', '=', start_datetime),
('end_datetime', '=', end_datetime),
('is_planning_preview', '=', True),
], limit=1)
if not planning:
planning = Planning.create({
'start_datetime': start_datetime,
'end_datetime': end_datetime,
'include_unassigned': include_unassigned,
})
return planning
@api.autovacuum
def _gc_planning_preview(self):
limit_dt = fields.Datetime.subtract(fields.Datetime.now(), months=3)
plannings = self.env['planning.planning'].search([
('is_planning_preview', '=', True),
('create_date', '<=', limit_dt),
])
plannings.unlink()