38186-vm/core/templates/core/payroll_dashboard.html
2026-02-03 23:42:44 +00:00

251 lines
12 KiB
HTML

{% extends 'base.html' %}
{% load humanize %}
{% block title %}Payroll Dashboard - Fox Fitt{% endblock %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="h2 fw-bold text-dark">Payroll Dashboard</h1>
<div>
<a href="{% url 'loan_list' %}" class="btn btn-outline-secondary me-2">Manage Loans</a>
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#addAdjustmentModal">
+ Add Adjustment
</button>
</div>
</div>
<!-- Analytics Section -->
<div class="row mb-5">
<!-- Outstanding Payments -->
<div class="col-md-4 mb-3">
<div class="card border-0 shadow-sm h-100 bg-warning bg-opacity-10">
<div class="card-body">
<h6 class="text-uppercase text-muted fw-bold small">Outstanding Payments</h6>
<div class="display-6 fw-bold text-dark">R {{ outstanding_total|intcomma }}</div>
<p class="text-muted small mb-0">Total pending (including adjustments)</p>
</div>
</div>
</div>
<!-- Recent Payments -->
<div class="col-md-4 mb-3">
<div class="card border-0 shadow-sm h-100 bg-success bg-opacity-10">
<div class="card-body">
<h6 class="text-uppercase text-muted fw-bold small">Recent Payments (2 Months)</h6>
<div class="display-6 fw-bold text-dark">R {{ recent_payments_total|intcomma }}</div>
<p class="text-muted small mb-0">Total paid out</p>
</div>
</div>
</div>
<!-- Project Costs -->
<div class="col-md-4 mb-3">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white fw-bold small text-uppercase text-muted">Project Costs (Active)</div>
<div class="card-body overflow-auto" style="max-height: 150px;">
{% if project_costs %}
<ul class="list-group list-group-flush">
{% for p in project_costs %}
<li class="list-group-item d-flex justify-content-between align-items-center px-0 py-2">
<span>{{ p.name }}</span>
<span class="fw-bold text-dark">R {{ p.cost|intcomma }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<p class="text-muted small mb-0">No active project costs.</p>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Filter Tabs -->
<ul class="nav nav-pills mb-4">
<li class="nav-item">
<a class="nav-link {% if active_tab == 'pending' %}active{% endif %}" href="?status=pending">Pending Payments</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_tab == 'paid' %}active{% endif %}" href="?status=paid">Payment History</a>
</li>
<li class="nav-item">
<a class="nav-link {% if active_tab == 'all' %}active{% endif %}" href="?status=all">All Records</a>
</li>
</ul>
<!-- Pending Payments Table -->
{% if active_tab == 'pending' or active_tab == 'all' %}
{% if workers_data %}
<div class="card border-0 shadow-sm mb-5">
<div class="card-header bg-white fw-bold">Pending Payments</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">Worker Name</th>
<th>Breakdown</th>
<th>Net Payable</th>
<th class="text-end pe-4">Action</th>
</tr>
</thead>
<tbody>
{% for item in workers_data %}
<tr>
<td class="ps-4">
<div class="fw-bold text-dark">{{ item.worker.name }}</div>
<div class="small text-muted">ID: {{ item.worker.id_no }}</div>
{% if item.adjustments %}
<div class="mt-1">
{% for adj in item.adjustments %}
<span class="badge bg-secondary opacity-75 small">
{{ adj.get_type_display }}: R {{ adj.amount }}
</span>
{% endfor %}
</div>
{% endif %}
</td>
<td>
<div class="small">
<div>Work: {{ item.unpaid_count }} days (R {{ item.unpaid_amount|intcomma }})</div>
<div class="{% if item.adj_amount < 0 %}text-danger{% else %}text-success{% endif %}">
Adjustments: R {{ item.adj_amount|intcomma }}
</div>
</div>
</td>
<td class="fw-bold fs-5 {% if item.total_payable < 0 %}text-danger{% else %}text-success{% endif %}">
R {{ item.total_payable|intcomma }}
</td>
<td class="text-end pe-4">
{% if item.total_payable > 0 %}
<form action="{% url 'process_payment' item.worker.id %}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-success"
onclick="return confirm('Confirm payment of R {{ item.total_payable }} to {{ item.worker.name }}? This will email the receipt.')">
Pay Now
</button>
</form>
{% else %}
<button class="btn btn-sm btn-secondary" disabled>Nothing to Pay</button>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% elif active_tab == 'pending' %}
<div class="alert alert-info shadow-sm mb-4">
<div class="d-flex align-items-center">
<div class="fs-4 me-3">🎉</div>
<div>
<strong>All caught up!</strong><br>
There are no outstanding payments for active workers.
</div>
</div>
</div>
{% endif %}
{% endif %}
<!-- Payment History Table -->
{% if active_tab == 'paid' or active_tab == 'all' %}
{% if paid_records %}
<div class="card border-0 shadow-sm">
<div class="card-header bg-white fw-bold">Payment History</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4">Date</th>
<th>Payslip ID</th>
<th>Worker</th>
<th>Net Amount</th>
<th class="text-end pe-4">Action</th>
</tr>
</thead>
<tbody>
{% for record in paid_records %}
<tr>
<td class="ps-4">{{ record.date|date:"M d, Y" }}</td>
<td class="text-muted">#{{ record.id|stringformat:"06d" }}</td>
<td>
<div class="fw-bold">{{ record.worker.name }}</div>
<div class="small text-muted">{{ record.worker.id_no }}</div>
</td>
<td class="fw-bold">R {{ record.amount|intcomma }}</td>
<td class="text-end pe-4">
<a href="{% url 'payslip_detail' record.id %}" class="btn btn-sm btn-outline-primary">
View Payslip
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% else %}
<div class="alert alert-light border shadow-sm">
No payment history found.
</div>
{% endif %}
{% endif %}
</div>
<!-- Add Adjustment Modal -->
<div class="modal fade" id="addAdjustmentModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title fw-bold">Add Payroll Adjustment</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form action="{% url 'add_adjustment' %}" method="POST">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Worker</label>
<select name="worker" class="form-select" required>
<option value="">Select a worker...</option>
{% for worker in all_workers %}
<option value="{{ worker.id }}">{{ worker.name }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Type</label>
<select name="type" class="form-select" required>
{% for code, label in adjustment_types %}
<option value="{{ code }}">{{ label }}</option>
{% endfor %}
</select>
</div>
<div class="mb-3">
<label class="form-label">Amount (R)</label>
<input type="number" name="amount" class="form-control" step="0.01" min="1" required>
<div class="form-text">For deductions, enter a positive number. It will be subtracted automatically.</div>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<input type="text" name="description" class="form-control" placeholder="e.g. Public Holiday Bonus" required>
</div>
<div class="mb-3">
<label class="form-label">Date</label>
<input type="date" name="date" class="form-control" value="{% now 'Y-m-d' %}">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save Adjustment</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}