diff --git a/app/vkk/templates/vkk/workhours/accounting/period/details.html b/app/vkk/templates/vkk/workhours/accounting/period/details.html index 5642bd3da6af50ca2eb6df79c03146e434812d82..c1ac501e656061fb74479ad84696435135d986d4 100644 --- a/app/vkk/templates/vkk/workhours/accounting/period/details.html +++ b/app/vkk/templates/vkk/workhours/accounting/period/details.html @@ -10,10 +10,14 @@ <th>{% translate "Projects not closed" %}</th> </thead> <body> - {% for project in projects %} + {% for department in departments %} <tr> - <td><a href="{% url 'vkk:workhours:accounting:periods:projects_open' view.kwargs.pk project.department__pk %}">{{ project.department__name }}</a></td> - <td>{{ project.projects_not_closed }}</td> + {% if not department.id %} + <td><a href=""></a>Ohne Zuweisung</td> + {% else %} + <td><a href="{% url 'vkk:workhours:accounting:periods:projects_open' view.kwargs.pk department.id %}">{{ department.name }}</a></td> + {% endif %} + <td>{{ department.projects_not_closed }}</td> </tr> {% endfor %} </tbody> diff --git a/app/vkk/templates/vkk/workhours/accounting/period/projects.html b/app/vkk/templates/vkk/workhours/accounting/period/projects.html index 85b2180fa6cec3f0b9b9b9f6b12a49a80aa3c5a9..b3d9f9dbf8b41e73a05dd7e9e1b2b461152a6828 100644 --- a/app/vkk/templates/vkk/workhours/accounting/period/projects.html +++ b/app/vkk/templates/vkk/workhours/accounting/period/projects.html @@ -28,6 +28,7 @@ <th>{% translate "invoice number" %}</th> <th>{% translate "Project Name" %}</th> <th></th> + <th>{% translate "receipt" %}</th> </thead> <body> {% for project in projects_closed %} @@ -35,6 +36,7 @@ <td>{{ project.invoice_number }}</td> <td>{{ project.name }}</td> <td><a href="{% url 'vkk:workhours:accounting:projects:project:export:overview' project.invoice_number %}">{% translate "Export" %}</a></td> + <td style="text-align: center;">{% if project.exists_receipt %}☺️{% endif %}</td> </tr> {% endfor %} </tbody> diff --git a/app/vkk/workhours/accounting/periods/views.py b/app/vkk/workhours/accounting/periods/views.py index 6a76eb10e0cf8b71062e5ec023086c08f73458b2..02d668376036aec2c669547d33967d93c940559b 100644 --- a/app/vkk/workhours/accounting/periods/views.py +++ b/app/vkk/workhours/accounting/periods/views.py @@ -1,4 +1,3 @@ -from django.db.models import Count, Q, Value, IntegerField, F from django.shortcuts import get_object_or_404 from vkk.workhours.accounting.views import AccountingDetailView from vkk.workhours.models import Period, Project, Department @@ -11,38 +10,72 @@ class AccountingPeriodDetailView(AccountingDetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - projects_open = Project.objects.exclude( - Q(projectassignment__isnull=True) | Q(projectassignment__periodclosure__period=kwargs["object"]) & Q( - projectassignment__periodclosure__is_closed_contributor=True) & Q(projectassignment__periodclosure__is_closed_manager=True) - ).exclude( - Q(start__lt=kwargs["object"].start) & Q(end__lt=kwargs["object"].end) | Q( - start__gt=kwargs["object"].start) & Q(start__gt=kwargs["object"].end) - ).values( - 'department__name', 'department__pk' - ).annotate( - projects_not_closed=Count('department__pk') - ).exclude(department__pk=None) + departments = Department.objects.raw(" \ + WITH selected_period AS ( \ + SELECT \ + vkk_period.id AS period_id, \ + vkk_period.start AS period_start, \ + vkk_period.end AS period_end \ + FROM vkk_period \ + WHERE vkk_period.id = %s \ + ), \ + filtered_projects AS ( \ + SELECT \ + vkk_project.id AS project_id, \ + vkk_project.department_id, \ + selected_period.period_id \ + FROM vkk_project, selected_period \ + WHERE \ + selected_period.period_end >= vkk_project.start \ + AND selected_period.period_start <= vkk_project.end \ + ), \ + closures AS ( \ + SELECT \ + vkk_periodclosure.project_assignment_id, \ + vkk_periodclosure.is_closed_manager \ + FROM \ + vkk_periodclosure JOIN selected_period \ + ON vkk_periodclosure.period_id = selected_period.period_id \ + ), \ + not_closed_assignments AS ( \ + SELECT \ + vkk_projectassignment.id AS assignment_id, \ + vkk_projectassignment.project_id \ + FROM \ + vkk_projectassignment LEFT JOIN closures \ + ON vkk_projectassignment.id = closures.project_assignment_id \ + WHERE \ + closures.is_closed_manager IS NULL \ + OR closures.is_closed_manager = FALSE \ + ), \ + not_closed_projects AS ( \ + SELECT \ + department_id, \ + COUNT(project_id) AS not_closed \ + FROM \ + filtered_projects p \ + WHERE \ + EXISTS ( \ + SELECT assignment_id \ + FROM not_closed_assignments c \ + WHERE \ + c.project_id = p.project_id \ + ) \ + GROUP BY department_id \ + ) \ + SELECT \ + id, \ + name, \ + accounting_entry, \ + invoice_number, \ + COALESCE(not_closed, 0) AS projects_not_closed \ + FROM \ + vkk_department FULL JOIN not_closed_projects \ + ON vkk_department.id = not_closed_projects.department_id \ + ORDER BY vkk_department.name \ + ;", [self.kwargs['pk']]) - projects_closed = Project.objects.filter( - Q(projectassignment__isnull=True) | Q(projectassignment__periodclosure__period=kwargs["object"]) & Q( - projectassignment__periodclosure__is_closed_contributor=True) & Q(projectassignment__periodclosure__is_closed_manager=True) - ).exclude( - Q(start__lt=kwargs["object"].start) & Q(end__lt=kwargs["object"].end) | Q( - start__gt=kwargs["object"].start) & Q(start__gt=kwargs["object"].end) - ).distinct( - 'department__pk' - ).values( - 'department__name', 'department__pk' - ).exclude( - department__pk__in=projects_open.values('department__pk') - ).annotate( - projects_not_closed=Value(0, IntegerField()) - ).exclude(department__pk=None) - - projects = projects_open.union( - projects_closed).order_by('department__name') - - context["projects"] = projects + context["departments"] = departments return context @@ -55,28 +88,150 @@ class AccountingPeriodDetailDepartmentView(AccountingDetailView): context = super().get_context_data(**kwargs) department = get_object_or_404( Department, pk=self.kwargs["department_pk"]) - projects_open = Project.objects.exclude( - Q(projectassignment__isnull=True) | Q(projectassignment__periodclosure__period=kwargs["object"]) & Q( - projectassignment__periodclosure__is_closed_contributor=True) & Q(projectassignment__periodclosure__is_closed_manager=True) - ).filter( - department=department, - ).exclude( - Q(start__lt=kwargs["object"].start) & Q(end__lt=kwargs["object"].end) | Q( - start__gt=kwargs["object"].start) & Q(start__gt=kwargs["object"].end) + projects_open = Project.objects.raw(" \ + WITH selected_period AS ( \ + SELECT \ + vkk_period.id AS period_id, \ + vkk_period.start AS period_start, \ + vkk_period.end AS period_end \ + FROM vkk_period \ + WHERE vkk_period.id = %s \ + ), \ + filtered_projects AS ( \ + SELECT \ + selected_period.period_id, \ + vkk_project.id, \ + vkk_project.invoice_number, \ + vkk_project.name, \ + vkk_project.contractor, \ + vkk_project.start, \ + vkk_project.end, \ + vkk_project.department_id \ + FROM vkk_project, selected_period \ + WHERE \ + selected_period.period_end >= vkk_project.start \ + AND selected_period.period_start <= vkk_project.end \ + AND vkk_project.department_id = %s \ + ), \ + closures AS ( \ + SELECT \ + vkk_periodclosure.project_assignment_id, \ + vkk_periodclosure.is_closed_manager \ + FROM \ + vkk_periodclosure JOIN selected_period \ + ON vkk_periodclosure.period_id = selected_period.period_id \ + ), \ + not_closed_assignments AS ( \ + SELECT \ + vkk_projectassignment.id AS assignment_id, \ + vkk_projectassignment.project_id \ + FROM \ + vkk_projectassignment LEFT JOIN closures \ + ON vkk_projectassignment.id = closures.project_assignment_id \ + WHERE \ + closures.is_closed_manager IS NULL \ + OR closures.is_closed_manager = FALSE \ + ) \ + SELECT \ + p.id, \ + p.invoice_number, \ + p.name, \ + p.contractor, \ + p.start, \ + p.end, \ + p.department_id \ + FROM \ + filtered_projects p \ + WHERE \ + EXISTS ( \ + SELECT assignment_id \ + FROM not_closed_assignments c \ + WHERE \ + c.project_id = p.id \ + ) \ + ORDER BY p.invoice_number;", + [self.kwargs['pk'], self.kwargs["department_pk"]] ) - projects_closed = Project.objects.filter( - Q(projectassignment__isnull=True) | Q(projectassignment__periodclosure__period=kwargs["object"]) & Q( - projectassignment__periodclosure__is_closed_contributor=True) & Q(projectassignment__periodclosure__is_closed_manager=True), - department=department, - ).exclude( - Q(start__lt=kwargs["object"].start) & Q(end__lt=kwargs["object"].end) | Q( - start__gt=kwargs["object"].start) & Q(start__gt=kwargs["object"].end) + projects_closed = Project.objects.raw(" \ + WITH selected_period AS ( \ + SELECT \ + vkk_period.id AS period_id, \ + vkk_period.start AS period_start, \ + vkk_period.end AS period_end \ + FROM vkk_period \ + WHERE vkk_period.id = %s \ + ), \ + filtered_projects AS ( \ + SELECT \ + selected_period.period_id, \ + vkk_project.id, \ + vkk_project.invoice_number, \ + vkk_project.name, \ + vkk_project.contractor, \ + vkk_project.start, \ + vkk_project.end, \ + vkk_project.department_id, \ + selected_period.period_start, \ + selected_period.period_end \ + FROM vkk_project, selected_period \ + WHERE \ + selected_period.period_end >= vkk_project.start \ + AND selected_period.period_start <= vkk_project.end \ + AND vkk_project.department_id = %s \ + ), \ + closures AS ( \ + SELECT \ + vkk_periodclosure.project_assignment_id, \ + vkk_periodclosure.is_closed_manager \ + FROM \ + vkk_periodclosure JOIN selected_period \ + ON vkk_periodclosure.period_id = selected_period.period_id \ + ), \ + not_closed_assignments AS ( \ + SELECT \ + vkk_projectassignment.id AS assignment_id, \ + vkk_projectassignment.project_id \ + FROM \ + vkk_projectassignment LEFT JOIN closures \ + ON vkk_projectassignment.id = closures.project_assignment_id \ + WHERE \ + closures.is_closed_manager IS NULL \ + OR closures.is_closed_manager = FALSE \ + ) \ + SELECT \ + p.id, \ + p.invoice_number, \ + p.name, \ + p.contractor, \ + p.start, \ + p.end, \ + p.department_id, \ + CASE \ + WHEN EXISTS ( \ + SELECT 1 \ + FROM vkk_receipt \ + WHERE \ + p.id = vkk_receipt.project_id \ + AND p.period_start = vkk_receipt.start \ + AND p.period_end = vkk_receipt.end \ + ) THEN TRUE \ + ELSE FALSE \ + END AS exists_receipt \ + FROM \ + filtered_projects p \ + WHERE \ + NOT EXISTS ( \ + SELECT assignment_id \ + FROM not_closed_assignments c \ + WHERE \ + c.project_id = p.id \ + ) \ + ORDER BY p.invoice_number;", + [self.kwargs['pk'], self.kwargs["department_pk"]] ) context["department"] = department - context["projects_open"] = projects_open.distinct().order_by( - 'invoice_number') - context["projects_closed"] = projects_closed.distinct().order_by( - 'invoice_number') + context["projects_open"] = projects_open + context["projects_closed"] = projects_closed return context