{# === PAGE HEADER === #}
{# On desktop: title left, buttons right in a row #}
{# On mobile: title on top, buttons below in a 2x2 grid #}
Payroll Dashboard
{# === ANALYTICS SUMMARY BAR — compact row of key numbers === #}
{# Always visible. Clicking "Show Details" expands the full stat cards and charts below. #}
{# Key numbers in a compact row #}
Outstanding
R {{ outstanding_total|floatformat:2 }}
Paid (60d)
R {{ recent_payments_total|floatformat:2 }}
Loans ({{ active_loans_count }})
R {{ active_loans_balance|floatformat:2 }}
{# Toggle button to expand/collapse full analytics #}
{# === FULL ANALYTICS (hidden by default — toggled by button above) === #}
{# --- Stat cards row --- #}
{# --- Left column: stat cards --- #}
{# Outstanding Total — with breakdown of wages vs adjustments #}
Outstanding Payments
R {{ outstanding_total|floatformat:2 }}
{% if pending_adj_add_total or pending_adj_sub_total %}
{# === ADJUSTMENTS TAB LINK === #}
{# Task 4: flat table view of every payroll adjustment with filters, #}
{# bulk actions, and row edit/delete. See _adjustment_row.html. #}
{# =============================================== #}
{# === PENDING PAYMENTS TAB === #}
{# =============================================== #}
{% if active_tab == 'pending' %}
{# === PENDING PAYMENTS FILTER BAR === #}
{# Lets admin filter by team, show only overdue workers, or exclude workers with loans #}
{# On mobile: hide Days, Day Rate, Log Amount, Adjustments, Net Adj columns #}
{# Only show: Worker (with badges), Total, Adjust + Pay buttons #}
{# All details are accessible by tapping the worker name (opens lookup modal) #}
{% if loan.active %}
Active
{% else %}
Paid Off
{% endif %}
{% empty %}
{% if loan_filter == 'active' %}No active loans or advances.{% else %}No loan/advance history.{% endif %}
{% endfor %}
{% endif %}
{# =============================================== #}
{# === ADJUSTMENTS TAB === #}
{# =============================================== #}
{# Flat, filterable table of every PayrollAdjustment in the system. #}
{# Filters run server-side via GET params (type, worker, team, status, date range). #}
{# Row actions reuse the existing Edit / Delete / Preview modals so no new JS is needed. #}
{% if active_tab == 'adjustments' %}
{# --- Cross-filter data: (team_id, worker_id) pairs for the Workers popover --- #}
{{ team_worker_pairs_json|json_script:"adjTeamWorkerPairs" }}
{# --- Sticky filter bar (pill-popover checkbox filters for Type/Workers/Teams) --- #}
{# --- Group-by toggle: Flat / By Type / By Worker --- #}
{# Clicking a pill sets the ?group_by= querystring; url_replace preserves #}
{# all other filters (type, worker, team, status, dates) so the view #}
{# re-renders the SAME filtered set, just re-bucketed. #}
{# --- Flat table of adjustments --- #}
{% if adj_page.object_list %}
{# aria-label is the accessible name screen readers announce; #}
{# title= is kept as the mouse-hover tooltip for sighted users. #}
{# Distinct id from the Add-Adjustment modal's own #adjSelectAll #}
{# anchor (line ~940) — duplicate ids are invalid HTML and caused the #}
{# modal's Select-All handler to silently bind to this checkbox instead. #}
{# === Sortable column headers — click toggles sort via filter form === #}
{# Each sortable
reflects the current sort/order from adj_filter_values. #}
{# The arrow icon is fa-sort (inactive), fa-sort-down (desc) or fa-sort-up (asc). #}
{# JS click handler is wired up in the DOMContentLoaded block further down. #}
Date
Worker
Type
Amount
Project
Team
Description
Status
Actions
{% if adj_groups %}
{# Grouped view: one per group with a clickable #}
{# header row. Each group's is a Bootstrap collapse #}
{# target so clicking the header hides or shows its rows. #}
{# Default state: every group expanded (class="collapse show"). #}
{% for group in adj_groups %}
{% for adj in group.rows %}
{% include 'core/_adjustment_row.html' with adj=adj additive_types=additive_types %}
{% endfor %}
{% endfor %}
{% else %}
{# Flat view (default when no group_by selected) — unchanged from Task 4. #}
{% for adj in adj_page.object_list %}
{% include 'core/_adjustment_row.html' with adj=adj additive_types=additive_types %}
{% endfor %}
{% endif %}
{# --- Pagination: flat view only. When grouped, group headers act as --- #}
{# --- their own navigation and totals cover the whole filtered set. --- #}
{% if adj_page.has_other_pages and not adj_groups %}
{% endif %}
{% else %}
{# No rows match the current filter set. Two recovery paths: clear filters (re-fetch unfiltered) or add a new adjustment (opens the existing #addAdjustmentModal). #}
{% endif %}
{# Floating bulk action bar: fixed at the bottom of the viewport, centred horizontally. #}
{# Shown when >= 1 unpaid row is selected. CSS .adj-bulk-bar + animation shipped in Task 2. #}
{# --- PREVIEW PAYSLIP MODAL --- #}
{# === BATCH PAY MODAL === #}
{# Shows a preview of which workers will be paid (based on team pay schedules), #}
{# then lets the admin confirm to process all payments at once. #}
Batch Pay by Schedule
{# Content loaded via JavaScript #}
Loading preview...
Payslip Preview & Repayments
{# Content loaded via JavaScript #}
Loading preview...
{# === WORKER LOOKUP MODAL === #}
{# Shows a comprehensive financial report card for any active worker. #}
{# Triggered by clicking a worker name or the "Worker Lookup" button. #}
Worker Lookup
{# Worker selector dropdown #}
{# Report card content — populated dynamically by JavaScript #}
Select a worker to view their report card.
{# ================================================================== #}
{# === JAVASCRIPT === #}
{# ================================================================== #}
{# Django's json_script filter safely outputs JSON without XSS risk #}
{{ overtime_data_json|json_script:"otDataJson" }}
{{ team_workers_map_json|json_script:"teamWorkersJson" }}
{{ chart_labels_json|json_script:"chartLabelsJson" }}
{{ chart_totals_json|json_script:"chartTotalsJson" }}
{{ project_chart_json|json_script:"projectChartJson" }}
{{ worker_chart_json|json_script:"workerChartJson" }}
{# === CHOICES.JS CDN — loaded only when the Adjustments tab is active === #}
{# Used by the Type / Workers / Teams multi-select filters. If the CDN fails #}
{# the