test: strengthen Task 4 absence-exclusion tests (parity + behavioral POST guard)

This commit is contained in:
Konrad du Plessis 2026-05-15 20:05:15 +02:00
parent 5fa3efcf64
commit 86b0cb9dd6

View File

@ -3542,4 +3542,47 @@ class ManagerSalariedAbsenceExclusionTests(TestCase):
def test_absenceedit_supervisor_excludes_fixed(self):
from core.forms import AbsenceEditForm
qs = AbsenceEditForm(user=self.sup).fields['worker'].queryset
self.assertIn(self.daily, qs)
self.assertNotIn(self.mgr, qs)
def test_absence_log_post_rejects_manager_id(self):
"""Behavioral guard (matches Task 3's POST-level rigor): the
ModelMultipleChoiceField re-validates submitted worker ids against
its excluded-fixed queryset. POSTing a manager's id must be rejected
with a `workers` form error and create ZERO Absence rows for the
manager which also prevents the underlying bug this feature exists
to stop: a paid manager-absence auto-creating a Bonus
PayrollAdjustment at daily_rate. A daily worker POSTed with the SAME
payload succeeds, proving the rejection is specific to the manager
(pay_type='fixed') and not a broken payload."""
self.client.force_login(self.admin)
# --- Manager id is rejected ---
resp = self.client.post(reverse('absence_log'), data={
'date': '2026-05-14',
'reason': 'sick',
'workers': [self.mgr.id],
'notes': 'should be rejected',
})
# Form re-rendered (not a redirect to success/confirm flow).
self.assertEqual(resp.status_code, 200)
self.assertIn('form', resp.context)
self.assertIn('workers', resp.context['form'].errors)
# No Absence row created for the manager — and therefore no
# auto-created Bonus PayrollAdjustment leaking at daily_rate.
self.assertEqual(Absence.objects.filter(worker=self.mgr).count(), 0)
self.assertEqual(
PayrollAdjustment.objects.filter(worker=self.mgr).count(), 0)
# --- Positive control: daily worker, identical payload, succeeds ---
resp2 = self.client.post(reverse('absence_log'), data={
'date': '2026-05-14',
'reason': 'sick',
'workers': [self.daily.id],
'notes': 'legit daily absence',
})
# No conflicts → immediate create + redirect to the absence list.
self.assertRedirects(
resp2, reverse('absence_list'), fetch_redirect_response=False)
self.assertEqual(Absence.objects.filter(worker=self.daily).count(), 1)
self.assertEqual(Absence.objects.filter(worker=self.mgr).count(), 0)