from rest_framework import serializers from .models import Fertilizer, FertilizationPlan, FertilizationEntry, DistributionPlan, DistributionGroup, DistributionGroupField class FertilizerSerializer(serializers.ModelSerializer): material_id = serializers.SerializerMethodField() class Meta: model = Fertilizer fields = [ 'id', 'name', 'maker', 'capacity_kg', 'nitrogen_pct', 'phosphorus_pct', 'potassium_pct', 'notes', 'material', 'material_id', ] def get_material_id(self, obj): return obj.material_id class FertilizationEntrySerializer(serializers.ModelSerializer): field_name = serializers.CharField(source='field.name', read_only=True) field_area_tan = serializers.DecimalField( source='field.area_tan', max_digits=6, decimal_places=4, read_only=True ) fertilizer_name = serializers.CharField(source='fertilizer.name', read_only=True) class Meta: model = FertilizationEntry fields = ['id', 'field', 'field_name', 'field_area_tan', 'fertilizer', 'fertilizer_name', 'bags'] class FertilizationPlanSerializer(serializers.ModelSerializer): variety_name = serializers.SerializerMethodField() crop_name = serializers.SerializerMethodField() entries = FertilizationEntrySerializer(many=True, read_only=True) field_count = serializers.SerializerMethodField() fertilizer_count = serializers.SerializerMethodField() is_confirmed = serializers.BooleanField(read_only=True) confirmed_at = serializers.DateTimeField(read_only=True) class Meta: model = FertilizationPlan fields = [ 'id', 'name', 'year', 'variety', 'variety_name', 'crop_name', 'calc_settings', 'entries', 'field_count', 'fertilizer_count', 'is_confirmed', 'confirmed_at', 'created_at', 'updated_at' ] def get_variety_name(self, obj): return obj.variety.name def get_crop_name(self, obj): return obj.variety.crop.name def get_field_count(self, obj): return obj.entries.values('field').distinct().count() def get_fertilizer_count(self, obj): return obj.entries.values('fertilizer').distinct().count() class FertilizationPlanWriteSerializer(serializers.ModelSerializer): """保存用(entries を一括で受け取る)""" entries = serializers.ListField(child=serializers.DictField(), write_only=True, required=False) class Meta: model = FertilizationPlan fields = ['id', 'name', 'year', 'variety', 'calc_settings', 'entries'] def create(self, validated_data): entries_data = validated_data.pop('entries', []) plan = FertilizationPlan.objects.create(**validated_data) self._save_entries(plan, entries_data) return plan def update(self, instance, validated_data): entries_data = validated_data.pop('entries', None) for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() if entries_data is not None: instance.entries.all().delete() self._save_entries(instance, entries_data) return instance def _save_entries(self, plan, entries_data): for entry in entries_data: FertilizationEntry.objects.create( plan=plan, field_id=entry['field_id'], fertilizer_id=entry['fertilizer_id'], bags=entry['bags'], ) # ─── 分配計画 ──────────────────────────────────────────────────────────── class DistributionGroupFieldSerializer(serializers.ModelSerializer): id = serializers.IntegerField(source='field.id', read_only=True) name = serializers.CharField(source='field.name', read_only=True) area_tan = serializers.DecimalField( source='field.area_tan', max_digits=6, decimal_places=4, read_only=True ) class Meta: model = DistributionGroupField fields = ['id', 'name', 'area_tan'] class DistributionGroupReadSerializer(serializers.ModelSerializer): fields = DistributionGroupFieldSerializer(source='field_assignments', many=True, read_only=True) class Meta: model = DistributionGroup fields = ['id', 'name', 'order', 'fields'] class FertilizationPlanForDistributionSerializer(serializers.ModelSerializer): """分配計画詳細に埋め込む施肥計画情報(肥料一覧・entries 含む)""" variety_name = serializers.SerializerMethodField() crop_name = serializers.SerializerMethodField() fertilizers = serializers.SerializerMethodField() entries = serializers.SerializerMethodField() class Meta: model = FertilizationPlan fields = ['id', 'name', 'year', 'variety_name', 'crop_name', 'fertilizers', 'entries'] def get_variety_name(self, obj): return obj.variety.name def get_crop_name(self, obj): return obj.variety.crop.name def get_fertilizers(self, obj): fert_ids = obj.entries.values_list('fertilizer_id', flat=True).distinct() from .models import Fertilizer as F fertilizers = F.objects.filter(id__in=fert_ids).order_by('name') return [{'id': f.id, 'name': f.name} for f in fertilizers] def get_entries(self, obj): return [ {'field': e.field_id, 'fertilizer': e.fertilizer_id, 'bags': str(e.bags)} for e in obj.entries.all() ] class DistributionPlanListSerializer(serializers.ModelSerializer): fertilization_plan_id = serializers.IntegerField(source='fertilization_plan.id', read_only=True) fertilization_plan_name = serializers.CharField(source='fertilization_plan.name', read_only=True) year = serializers.IntegerField(source='fertilization_plan.year', read_only=True) variety_name = serializers.SerializerMethodField() crop_name = serializers.SerializerMethodField() group_count = serializers.SerializerMethodField() field_count = serializers.SerializerMethodField() class Meta: model = DistributionPlan fields = [ 'id', 'name', 'fertilization_plan_id', 'fertilization_plan_name', 'year', 'variety_name', 'crop_name', 'group_count', 'field_count', 'created_at', 'updated_at', ] def get_variety_name(self, obj): return obj.fertilization_plan.variety.name def get_crop_name(self, obj): return obj.fertilization_plan.variety.crop.name def get_group_count(self, obj): return obj.groups.count() def get_field_count(self, obj): return obj.distributiongroupfield_set.count() class DistributionPlanReadSerializer(serializers.ModelSerializer): fertilization_plan = FertilizationPlanForDistributionSerializer(read_only=True) groups = DistributionGroupReadSerializer(many=True, read_only=True) unassigned_fields = serializers.SerializerMethodField() class Meta: model = DistributionPlan fields = ['id', 'name', 'fertilization_plan', 'groups', 'unassigned_fields', 'created_at', 'updated_at'] def get_unassigned_fields(self, obj): assigned_ids = obj.distributiongroupfield_set.values_list('field_id', flat=True) plan_field_ids = obj.fertilization_plan.entries.values_list('field_id', flat=True).distinct() from apps.fields.models import Field as F unassigned = F.objects.filter(id__in=plan_field_ids).exclude(id__in=assigned_ids).order_by('display_order', 'id') return [{'id': f.id, 'name': f.name, 'area_tan': str(f.area_tan)} for f in unassigned] class DistributionPlanWriteSerializer(serializers.ModelSerializer): fertilization_plan_id = serializers.IntegerField(write_only=True) groups = serializers.ListField(child=serializers.DictField(), write_only=True, required=False) class Meta: model = DistributionPlan fields = ['id', 'name', 'fertilization_plan_id', 'groups'] def create(self, validated_data): groups_data = validated_data.pop('groups', []) plan = DistributionPlan.objects.create(**validated_data) self._save_groups(plan, groups_data) return plan def update(self, instance, validated_data): groups_data = validated_data.pop('groups', None) instance.name = validated_data.get('name', instance.name) instance.save() if groups_data is not None: instance.groups.all().delete() self._save_groups(instance, groups_data) return instance def _save_groups(self, plan, groups_data): for g_data in groups_data: group = DistributionGroup.objects.create( distribution_plan=plan, name=g_data['name'], order=g_data.get('order', 0), ) for field_id in g_data.get('field_ids', []): DistributionGroupField.objects.create( distribution_plan=plan, group=group, field_id=field_id, )