feat(fusion_clock): open shifts + self-assign + bulk apply [B4-B5]
Model: fclk_create_open_shifts/claim_open_shift/release_shift (days-before cutoff + role eligibility)/bulk_apply. Planner: Open Shift… panel, open-shifts strip with delete, Apply-to-dept; load includes open shifts. Portal: claim open shifts + release own upcoming shifts with feedback banners. Tests for claim/role-gate/release/bulk. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,9 +79,26 @@ class FusionClockShiftPlanner(http.Controller):
|
||||
('company_id', 'in', request.env.user.company_ids.ids),
|
||||
], order='sequence, name')
|
||||
|
||||
open_rows = Schedule.search([
|
||||
('is_open', '=', True),
|
||||
('company_id', 'in', request.env.user.company_ids.ids),
|
||||
('schedule_date', '>=', start),
|
||||
('schedule_date', '<=', days[-1]),
|
||||
], order='schedule_date, start_time')
|
||||
open_by_day = {}
|
||||
for row in open_rows:
|
||||
open_by_day.setdefault(str(row.schedule_date), []).append({
|
||||
'id': row.id,
|
||||
'label': row.fclk_display_value(),
|
||||
'role_name': row.role_id.name or '',
|
||||
'role_color': row.role_id._get_color_from_code(True) if row.role_id else '',
|
||||
'hours_display': Schedule.fclk_hours_display(row.planned_hours),
|
||||
})
|
||||
|
||||
return {
|
||||
'week_start': str(start),
|
||||
'week_end': str(days[-1]),
|
||||
'open_shifts': open_by_day,
|
||||
'days': [{
|
||||
'date': str(day),
|
||||
'weekday': day.strftime('%a').upper(),
|
||||
@@ -277,6 +294,49 @@ class FusionClockShiftPlanner(http.Controller):
|
||||
Schedule.fclk_clear_recurrence(schedule)
|
||||
return {'success': True, 'data': self._load_week_data(week_start)}
|
||||
|
||||
@http.route('/fusion_clock/shift_planner/create_open_shift', type='jsonrpc', auth='user', methods=['POST'])
|
||||
def create_open_shift(self, date=None, start_time=None, end_time=None, role_id=None,
|
||||
count=1, break_minutes=0.0, week_start=None, **kw):
|
||||
"""Create one or more open (unassignable) shifts for a day."""
|
||||
if not self._check_manager():
|
||||
return {'error': 'Access denied.'}
|
||||
Schedule = request.env['fusion.clock.schedule'].sudo()
|
||||
company = request.env.company
|
||||
try:
|
||||
Schedule.fclk_create_open_shifts(
|
||||
company, date, start_time, end_time,
|
||||
role_id=role_id, count=count, break_minutes=break_minutes)
|
||||
except ValidationError as exc:
|
||||
return {'success': False, 'message': str(exc.args[0] if exc.args else exc)}
|
||||
return {'success': True, 'data': self._load_week_data(week_start)}
|
||||
|
||||
@http.route('/fusion_clock/shift_planner/delete_open_shift', type='jsonrpc', auth='user', methods=['POST'])
|
||||
def delete_open_shift(self, schedule_id=None, week_start=None, **kw):
|
||||
if not self._check_manager():
|
||||
return {'error': 'Access denied.'}
|
||||
Schedule = request.env['fusion.clock.schedule'].sudo()
|
||||
row = Schedule.browse(int(schedule_id or 0))
|
||||
if row.exists() and row.is_open:
|
||||
row.unlink()
|
||||
return {'success': True, 'data': self._load_week_data(week_start)}
|
||||
|
||||
@http.route('/fusion_clock/shift_planner/bulk_apply', type='jsonrpc', auth='user', methods=['POST'])
|
||||
def bulk_apply(self, employee_ids=None, date=None, payload=None, week_start=None, **kw):
|
||||
"""Apply one shift to several employees at once (Apply Also To)."""
|
||||
if not self._check_manager():
|
||||
return {'error': 'Access denied.'}
|
||||
employees = self._manager_employees()
|
||||
wanted = {int(eid) for eid in (employee_ids or [])}
|
||||
employees = employees.filtered(lambda e: e.id in wanted)
|
||||
if not employees:
|
||||
return {'success': False, 'message': 'Pick at least one employee.'}
|
||||
Schedule = request.env['fusion.clock.schedule'].sudo()
|
||||
try:
|
||||
Schedule.fclk_bulk_apply(employees, date, payload or {}, request.env.user)
|
||||
except ValidationError as exc:
|
||||
return {'success': False, 'message': str(exc.args[0] if exc.args else exc)}
|
||||
return {'success': True, 'data': self._load_week_data(week_start)}
|
||||
|
||||
@http.route('/fusion_clock/shift_planner/export_xlsx', type='jsonrpc', auth='user', methods=['POST'])
|
||||
def export_xlsx(self, week_start=None, **kw):
|
||||
if not self._check_manager():
|
||||
|
||||
Reference in New Issue
Block a user