- Follow home/user-guides/ through one GUIDE_PATH_PREFIX constant. - Add a read-only Origin Zone detail view with the map as the main panel. - Name due diligence explicitly and add its section headings. - Add admin-only, four-eyes specification approval (portal and API). - Empty the New-zone geometry placeholder instead of showing null.
186 lines
7.4 KiB
Python
186 lines
7.4 KiB
Python
from rest_framework import viewsets, permissions, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
|
|
from .models import (
|
|
ProductSpecification, Facility, OriginZone, CollectorGroup, HarvestIntake,
|
|
IntakeBatchLineage, DueDiligenceCase, EUDREvidence, RiskAssessment,
|
|
MitigationAction, DueDiligenceStatementReference,
|
|
)
|
|
from .serializers import (
|
|
ProductSpecificationSerializer, FacilitySerializer, OriginZoneSerializer,
|
|
CollectorGroupSerializer, HarvestIntakeSerializer, IntakeBatchLineageSerializer,
|
|
DueDiligenceCaseSerializer, EUDREvidenceSerializer, RiskAssessmentSerializer,
|
|
MitigationActionSerializer, DueDiligenceStatementReferenceSerializer,
|
|
)
|
|
from .permissions import IsOpsOrAdmin, IsAdmin
|
|
from . import services
|
|
|
|
|
|
class ProductSpecificationViewSet(viewsets.ModelViewSet):
|
|
queryset = ProductSpecification.objects.prefetch_related("parameters").all()
|
|
serializer_class = ProductSpecificationSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
def perform_create(self, serializer):
|
|
serializer.save(
|
|
created_by=self.request.user,
|
|
status=ProductSpecification.Status.DRAFT,
|
|
is_current=False,
|
|
)
|
|
|
|
@action(detail=True, methods=["post"], permission_classes=[IsAdmin])
|
|
def approve(self, request, pk=None):
|
|
spec = self.get_object()
|
|
try:
|
|
services.approve_specification(spec, request.user)
|
|
except ValueError as exc:
|
|
return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
|
return Response(ProductSpecificationSerializer(spec).data)
|
|
|
|
def get_permissions(self):
|
|
if self.action in ("create", "update", "partial_update", "destroy", "approve"):
|
|
return [permission() for permission in [IsAdmin]]
|
|
return [permission() for permission in [IsOpsOrAdmin]]
|
|
|
|
|
|
class FacilityViewSet(viewsets.ModelViewSet):
|
|
queryset = Facility.objects.all()
|
|
serializer_class = FacilitySerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
|
|
class OriginZoneViewSet(viewsets.ModelViewSet):
|
|
queryset = OriginZone.objects.select_related("facility", "verified_by").all()
|
|
serializer_class = OriginZoneSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def verify(self, request, pk=None):
|
|
zone = self.get_object()
|
|
outcome = request.data.get("verified", "true")
|
|
verified = str(outcome).lower() in ("true", "1", "yes")
|
|
zone.verification_status = "verified" if verified else "rejected"
|
|
zone.verified_by = request.user
|
|
from django.utils import timezone
|
|
zone.verified_at = timezone.now()
|
|
zone.save()
|
|
return Response(OriginZoneSerializer(zone).data)
|
|
|
|
|
|
class CollectorGroupViewSet(viewsets.ModelViewSet):
|
|
queryset = CollectorGroup.objects.all()
|
|
serializer_class = CollectorGroupSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
|
|
class HarvestIntakeViewSet(viewsets.ModelViewSet):
|
|
queryset = HarvestIntake.objects.select_related("origin_zone", "collector_group").all()
|
|
serializer_class = HarvestIntakeSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
|
|
class IntakeBatchLineageViewSet(viewsets.ModelViewSet):
|
|
queryset = IntakeBatchLineage.objects.select_related("batch", "harvest_intake").all()
|
|
serializer_class = IntakeBatchLineageSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
def perform_create(self, serializer):
|
|
lineage = serializer.save()
|
|
services.ensure_due_diligence_case(lineage.batch)
|
|
|
|
|
|
class EUDREvidenceViewSet(viewsets.ModelViewSet):
|
|
queryset = EUDREvidence.objects.select_related("case", "verified_by").all()
|
|
serializer_class = EUDREvidenceSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
def perform_create(self, serializer):
|
|
evidence = serializer.save()
|
|
case = evidence.case
|
|
services.run_completeness_check(case)
|
|
|
|
|
|
class RiskAssessmentViewSet(viewsets.ModelViewSet):
|
|
queryset = RiskAssessment.objects.select_related("case", "assessed_by").all()
|
|
serializer_class = RiskAssessmentSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
|
|
class MitigationActionViewSet(viewsets.ModelViewSet):
|
|
queryset = MitigationAction.objects.select_related("case").all()
|
|
serializer_class = MitigationActionSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def complete(self, request, pk=None):
|
|
mitigation = self.get_object()
|
|
mitigation.status = MitigationAction.Status.VERIFIED
|
|
from django.utils import timezone
|
|
mitigation.completed_at = timezone.now()
|
|
mitigation.save()
|
|
services.run_completeness_check(mitigation.case)
|
|
return Response(MitigationActionSerializer(mitigation).data)
|
|
|
|
|
|
class DueDiligenceStatementReferenceViewSet(viewsets.ModelViewSet):
|
|
queryset = DueDiligenceStatementReference.objects.select_related("case", "submitted_by").all()
|
|
serializer_class = DueDiligenceStatementReferenceSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
|
|
class DueDiligenceCaseViewSet(viewsets.ModelViewSet):
|
|
queryset = DueDiligenceCase.objects.select_related(
|
|
"batch", "approved_by", "assessed_by"
|
|
).prefetch_related("evidence", "risk_assessments", "mitigation_actions", "statement_references").order_by("-updated_at").all()
|
|
serializer_class = DueDiligenceCaseSerializer
|
|
permission_classes = [IsOpsOrAdmin]
|
|
|
|
def perform_create(self, serializer):
|
|
serializer.save()
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def check(self, request, pk=None):
|
|
case = self.get_object()
|
|
services.run_completeness_check(case)
|
|
return Response(DueDiligenceCaseSerializer(case).data)
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def assess_risk(self, request, pk=None):
|
|
case = self.get_object()
|
|
risk = services.evaluate_risk(case, user=request.user)
|
|
return Response({"risk_assessment_id": str(risk.id), **RiskAssessmentSerializer(risk).data})
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def approve(self, request, pk=None):
|
|
case = self.get_object()
|
|
try:
|
|
services.approve_case(case, request.user)
|
|
except ValueError as exc:
|
|
return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
|
return Response(DueDiligenceCaseSerializer(case).data)
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def reject(self, request, pk=None):
|
|
case = self.get_object()
|
|
reason = request.data.get("reason", "")
|
|
try:
|
|
services.reject_case(case, request.user, reason)
|
|
except ValueError as exc:
|
|
return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
|
return Response(DueDiligenceCaseSerializer(case).data)
|
|
|
|
@action(detail=True, methods=["post"])
|
|
def record_submission(self, request, pk=None):
|
|
case = self.get_object()
|
|
dds_reference = request.data.get("dds_reference", "")
|
|
submission_date = request.data.get("submission_date")
|
|
if not dds_reference:
|
|
return Response({"detail": "dds_reference is required"}, status=status.HTTP_400_BAD_REQUEST)
|
|
ref = services.record_submission(case, request.user, dds_reference, submission_date)
|
|
return Response(DueDiligenceStatementReferenceSerializer(ref).data)
|
|
|
|
@action(detail=True, methods=["get"])
|
|
def evidence_package(self, request, pk=None):
|
|
case = self.get_object()
|
|
return Response(services.evidence_package(case))
|