Files
Odoo-Modules/fusion_clock/models/clock_shift.py
gsinghpal b4ca85e291 feat(fusion_clock): native shift roles (fusion.clock.role) [A1-A3]
Replaces Odoo Planning's planning.role: name+colour model with the same
1-11 palette, employee default/allowed role fields, Employee Roles editor,
role_id on shift template + schedule with default resolution, ACLs, menus.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:42:04 -04:00

92 lines
3.0 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
from odoo import models, fields
class FusionClockShift(models.Model):
_name = 'fusion.clock.shift'
_description = 'Clock Shift Schedule'
_order = 'sequence, name'
_rec_name = 'name'
name = fields.Char(
string='Shift Name',
required=True,
help="E.g. 'Morning Shift', 'Evening Shift'.",
)
start_time = fields.Float(
string='Start Time',
required=True,
default=9.0,
help="Shift start in 24h float (e.g. 7.0 = 7:00 AM).",
)
end_time = fields.Float(
string='End Time',
required=True,
default=17.0,
help="Shift end in 24h float (e.g. 15.0 = 3:00 PM).",
)
break_minutes = fields.Float(
string='Break Duration (min)',
default=30.0,
help="Unpaid break duration in minutes for this shift.",
)
sequence = fields.Integer(default=10)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company,
required=True,
)
active = fields.Boolean(default=True)
color = fields.Char(string='Color', default='#3B82F6')
role_id = fields.Many2one(
'fusion.clock.role',
string='Default Role',
help="Role assigned to shifts created from this template "
"(drives the colour/label on the employee's portal schedule).",
)
# Weekday pattern — which days this recurring shift applies as the baseline
# when there is no posted planner entry for the day. Default Mon-Fri.
day_mon = fields.Boolean(string='Mon', default=True)
day_tue = fields.Boolean(string='Tue', default=True)
day_wed = fields.Boolean(string='Wed', default=True)
day_thu = fields.Boolean(string='Thu', default=True)
day_fri = fields.Boolean(string='Fri', default=True)
day_sat = fields.Boolean(string='Sat', default=False)
day_sun = fields.Boolean(string='Sun', default=False)
employee_ids = fields.One2many(
'hr.employee',
'x_fclk_shift_id',
string='Assigned Employees',
)
employee_count = fields.Integer(
string='Employees',
compute='_compute_employee_count',
)
def _compute_employee_count(self):
for rec in self:
rec.employee_count = len(rec.employee_ids)
def covers_weekday(self, date):
"""Return True if this recurring shift applies on the given date's
weekday (Mon=0 .. Sun=6)."""
self.ensure_one()
date_obj = fields.Date.to_date(date)
if not date_obj:
return False
days = (self.day_mon, self.day_tue, self.day_wed, self.day_thu,
self.day_fri, self.day_sat, self.day_sun)
return bool(days[date_obj.weekday()])
@property
def scheduled_hours(self):
"""Return the scheduled work hours for this shift (excluding break)."""
raw = self.end_time - self.start_time
return max(raw - (self.break_minutes / 60.0), 0.0)