135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
from rest_framework import serializers
|
|
|
|
from apps.accounts.serializers import PkAsIdMixin
|
|
from apps.farms.models import Cycle, Flock, Kandang, Site
|
|
|
|
|
|
class SiteSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Site
|
|
fields = ["id", "site_name", "user", "created_at", "updated_at"]
|
|
read_only_fields = ["id", "created_at", "updated_at"]
|
|
|
|
|
|
class FeedInButtonUrlSerializer(serializers.Serializer):
|
|
label = serializers.CharField(max_length=50, required=False, allow_blank=True, default="")
|
|
url = serializers.URLField(max_length=500)
|
|
|
|
|
|
class KandangSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
|
feed_in_button_urls = FeedInButtonUrlSerializer(many=True, required=False)
|
|
|
|
class Meta:
|
|
model = Kandang
|
|
fields = [
|
|
"id",
|
|
"kandang_name",
|
|
"feed_in_button_urls",
|
|
"site",
|
|
"created_at",
|
|
"updated_at",
|
|
]
|
|
read_only_fields = ["id", "created_at", "updated_at"]
|
|
|
|
def validate_feed_in_button_urls(self, value):
|
|
cleaned = []
|
|
for item in value or []:
|
|
url = str(item.get("url", "")).strip()
|
|
if not url:
|
|
continue
|
|
label = str(item.get("label", "") or "").strip()[:50]
|
|
cleaned.append({"label": label, "url": url})
|
|
return cleaned
|
|
|
|
def update(self, instance, validated_data):
|
|
urls = validated_data.pop("feed_in_button_urls", None)
|
|
instance = super().update(instance, validated_data)
|
|
if urls is not None:
|
|
instance.feed_in_button_urls = urls
|
|
instance.save(update_fields=["feed_in_button_urls", "updated_at"])
|
|
return instance
|
|
|
|
def to_representation(self, instance):
|
|
data = super().to_representation(instance)
|
|
urls = data.get("feed_in_button_urls") or []
|
|
if not isinstance(urls, list):
|
|
urls = []
|
|
data["feed_in_button_urls"] = [
|
|
{"label": str(item.get("label", "") or ""), "url": str(item.get("url", "") or "")}
|
|
for item in urls
|
|
if isinstance(item, dict) and str(item.get("url", "") or "").strip()
|
|
]
|
|
return data
|
|
|
|
|
|
class FlockSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
|
class Meta:
|
|
model = Flock
|
|
fields = ["id", "flock_name", "kandang", "created_at", "updated_at"]
|
|
read_only_fields = ["id", "created_at", "updated_at"]
|
|
|
|
|
|
class CycleSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
|
kandang = serializers.PrimaryKeyRelatedField(queryset=Kandang.objects.all())
|
|
kandang_name = serializers.CharField(source="kandang.kandang_name", read_only=True)
|
|
chick_in_weight = serializers.IntegerField(source="doc_in_weight")
|
|
current_day = serializers.IntegerField(read_only=True)
|
|
visible_through_date = serializers.DateField(read_only=True)
|
|
soft_end_date = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Cycle
|
|
fields = [
|
|
"id",
|
|
"kandang",
|
|
"kandang_name",
|
|
"total_days",
|
|
"current_day",
|
|
"visible_through_date",
|
|
"soft_end_date",
|
|
"start_date",
|
|
"end_date",
|
|
"chick_in_weight",
|
|
"doc_in_count",
|
|
"feed_initial_balance",
|
|
"feed_initial_balance_date",
|
|
"status",
|
|
"proposed_end_date",
|
|
"close_requested_at",
|
|
"close_requested_by",
|
|
"created_at",
|
|
"updated_at",
|
|
]
|
|
read_only_fields = [
|
|
"id",
|
|
"kandang_name",
|
|
"feed_initial_balance",
|
|
"feed_initial_balance_date",
|
|
"end_date",
|
|
"status",
|
|
"proposed_end_date",
|
|
"close_requested_at",
|
|
"close_requested_by",
|
|
"created_at",
|
|
"updated_at",
|
|
"soft_end_date",
|
|
]
|
|
|
|
def get_soft_end_date(self, obj: Cycle):
|
|
return obj.soft_end_date()
|
|
|
|
def validate(self, attrs):
|
|
attrs.pop("status", None)
|
|
# Defense in depth: end_date is read-only (GM approve only).
|
|
attrs.pop("end_date", None)
|
|
if self.instance is None:
|
|
attrs.setdefault("total_days", 1)
|
|
start = attrs.get("start_date", getattr(self.instance, "start_date", None))
|
|
end = getattr(self.instance, "end_date", None) if self.instance else None
|
|
if start and end and end < start:
|
|
raise serializers.ValidationError({"end_date": "Must be on or after start_date."})
|
|
return attrs
|
|
|
|
def to_representation(self, instance):
|
|
return super().to_representation(instance)
|