@@ -138,6 +138,9 @@
Loading
138 138
        null=True,
139 139
        related_name="agent_office_export_applications",
140 140
    )
141 +
    case_owner = models.ForeignKey(
142 +
        User, on_delete=models.PROTECT, blank=True, null=True, related_name="+",
143 +
    )
141 144
142 145
    case_notes = models.ManyToManyField(CaseNote)
143 146

@@ -8,5 +8,10 @@
Loading
8 8
    path("create", views.ExportApplicationCreateView.as_view(), name="create"),
9 9
    path("com/<int:pk>/edit/", views.edit_com, name="com-edit"),
10 10
    path("com/<int:pk>/submit/", views.submit_com, name="com-submit"),
11 +
    path("case/<int:pk>/take_ownership/", views.take_ownership, name="case-take-ownership"),
12 +
    path(
13 +
        "case/<int:pk>/release_ownership/", views.release_ownership, name="case-release-ownership",
14 +
    ),
15 +
    path("case/<int:pk>/management/", views.Management.as_view(), name="case-management"),
11 16
    # TODO: add certificate of free sale URLs
12 17
]

@@ -1,11 +1,13 @@
Loading
1 1
import structlog as logging
2 2
3 -
4 3
from django.contrib.auth.decorators import login_required, permission_required
4 +
from django.contrib.auth.mixins import PermissionRequiredMixin
5 5
from django.db import transaction
6 6
from django.shortcuts import get_object_or_404, redirect, render
7 7
from django.urls import reverse_lazy, reverse
8 8
from django.utils import timezone
9 +
from django.views.decorators.http import require_POST
10 +
from django.views.generic import DetailView
9 11
10 12
from web.views import ModelCreateView
11 13
from web.flow.models import Task
@@ -17,6 +19,7 @@
Loading
17 19
logger = logging.get_logger(__name__)
18 20
19 21
permissions = "web.IMP_CERT_EDIT_APPLICATION"
22 +
export_case_officer_permission = "web.export_case_officer"
20 23
21 24
22 25
class ExportApplicationCreateView(ModelCreateView):
@@ -168,3 +171,35 @@
Loading
168 171
        }
169 172
170 173
        return render(request, "web/domains/case/export/submit-com.html", context)
174 +
175 +
176 +
@login_required
177 +
@permission_required(export_case_officer_permission, raise_exception=True)
178 +
@require_POST
179 +
def take_ownership(request, pk):
180 +
    with transaction.atomic():
181 +
        application = get_object_or_404(ExportApplication.objects.select_for_update(), pk=pk)
182 +
        application.get_task(ExportApplication.SUBMITTED, "process")
183 +
        application.case_owner = request.user
184 +
        application.save()
185 +
186 +
    return redirect(reverse("workbasket"))
187 +
188 +
189 +
@login_required
190 +
@permission_required(export_case_officer_permission, raise_exception=True)
191 +
@require_POST
192 +
def release_ownership(request, pk):
193 +
    with transaction.atomic():
194 +
        application = get_object_or_404(ExportApplication.objects.select_for_update(), pk=pk)
195 +
        application.get_task(ExportApplication.SUBMITTED, "process")
196 +
        application.case_owner = None
197 +
        application.save()
198 +
199 +
    return redirect(reverse("workbasket"))
200 +
201 +
202 +
class Management(PermissionRequiredMixin, DetailView):
203 +
    model = ExportApplication
204 +
    permission_required = export_case_officer_permission
205 +
    template_name = "web/domains/case/export/management.html"

@@ -103,6 +103,9 @@
Loading
103 103
104 104
        return Exporter.objects.filter(is_active=True, members=self).count() > 0
105 105
106 +
    def is_export_case_officer(self):
107 +
        return self.has_perm("web.export_case_officer")
108 +
106 109
    def set_temp_password(self, length=8):
107 110
        """
108 111
        Generates a random alphanumerical password of given length.
Files Coverage
config 57.82%
web 78.69%
Project Totals (133 files) 78.10%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading