from rest_framework import serializers from .models import ProcessingBatch class ProcessingBatchListSerializer(serializers.ModelSerializer): qc_status = serializers.SerializerMethodField() shipment_status = serializers.SerializerMethodField() class Meta: model = ProcessingBatch fields = ["id", "batch_reference", "origin_facility", "grade", "weight_kg", "harvest_date", "status", "qc_status", "shipment_status", "created_at"] def get_qc_status(self, obj): qc = obj.qc_results.first() if qc: return "pass" if qc.overall_pass else "fail" return "pending" def get_shipment_status(self, obj): shipment = obj.shipments.first() return shipment.status if shipment else None class ProcessingBatchDetailSerializer(serializers.ModelSerializer): created_by_name = serializers.CharField(source="created_by.full_name", read_only=True) qc_results = serializers.SerializerMethodField() shipments = serializers.SerializerMethodField() documents = serializers.SerializerMethodField() class Meta: model = ProcessingBatch fields = "__all__" def get_qc_results(self, obj): qc = obj.qc_results.first() if not qc: return None from apps.qc.serializers import QCResultSerializer return QCResultSerializer(qc).data def get_shipments(self, obj): shipments = obj.shipments.all() from apps.shipments.serializers import ShipmentSerializer return ShipmentSerializer(shipments, many=True).data def get_documents(self, obj): docs = obj.documents.all() from apps.documents.serializers import DocumentSerializer return DocumentSerializer(docs, many=True).data # Mirrors apps/ops/forms.py: a QC status is set by recording a QC result, not by # hand, and a failed batch is sticky — only a new result moves it. The portal # enforces this in BatchForm; without the same rule here the write serializer is # a way around the screen. QC_SET_STATUSES = { ProcessingBatch.Status.QC_PASS, ProcessingBatch.Status.QC_FAIL, } class ProcessingBatchWriteSerializer(serializers.ModelSerializer): class Meta: model = ProcessingBatch fields = ["id", "batch_reference", "harvest_date", "weight_kg", "grade", "origin_facility", "notes", "status"] read_only_fields = ["id"] def validate_status(self, status): instance = self.instance unchanged = instance is not None and status == instance.status if status in QC_SET_STATUSES and not unchanged: raise serializers.ValidationError( f"Batch status {ProcessingBatch.Status(status).label} is set by the " "QC result, not by hand." ) if ( instance is not None and instance.status == ProcessingBatch.Status.QC_FAIL and status != ProcessingBatch.Status.QC_FAIL ): raise serializers.ValidationError( "A batch that has failed QC cannot be moved by hand; a new QC " "result is what moves it." ) return status