Source code for ferrosoft.apps.befundung.api.serializers

import json
from pprint import pprint

from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from ferrosoft.apps.befundung.models import (
    Reduction,
    Refusal,
    Photo,
    Examination,
    Settings,
    ExaminationRequest,
    ExaminationPhotoRequest,
)


[docs] class SettingsSerializer(serializers.ModelSerializer):
[docs] class Meta: model = Settings fields = "__all__"
[docs] @classmethod def get_instance_dict(cls) -> dict: instance = Settings.get_instance() return cls(instance).data
[docs] class ReductionSerializer(serializers.ModelSerializer):
[docs] class Meta: model = Reduction fields = [ "reduction_type", "label", "value", ]
[docs] class RefusalSerializer(serializers.ModelSerializer):
[docs] class Meta: model = Refusal fields = [ "material_name", "value", ]
[docs] class PhotoSerializer(serializers.ModelSerializer):
[docs] class Meta: model = Photo fields = [ "image_file", ]
image_file = Base64ImageField()
[docs] class ExaminationSerializer(serializers.ModelSerializer):
[docs] class Meta: model = Examination fields = [ "id", "weighing_slip_id", "trader_approval", "comment", "exam_date", "material", "license_plate_no", "auditor_token", "customer_name", "refused_material", # The following are related models. "reductions", "refusals", "photos", ]
reductions = ReductionSerializer(many=True) refusals = RefusalSerializer(many=True) photos = PhotoSerializer(many=True)
[docs] def create(self, validated_data): reductions_data = validated_data.pop("reductions") refusals_data = validated_data.pop("refusals") photos_data = validated_data.pop("photos") exam = Examination.objects.create(**validated_data) Reduction.objects.bulk_create( [Reduction(examination=exam, **data) for data in reductions_data] ) Refusal.objects.bulk_create( [Refusal(examination=exam, **data) for data in refusals_data] ) Photo.objects.bulk_create( [Photo(examination=exam, **data) for data in photos_data] ) return exam
[docs] def to_internal_value(self, data): # Before introduction of DRF, a legacy format was in use, where reductions # and refusals are dictionaries. They need to be transformed transparently # to the current format. reductions = data.get("reductions", {}) if isinstance(reductions, dict): data["reductions"] = [ { "reduction_type": rtype, "value": value or 0, } for rtype, value in reductions.items() ] elif isinstance(reductions, list): # Need to filter garbage data out, i.e. custom reductions without a label. data["reductions"] = list( filter( lambda r: r.get("reduction_type", "") != "custom" or r.get("label") != "", reductions, ) ) refusals = data.get("refusals", {}) if isinstance(refusals, dict): data["refusals"] = [ { "material_name": name, "value": value or 0, } for name, value in refusals.items() ] power_photos = self._get_power_photos( data.get("photos", None), data.get("weighing_slip_id", None) ) data["photos"] = [ { "image_file": photo.get("Value", ""), } for photo in power_photos ] # Comment may come in as array, must be transformed to delimiter separated value. comment = data.get("comment", None) if isinstance(comment, list): data["comment"] = "\n".join(comment) return super().to_internal_value(data)
def _get_power_photos(self, unvalidated_photos, weighing_slip_id: str | None): if len(unvalidated_photos) > 0: return self._parse_power_photos(unvalidated_photos) # If photos are missing, this is likely a replay request. # Load photos from ExaminationPhotoRequest. if weighing_slip_id is None: return [] photo_request = ExaminationPhotoRequest.objects.filter( request__weighing_slip_id=weighing_slip_id ).first() if photo_request is None: return [] return self._parse_power_photos(photo_request.payload) def _parse_power_photos(self, unvalidated_photos): # PowerApps may send photos either as a normal list of objects # or as a JSON-encoded list. Support both cases. if isinstance(unvalidated_photos, list): return self._ensure_power_photos(unvalidated_photos) elif isinstance(unvalidated_photos, str): return self._ensure_power_photos(json.loads(unvalidated_photos)) else: raise ValueError("Photos must be a list or a string") @staticmethod def _ensure_power_photos(unvalidated_photos: list) -> list: photos = [] for photo in unvalidated_photos: if isinstance(photo, dict): photos.append(photo) return photos