Files
2026-05-02 04:49:29 +03:30

179 lines
6.9 KiB
Python

from rest_framework import serializers
from farmer_calendar.enums import FARMER_TAG_VALUES, PRIORITY_INPUT_MAP
from farmer_calendar.models import FarmerCalendarZone
from .models import FarmerTodoTask
class FarmerTodoTaskResponseSerializer(serializers.ModelSerializer):
id = serializers.UUIDField(source="uuid", read_only=True)
zone = serializers.CharField(source="zone.value", read_only=True, allow_null=True)
scheduledDate = serializers.DateField(source="scheduled_date", format="%Y-%m-%d", read_only=True)
time = serializers.TimeField(format="%H:%M", read_only=True)
note = serializers.CharField(source="description", read_only=True)
tags = serializers.SerializerMethodField()
class Meta:
model = FarmerTodoTask
fields = [
"id",
"title",
"zone",
"scheduledDate",
"time",
"priority",
"note",
"tags",
"status",
]
def get_tags(self, obj):
raw_tags = obj.extended_props.get("tags", [])
return [tag for tag in raw_tags if tag in FARMER_TAG_VALUES]
class FarmerTodoChoiceSerializer(serializers.Serializer):
id = serializers.CharField()
label = serializers.CharField()
value = serializers.CharField()
class FarmerTodoZoneSerializer(FarmerTodoChoiceSerializer):
prefix = "zone_"
class FarmerTodoTagSerializer(FarmerTodoChoiceSerializer):
pass
class FarmerTodoTaskWriteSerializer(serializers.Serializer):
title = serializers.CharField(max_length=255, required=False)
zone = serializers.CharField(max_length=255, required=False)
scheduledDate = serializers.DateField(required=False, format="%Y-%m-%d", input_formats=["%Y-%m-%d"])
time = serializers.TimeField(required=False, format="%H:%M", input_formats=["%H:%M"])
priority = serializers.CharField(required=False)
note = serializers.CharField(required=False, allow_blank=True, default="")
tags = serializers.ListField(
child=serializers.CharField(max_length=100),
required=False,
default=list,
allow_empty=True,
)
status = serializers.ChoiceField(choices=[FarmerTodoTask.STATUS_OPEN, FarmerTodoTask.STATUS_DONE], required=False)
farm_uuid = serializers.UUIDField(required=False, write_only=True)
def validate_title(self, value):
value = value.strip()
if not value:
raise serializers.ValidationError("title cannot be empty")
return value
def validate_zone(self, value):
value = value.strip()
if not value:
raise serializers.ValidationError("zone cannot be empty")
return value
def validate_priority(self, value):
normalized = PRIORITY_INPUT_MAP.get(value.strip().lower(), PRIORITY_INPUT_MAP.get(value.strip()))
if normalized is None:
raise serializers.ValidationError("priority must be one of زیاد, متوسط, کم, high, medium, low")
return normalized
def validate_tags(self, value):
normalized = []
for tag in value:
cleaned = tag.strip()
if cleaned:
if cleaned not in FARMER_TAG_VALUES:
raise serializers.ValidationError(f"tag `{cleaned}` is not valid")
normalized.append(cleaned)
return normalized
def validate(self, attrs):
if not self.partial:
required_fields = ["title", "zone", "scheduledDate", "time", "priority"]
errors = {}
for field in required_fields:
if field not in attrs:
errors[field] = [f"{field} is required"]
if errors:
raise serializers.ValidationError(errors)
return attrs
@staticmethod
def _sync_zone(task, zone_value):
zone, _ = FarmerCalendarZone.objects.get_or_create(
farm=task.farm,
value=zone_value,
defaults={"label": zone_value},
)
if zone.label != zone_value:
zone.label = zone_value
zone.save(update_fields=["label", "updated_at"])
task.zone = zone
def create(self, validated_data):
zone_value = validated_data.pop("zone")
tags = validated_data.pop("tags", [])
validated_data.pop("farm_uuid", None)
validated_data["scheduled_date"] = validated_data.pop("scheduledDate")
validated_data["description"] = validated_data.pop("note", "")
validated_data["extended_props"] = {"tags": tags}
farm = validated_data["farm"]
zone, _ = FarmerCalendarZone.objects.get_or_create(
farm=farm,
value=zone_value,
defaults={"label": zone_value},
)
if zone.label != zone_value:
zone.label = zone_value
zone.save(update_fields=["label", "updated_at"])
task = FarmerTodoTask.objects.create(zone=zone, **validated_data)
return task
def update(self, instance, validated_data):
zone_value = validated_data.pop("zone", None)
tags = validated_data.pop("tags", None)
validated_data.pop("farm_uuid", None)
if "scheduledDate" in validated_data:
validated_data["scheduled_date"] = validated_data.pop("scheduledDate")
if "note" in validated_data:
validated_data["description"] = validated_data.pop("note")
if tags is not None:
extended_props = dict(instance.extended_props or {})
extended_props["tags"] = tags
validated_data["extended_props"] = extended_props
for attr, value in validated_data.items():
setattr(instance, attr, value)
if zone_value is not None:
self._sync_zone(instance, zone_value)
instance.save()
return instance
class FarmerTodoListQuerySerializer(serializers.Serializer):
status = serializers.ChoiceField(choices=[FarmerTodoTask.STATUS_OPEN, FarmerTodoTask.STATUS_DONE], required=False)
priority = serializers.CharField(required=False)
date = serializers.DateField(required=False, input_formats=["%Y-%m-%d"])
from_date = serializers.DateField(required=False, input_formats=["%Y-%m-%d"], source="from")
to = serializers.DateField(required=False, input_formats=["%Y-%m-%d"])
zone = serializers.CharField(required=False)
search = serializers.CharField(required=False)
farm_uuid = serializers.UUIDField(required=False)
def validate_priority(self, value):
normalized = PRIORITY_INPUT_MAP.get(value.strip().lower(), PRIORITY_INPUT_MAP.get(value.strip()))
if normalized is None:
raise serializers.ValidationError("priority must be one of زیاد, متوسط, کم, high, medium, low")
return normalized
def validate(self, attrs):
from_date = attrs.get("from")
to_date = attrs.get("to")
if from_date and to_date and to_date < from_date:
raise serializers.ValidationError({"to": "to cannot be before from"})
return attrs