22 Commits

Author SHA1 Message Date
Konrad du Plessis
37268801a1 feat(absences): list + edit + delete + CSV export
/absences/ filtered list with pagination + reason badges;
/absences/<id>/edit/ syncs adjustment on save; /absences/<id>/delete/
cascades unpaid adjustment, refuses if paid; /absences/export/
admin-only CSV. 10 tests.
2026-05-14 20:54:50 +02:00
Konrad du Plessis
b5833f675d feat(absences): log + confirm views + templates + URLs
/absences/log/ accepts form; no-conflict path creates absences
atomically; conflict path stashes pending data in session and
redirects to /absences/log/confirm/ (yellow warning + per-row
'Remove from WorkLog' checkboxes). Confirm POST runs atomic
transaction: remove flagged workers from WorkLogs, create
Absences, sync payroll adjustments. 10 tests.
2026-05-14 20:26:31 +02:00
Konrad du Plessis
864ae722c4 feat(site-report): structured site progress logging — Phase A.1
Companion to attendance: capture WHAT was done on site each day,
alongside WHO worked. Optional 1:1 with WorkLog. Mobile-first form
auto-redirected from /attendance/log/ on success (with a Skip link).

Why this design (vs. extending WorkLog or per-project templates):

- Hybrid schema. Stable + queryable fields are real columns
  (`weather`, `temperature_min`, `temperature_max`, `notes`,
  `created_by`, `created_at`, `updated_at`). The METRICS that change
  per project / over time live in a single JSONField with shape
  `{counts: {key: int}, checks: {key: bool}}` — driven by
  `core/site_report_schema.py`. Adding a new metric is a one-line
  edit to that file, NO migration required. Old reports without the
  new key just render as 0 / unchecked.

- Two-step flow. Attendance form is unchanged; on successful POST
  the supervisor lands on `/site-report/<work_log_id>/edit/` for the
  most-recently-created log. They can fill in progress details
  (~30 sec on a phone) or click "Skip" to home. WorkLogs without a
  SiteReport are completely valid historic rows.

- Permission scope mirrors WorkLog access. Anyone who can see the
  parent log (admin / log's supervisor / project's supervisors) can
  see + edit its SiteReport. Wraps the existing pattern from
  `work_history()` in a small helper `_can_access_site_report()`.

What ships:

  Models:
    - SiteReport (1:1 → WorkLog, weather choices, IntegerField temps,
      JSONField metrics defaulting to {})
    - Migration 0013_add_site_report (pure CreateModel, no schema
      changes to existing tables)

  Schema:
    - core/site_report_schema.py (NEW) — single source of truth for
      the metric list. Currently 7 counts + 4 checks per Konrad's
      v1 spec. Helpers: get_count_keys, get_check_keys, label_for,
      empty_metrics.

  Form:
    - SiteReportForm (in core/forms.py) — ModelForm with the four
      stable fields PLUS dynamic IntegerField/BooleanField per
      metric in __init__. save() serializes both halves into the
      JSON blob. clean() validates min ≤ max temperature.

  Views:
    - site_report_edit — create-or-update; stamps created_by on
      first save; preserves it on subsequent admin edits
    - site_report_detail — read-only display; 404 when no report
    - attendance_log redirect updated to two-step flow
    - _can_access_site_report — shared permission helper

  URLs:
    - /site-report/<work_log_id>/edit/  (name: site_report_edit)
    - /site-report/<work_log_id>/       (name: site_report_detail)

  Templates:
    - site_report_edit.html — mobile-first stack of inputs, weather
      as a chunky icon-button row (☀️ ☁️ 🌧️ ⛈️ 🥵 🥶 💨), counts in a
      2-col grid, checks as toggle switches, Notes textarea, Skip
      + Save buttons. Iterates pre-built (metric, bound_field)
      pairs from the view to avoid needing a new template filter.
    - site_report_detail.html — counts as accent-coloured value
      cards, checks as a check-list, weather + temp + notes + edit
      link.
    - work_history.html — added a small clipboard icon next to
      each row's date: filled (linked to detail) when a report
      exists, muted outline (linked to edit) when not. Click is
      event.stopPropagation()-ed so the row's payroll-modal
      handler doesn't also fire.

  Performance:
    - work_history queryset adds .select_related('site_report') so
      the new template indicator doesn't introduce an N+1.

  Admin:
    - SiteReport registered with raw_id_fields on work_log +
      created_by, list filters on weather + project + date.

  Tests (16 new, full suite 85/85):
    - SiteReportModelTests — defaults, 1:1 reverse accessor,
      arbitrary-key JSON round-trip
    - SiteReportFormTests — dynamic field generation, save
      serialisation, temp validation, instance pre-fill
    - SiteReportEditViewTests — admin GET/POST, project
      supervisor allowed, outsider supervisor 403, created_by
      preserved on subsequent admin edits
    - SiteReportDetailViewTests — 404 when absent, displays data
      when present
    - AttendanceLogRedirectsToSiteReportTests — confirms the
      two-step flow

  CLAUDE.md updates:
    - SiteReport added to "Key Models" with shape + reverse-accessor note
    - New "SiteReport metric schema" section near "UI-vs-DB
      naming drift" — explains the JSON-column-with-Python-source
      pattern, when it's safe, what NOT to do (rename a key with
      data), and where the keys appear across the codebase
    - URL Routes table gets the two new endpoints

What's NOT in this commit (deferred per the brainstorm plan):
  - JournalEntry model + manual web-entry UI (Phase A.2 — depends
    on Konrad's Q7 answer about Vi/recipient field)
  - Letterly inbound webhook (Phase B — integrations branch only,
    depends on Q5 sample payload)
  - Photos on site reports (Q9, defaulted to "future")
  - Per-project metric templates (Q4, defaulted to "same set for all v1")

Reference plan: ~/.claude/plans/prancy-painting-brook.md (local).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 02:29:33 +02:00
Konrad du Plessis
03f177e7d0 feat(adjustments): bulk-delete unpaid rows + floating action bar
New POST /payroll/adjustments/bulk-delete/ endpoint takes a list of
adjustment_ids and DELETEs the ones that are still unpaid
(payroll_record__isnull=True at the DB level) — paid rows are silently
skipped, defensive against stale-UI race conditions. Admin-only;
supervisors get 403. Returns JSON {deleted, requested}.

Floating bar slides up from the bottom of the viewport when >=1 row
selected: shows count + Delete + Clear. Confirm dialog guards the
POST. On success, page reloads to reflect the new state.

CSRF via X-CSRFToken header from the csrftoken cookie (Django
middleware sets this). Two new tests lock in the 'only unpaid' +
'admin-only' contracts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 18:51:54 +02:00
Konrad du Plessis
b4c3109c29 Add URL routes + stubs for work log payroll cross-link
Routes /history/<id>/ and /history/<id>/payroll/ajax/ to stub views.
Both admin-gated; no data yet. Sets up the surface for Tasks 2-4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 13:43:13 +02:00
Konrad du Plessis
3c28387dd3 WIP: 2026-04-22 session checkpoint
Complete working state of the session. Will be split into two deploy
phases (safety scaffolding then feature release) before merging to ai-dev.

Includes:
- Security fixes (email creds / SECRET_KEY / DEBUG / CSRF)
- Backup + restore management commands and browser endpoints
- WeasyPrint migration (replaces xhtml2pdf)
- New Worker fields + WorkerCertificate + WorkerWarning models
- Worker / Team / Project friendly management UIs
- Dashboard cert-expiry card + Manage All buttons
- Bootstrap tooltips (global init + theme-aware CSS)
- Django admin template override (taller M2M pickers)
- Money filter for ZAR currency formatting
- Resources dropdown nav
- Massive CLAUDE.md expansion + deploy plan docs

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 00:19:15 +02:00
Konrad du Plessis
60ee21dd61 Add Worker Lookup modal to payroll dashboard
New AJAX endpoint (worker_lookup_ajax) returns a comprehensive financial
report card for any active worker. Modal shows: amount payable, outstanding
loans, paid this month/year, loans this year, recent activity, active loans
table, current project + days, PPE sizing, drivers license, and notes.
Worker names across all dashboard tabs are now clickable links that open
the modal. Header button with searchable dropdown for quick access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 14:15:04 +02:00
Konrad du Plessis
2e6881b7a4 Add batch pay feature and fix pay period cutoff logic
Batch Pay: new button on payroll dashboard lets admins pay multiple
workers at once using team pay schedules. Shows preview modal with
eligible workers, then processes all payments in one click.

Fix: "Split at Pay Date" now uses cutoff_date (end of last completed
period) instead of current period end. This includes ALL overdue work
across completed periods, not just one period.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:16:21 +02:00
Konrad du Plessis
2c8d80e4a1 Add /run-migrate/ endpoint for browser-based migration
Flatlogic's "Pull Latest" doesn't always run migrations automatically.
This endpoint lets you visit /run-migrate/ to apply pending migrations
to the production MySQL database from the browser.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 21:19:55 +02:00
Konrad du Plessis
0257b454af Add Advance Payment system + enhanced preview modal with inline repayments
Redesign Advance Payments to work like loans with tracked balances:
- Add loan_type field to Loan model ('loan' or 'advance')
- Move Advance Payment from DEDUCTIVE to ADDITIVE types (worker receives money)
- Add new Advance Repayment type for deducting from future salary
- Create/edit/delete handlers mirror New Loan behavior for advances
- Loans & Advances tab with type badges and filter buttons

Enhance Payslip Preview modal into "Worker Payment Hub":
- Show outstanding loans & advances with balances in preview
- Inline repayment form per loan (amount pre-filled, note, Deduct button)
- AJAX add_repayment_ajax endpoint creates adjustment without page reload
- Modal auto-refreshes after repayment showing updated net pay
- New refreshPreview() JS function enables re-fetching after AJAX

Other changes:
- Rename History to Work History in navbar
- Advance-specific payslip layout for pure advance payments
- Fix JS noProjectTypes to hide Project field for advance types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 10:46:58 +02:00
Konrad du Plessis
2aad9ac623 Add Export Workers CSV — downloads all worker data as spreadsheet
Admin-only CSV export with name, ID number, phone, salary, daily rate,
employment date, active status, and notes. Button on dashboard next to
Manage Resources header.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:36:57 +02:00
Konrad du Plessis
fc63d972b1 Add expense receipt feature: form, view, templates, email + PDF
Straight port from V2 adapted for V5 field names. Creates expense
receipts with dynamic line items, VAT calculation (Included/Excluded/
None at 15%), and emails HTML + PDF to Spark Receipt. Uses lazy
xhtml2pdf import to avoid crashing if not installed on server.

Files: forms.py (ExpenseReceiptForm + FormSet), views.py (create_receipt),
create_receipt.html, receipt_email.html, receipt_pdf.html, urls.py, base.html

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 21:38:14 +02:00
Konrad du Plessis
c8c78dd88e Add payslip feature: detail page, PDF generation, and email to Spark
- core/utils.py: render_to_pdf() wrapper for xhtml2pdf
- core/templates/core/pdf/payslip_pdf.html: A4 PDF payslip (matches V2 layout)
- core/templates/core/email/payslip_email.html: HTML email body for Spark
- core/templates/core/payslip.html: browser payslip detail page with print
- core/views.py: add payslip_detail view, wire email+PDF into process_payment
- core/urls.py: add payroll/payslip/<pk>/ route
- config/settings.py: add SPARK_RECEIPT_EMAIL setting
- payroll_dashboard.html: add "View" payslip link in Payment History tab

All templates show adjustments (bonuses, deductions, overtime, loan repayments)
as line items. Amounts always show 2 decimal places. Email failure does not
roll back payment — handled gracefully with warning message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 20:37:04 +02:00
Konrad du Plessis
aaf86c2513 Add production data import from V2 CSV backup
Imports 57 rows of real data: 14 workers, 2 projects, 2 supervisors,
38 work logs (Jan 23 - Feb 21), 19 adjustments (deductions, bonuses,
overtime, loan repayments, advance payments). Includes PayrollRecords
for paid entries. Visit /import-data/ to trigger from browser.

Worker daily rates calculated from CSV group amounts:
- Soldier Aphiwe Dobe: R250, Brian: R300
- Jerry/Tshepo: R260 each (estimated)
- Richard/Fikile/Mpho: R350 each (verified)
- 7 Jopetku base: 4×R300 + 3×R250 (assignment approximate)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 19:47:47 +02:00
Konrad du Plessis
e4b81838a3 Remove temporary /setup/ URL and view — admin works fine
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 19:18:03 +02:00
Konrad du Plessis
98ef3f5b90 Add temporary /setup/ URL to bootstrap admin + test data from browser
Visit your-site.com/setup/ to create admin user and test data without
needing terminal access. Links to admin panel and dashboard after setup.
REMOVE THIS after initial testing is complete.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:55:59 +02:00
Konrad du Plessis
efe5f08682 Add Phase 3: Payroll Dashboard with full payment processing
- PayrollAdjustmentForm with project validation for types that require it
- 7 payroll views: dashboard, process_payment, price_overtime, add/edit/delete
  adjustment, preview_payslip (all admin-only)
- Payroll dashboard template with analytics cards, Chart.js charts (monthly
  totals + per-project costs), 3 tabs (Pending/Paid/Loans), 5 modals
- XSS-safe JavaScript using createElement+textContent (zero innerHTML)
- Fix: outstanding-by-project now handles partially-paid WorkLogs per-worker
- Fix: active loan count and balance computed via aggregate in view
- Payroll navbar link wired up, 7 URL patterns added
- Zero model/migration changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:47:12 +02:00
Konrad du Plessis
77236dd78f Phase 2B: Enhanced attendance, work history filters, supervisor dashboard
- Attendance form: date range (start+end), Sat/Sun checkboxes, conflict
  detection with Skip/Overwrite, supervisor auto-set, estimated cost card
- Work history: filter by worker/project/payment status, CSV export,
  payment status badges (Paid/Unpaid)
- Supervisor dashboard: stat cards for projects, teams, workers count
- Forms: supervisor filtering (non-admins only see their projects/workers)
- Navbar: History link now works, cleaned up inline styles in base.html
- Management command: setup_groups creates Admin + Work Logger groups
- No model/migration changes — database is untouched

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 16:28:18 +02:00
Flatlogic Bot
306fb0e95d Ver 1.04 2026-02-22 13:31:37 +00:00
Flatlogic Bot
28c36a1e12 Ver 1.02 2026-02-22 12:55:15 +00:00
Flatlogic Bot
d10151cf40 Ver 01 2026-02-22 12:26:15 +00:00
Flatlogic Bot
d3fb8046d5 Initial version 2026-02-22 12:14:54 +00:00