from rest_framework import serializers class FertilizationRecommendRequestSerializer(serializers.Serializer): """سریالایزر ورودی برای درخواست توصیه کودهی.""" farm_uuid = serializers.CharField(required=False, help_text="شناسه یکتای مزرعه") sensor_uuid = serializers.CharField(required=False, help_text="نام قدیمی برای farm_uuid") crop_id = serializers.CharField(required=False, allow_blank=True, help_text="شناسه یا نام محصول") plant_name = serializers.CharField(required=False, allow_blank=True, help_text="نام گیاه") growth_stage = serializers.CharField(required=False, allow_blank=True, help_text="مرحله رشد گیاه") query = serializers.CharField(required=False, allow_blank=True, help_text="سوال اختیاری") def validate(self, attrs): farm_uuid = attrs.get("farm_uuid") or attrs.get("sensor_uuid") if not farm_uuid: raise serializers.ValidationError({"farm_uuid": "farm_uuid الزامی است."}) crop_id = (attrs.get("crop_id") or "").strip() plant_name = (attrs.get("plant_name") or "").strip() if crop_id and not plant_name: attrs["plant_name"] = crop_id attrs["farm_uuid"] = farm_uuid return attrs class NpkRatioSerializer(serializers.Serializer): n = serializers.FloatField() p = serializers.FloatField() k = serializers.FloatField() label = serializers.CharField() class FertilizationApplicationMethodSerializer(serializers.Serializer): id = serializers.CharField() label = serializers.CharField() class FertilizationApplicationIntervalSerializer(serializers.Serializer): value = serializers.IntegerField() unit = serializers.CharField() label = serializers.CharField() class FertilizationDosageSerializer(serializers.Serializer): base_amount_per_hectare = serializers.FloatField() base_amount_per_square_meter = serializers.FloatField() unit = serializers.CharField() label = serializers.CharField() calculation_basis = serializers.CharField() class PrimaryFertilizationRecommendationSerializer(serializers.Serializer): fertilizer_code = serializers.CharField() fertilizer_name = serializers.CharField() display_title = serializers.CharField() fertilizer_type = serializers.CharField() npk_ratio = NpkRatioSerializer() application_method = FertilizationApplicationMethodSerializer() application_interval = FertilizationApplicationIntervalSerializer() dosage = FertilizationDosageSerializer() reasoning = serializers.CharField() summary = serializers.CharField() class FertilizationNutrientSerializer(serializers.Serializer): key = serializers.CharField() name = serializers.CharField() value = serializers.FloatField() unit = serializers.CharField() description = serializers.CharField(required=False, allow_blank=True) class FertilizationNutrientAnalysisSerializer(serializers.Serializer): macro = FertilizationNutrientSerializer(many=True) micro = FertilizationNutrientSerializer(many=True) class FertilizationGuideStepSerializer(serializers.Serializer): step_number = serializers.IntegerField() title = serializers.CharField() description = serializers.CharField() class FertilizationApplicationGuideSerializer(serializers.Serializer): safety_warning = serializers.CharField() steps = FertilizationGuideStepSerializer(many=True) class AlternativeFertilizationRecommendationSerializer(serializers.Serializer): fertilizer_code = serializers.CharField() fertilizer_name = serializers.CharField() fertilizer_type = serializers.CharField() usage_method = serializers.CharField() description = serializers.CharField() class FertilizationSectionSerializer(serializers.Serializer): type = serializers.CharField() title = serializers.CharField() icon = serializers.CharField(required=False, allow_blank=True) content = serializers.CharField(required=False, allow_blank=True) items = serializers.ListField(child=serializers.CharField(), required=False) fertilizerType = serializers.CharField(required=False, allow_blank=True) amount = serializers.CharField(required=False, allow_blank=True) applicationMethod = serializers.CharField(required=False, allow_blank=True) timing = serializers.CharField(required=False, allow_blank=True) validityPeriod = serializers.CharField(required=False, allow_blank=True) expandableExplanation = serializers.CharField(required=False, allow_blank=True) class FertilizationRecommendationResponseDataSerializer(serializers.Serializer): primary_recommendation = PrimaryFertilizationRecommendationSerializer() nutrient_analysis = FertilizationNutrientAnalysisSerializer() application_guide = FertilizationApplicationGuideSerializer() alternative_recommendations = AlternativeFertilizationRecommendationSerializer(many=True) sections = FertilizationSectionSerializer(many=True, required=False) class FertilizationPlanParserRequestSerializer(serializers.Serializer): message = serializers.CharField(required=False, allow_blank=True, help_text="توضیح آزاد کاربر درباره برنامه کودهی") answers = serializers.JSONField(required=False, help_text="پاسخ های تکمیلی کاربر به سوالات مرحله قبل") partial_plan = serializers.JSONField(required=False, help_text="داده استخراج شده مرحله قبل برای ادامه تکمیل") farm_uuid = serializers.CharField(required=False, allow_blank=True, help_text="شناسه مزرعه برای غنی سازی context") def validate(self, attrs): message = (attrs.get("message") or "").strip() answers = attrs.get("answers") partial_plan = attrs.get("partial_plan") if not message and not isinstance(answers, dict) and not isinstance(partial_plan, dict): raise serializers.ValidationError( "حداقل یکی از message، answers یا partial_plan باید ارسال شود." ) return attrs class PlanClarificationQuestionSerializer(serializers.Serializer): id = serializers.CharField() field = serializers.CharField() question = serializers.CharField() rationale = serializers.CharField(required=False, allow_blank=True) class FertilizationPlanParserResponseSerializer(serializers.Serializer): status = serializers.CharField() status_fa = serializers.CharField() summary = serializers.CharField() missing_fields = serializers.ListField(child=serializers.CharField()) questions = PlanClarificationQuestionSerializer(many=True) collected_data = serializers.JSONField() final_plan = serializers.JSONField(required=False, allow_null=True)