Files
Odoo-Modules/fusion_planning/controllers/portal_schedule.py
gsinghpal 85bbd8a20e fix(portal): recover full-bleed wrapper fix + Schedule Payslips tab
These round-2 portal fixes (white-border wrapper neutralisation in
portal_clock.css, and the Payslips nav tab on the fusion_planning Schedule
page) were briefly bundled into a concurrent NFC commit that a parallel session
then rebased, dropping them from main. They are deployed and verified on entech
(fusion_clock 3.12.3 / fusion_planning 1.3.0); re-committing so git matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 22:36:38 -04:00

101 lines
3.7 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)
import logging
from collections import OrderedDict
from datetime import timedelta
import pytz
from odoo import http, fields
from odoo.http import request
_logger = logging.getLogger(__name__)
class FusionPlanningPortal(http.Controller):
"""Portal controller exposing the employee's published Planning shifts."""
@http.route('/my/clock/schedule', type='http', auth='user', website=True)
def portal_schedule(self, **kw):
employee = request.env.user.employee_id
if not employee:
return request.redirect('/my')
tz_name = employee.tz or request.env.user.tz or 'UTC'
try:
local_tz = pytz.timezone(tz_name)
except pytz.UnknownTimeZoneError:
local_tz = pytz.UTC
now_utc = fields.Datetime.now()
horizon_utc = now_utc + timedelta(days=60)
Slot = request.env['planning.slot'].sudo()
domain = [
('state', '=', 'published'),
('end_datetime', '>=', now_utc),
('start_datetime', '<=', horizon_utc),
]
if employee.resource_id:
domain.append(('resource_id', '=', employee.resource_id.id))
else:
domain.append(('resource_id', '=', -1))
slots = Slot.search(domain, order='start_datetime asc', limit=200)
groups = OrderedDict()
today_local = fields.Datetime.context_timestamp(
request.env.user, now_utc
).date()
for slot in slots:
local_start = pytz.UTC.localize(slot.start_datetime).astimezone(local_tz)
local_end = pytz.UTC.localize(slot.end_datetime).astimezone(local_tz)
day = local_start.date()
delta_days = (day - today_local).days
if delta_days == 0:
bucket_key = 'Today'
elif delta_days == 1:
bucket_key = 'Tomorrow'
elif 0 <= delta_days <= 6:
bucket_key = local_start.strftime('%A')
else:
bucket_key = local_start.strftime('%b %d')
groups.setdefault(bucket_key, []).append({
'slot': slot,
'day_label': local_start.strftime('%a').upper(),
'day_num': local_start.strftime('%d'),
'date_full': local_start.strftime('%b %d, %Y'),
'time_range': '%s - %s' % (
local_start.strftime('%I:%M %p').lstrip('0'),
local_end.strftime('%I:%M %p').lstrip('0'),
),
'duration_hours': round(slot.allocated_hours or 0.0, 1),
'role_name': slot.role_id.name if slot.role_id else '',
'role_color': slot.role_id.color if slot.role_id else 0,
'note': slot.name or '',
})
next_slot_data = None
if slots:
next_slot = slots[0]
local_start = pytz.UTC.localize(next_slot.start_datetime).astimezone(local_tz)
next_slot_data = {
'date': local_start.strftime('%a, %b %d'),
'time': local_start.strftime('%I:%M %p').lstrip('0'),
'role': next_slot.role_id.name if next_slot.role_id else '',
}
values = {
'employee': employee,
'groups': groups,
'slot_count': len(slots),
'next_slot': next_slot_data,
'page_name': 'fusion_clock_schedule',
# Match the other portal pages so the Payslips nav tab appears
# consistently when payroll is installed.
'show_payslips': 'hr.payslip' in request.env,
}
return request.render('fusion_planning.portal_schedule_page', values)