polish: Salary multi-adjustment payslip-layout guard test; tighten list test; a11y badge contrast
This commit is contained in:
parent
862766f9b5
commit
268a050397
@ -3743,10 +3743,20 @@ class ManagerSalariedPayUITests(TestCase):
|
||||
Worker.objects.create(
|
||||
name='UI Mgr', id_number='MSU-M', monthly_salary=Decimal('40000'),
|
||||
pay_type='fixed')
|
||||
# A plain daily worker (default pay_type) alongside the manager so
|
||||
# we can prove BOTH the salaried and the daily indicator render.
|
||||
Worker.objects.create(
|
||||
name='UI Daily', id_number='MSU-D', monthly_salary=Decimal('6000'))
|
||||
# worker_list status filter param confirmed in CLAUDE.md routes table.
|
||||
resp = self.client.get(reverse('worker_list') + '?status=all')
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertContains(resp, 'Manager')
|
||||
# Assert the FULL salaried label (not just the 'Manager' substring)
|
||||
# and the daily worker's exact 'Daily' chip markup. 'Daily' alone is
|
||||
# too generic to assert on a whole page, so we target the closing
|
||||
# markup of the daily badge span (list.html line ~101) which only
|
||||
# the daily branch emits.
|
||||
self.assertContains(resp, 'Manager / Salaried')
|
||||
self.assertContains(resp, '>Daily</span>')
|
||||
|
||||
def test_salary_immediate_payslip_has_no_zero_days_line(self):
|
||||
# Absorbed Task-5 review #2: an immediate Salary payment's payslip
|
||||
@ -3807,3 +3817,52 @@ class ManagerSalariedPayUITests(TestCase):
|
||||
html = render_to_string('core/pdf/payslip_pdf.html', ctx)
|
||||
self.assertNotIn('days worked', html) # generic Base Pay line absent
|
||||
self.assertIn('Salary', html)
|
||||
|
||||
def test_salary_with_other_adjustment_uses_normal_payslip_layout(self):
|
||||
# MONEY-DOCUMENT PRESENTATION GUARD (negative path).
|
||||
# The clean single-line "Salary Details" payslip layout must ONLY
|
||||
# fire for a standalone single-Salary payment (the immediate
|
||||
# add_adjustment path). When a Salary adjustment is paid ALONGSIDE
|
||||
# another adjustment (here a Deduction) they net into ONE
|
||||
# PayrollRecord with TWO linked adjustments — len(adjs_list)==1 is
|
||||
# False, so payslip_detail's is_salary guard must stay False and
|
||||
# the NORMAL multi-item layout (work-log table + adjustments table
|
||||
# + Net Payable) must render. This locks the shared guard so it
|
||||
# can't later be refactored into misfiring on a multi-adjustment
|
||||
# record (which would hide the deduction on a money document).
|
||||
proj = Project.objects.create(name='NormLayout Proj')
|
||||
mgr = Worker.objects.create(
|
||||
name='NormLayout Mgr', id_number='MSU-NL',
|
||||
monthly_salary=Decimal('40000'), pay_type='fixed')
|
||||
sal = PayrollAdjustment.objects.create(
|
||||
worker=mgr, type='Salary', amount=Decimal('40000.00'),
|
||||
date=_date(2026, 5, 25), project=proj) # unpaid
|
||||
ded = PayrollAdjustment.objects.create(
|
||||
worker=mgr, type='Deduction', amount=Decimal('1000.00'),
|
||||
date=_date(2026, 5, 25), project=proj) # unpaid
|
||||
# Pay flow nets both into a single PayrollRecord (40000 - 1000).
|
||||
self.client.post(reverse('process_payment', args=[mgr.id]))
|
||||
sal.refresh_from_db()
|
||||
ded.refresh_from_db()
|
||||
self.assertIsNotNone(sal.payroll_record)
|
||||
self.assertEqual(sal.payroll_record, ded.payroll_record)
|
||||
pr = sal.payroll_record
|
||||
self.assertEqual(pr.amount_paid, Decimal('39000.00'))
|
||||
self.assertEqual(pr.adjustments.count(), 2) # NOT 1
|
||||
|
||||
resp = self.client.get(reverse('payslip_detail', args=[pr.id]))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
body = resp.content.decode()
|
||||
# NORMAL/generic branch markup (payslip.html lines ~168/197/254)
|
||||
# MUST be present — these strings exist ONLY in the {% else %}
|
||||
# generic branch, never in the clean is_salary branch.
|
||||
self.assertIn('Work Log Details (Attendance)', body)
|
||||
self.assertIn('Base Pay Subtotal', body)
|
||||
self.assertIn('Net Payable:', body)
|
||||
# Clean single-Salary branch headings (payslip.html lines ~134/159)
|
||||
# MUST be ABSENT — if the is_salary guard wrongly fired for this
|
||||
# 2-adjustment record, "Salary Details" / "Salary Amount:" would
|
||||
# appear and this assertion would fail (the whole point of the
|
||||
# guard test).
|
||||
self.assertNotIn('Salary Details', body)
|
||||
self.assertNotIn('Salary Amount:', body)
|
||||
|
||||
@ -92,7 +92,7 @@
|
||||
/* Salary (manager / fixed monthly pay) — a distinct teal, not used by
|
||||
any other type; reads as "regular salary/pay", separate from the
|
||||
forest-green Bonus and the slate-blue Advance. */
|
||||
--badge-salary-bg: #1f7a70; --badge-salary-fg: #d6f1ec;
|
||||
--badge-salary-bg: #1a6b62; --badge-salary-fg: #e3f5f1;
|
||||
|
||||
/* === PAYROLL DASHBOARD action-button tokens (dark theme) ===
|
||||
Soft-fill pastels for the 4 action buttons at the top of /payroll/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user