236 lines
9.8 KiB
Python
236 lines
9.8 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
from django.apps import apps
|
|
|
|
from rest_framework import serializers
|
|
|
|
|
|
class QueryJSONField(serializers.JSONField):
|
|
def to_internal_value(self, data):
|
|
if isinstance(data, str):
|
|
data = data.strip()
|
|
if not data:
|
|
return None
|
|
try:
|
|
data = json.loads(data)
|
|
except json.JSONDecodeError as exc:
|
|
raise serializers.ValidationError("فرمت JSON نامعتبر است.") from exc
|
|
return super().to_internal_value(data)
|
|
|
|
|
|
class PlantNameAliasMixin:
|
|
plant_name_field = "plant_name"
|
|
plant_alias_fields = ("crop", "crop_name")
|
|
|
|
def _get_raw_plant_name(self, attrs):
|
|
value = attrs.get(self.plant_name_field)
|
|
if value not in (None, ""):
|
|
return value
|
|
|
|
for alias in self.plant_alias_fields:
|
|
alias_value = self.initial_data.get(alias) if hasattr(self, "initial_data") else None
|
|
if alias_value not in (None, ""):
|
|
return alias_value
|
|
return value
|
|
|
|
def _resolve_plant_name(self, attrs, *, required: bool) -> dict:
|
|
raw_value = self._get_raw_plant_name(attrs)
|
|
if raw_value in (None, ""):
|
|
if required:
|
|
raise serializers.ValidationError(
|
|
{self.plant_name_field: "یکی از plant_name، crop یا crop_name باید ارسال شود."}
|
|
)
|
|
attrs[self.plant_name_field] = ""
|
|
return attrs
|
|
|
|
resolved_value = apps.get_app_config("plant").resolve_plant_name(str(raw_value))
|
|
attrs[self.plant_name_field] = resolved_value or str(raw_value).strip()
|
|
return attrs
|
|
|
|
|
|
class GrowthSimulationRequestSerializer(PlantNameAliasMixin, serializers.Serializer):
|
|
plant_name = serializers.CharField(required=False, allow_blank=True, help_text="نام گیاه")
|
|
dynamic_parameters = serializers.ListField(
|
|
child=serializers.CharField(),
|
|
allow_empty=False,
|
|
help_text="پارامترهای متغیر رشد که باید در خروجی گزارش شوند.",
|
|
)
|
|
farm_uuid = serializers.UUIDField(required=False, allow_null=True)
|
|
weather = serializers.JSONField(required=False)
|
|
soil_parameters = serializers.JSONField(required=False)
|
|
site_parameters = serializers.JSONField(required=False)
|
|
crop_parameters = serializers.JSONField(required=False)
|
|
agromanagement = serializers.JSONField(required=False)
|
|
irrigation_recommendation = serializers.JSONField(required=False)
|
|
fertilization_recommendation = serializers.JSONField(required=False)
|
|
page_size = serializers.IntegerField(required=False, min_value=1, max_value=50)
|
|
|
|
def validate(self, attrs):
|
|
attrs = self._resolve_plant_name(attrs, required=True)
|
|
if not attrs.get("farm_uuid") and not attrs.get("weather"):
|
|
raise serializers.ValidationError(
|
|
"یکی از farm_uuid یا weather باید ارسال شود."
|
|
)
|
|
return attrs
|
|
|
|
|
|
class GrowthSimulationQueuedSerializer(serializers.Serializer):
|
|
task_id = serializers.UUIDField()
|
|
status_url = serializers.CharField()
|
|
plant_name = serializers.CharField()
|
|
|
|
|
|
class GrowthStageMetricSerializer(serializers.Serializer):
|
|
start = serializers.FloatField()
|
|
end = serializers.FloatField()
|
|
min = serializers.FloatField()
|
|
max = serializers.FloatField()
|
|
avg = serializers.FloatField()
|
|
|
|
|
|
class GrowthStageSerializer(serializers.Serializer):
|
|
order = serializers.IntegerField()
|
|
stage_code = serializers.CharField()
|
|
stage_name = serializers.CharField()
|
|
start_date = serializers.DateField()
|
|
end_date = serializers.DateField()
|
|
days_count = serializers.IntegerField()
|
|
metrics = serializers.JSONField()
|
|
|
|
|
|
class GrowthPaginationSerializer(serializers.Serializer):
|
|
page = serializers.IntegerField()
|
|
page_size = serializers.IntegerField()
|
|
total_items = serializers.IntegerField()
|
|
total_pages = serializers.IntegerField()
|
|
has_next = serializers.BooleanField()
|
|
has_previous = serializers.BooleanField()
|
|
|
|
|
|
class GrowthSimulationResultSerializer(serializers.Serializer):
|
|
plant_name = serializers.CharField()
|
|
dynamic_parameters = serializers.ListField(child=serializers.CharField())
|
|
engine = serializers.CharField(allow_null=True)
|
|
model_name = serializers.CharField(allow_null=True)
|
|
scenario_id = serializers.IntegerField(allow_null=True)
|
|
simulation_warning = serializers.CharField(allow_null=True, allow_blank=True)
|
|
summary_metrics = serializers.JSONField()
|
|
stage_timeline = GrowthStageSerializer(many=True)
|
|
stages_page = GrowthStageSerializer(many=True)
|
|
pagination = GrowthPaginationSerializer()
|
|
daily_records_count = serializers.IntegerField()
|
|
default_page_size = serializers.IntegerField()
|
|
|
|
|
|
|
|
class CurrentFarmChartRequestSerializer(PlantNameAliasMixin, serializers.Serializer):
|
|
farm_uuid = serializers.UUIDField(help_text="شناسه یکتای مزرعه")
|
|
plant_name = serializers.CharField(required=False, allow_blank=True, help_text="نام گیاه")
|
|
irrigation_recommendation = serializers.JSONField(required=False)
|
|
fertilization_recommendation = serializers.JSONField(required=False)
|
|
|
|
def validate(self, attrs):
|
|
return self._resolve_plant_name(attrs, required=False)
|
|
|
|
|
|
class CurrentFarmChartResponseSerializer(serializers.Serializer):
|
|
farm_uuid = serializers.CharField(allow_null=True)
|
|
plant_name = serializers.CharField()
|
|
engine = serializers.CharField(allow_null=True)
|
|
model_name = serializers.CharField(allow_null=True)
|
|
scenario_id = serializers.IntegerField(allow_null=True)
|
|
simulation_warning = serializers.CharField(allow_null=True, allow_blank=True)
|
|
categories = serializers.ListField(child=serializers.CharField())
|
|
series = serializers.JSONField()
|
|
summary = serializers.JSONField()
|
|
current_state = serializers.JSONField()
|
|
metrics = serializers.JSONField()
|
|
daily_output = serializers.JSONField()
|
|
|
|
|
|
class HarvestPredictionRequestSerializer(PlantNameAliasMixin, serializers.Serializer):
|
|
farm_uuid = serializers.UUIDField(help_text="شناسه یکتای مزرعه")
|
|
plant_name = serializers.CharField(required=False, allow_blank=True, help_text="نام گیاه")
|
|
irrigation_recommendation = serializers.JSONField(required=False)
|
|
fertilization_recommendation = serializers.JSONField(required=False)
|
|
|
|
def validate(self, attrs):
|
|
return self._resolve_plant_name(attrs, required=False)
|
|
|
|
|
|
class HarvestPredictionResponseSerializer(serializers.Serializer):
|
|
date = serializers.CharField()
|
|
dateFormatted = serializers.CharField()
|
|
daysUntil = serializers.IntegerField()
|
|
description = serializers.CharField()
|
|
optimalWindowStart = serializers.CharField()
|
|
optimalWindowEnd = serializers.CharField()
|
|
gddDetails = serializers.JSONField()
|
|
|
|
|
|
class YieldPredictionRequestSerializer(PlantNameAliasMixin, serializers.Serializer):
|
|
farm_uuid = serializers.UUIDField(help_text="شناسه یکتای مزرعه")
|
|
plant_name = serializers.CharField(required=False, allow_blank=True, help_text="نام گیاه")
|
|
irrigation_recommendation = serializers.JSONField(required=False)
|
|
fertilization_recommendation = serializers.JSONField(required=False)
|
|
|
|
def validate(self, attrs):
|
|
return self._resolve_plant_name(attrs, required=False)
|
|
|
|
|
|
class YieldPredictionResponseSerializer(serializers.Serializer):
|
|
farm_uuid = serializers.CharField()
|
|
plant_name = serializers.CharField(allow_null=True)
|
|
predictedYieldTons = serializers.FloatField()
|
|
predictedYieldRaw = serializers.FloatField()
|
|
unit = serializers.CharField()
|
|
sourceUnit = serializers.CharField()
|
|
simulationEngine = serializers.CharField(allow_null=True)
|
|
simulationModel = serializers.CharField(allow_null=True)
|
|
scenarioId = serializers.IntegerField(allow_null=True)
|
|
simulationWarning = serializers.CharField(allow_null=True, allow_blank=True)
|
|
supportingMetrics = serializers.JSONField()
|
|
|
|
|
|
class YieldHarvestSummaryQuerySerializer(serializers.Serializer):
|
|
farm_uuid = serializers.UUIDField(required=True, help_text="شناسه یکتای مزرعه")
|
|
season_year = serializers.IntegerField(required=False, help_text="سال زراعی")
|
|
crop_name = serializers.CharField(required=False, allow_blank=True, help_text="نام محصول")
|
|
include_narrative = serializers.BooleanField(
|
|
required=False,
|
|
default=False,
|
|
help_text="در صورت true بودن، بخش روایت نیز در آینده اضافه می شود.",
|
|
)
|
|
irrigation_recommendation = QueryJSONField(
|
|
required=False,
|
|
allow_null=True,
|
|
help_text="برنامه آبیاری به صورت JSON برای تزریق به PCSE.",
|
|
)
|
|
fertilization_recommendation = QueryJSONField(
|
|
required=False,
|
|
allow_null=True,
|
|
help_text="برنامه کودهی به صورت JSON برای تزریق به PCSE.",
|
|
)
|
|
|
|
def validate(self, attrs):
|
|
raw_crop_name = attrs.get("crop_name")
|
|
if raw_crop_name in (None, "") and hasattr(self, "initial_data"):
|
|
raw_crop_name = self.initial_data.get("plant_name") or self.initial_data.get("crop")
|
|
if raw_crop_name not in (None, ""):
|
|
resolved_crop_name = apps.get_app_config("plant").resolve_plant_name(str(raw_crop_name))
|
|
attrs["crop_name"] = resolved_crop_name or str(raw_crop_name).strip()
|
|
return attrs
|
|
|
|
|
|
class YieldHarvestSummaryResponseSerializer(serializers.Serializer):
|
|
farm_uuid = serializers.CharField()
|
|
season_highlights_card = serializers.JSONField()
|
|
yield_prediction = serializers.JSONField()
|
|
harvest_prediction_card = serializers.JSONField()
|
|
harvest_readiness_zones = serializers.JSONField()
|
|
yield_quality_bands = serializers.JSONField()
|
|
harvest_operations_card = serializers.JSONField()
|
|
yield_prediction_chart = serializers.JSONField()
|