From a1804debdb73fea20dd571e353d49770c38e2ec2 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 22 Jan 2026 00:00:28 +0000 Subject: [PATCH] Dashboard changes to list Incomplete folders --- core/__pycache__/views.cpython-311.pyc | Bin 36657 -> 37860 bytes core/templates/core/dashboard.html | 24 ++++++++++++++- core/views.py | 39 +++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index b95adf8c7d861e8324dd415c958c808b5aed11e8..9f2c181c1f63c13c1b7230fa86e2d7c306030b58 100644 GIT binary patch delta 7554 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 g +
+
+
+
Incomplete Folder Breakdown
+ {% if incomplete_folder_breakdown %} + + {% else %} +

All required folders are complete for all jobs, or no required folders are defined.

+ {% endif %} +
+
+
+
Recent Repair Jobs
diff --git a/core/views.py b/core/views.py index bba0cee..4447876 100644 --- a/core/views.py +++ b/core/views.py @@ -16,6 +16,9 @@ from django.core.mail import send_mail from django.conf import settings from django.urls import reverse from django.utils import timezone +from django.contrib.auth import get_user_model + +User = get_user_model() from .models import Company, Profile, JobStatus, RequiredFolder, Job, JobFolderCompletion, JobFile, Invitation from .forms import CompanyForm, JobStatusForm, RequiredFolderForm, JobForm, JobFileForm, ImportJobsForm, InviteUserForm @@ -117,15 +120,34 @@ def dashboard(request): jobs_by_status = jobs.values('status__name').annotate(count=Count('id')).order_by('status__name') - # Jobs with incomplete folders + # Jobs with incomplete folders (overall count, existing logic) jobs_with_incomplete_folders = jobs.filter(folder_completions__is_completed=False).distinct().count() + # NEW LOGIC: Breakdown of incomplete folders per RequiredFolder + incomplete_folder_breakdown = [] + required_folders = company.required_folders.all() + + for folder in required_folders: + # Count jobs where this specific folder is NOT completed + missing_count = Job.objects.filter( + company=company, + folder_completions__folder=folder, + folder_completions__is_completed=False + ).distinct().count() + + if missing_count > 0: # Only include if there are missing jobs for this folder + incomplete_folder_breakdown.append({ + 'folder': folder, + 'missing_count': missing_count + }) + context = { 'company': company, 'total_jobs': total_jobs, 'jobs_by_status': jobs_by_status, - 'jobs_with_incomplete_folders': jobs_with_incomplete_folders, + 'jobs_with_incomplete_folders': jobs_with_incomplete_folders, # Keep existing for now 'jobs': jobs.order_by('-created_at')[:5], + 'incomplete_folder_breakdown': incomplete_folder_breakdown, # NEW CONTEXT VARIABLE } return render(request, 'core/dashboard.html', context) @@ -137,6 +159,19 @@ def job_list(request): company = profile.company jobs = Job.objects.filter(company=company).order_by('-created_at') + + # NEW LOGIC: Filter by missing_folder_id + missing_folder_id = request.GET.get('missing_folder_id') + if missing_folder_id: + # Find all jobs that have this folder as required but it's not completed + jobs = jobs.filter( + folder_completions__folder__id=missing_folder_id, + folder_completions__is_completed=False + ).distinct() + + # Optional: Get the folder name to display in the template + missing_folder = get_object_or_404(RequiredFolder, pk=missing_folder_id, company=company) + messages.info(request, f"Showing jobs missing '{missing_folder.name}' folder completion.") return render(request, 'core/job_list.html', { 'jobs': jobs,