From fe7d0d6a708c67cd7c041eb1730dfa2b4323404a Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 21 Feb 2026 22:36:49 +0000 Subject: [PATCH] Ver 15.07 Adjustment to projects save (gemini) --- core/__pycache__/views.cpython-311.pyc | Bin 73742 -> 75566 bytes core/templates/core/payroll_dashboard.html | 20 ++++++++++++ core/views.py | 36 ++++++++++++++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 5c00a4ec4d87099a5fff307cd0fac3920bf7c3bc..dcd3c6c073e2a25314477a1e7072c7d8c6be35e6 100644 GIT binary patch delta 4947 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 DjXD&0 delta 3629 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 diff --git a/core/templates/core/payroll_dashboard.html b/core/templates/core/payroll_dashboard.html index b0b2d6b..6156722 100644 --- a/core/templates/core/payroll_dashboard.html +++ b/core/templates/core/payroll_dashboard.html @@ -177,6 +177,7 @@ data-adj-description="{{ adj.description }}" data-adj-date="{{ adj.date|date:'Y-m-d' }}" data-adj-worker="{{ item.worker.name }}" + data-adj-project="{% if adj.work_log %}{{ adj.work_log.project_id }}{% endif %}" title="{% if adj.type == 'ADVANCE' %}Click to delete (cannot edit){% else %}Click to edit{% endif %}"> {{ adj.get_type_display }}: R {{ adj.amount }} {% if adj.type != 'ADVANCE' %}✎{% endif %} @@ -487,6 +488,15 @@ {% endfor %} +

+ + +
@@ -530,6 +540,15 @@
+
+ + +
@@ -760,6 +779,7 @@ document.addEventListener('DOMContentLoaded', function() { } document.getElementById('editAdjWorkerName').textContent = this.dataset.adjWorker; + document.getElementById("editAdjProject").value = this.dataset.adjProject || ""; document.getElementById('editAdjAmount').value = this.dataset.adjAmount; document.getElementById('editAdjDescription').value = this.dataset.adjDescription; document.getElementById('editAdjDate').value = this.dataset.adjDate; diff --git a/core/views.py b/core/views.py index ac897e0..3510020 100644 --- a/core/views.py +++ b/core/views.py @@ -994,6 +994,7 @@ def payroll_dashboard(request): 'active_tab': status_filter, 'all_workers': all_workers, 'all_teams': all_teams, + 'all_projects': Project.objects.filter(is_active=True).order_by('name'), 'team_workers_map_json': json.dumps(team_workers_map), 'adjustment_types': PayrollAdjustment.ADJUSTMENT_TYPES, 'loans': loans, @@ -1283,6 +1284,7 @@ def add_adjustment(request): description = request.POST.get('description') date = request.POST.get('date') or timezone.now().date() loan_id = request.POST.get('loan_id') # Optional, for repayments + project_id = request.POST.get('project_id') # Optional, for linking to a project try: amount = Decimal(amount_str) if amount_str else None @@ -1329,12 +1331,22 @@ def add_adjustment(request): # Create ADVANCE adjustment + PayrollRecord atomically with transaction.atomic(): + work_log_link = None + if project_id: + # Try to find a worklog for this worker and project to link the adjustment to the project + work_log_link = worker.work_logs.filter(project_id=project_id).order_by('-date').first() + if not work_log_link: + # Fallback: any worklog for project + from .models import WorkLog + work_log_link = WorkLog.objects.filter(project_id=project_id).order_by('-date').first() + PayrollAdjustment.objects.create( worker=worker, type='ADVANCE', amount=advance_amount, description=description or 'Advance payment', date=date, + work_log=work_log_link, ) advance_date = date if isinstance(date, datetime.date) else timezone.now().date() @@ -1342,6 +1354,8 @@ def add_adjustment(request): worker=worker, amount=advance_amount, date=advance_date, + type='ADVANCE', + notes=description or 'Advance payment' ) # Send advance payslip to Spark (outside transaction) @@ -1398,13 +1412,23 @@ def add_adjustment(request): reason=description ) + work_log_link = None + if project_id: + # Try to find a worklog for this worker and project to link the adjustment to the project + work_log_link = worker.work_logs.filter(project_id=project_id).order_by('-date').first() + if not work_log_link: + # Fallback: any worklog for project + from .models import WorkLog + work_log_link = WorkLog.objects.filter(project_id=project_id).order_by("-date").first() + PayrollAdjustment.objects.create( worker=worker, type=adj_type, amount=amount, description=description, date=date, - loan=loan + loan=loan, + work_log=work_log_link ) success_names.append(worker.name) @@ -1445,6 +1469,7 @@ def edit_adjustment(request, pk): description = request.POST.get('description') date = request.POST.get('date') new_type = request.POST.get('type') + project_id = request.POST.get('project_id') if amount: adj.amount = Decimal(amount) @@ -1453,6 +1478,15 @@ def edit_adjustment(request, pk): if date: adj.date = date + if project_id: + work_log_link = adj.worker.work_logs.filter(project_id=project_id).order_by('-date').first() + if not work_log_link: + from .models import WorkLog + work_log_link = WorkLog.objects.filter(project_id=project_id).order_by('-date').first() + adj.work_log = work_log_link + elif project_id == '': + adj.work_log = None + # Only allow type change for BONUS/DEDUCTION (others have linked objects) if new_type and adj.type in ('BONUS', 'DEDUCTION') and new_type in ('BONUS', 'DEDUCTION'): adj.type = new_type