feat(fusion_clock): Publish & Notify range + portal Schedule fold-in [A6-A7]
Generalise post_week into fclk_publish_range/fclk_email_posted_range + planner Publish… panel + publish_range endpoint. Fold the /my/clock/schedule controller+template+css from fusion_planning into fusion_clock (native schedule only, role colour); inline Schedule nav across all portal pages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -432,22 +432,23 @@ class FusionClockSchedule(models.Model):
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def fclk_email_posted_week(self, employee, week_start, week_end):
|
||||
"""Email one employee a summary of their POSTED shifts for the week."""
|
||||
def fclk_email_posted_range(self, employee, start, end, message=None):
|
||||
"""Email one employee a summary of their POSTED shifts between two
|
||||
dates (inclusive). Optional ``message`` is shown above the schedule."""
|
||||
employee = employee.sudo()
|
||||
if not employee.work_email:
|
||||
return False
|
||||
from .hr_attendance import _fclk_email_wrap
|
||||
entries = self.sudo().search([
|
||||
('employee_id', '=', employee.id),
|
||||
('schedule_date', '>=', week_start),
|
||||
('schedule_date', '<=', week_end),
|
||||
('schedule_date', '>=', start),
|
||||
('schedule_date', '<=', end),
|
||||
('state', '=', 'posted'),
|
||||
])
|
||||
by_date = {entry.schedule_date: entry for entry in entries}
|
||||
rows = []
|
||||
day = week_start
|
||||
while day <= week_end:
|
||||
day = start
|
||||
while day <= end:
|
||||
entry = by_date.get(day)
|
||||
rows.append((
|
||||
day.strftime('%a %b %d'),
|
||||
@@ -455,20 +456,23 @@ class FusionClockSchedule(models.Model):
|
||||
))
|
||||
day += timedelta(days=1)
|
||||
company = employee.company_id or self.env.company
|
||||
summary = (
|
||||
f'Hello <strong>{employee.name}</strong>, your shifts for '
|
||||
f'<strong>{start.strftime("%b %d")} - {end.strftime("%b %d, %Y")}</strong> '
|
||||
f'have been posted.'
|
||||
)
|
||||
if message:
|
||||
summary += f'<br/><br/>{message}'
|
||||
body = _fclk_email_wrap(
|
||||
company_name=company.name or '',
|
||||
title='Your Posted Schedule',
|
||||
summary=(
|
||||
f'Hello <strong>{employee.name}</strong>, your shifts for '
|
||||
f'<strong>{week_start.strftime("%b %d")} - {week_end.strftime("%b %d, %Y")}</strong> '
|
||||
f'have been posted.'
|
||||
),
|
||||
sections=[('This Week', rows)],
|
||||
note='Log in to <a href="/my/clock" style="color:#10B981;">your portal</a> for details.',
|
||||
summary=summary,
|
||||
sections=[('Schedule', rows)],
|
||||
note='Log in to <a href="/my/clock/schedule" style="color:#10B981;">your portal</a> for details.',
|
||||
)
|
||||
try:
|
||||
mail = self.env['mail.mail'].sudo().create({
|
||||
'subject': f'Your schedule: {week_start.strftime("%b %d")} - {week_end.strftime("%b %d")}',
|
||||
'subject': f'Your schedule: {start.strftime("%b %d")} - {end.strftime("%b %d")}',
|
||||
'email_from': company.email or '',
|
||||
'email_to': employee.work_email,
|
||||
'body_html': body,
|
||||
@@ -482,6 +486,36 @@ class FusionClockSchedule(models.Model):
|
||||
)
|
||||
return False
|
||||
|
||||
@api.model
|
||||
def fclk_email_posted_week(self, employee, week_start, week_end):
|
||||
"""Back-compat wrapper — email one employee their posted week."""
|
||||
return self.fclk_email_posted_range(employee, week_start, week_end)
|
||||
|
||||
@api.model
|
||||
def fclk_publish_range(self, employees, start, end, message=None):
|
||||
"""Post every draft shift in [start, end] for the given employees and
|
||||
email each affected employee. Returns (posted_count, notified_count)."""
|
||||
Schedule = self.sudo()
|
||||
domain = [
|
||||
('employee_id', 'in', employees.ids),
|
||||
('schedule_date', '>=', start),
|
||||
('schedule_date', '<=', end),
|
||||
('state', '!=', 'posted'),
|
||||
]
|
||||
# Never auto-post open (unassigned) shifts (Phase B field).
|
||||
if 'is_open' in Schedule._fields:
|
||||
domain.append(('is_open', '=', False))
|
||||
drafts = Schedule.search(domain)
|
||||
posted = len(drafts)
|
||||
affected = drafts.mapped('employee_id')
|
||||
if drafts:
|
||||
drafts.write({'state': 'posted', 'posted_date': fields.Datetime.now()})
|
||||
notified = 0
|
||||
for employee in affected:
|
||||
if Schedule.fclk_email_posted_range(employee, start, end, message=message):
|
||||
notified += 1
|
||||
return posted, notified
|
||||
|
||||
|
||||
class FusionClockScheduleAudit(models.Model):
|
||||
_name = 'fusion.clock.schedule.audit'
|
||||
|
||||
Reference in New Issue
Block a user