from django.shortcuts import render, redirect, get_object_or_404 from django.utils import timezone from django.db.models import Sum from decimal import Decimal from .models import Worker, Project, WorkLog, Team, PayrollRecord, Loan, PayrollAdjustment from .forms import AttendanceLogForm from django.contrib import messages from django.contrib.auth.decorators import login_required from django.http import JsonResponse, HttpResponseForbidden def is_admin(user): return user.is_staff or user.is_superuser def is_supervisor(user): return user.supervised_teams.exists() or user.assigned_projects.exists() or user.groups.filter(name='Work Logger').exists() def is_staff_or_supervisor(user): return is_admin(user) or is_supervisor(user) # Home view for the dashboard @login_required def index(request): user = request.user if is_admin(user): # Calculate total value of unpaid work and break it down by project unpaid_worklogs = WorkLog.objects.filter(payroll_records__isnull=True).prefetch_related('workers', 'project') outstanding_payments = Decimal('0.00') outstanding_by_project = {} for wl in unpaid_worklogs: project_name = wl.project.name if project_name not in outstanding_by_project: outstanding_by_project[project_name] = Decimal('0.00') for worker in wl.workers.all(): cost = worker.daily_rate outstanding_payments += cost outstanding_by_project[project_name] += cost # Include unpaid payroll adjustments in the outstanding calculations unpaid_adjustments = PayrollAdjustment.objects.filter(payroll_record__isnull=True) for adj in unpaid_adjustments: outstanding_payments += adj.amount project_name = adj.project.name if adj.project else 'General' if project_name not in outstanding_by_project: outstanding_by_project[project_name] = Decimal('0.00') outstanding_by_project[project_name] += adj.amount # Sum the total amount paid out over the last 60 days sixty_days_ago = timezone.now().date() - timezone.timedelta(days=60) paid_this_month = PayrollRecord.objects.filter(date__gte=sixty_days_ago).aggregate(total=Sum('amount_paid'))['total'] or Decimal('0.00') # Tally the count and total balance of active loans active_loans_qs = Loan.objects.filter(active=True) active_loans_count = active_loans_qs.count() active_loans_balance = active_loans_qs.aggregate(total=Sum('remaining_balance'))['total'] or Decimal('0.00') start_of_week = timezone.now().date() - timezone.timedelta(days=timezone.now().date().weekday()) this_week_logs = WorkLog.objects.filter(date__gte=start_of_week).count() recent_activity = WorkLog.objects.all().order_by('-date', '-id')[:5] # Get all workers, projects, and teams for the Manage Resources tab workers = Worker.objects.all().order_by('name') projects = Project.objects.all().order_by('name') teams = Team.objects.all().order_by('name') context = { 'is_admin': True, 'outstanding_payments': outstanding_payments, 'paid_this_month': paid_this_month, 'active_loans_count': active_loans_count, 'active_loans_balance': active_loans_balance, 'outstanding_by_project': outstanding_by_project, 'this_week_logs': this_week_logs, 'recent_activity': recent_activity, 'workers': workers, 'projects': projects, 'teams': teams, } return render(request, 'core/index.html', context) else: start_of_week = timezone.now().date() - timezone.timedelta(days=timezone.now().date().weekday()) this_week_logs = WorkLog.objects.filter(date__gte=start_of_week, supervisor=user).count() recent_activity = WorkLog.objects.filter(supervisor=user).order_by('-date', '-id')[:5] context = { 'is_admin': False, 'this_week_logs': this_week_logs, 'recent_activity': recent_activity, } return render(request, 'core/index.html', context) # View for logging attendance @login_required def attendance_log(request): if request.method == 'POST': form = AttendanceLogForm(request.POST) if form.is_valid(): form.save() messages.success(request, 'Attendance logged successfully!') return redirect('home') else: form = AttendanceLogForm(initial={'date': timezone.now().date(), 'supervisor': request.user}) return render(request, 'core/attendance_log.html', {'form': form}) # Work history view @login_required def work_history(request): if is_admin(request.user): logs = WorkLog.objects.all().order_by('-date', '-id') else: logs = WorkLog.objects.filter(supervisor=request.user).order_by('-date', '-id') return render(request, 'core/work_history.html', {'logs': logs}) # API view to toggle resource active status @login_required def toggle_active(request, model_name, item_id): if request.method != 'POST': return HttpResponseForbidden("Only POST requests are allowed.") if not is_admin(request.user): return HttpResponseForbidden("Not authorized.") model_map = { 'worker': Worker, 'project': Project, 'team': Team } if model_name not in model_map: return JsonResponse({'error': 'Invalid model'}, status=400) model = model_map[model_name] try: item = model.objects.get(id=item_id) item.active = not item.active item.save() return JsonResponse({'status': 'success', 'active': item.active}) except model.DoesNotExist: return JsonResponse({'error': 'Item not found'}, status=404)