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:
parent
39cbda11e5
commit
6d37d1ba9b
@ -214,6 +214,66 @@ class WorkLogPayrollAjaxTests(TestCase):
|
|||||||
resp = self.client.get('/history/99999/payroll/ajax/')
|
resp = self.client.get('/history/99999/payroll/ajax/')
|
||||||
self.assertEqual(resp.status_code, 404)
|
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 ===
|
# === TESTS FOR THE WORK LOG PAYROLL FULL-PAGE VIEW ===
|
||||||
# These cover the HTML page at /history/<id>/ that shares the same context
|
# These cover the HTML page at /history/<id>/ that shares the same context
|
||||||
|
|||||||
@ -144,3 +144,25 @@ No third-party dependencies added.
|
|||||||
## Next step
|
## Next step
|
||||||
|
|
||||||
Hand off to `superpowers:writing-plans` to produce a task-by-task implementation plan with review checkpoints.
|
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.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user