Task 10: add Task 3 full-payload test + mark design doc as shipped

Adds a consolidated regression test to WorkLogPayrollAjaxTests that
exercises: paid worker serialization shape, null team branch, OT flag
in JSON, full_page_url value, and adjustment payslip-link serialization.
Closes the 'Important' coverage gap flagged in Task 3's quality review.

Also appends a 'Shipped' block to the design doc summarising QA
status and capturing all five deferred nits (admin-gate consistency,
template branch tests, |default:0 redundancy, admin-gate expression
readability, background vs background-color) so they survive the
merge into project history.

All 19 tests pass. manage.py check clean. No migrations needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-22 18:23:24 +02:00
parent 39cbda11e5
commit 6d37d1ba9b
2 changed files with 82 additions and 0 deletions

View File

@ -214,6 +214,66 @@ class WorkLogPayrollAjaxTests(TestCase):
resp = self.client.get('/history/99999/payroll/ajax/')
self.assertEqual(resp.status_code, 404)
def test_full_payload_with_paid_worker_null_team_and_ot(self):
"""One scenario exercising: paid worker, null team, OT flag, full URL."""
# Create a paid worker on a separate log with no team (null team edge case)
# and with overtime hours but no priced_workers (unpriced OT flag).
project = Project.objects.create(name='P-full')
paid_worker = Worker.objects.create(
name='Paula', id_number='P1', monthly_salary=Decimal('4000')
)
log = WorkLog.objects.create(
date=datetime.date(2026, 4, 11),
project=project,
team=None, # null team
supervisor=self.admin,
overtime_amount=Decimal('1.50'), # > 0 and no priced_workers -> flag fires
)
log.workers.add(paid_worker)
# Link a PayrollRecord so Paula shows as Paid
record = PayrollRecord.objects.create(
worker=paid_worker,
amount_paid=Decimal('250.00'),
date=datetime.date(2026, 4, 16),
)
record.work_logs.add(log)
# Link an adjustment to the same log
adj = PayrollAdjustment.objects.create(
worker=paid_worker,
project=project,
type='Overtime',
amount=Decimal('75.00'),
date=datetime.date(2026, 4, 11),
description='OT pricing',
work_log=log,
payroll_record=record,
)
self.client.login(username='admin', password='pass')
resp = self.client.get(reverse('work_log_payroll_ajax', args=[log.id]))
self.assertEqual(resp.status_code, 200)
data = resp.json()
# Null team branch
self.assertIsNone(data['team'])
# Project is still present
self.assertEqual(data['project']['name'], 'P-full')
# Paid worker serialization shape
paula_row = next(r for r in data['worker_rows'] if r['worker_name'] == 'Paula')
self.assertEqual(paula_row['status'], 'Paid')
self.assertEqual(paula_row['payroll_record_id'], record.pk)
self.assertEqual(paula_row['paid_date'], '2026-04-16')
# OT flag fires (overtime > 0, no priced_workers)
self.assertTrue(data['overtime_needs_pricing'])
# full_page_url is the reverse of work_log_payroll_detail
self.assertEqual(data['full_page_url'], f'/history/{log.id}/')
# Adjustment serialized with payslip link
self.assertEqual(len(data['adjustments']), 1)
self.assertEqual(data['adjustments'][0]['type'], 'Overtime')
self.assertEqual(data['adjustments'][0]['payroll_record_id'], record.pk)
# === TESTS FOR THE WORK LOG PAYROLL FULL-PAGE VIEW ===
# These cover the HTML page at /history/<id>/ that shares the same context

View File

@ -144,3 +144,25 @@ No third-party dependencies added.
## Next step
Hand off to `superpowers:writing-plans` to produce a task-by-task implementation plan with review checkpoints.
---
## Shipped — 22 Apr 2026
**Commits:** 1c00ba2 (design) through the Task 10 "shipped" commit (this one).
**Plan:** `docs/plans/2026-04-22-work-log-payroll-crosslink-plan.md`.
**QA summary:**
- 19 tests pass (`python manage.py test core.tests`)
- `python manage.py check` — no new issues
- No model changes, no migrations, no pushed-to-prod artefacts
- Three entry points clickable for admins; supervisors unchanged
**Deferred for future passes (non-blocking):**
- Admin-gate consistency: work_history uses `{% if is_admin %}`; teams/projects detail templates use `{% if user.is_staff or user.is_superuser %}`. Both semantically identical but stylistically inconsistent.
- Task 4 template branch tests: OT banner, adjustments table, Paid badge, Inactive worker — covered end-to-end via modal tests now, not via Django test client.
- Task 4 template: redundant `|default:0` on `log.overtime_amount` (harmless, renders "0" instead of "0.00").
- Task 5 admin gate: `user.is_authenticated and user.is_staff or user.is_superuser` could be simplified to `user.is_staff or user.is_superuser`.
- `background` shorthand in Task 9 hover rule could be `background-color` for precision (pedantic).
**"Pay these workers now" modal action** and **"Add adjustment pre-filled for this log" shortcut** — explicitly out-of-scope per the design; revisit if users ask.