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/')
|
||||
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
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user