feat(fusion_clock): multi-day leave requests (date range)
Request Leave now takes a From/To date range instead of a single day (the To field is optional -> single-day). Added date_to to fusion.clock.leave.request (start kept as leave_date), with overlap detection on submit and a date_to >= leave_date constraint. The absence check and reports now treat a leave as covering its whole span. The form shows two date inputs; the controller accepts date_from/date_to (the old single leave_date payload is still honoured). A migration backfills date_to = leave_date for existing rows. Live and verified on entech 19.0.3.13.0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
# License OPL-1 (Odoo Proprietary License v1.0)
|
||||
|
||||
import logging
|
||||
from odoo import models, fields, api
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -23,10 +24,16 @@ class FusionClockLeaveRequest(models.Model):
|
||||
ondelete='cascade',
|
||||
)
|
||||
leave_date = fields.Date(
|
||||
string='Leave Date',
|
||||
string='From Date',
|
||||
required=True,
|
||||
index=True,
|
||||
)
|
||||
date_to = fields.Date(
|
||||
string='To Date',
|
||||
index=True,
|
||||
help="Last day of the leave (inclusive); equals the start date for a "
|
||||
"single-day request.",
|
||||
)
|
||||
reason = fields.Text(
|
||||
string='Reason',
|
||||
required=True,
|
||||
@@ -59,15 +66,32 @@ class FusionClockLeaveRequest(models.Model):
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.depends('employee_id', 'leave_date')
|
||||
@api.depends('employee_id', 'leave_date', 'date_to')
|
||||
def _compute_display_name(self):
|
||||
for rec in self:
|
||||
emp = rec.employee_id.name or ''
|
||||
date_str = str(rec.leave_date) if rec.leave_date else ''
|
||||
rec.display_name = f"{emp} - Leave ({date_str})"
|
||||
rec.display_name = f"{emp} - Leave ({rec._fclk_date_label()})"
|
||||
|
||||
def _fclk_date_label(self):
|
||||
"""Human label for the leave period: a single date, or 'from to to'."""
|
||||
self.ensure_one()
|
||||
if not self.leave_date:
|
||||
return ''
|
||||
if self.date_to and self.date_to != self.leave_date:
|
||||
return f"{self.leave_date} to {self.date_to}"
|
||||
return str(self.leave_date)
|
||||
|
||||
@api.constrains('leave_date', 'date_to')
|
||||
def _check_leave_dates(self):
|
||||
for rec in self:
|
||||
if rec.date_to and rec.leave_date and rec.date_to < rec.leave_date:
|
||||
raise ValidationError(_("The end date cannot be before the start date."))
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if not vals.get('date_to') and vals.get('leave_date'):
|
||||
vals['date_to'] = vals['leave_date']
|
||||
records = super().create(vals_list)
|
||||
for rec in records:
|
||||
rec._notify_office_user()
|
||||
@@ -86,7 +110,7 @@ class FusionClockLeaveRequest(models.Model):
|
||||
try:
|
||||
self.env['mail.activity'].sudo().create({
|
||||
'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id,
|
||||
'summary': f"Leave Request: {self.employee_id.name} on {self.leave_date}",
|
||||
'summary': f"Leave Request: {self.employee_id.name} ({self._fclk_date_label()})",
|
||||
'note': f"Reason: {self.reason}",
|
||||
'user_id': office_user.id,
|
||||
'res_model_id': self.env['ir.model']._get_id('fusion.clock.leave.request'),
|
||||
@@ -102,7 +126,7 @@ class FusionClockLeaveRequest(models.Model):
|
||||
self.env['fusion.clock.activity.log'].sudo().create({
|
||||
'employee_id': self.employee_id.id,
|
||||
'log_type': 'leave_request',
|
||||
'description': f"Leave requested for {self.leave_date}: {self.reason}",
|
||||
'description': f"Leave requested for {self._fclk_date_label()}: {self.reason}",
|
||||
'source': 'portal' if self.created_from == 'portal' else 'system',
|
||||
})
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user