ixg_platform/apps/compliance/views.py
ixgadmin d74f0814da Finish the wiki root move, zone map view and spec approval
- 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.
2026-10-27 17:41:08 +00:00

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))