- money filter: format via Decimal(str(...)) instead of float — money
never passes through binary floating point on its way to the screen
- preview_payslip / worker_lookup_ajax: accumulate totals in Decimal,
convert to float only at the JsonResponse boundary, so previews are
bit-identical to what _process_single_payment records
- price_overtime: explicit .quantize(0.01) instead of letting the DB
engine silently round the 3rd decimal place
- stacked-chart wage rollup: Decimal(str(salary)) — on SQLite dev the
value arrives as float and Decimal(float) keeps the binary noise
- payroll_dashboard fmt(): en-ZA space-separated thousands like every
other money helper on the page (was the one comma-format outlier)
- base.html admin gate: '(auth and staff) or superuser' precedence trap
replaced with 'staff or superuser' — exact same truth table (both
flags False on AnonymousUser), matches server-side is_admin()
- attendance_log.html: worker day-rates now ship via the house
json_script pattern instead of |safe-rendering a Python dict repr
into the script block
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>