# Worker Lookup Modal — Implementation Plan

> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

**Goal:** Add a "Worker Lookup" modal to the payroll dashboard that shows a comprehensive financial report card for any active worker — payable amount, loans, recent payments, sizing, and notes.

**Architecture:** New AJAX endpoint (`worker_lookup_ajax`) returns JSON with all worker data. Modal HTML + JS in the dashboard template dynamically renders the data using safe DOM methods (textContent, createElement). Worker names across all dashboard tabs become clickable links that open the modal. A "Worker Lookup" button in the header lets you search any active worker.

**Tech Stack:** Django views (JSON), Bootstrap 5 modal, vanilla JavaScript (matching existing patterns)

---

### Task 1: Add the AJAX backend endpoint

**Files:**
- Modify: `core/views.py` (add new view after `preview_payslip` at ~line 2155)
- Modify: `core/urls.py` (add new URL pattern at ~line 54)

**Step 1: Add URL pattern in `core/urls.py`**

Add after the `preview_payslip` URL (line 51):

```python
# Worker lookup — AJAX report card for a single worker (returns JSON)
path('payroll/worker-lookup/<int:worker_id>/', views.worker_lookup_ajax, name='worker_lookup_ajax'),
```

**Step 2: Add `worker_lookup_ajax` view in `core/views.py`**

Add after `preview_payslip` function (after line 2155). The view:

1. Checks admin access (`is_admin`)
2. Fetches the Worker object with all model fields (sizing, license, notes)
3. Calculates Amount Payable:
   - Unpaid WorkLogs x daily_rate (same logic as `preview_payslip` lines 2069-2083)
   - Net pending adjustments (additive minus deductive)
4. Outstanding Loans: `Loan.filter(worker=worker, active=True).aggregate(Sum('remaining_balance'))`
5. Paid This Month: `PayrollRecord.filter(worker=worker, date__year=now.year, date__month=now.month).aggregate(Sum('amount_paid'))`
6. Loans This Year: `Loan.filter(worker=worker, date__year=now.year).aggregate(Sum('principal_amount'))`
7. Paid This Year: `PayrollRecord.filter(worker=worker, date__year=now.year).aggregate(Sum('amount_paid'))`
8. Last Payslip: `PayrollRecord.filter(worker=worker).order_by('-date').first()` -> date + amount
9. Last Loan Given: `Loan.filter(worker=worker).order_by('-date').first()` -> date + amount + reason
10. Last Loan Repayment: `PayrollAdjustment.filter(worker=worker, type='Loan Repayment', payroll_record__isnull=False).order_by('-date').first()` -> date + amount
11. Last Advance: `PayrollAdjustment.filter(worker=worker, type='Advance Payment', payroll_record__isnull=False).order_by('-date').first()` -> date + amount
12. Active Loans list: `Loan.filter(worker=worker, active=True).order_by('-date')` -> type, principal, balance, date, reason
13. Current Project: most recent WorkLog -> project name + count of logs on that project
14. Team: `get_worker_active_team(worker)` -> team name

**Step 3: Verify imports**

Ensure `Sum` is imported from `django.db.models` at the top of `views.py`. Check for existing `from django.db.models import ...` line and add `Sum` if missing.

---

### Task 2: Add the modal HTML to the dashboard template

**Files:**
- Modify: `core/templates/core/payroll_dashboard.html`

**Step 1: Add "Worker Lookup" button in the page header (line 15)**

Add a new button in the header button group, before Batch Pay.

**Step 2: Add the Worker Lookup modal HTML**

Add after the `previewPayslipModal` (after line ~783). The modal contains:
- Worker dropdown in header
- A body div (`#workerLookupBody`) that gets populated by JS
- Placeholder text as default content

**Step 3: Pass `active_workers_list` from the view**

In `core/views.py`, in the `payroll_dashboard` view, add to the context dict:

```python
'active_workers_list': Worker.objects.filter(active=True).order_by('name'),
```

---

### Task 3: Make worker names clickable across all tabs

**Files:**
- Modify: `core/templates/core/payroll_dashboard.html`

Replace `<strong>worker.name</strong>` with clickable links using class `worker-lookup-link` and `data-worker-id` at:

- **Pending Payments tab** (line 268)
- **Payment History tab** (line 365)
- **Loans & Advances tab** (line 432)

---

### Task 4: Add JavaScript to fetch data and render the modal

**Files:**
- Modify: `core/templates/core/payroll_dashboard.html` (JS section at bottom)

**Step 1: Add the `loadWorkerLookup(workerId)` function**

This function:
1. Shows a loading spinner in `#workerLookupBody`
2. Fetches `/payroll/worker-lookup/<workerId>/` via fetch API
3. Builds the report card using safe DOM methods (createElement, textContent — no innerHTML with user data)
4. Renders sections: Identity, Quick Stats (4 cards), Recent Activity, Active Loans table, Paid This Year, Sizing & Info

Format currency as `R X,XXX.XX` using `toLocaleString('en-ZA', {minimumFractionDigits: 2})`.

**Step 2: Add event listeners**

- Worker Lookup button click -> open modal with empty dropdown
- Dropdown change -> call `loadWorkerLookup(selectedId)`
- `.worker-lookup-link` click -> set dropdown value, load data, open modal

---

### Task 5: Update CLAUDE.md

**Files:**
- Modify: `CLAUDE.md`

- Add Worker Lookup documentation to Development Workflow section
- Add URL route to the URL Routes table
- Update view count from "27 functions" to "28 functions"

---

### Task 6: Test locally

1. Start dev server: `run_dev.bat`
2. Go to `/payroll/` -> verify "Worker Lookup" button appears in header
3. Click "Worker Lookup" -> modal opens with dropdown -> select a worker -> report card loads
4. Click a worker name in Pending Payments -> modal opens with that worker's data
5. Click a worker name in Payment History -> same
6. Click a worker name in Loans & Advances -> same
7. Switch workers via dropdown while modal is open -> data refreshes
8. Verify all sections render correctly:
   - Quick stats show correct amounts
   - Recent activity shows dates and amounts (or "None")
   - Active loans table shows if worker has loans
   - Sizing and notes display at bottom
9. Verify existing functionality is unbroken:
   - Preview payslip modal still works
   - Quick adjust button still works
   - Pay/Batch pay still works
