diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc
index 0cae82c..20b523f 100644
Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ
diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc
index 366ef82..9d83914 100644
Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ
diff --git a/core/templates/core/work_log_list.html b/core/templates/core/work_log_list.html
index a6954d6..9c17790 100644
--- a/core/templates/core/work_log_list.html
+++ b/core/templates/core/work_log_list.html
@@ -11,9 +11,14 @@
Work Log History
Filter and review historical daily work logs.
-
- + New Entry
-
+
@@ -82,6 +87,7 @@
Date |
Project |
Labourers |
+ Amount |
Status / Payslip |
Supervisor |
Action |
@@ -121,6 +127,9 @@
{% endif %}
+
+ R {{ log.display_amount|floatformat:2 }}
+ |
{% with payslip=log.paid_in.first %}
{% if payslip %}
@@ -156,6 +165,13 @@
{% endfor %}
+ |
+
+ | Total: |
+ R {{ total_amount|floatformat:2 }} |
+ |
+
+
{% else %}
diff --git a/core/urls.py b/core/urls.py
index b5f1475..f06bb24 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -2,7 +2,8 @@ from django.urls import path
from .views import (
home,
log_attendance,
- work_log_list,
+ work_log_list,
+ export_work_log_csv,
manage_resources,
toggle_resource_status,
payroll_dashboard,
@@ -14,6 +15,7 @@ urlpatterns = [
path("", home, name="home"),
path("log-attendance/", log_attendance, name="log_attendance"),
path("work-logs/", work_log_list, name="work_log_list"),
+ path("work-logs/export/", export_work_log_csv, name="export_work_log_csv"),
path("manage-resources/", manage_resources, name="manage_resources"),
path("manage-resources/toggle///", toggle_resource_status, name="toggle_resource_status"),
path("payroll/", payroll_dashboard, name="payroll_dashboard"),
diff --git a/core/views.py b/core/views.py
index 956a7db..f4d7f32 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,6 +1,7 @@
import os
import platform
import json
+import csv
from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from django.contrib.auth.decorators import login_required
@@ -8,7 +9,7 @@ from django.db.models import Sum, Q, Prefetch
from django.core.mail import send_mail
from django.conf import settings
from django.contrib import messages
-from django.http import JsonResponse
+from django.http import JsonResponse, HttpResponse
from .models import Worker, Project, Team, WorkLog, PayrollRecord
from .forms import WorkLogForm
from datetime import timedelta
@@ -156,8 +157,11 @@ def work_log_list(request):
logs = WorkLog.objects.all().prefetch_related('workers', 'project', 'supervisor', 'paid_in').order_by('-date', '-id')
+ target_worker = None
if worker_id:
logs = logs.filter(workers__id=worker_id)
+ # Fetch the worker to get the day rate reliably
+ target_worker = Worker.objects.filter(id=worker_id).first()
if team_id:
# Find workers in this team and filter logs containing them
@@ -180,9 +184,23 @@ def work_log_list(request):
else:
logs = logs.filter(paid_in__isnull=True)
+ # Calculate amounts for display
+ # Convert to list to attach attributes
+ final_logs = []
+ total_amount = 0
+ for log in logs:
+ if target_worker:
+ log.display_amount = target_worker.day_rate
+ else:
+ # Sum of all workers in this log
+ log.display_amount = sum(w.day_rate for w in log.workers.all())
+ final_logs.append(log)
+ total_amount += log.display_amount
+
# Context for filters
context = {
- 'logs': logs,
+ 'logs': final_logs,
+ 'total_amount': total_amount,
'workers': Worker.objects.filter(is_active=True).order_by('name'),
'teams': Team.objects.filter(is_active=True).order_by('name'),
'projects': Project.objects.filter(is_active=True).order_by('name'),
@@ -190,10 +208,71 @@ def work_log_list(request):
'selected_team': int(team_id) if team_id else None,
'selected_project': int(project_id) if project_id else None,
'selected_payment_status': payment_status,
+ 'target_worker': target_worker,
}
return render(request, 'core/work_log_list.html', context)
+def export_work_log_csv(request):
+ """Export filtered work logs to CSV."""
+ worker_id = request.GET.get('worker')
+ team_id = request.GET.get('team')
+ project_id = request.GET.get('project')
+ payment_status = request.GET.get('payment_status')
+
+ logs = WorkLog.objects.all().prefetch_related('workers', 'project', 'supervisor', 'paid_in').order_by('-date', '-id')
+
+ target_worker = None
+ if worker_id:
+ logs = logs.filter(workers__id=worker_id)
+ target_worker = Worker.objects.filter(id=worker_id).first()
+
+ if team_id:
+ team_workers = Worker.objects.filter(teams__id=team_id)
+ logs = logs.filter(workers__in=team_workers).distinct()
+
+ if project_id:
+ logs = logs.filter(project_id=project_id)
+
+ if payment_status == 'paid':
+ logs = logs.filter(paid_in__isnull=False).distinct()
+ elif payment_status == 'unpaid':
+ if worker_id:
+ worker = get_object_or_404(Worker, pk=worker_id)
+ logs = logs.exclude(paid_in__worker=worker)
+ else:
+ logs = logs.filter(paid_in__isnull=True)
+
+ response = HttpResponse(content_type='text/csv')
+ response['Content-Disposition'] = 'attachment; filename="work_logs.csv"'
+
+ writer = csv.writer(response)
+ writer.writerow(['Date', 'Project', 'Workers', 'Amount', 'Payment Status', 'Supervisor'])
+
+ for log in logs:
+ # Amount Logic
+ if target_worker:
+ display_amount = target_worker.day_rate
+ workers_str = target_worker.name
+ else:
+ display_amount = sum(w.day_rate for w in log.workers.all())
+ workers_str = ", ".join([w.name for w in log.workers.all()])
+
+ # Payment Status Logic
+ is_paid = log.paid_in.exists()
+ status_str = "Paid" if is_paid else "Pending"
+
+ writer.writerow([
+ log.date,
+ log.project.name,
+ workers_str,
+ f"{display_amount:.2f}",
+ status_str,
+ log.supervisor.username if log.supervisor else "System"
+ ])
+
+ return response
+
def manage_resources(request):
"""View to manage active status of resources."""
# Prefetch teams for workers to avoid N+1 in template
@@ -227,7 +306,7 @@ def toggle_resource_status(request, model_type, pk):
return JsonResponse({
'success': True,
'is_active': obj.is_active,
- 'message': f"{obj.name} is now {'Active' if obj.is_active else 'Inactive'}."
+ 'message': f"{obj.name} is now {'Active' if obj.is_active else 'Inactive'}ணை."
})
return redirect('manage_resources')
@@ -346,4 +425,4 @@ def payslip_detail(request, pk):
'record': record,
'logs': logs,
}
- return render(request, 'core/payslip.html', context)
\ No newline at end of file
+ return render(request, 'core/payslip.html', context)