feat: exclude fixed-salary managers from absence pickers

This commit is contained in:
Konrad du Plessis 2026-05-15 19:55:42 +02:00
parent 0f45d64eea
commit 5fa3efcf64
2 changed files with 47 additions and 4 deletions

View File

@ -660,7 +660,7 @@ class AbsenceLogForm(forms.ModelForm):
help_text='Optional — narrows the worker list below.',
)
workers = forms.ModelMultipleChoiceField(
queryset=Worker.objects.filter(active=True),
queryset=Worker.objects.filter(active=True).exclude(pay_type='fixed'),
widget=forms.CheckboxSelectMultiple,
)
@ -699,7 +699,7 @@ class AbsenceLogForm(forms.ModelForm):
active=True,
teams__supervisor=user,
teams__active=True,
).distinct()
).exclude(pay_type='fixed').distinct()
)
# Project dropdown — only projects this supervisor is assigned to.
# Mirrors the AttendanceLogForm supervisor scoping pattern.
@ -840,7 +840,7 @@ class AbsenceEditForm(forms.ModelForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
# Default: every active worker. Admins (staff/superuser) keep this list.
self.fields['worker'].queryset = Worker.objects.filter(active=True)
self.fields['worker'].queryset = Worker.objects.filter(active=True).exclude(pay_type='fixed')
# Project is optional — leave blank for non-project absences.
self.fields['project'].required = False
# Supervisor scope: when a non-admin opens the edit form, the worker
@ -853,7 +853,7 @@ class AbsenceEditForm(forms.ModelForm):
active=True,
teams__supervisor=user,
teams__active=True,
).distinct()
).exclude(pay_type='fixed').distinct()
self.fields['project'].queryset = Project.objects.filter(
active=True, supervisors=user,
)

View File

@ -3500,3 +3500,46 @@ class ManagerSalariedAttendanceExclusionTests(TestCase):
ids = tw_map.get(str(self.team.id)) or tw_map.get(self.team.id) or []
self.assertIn(self.daily.id, ids)
self.assertNotIn(self.mgr.id, ids)
# === MANAGER / SALARIED ABSENCE-PICKER EXCLUSION TESTS (Task 4) ===
# A pay_type='fixed' manager must be impossible to mark absent — the
# AbsenceLogForm worker picker (admin default + supervisor branch) and
# the AbsenceEditForm worker picker (admin + supervisor branch) must
# exclude fixed-salary workers. (Managers stay selectable in payroll
# modals / team-edit — those are NOT touched by this task.)
class ManagerSalariedAbsenceExclusionTests(TestCase):
def setUp(self):
self.admin = User.objects.create_user('msab_admin', password='x', is_staff=True)
self.sup = User.objects.create_user('msab_sup', password='x')
self.daily = Worker.objects.create(
name='Abs Daily', id_number='MSAB-D', monthly_salary=Decimal('6000'))
self.mgr = Worker.objects.create(
name='Abs Mgr', id_number='MSAB-M', monthly_salary=Decimal('40000'),
pay_type='fixed')
self.team = Team.objects.create(name='MSAB Team', supervisor=self.sup, active=True)
self.team.workers.add(self.daily, self.mgr)
def test_absencelog_admin_excludes_fixed(self):
from core.forms import AbsenceLogForm
qs = AbsenceLogForm(user=self.admin).fields['workers'].queryset
self.assertIn(self.daily, qs)
self.assertNotIn(self.mgr, qs)
def test_absencelog_supervisor_excludes_fixed(self):
from core.forms import AbsenceLogForm
qs = AbsenceLogForm(user=self.sup).fields['workers'].queryset
self.assertIn(self.daily, qs)
self.assertNotIn(self.mgr, qs)
def test_absenceedit_admin_excludes_fixed(self):
from core.forms import AbsenceEditForm
qs = AbsenceEditForm(user=self.admin).fields['worker'].queryset
self.assertIn(self.daily, qs)
self.assertNotIn(self.mgr, qs)
def test_absenceedit_supervisor_excludes_fixed(self):
from core.forms import AbsenceEditForm
qs = AbsenceEditForm(user=self.sup).fields['worker'].queryset
self.assertNotIn(self.mgr, qs)