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>
85 lines
3.8 KiB
Python
85 lines
3.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
|
|
from datetime import date, timedelta
|
|
|
|
from odoo.exceptions import ValidationError
|
|
from odoo.tests import tagged
|
|
from odoo.tests.common import TransactionCase
|
|
|
|
|
|
@tagged('-at_install', 'post_install', 'fusion_clock')
|
|
class TestOpenShift(TransactionCase):
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.S = self.env['fusion.clock.schedule']
|
|
|
|
def test_open_shift_needs_no_employee_and_gets_company(self):
|
|
sch = self.S.create({
|
|
'is_open': True, 'schedule_date': date(2026, 6, 1),
|
|
'start_time': 9.0, 'end_time': 17.0, 'state': 'posted'})
|
|
self.assertFalse(sch.employee_id)
|
|
self.assertTrue(sch.company_id, "open shift falls back to the active company")
|
|
|
|
def test_assigned_shift_requires_employee(self):
|
|
with self.assertRaises(ValidationError):
|
|
self.S.create({
|
|
'schedule_date': date(2026, 6, 1),
|
|
'start_time': 9.0, 'end_time': 17.0})
|
|
|
|
def test_two_open_shifts_same_day_allowed(self):
|
|
d = date(2026, 6, 1)
|
|
self.S.create({'is_open': True, 'schedule_date': d, 'start_time': 8.0, 'end_time': 12.0})
|
|
self.S.create({'is_open': True, 'schedule_date': d, 'start_time': 13.0, 'end_time': 17.0})
|
|
self.assertEqual(
|
|
self.S.search_count([('is_open', '=', True), ('schedule_date', '=', d)]), 2)
|
|
|
|
def test_split_shift_for_same_employee_allowed(self):
|
|
emp = self.env['hr.employee'].create({'name': 'Splitter'})
|
|
d = date(2026, 6, 1)
|
|
self.S.create({'employee_id': emp.id, 'schedule_date': d, 'start_time': 8.0, 'end_time': 12.0})
|
|
self.S.create({'employee_id': emp.id, 'schedule_date': d, 'start_time': 13.0, 'end_time': 17.0})
|
|
self.assertEqual(
|
|
self.S.search_count([('employee_id', '=', emp.id), ('schedule_date', '=', d)]), 2,
|
|
"the hard one-shift-per-day uniqueness is gone")
|
|
|
|
def test_claim_open_shift_assigns_to_employee(self):
|
|
emp = self.env['hr.employee'].create({'name': 'Claimer'})
|
|
op = self.S.create({
|
|
'is_open': True, 'schedule_date': date(2026, 6, 10),
|
|
'start_time': 9.0, 'end_time': 17.0, 'state': 'posted'})
|
|
self.S.fclk_claim_open_shift(op, emp)
|
|
self.assertFalse(op.is_open)
|
|
self.assertEqual(op.employee_id, emp)
|
|
|
|
def test_claim_enforces_role_eligibility(self):
|
|
forklift = self.env['fusion.clock.role'].create({'name': 'Forklift', 'color': 2})
|
|
desk = self.env['fusion.clock.role'].create({'name': 'Desk', 'color': 3})
|
|
emp = self.env['hr.employee'].create({
|
|
'name': 'Picky', 'x_fclk_role_ids': [(6, 0, [desk.id])]})
|
|
op = self.S.create({
|
|
'is_open': True, 'schedule_date': date(2026, 6, 10),
|
|
'start_time': 9.0, 'end_time': 17.0, 'role_id': forklift.id, 'state': 'posted'})
|
|
with self.assertRaises(ValidationError):
|
|
self.S.fclk_claim_open_shift(op, emp)
|
|
|
|
def test_release_returns_shift_to_open_pool(self):
|
|
emp = self.env['hr.employee'].create({'name': 'Releaser'})
|
|
future = date.today() + timedelta(days=30)
|
|
sch = self.S.create({
|
|
'employee_id': emp.id, 'schedule_date': future,
|
|
'start_time': 9.0, 'end_time': 17.0, 'state': 'posted'})
|
|
self.S.fclk_release_shift(sch, emp)
|
|
self.assertTrue(sch.is_open)
|
|
self.assertFalse(sch.employee_id)
|
|
|
|
def test_bulk_apply_to_many_employees(self):
|
|
e1 = self.env['hr.employee'].create({'name': 'Bulk A'})
|
|
e2 = self.env['hr.employee'].create({'name': 'Bulk B'})
|
|
d = date(2026, 6, 10)
|
|
self.S.fclk_bulk_apply(e1 + e2, d, {'start_time': 8.0, 'end_time': 16.0, 'break_minutes': 0.0})
|
|
self.assertEqual(
|
|
self.S.search_count([('schedule_date', '=', d), ('employee_id', 'in', (e1 + e2).ids)]), 2)
|