feat: exclude fixed-salary managers from attendance pickers
This commit is contained in:
parent
482f88bb10
commit
65df9f817e
@ -105,13 +105,14 @@ class AttendanceLogForm(forms.ModelForm):
|
|||||||
supervised_teams = Team.objects.filter(supervisor=self.user, active=True)
|
supervised_teams = Team.objects.filter(supervisor=self.user, active=True)
|
||||||
self.fields['workers'].queryset = Worker.objects.filter(
|
self.fields['workers'].queryset = Worker.objects.filter(
|
||||||
active=True,
|
active=True,
|
||||||
teams__in=supervised_teams
|
teams__in=supervised_teams,
|
||||||
).distinct()
|
).exclude(pay_type='fixed').distinct()
|
||||||
# Only show teams this supervisor manages
|
# Only show teams this supervisor manages
|
||||||
self.fields['team'].queryset = supervised_teams
|
self.fields['team'].queryset = supervised_teams
|
||||||
else:
|
else:
|
||||||
# Admins see everything
|
# Admins see everything
|
||||||
self.fields['workers'].queryset = Worker.objects.filter(active=True)
|
self.fields['workers'].queryset = Worker.objects.filter(
|
||||||
|
active=True).exclude(pay_type='fixed')
|
||||||
self.fields['project'].queryset = Project.objects.filter(active=True)
|
self.fields['project'].queryset = Project.objects.filter(active=True)
|
||||||
self.fields['team'].queryset = Team.objects.filter(active=True)
|
self.fields['team'].queryset = Team.objects.filter(active=True)
|
||||||
|
|
||||||
|
|||||||
@ -3395,3 +3395,40 @@ class ManagerSalariedPayTypeRegistrationTests(TestCase):
|
|||||||
def test_salary_is_additive(self):
|
def test_salary_is_additive(self):
|
||||||
from core.views import ADDITIVE_TYPES
|
from core.views import ADDITIVE_TYPES
|
||||||
self.assertIn('Salary', ADDITIVE_TYPES)
|
self.assertIn('Salary', ADDITIVE_TYPES)
|
||||||
|
|
||||||
|
|
||||||
|
# === MANAGER / SALARIED PAY - attendance picker exclusion ===
|
||||||
|
# A pay_type='fixed' manager must be impossible to add to a WorkLog.
|
||||||
|
# They are excluded at the attendance picker + supporting maps so
|
||||||
|
# they can never be selected for / auto-checked into a WorkLog or
|
||||||
|
# counted in the attendance cost estimate.
|
||||||
|
class ManagerSalariedAttendanceExclusionTests(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.admin = User.objects.create_user('msa_admin', password='x', is_staff=True)
|
||||||
|
self.sup = User.objects.create_user('msa_sup', password='x')
|
||||||
|
self.daily = Worker.objects.create(
|
||||||
|
name='Daily Del', id_number='MSA-D', monthly_salary=Decimal('6000'))
|
||||||
|
self.mgr = Worker.objects.create(
|
||||||
|
name='Mgr Mo', id_number='MSA-M', monthly_salary=Decimal('40000'),
|
||||||
|
pay_type='fixed')
|
||||||
|
self.team = Team.objects.create(name='MSA Team', supervisor=self.sup)
|
||||||
|
self.team.workers.add(self.daily, self.mgr)
|
||||||
|
|
||||||
|
def test_attendance_admin_picker_excludes_fixed(self):
|
||||||
|
from core.forms import AttendanceLogForm
|
||||||
|
qs = AttendanceLogForm(user=self.admin).fields['workers'].queryset
|
||||||
|
self.assertIn(self.daily, qs)
|
||||||
|
self.assertNotIn(self.mgr, qs)
|
||||||
|
|
||||||
|
def test_attendance_supervisor_picker_excludes_fixed(self):
|
||||||
|
from core.forms import AttendanceLogForm
|
||||||
|
qs = AttendanceLogForm(user=self.sup).fields['workers'].queryset
|
||||||
|
self.assertIn(self.daily, qs)
|
||||||
|
self.assertNotIn(self.mgr, qs)
|
||||||
|
|
||||||
|
def test_team_workers_map_excludes_fixed(self):
|
||||||
|
from core.views import _build_team_workers_map
|
||||||
|
m = _build_team_workers_map(self.admin)
|
||||||
|
ids = m.get(self.team.id) or m.get(str(self.team.id)) or []
|
||||||
|
self.assertIn(self.daily.id, ids)
|
||||||
|
self.assertNotIn(self.mgr.id, ids)
|
||||||
|
|||||||
@ -586,7 +586,8 @@ def _build_team_workers_map(user):
|
|||||||
teams_qs = Team.objects.filter(active=True).prefetch_related(
|
teams_qs = Team.objects.filter(active=True).prefetch_related(
|
||||||
Prefetch(
|
Prefetch(
|
||||||
'workers',
|
'workers',
|
||||||
queryset=Worker.objects.filter(active=True),
|
# Managers (pay_type='fixed') never go on a WorkLog.
|
||||||
|
queryset=Worker.objects.filter(active=True).exclude(pay_type='fixed'),
|
||||||
to_attr='active_workers_cached',
|
to_attr='active_workers_cached',
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -789,7 +790,8 @@ def attendance_log(request):
|
|||||||
# (admins only — supervisors don't see the cost card)
|
# (admins only — supervisors don't see the cost card)
|
||||||
worker_rates = {}
|
worker_rates = {}
|
||||||
if is_admin(user):
|
if is_admin(user):
|
||||||
for w in Worker.objects.filter(active=True):
|
# Managers (pay_type='fixed') never go on a WorkLog.
|
||||||
|
for w in Worker.objects.filter(active=True).exclude(pay_type='fixed'):
|
||||||
worker_rates[str(w.id)] = str(w.daily_rate)
|
worker_rates[str(w.id)] = str(w.daily_rate)
|
||||||
|
|
||||||
# Build team→workers mapping so the JS can auto-check workers when a
|
# Build team→workers mapping so the JS can auto-check workers when a
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user