Add quick 'Adjust' button to pending payments table rows

Each worker row now has an Adjust button (slider icon) that opens the
Add Adjustment modal with that worker pre-checked and their most recent
project pre-selected. Header Add Adjustment button resets the modal
to a clean state (no workers pre-checked).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-03-25 10:25:10 +02:00
parent c3bbffe9c0
commit cfed13c9f5
2 changed files with 63 additions and 0 deletions

View File

@ -308,6 +308,12 @@
data-worker-name="{{ wd.worker.name }}">
<i class="fas fa-eye"></i>
</button>
<button type="button" class="btn btn-sm btn-outline-secondary quick-adjust-btn"
data-worker-id="{{ wd.worker.id }}"
data-worker-project="{{ wd.last_project_id|default:'' }}"
title="Add adjustment for {{ wd.worker.name }}">
<i class="fas fa-sliders-h"></i>
</button>
<form method="POST" action="{% url 'process_payment' wd.worker.id %}"
class="d-inline pay-form">
{% csrf_token %}
@ -1389,6 +1395,59 @@ document.addEventListener('DOMContentLoaded', function() {
});
}
// === QUICK ADJUST BUTTON ===
// Opens the Add Adjustment modal with one worker pre-checked
// and their most recent project pre-selected.
var _quickAdjustOpen = false; // Flag to distinguish quick-adjust from header button
document.querySelectorAll('.quick-adjust-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
_quickAdjustOpen = true;
var workerId = this.dataset.workerId;
var projectId = this.dataset.workerProject;
// Uncheck all workers, then check only the target worker
addAdjWorkerCheckboxes.forEach(function(cb) {
cb.checked = (cb.value === workerId);
});
updateWorkerCount();
// Pre-select the worker's most recent project (if available)
if (projectId && addAdjProject) {
addAdjProject.value = projectId;
}
// Reset type to default (Bonus) and trigger field visibility update
if (addAdjType) {
addAdjType.value = 'Bonus';
toggleProjectField();
}
// Open the modal
var modal = new bootstrap.Modal(document.getElementById('addAdjustmentModal'));
modal.show();
});
});
// When the modal is opened from the HEADER button (not quick-adjust),
// clear any pre-selected workers and project from a previous quick-adjust.
var addAdjModal = document.getElementById('addAdjustmentModal');
if (addAdjModal) {
addAdjModal.addEventListener('show.bs.modal', function() {
if (_quickAdjustOpen) {
_quickAdjustOpen = false;
return; // Quick-adjust already set the values
}
// Reset: uncheck all workers, clear project, reset type
addAdjWorkerCheckboxes.forEach(function(cb) { cb.checked = false; });
updateWorkerCount();
if (addAdjProject) addAdjProject.value = '';
if (addAdjType) {
addAdjType.value = 'Bonus';
toggleProjectField();
}
});
}
// Form validation: ensure at least one worker is selected before submit.
// Without this, the form would submit and silently create 0 adjustments.
var addAdjForm = document.querySelector('#addAdjustmentModal form');

View File

@ -921,6 +921,9 @@ def payroll_dashboard(request):
has_loan = Loan.objects.filter(worker=worker, active=True).exists()
# Most recent project — used by the "Adjust" button to pre-select project
last_project_id = unpaid_logs[-1].project_id if unpaid_logs else None
workers_data.append({
'worker': worker,
'unpaid_count': log_count,
@ -935,6 +938,7 @@ def payroll_dashboard(request):
'is_overdue': is_overdue,
'has_loan': has_loan,
'earliest_unpaid': earliest_unpaid,
'last_project_id': last_project_id,
})
outstanding_total += max(total_payable, Decimal('0.00'))
unpaid_wages_total += log_amount