The ops form refuses a shipment with no vessel, container, ETD or ETA, and one whose departure is after its arrival. The serializer now requires the same fields and refuses the same contradiction, so the API cannot accept a record the portal would reject. Partial updates stay partial: a status change alone does not require the other fields, and the date check falls back to the stored values.
35 lines
1.4 KiB
Python
35 lines
1.4 KiB
Python
from rest_framework import serializers
|
|
|
|
from .models import Shipment
|
|
|
|
|
|
class ShipmentSerializer(serializers.ModelSerializer):
|
|
"""Mirror the ops form's rules, so the API cannot accept what the portal refuses.
|
|
|
|
The model tolerates a blank vessel or container and a missing date, because
|
|
records also arrive through this API. But a shipment is what the buyer's page
|
|
shows, so the fields the buyer reads are required here too, and a departure
|
|
after the arrival is refused. The bill of lading and the forwarder stay
|
|
optional; the ports keep their model defaults.
|
|
"""
|
|
|
|
class Meta:
|
|
model = Shipment
|
|
fields = "__all__"
|
|
read_only_fields = ["id", "created_at"]
|
|
extra_kwargs = {
|
|
"status": {"required": True},
|
|
"vessel_name": {"required": True, "allow_blank": False},
|
|
"container_ref": {"required": True, "allow_blank": False},
|
|
"etd_nigeria": {"required": True, "allow_null": False},
|
|
"eta_uk": {"required": True, "allow_null": False},
|
|
}
|
|
|
|
def validate(self, attrs):
|
|
etd = attrs.get("etd_nigeria", getattr(self.instance, "etd_nigeria", None))
|
|
eta = attrs.get("eta_uk", getattr(self.instance, "eta_uk", None))
|
|
if etd and eta and etd > eta:
|
|
raise serializers.ValidationError(
|
|
{"eta_uk": "The ETA cannot be before the ETD. Check the two dates."}
|
|
)
|
|
return attrs
|