diff --git a/backend/apps/levee_work/serializers.py b/backend/apps/levee_work/serializers.py index 32aa780..e46d1f3 100644 --- a/backend/apps/levee_work/serializers.py +++ b/backend/apps/levee_work/serializers.py @@ -1,4 +1,5 @@ from django.db import transaction +from decimal import Decimal from rest_framework import serializers from apps.plans.models import Plan @@ -34,6 +35,7 @@ class LeveeWorkSessionSerializer(serializers.ModelSerializer): items = LeveeWorkSessionItemReadSerializer(many=True, read_only=True) work_record_id = serializers.IntegerField(source='work_record.id', read_only=True) item_count = serializers.SerializerMethodField() + total_area_tan = serializers.SerializerMethodField() class Meta: model = LeveeWorkSession @@ -45,6 +47,7 @@ class LeveeWorkSessionSerializer(serializers.ModelSerializer): 'notes', 'work_record_id', 'item_count', + 'total_area_tan', 'items', 'created_at', 'updated_at', @@ -53,6 +56,10 @@ class LeveeWorkSessionSerializer(serializers.ModelSerializer): def get_item_count(self, obj): return len(obj.items.all()) + def get_total_area_tan(self, obj): + total = sum((item.field.area_tan or Decimal('0')) for item in obj.items.all()) + return str(total) + class LeveeWorkSessionItemWriteInputSerializer(serializers.Serializer): field = serializers.IntegerField() diff --git a/backend/apps/levee_work/tests.py b/backend/apps/levee_work/tests.py new file mode 100644 index 0000000..ac6c4f0 --- /dev/null +++ b/backend/apps/levee_work/tests.py @@ -0,0 +1,58 @@ +from django.test import TestCase + +from apps.fields.models import Field +from apps.plans.models import Crop, Plan, Variety + +from .models import LeveeWorkSession, LeveeWorkSessionItem +from .serializers import LeveeWorkSessionSerializer + + +class LeveeWorkSessionSerializerTests(TestCase): + def test_total_area_tan_is_included(self): + crop = Crop.objects.create(name='水稲') + variety = Variety.objects.create(crop=crop, name='にこまる') + field_a = Field.objects.create( + name='足川北上', + address='高知県高岡郡', + area_tan='1.2000', + area_m2=1200, + owner_name='吉田', + group_name='北', + display_order=1, + ) + field_b = Field.objects.create( + name='足川南', + address='高知県高岡郡', + area_tan='0.8000', + area_m2=800, + owner_name='吉田', + group_name='南', + display_order=2, + ) + plan_a = Plan.objects.create(field=field_a, year=2026, crop=crop, variety=variety, notes='') + plan_b = Plan.objects.create(field=field_b, year=2026, crop=crop, variety=variety, notes='') + session = LeveeWorkSession.objects.create( + year=2026, + date='2026-04-06', + title='水稲畔塗', + notes='', + ) + LeveeWorkSessionItem.objects.create( + session=session, + field=field_a, + plan=plan_a, + crop_name_snapshot='水稲', + variety_name_snapshot='にこまる', + ) + LeveeWorkSessionItem.objects.create( + session=session, + field=field_b, + plan=plan_b, + crop_name_snapshot='水稲', + variety_name_snapshot='にこまる', + ) + + data = LeveeWorkSessionSerializer(session).data + + self.assertEqual(data['item_count'], 2) + self.assertEqual(data['total_area_tan'], '2.0000') diff --git a/frontend/src/app/levee-work/page.tsx b/frontend/src/app/levee-work/page.tsx index 6117f6a..8466fa4 100644 --- a/frontend/src/app/levee-work/page.tsx +++ b/frontend/src/app/levee-work/page.tsx @@ -203,6 +203,10 @@ function LeveeWorkPageContent() { return sortedCandidates.filter((candidate) => form.selectedFieldIds.has(candidate.field_id)); }, [form, sortedCandidates]); + const selectedAreaTan = useMemo(() => { + return selectedCandidates.reduce((sum, candidate) => sum + Number(candidate.field_area_tan || '0'), 0); + }, [selectedCandidates]); + const handleSort = (nextKey: SortKey) => { if (sortKey === nextKey) { setSortDirection((current) => (current === 'asc' ? 'desc' : 'asc')); @@ -335,7 +339,9 @@ function LeveeWorkPageContent() { >
{session.title}
{session.date}
-
{session.item_count}圃場
+
+ {session.item_count}圃場 / {Number(session.total_area_tan).toFixed(2)}反 +
))} @@ -388,7 +394,9 @@ function LeveeWorkPageContent() {

対象圃場一覧

-

{selectedCount} / {candidates.length} 圃場を選択中

+

+ {selectedCount} / {candidates.length} 圃場を選択中 / 合計 {selectedAreaTan.toFixed(2)}反 +