feat: add Worker.pay_type discriminator + is_salaried property

This commit is contained in:
Konrad du Plessis 2026-05-15 19:08:39 +02:00
parent 4dadb7cf23
commit 3c471691f3
3 changed files with 58 additions and 0 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-05-15 17:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0015_absence_project'),
]
operations = [
migrations.AddField(
model_name='worker',
name='pay_type',
field=models.CharField(choices=[('daily', 'Daily-rated'), ('fixed', 'Fixed salary')], default='daily', help_text='Daily-rated workers are logged per day. Fixed-salary staff (managers) are paid a set monthly amount and are never added to a work log.', max_length=10),
),
]

View File

@ -72,6 +72,22 @@ class Worker(models.Model):
notes = models.TextField(blank=True)
active = models.BooleanField(default=True)
# === PAY TYPE ===
# 'daily' = normal field worker, paid per logged work day (daily_rate).
# 'fixed' = manager / salaried staff: paid a fixed monthly amount via a
# 'Salary' PayrollAdjustment, never logged on a WorkLog. See
# CLAUDE.md "Manager / Salaried pay" + the Path-A naming note.
PAY_TYPE_CHOICES = [
('daily', 'Daily-rated'),
('fixed', 'Fixed salary'),
]
pay_type = models.CharField(
max_length=10, choices=PAY_TYPE_CHOICES, default='daily',
help_text='Daily-rated workers are logged per day. Fixed-salary '
'staff (managers) are paid a set monthly amount and are '
'never added to a work log.',
)
# === SIZING ===
# Clothing and boot sizes for PPE (personal protective equipment) ordering
shoe_size = models.CharField(max_length=20, blank=True)
@ -94,6 +110,11 @@ class Worker(models.Model):
# monthly salary divided by 20 working days
return (self.monthly_salary / Decimal('20.00')).quantize(Decimal('0.01'))
@property
def is_salaried(self):
# True for managers / fixed-salary staff (pay_type='fixed').
return self.pay_type == 'fixed'
def __str__(self):
return self.name

View File

@ -3364,3 +3364,22 @@ class DashboardPaidThisMonthTests(TestCase):
"""No payments in the current month → zero (not None)."""
resp = self.client.get('/')
self.assertEqual(resp.context['paid_this_month'], Decimal('0.00'))
class ManagerSalariedPayModelTests(TestCase):
"""Worker.pay_type discriminator + is_salaried convenience property."""
def test_pay_type_defaults_to_daily(self):
w = Worker.objects.create(
name='Daily Dan', id_number='PT-D1', monthly_salary=Decimal('6000.00'),
)
self.assertEqual(w.pay_type, 'daily')
self.assertFalse(w.is_salaried)
def test_pay_type_fixed_is_salaried(self):
m = Worker.objects.create(
name='Manager Fitz', id_number='PT-M1',
monthly_salary=Decimal('40000.00'), pay_type='fixed',
)
self.assertEqual(m.pay_type, 'fixed')
self.assertTrue(m.is_salaried)