185 lines
6.2 KiB
Python
185 lines
6.2 KiB
Python
from rest_framework import viewsets, status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.response import Response
|
|
from django.db.models import Sum
|
|
from .models import Crop, Variety, Plan, RiceTransplantPlan
|
|
from .serializers import (
|
|
CropSerializer,
|
|
VarietySerializer,
|
|
PlanSerializer,
|
|
RiceTransplantPlanSerializer,
|
|
RiceTransplantPlanWriteSerializer,
|
|
)
|
|
from apps.fields.models import Field
|
|
|
|
|
|
class CropViewSet(viewsets.ModelViewSet):
|
|
queryset = Crop.objects.all()
|
|
serializer_class = CropSerializer
|
|
|
|
|
|
class VarietyViewSet(viewsets.ModelViewSet):
|
|
queryset = Variety.objects.all()
|
|
serializer_class = VarietySerializer
|
|
|
|
|
|
class PlanViewSet(viewsets.ModelViewSet):
|
|
queryset = Plan.objects.all()
|
|
serializer_class = PlanSerializer
|
|
|
|
def get_queryset(self):
|
|
queryset = Plan.objects.all()
|
|
year = self.request.query_params.get('year')
|
|
if year:
|
|
queryset = queryset.filter(year=year)
|
|
return queryset
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def summary(self, request):
|
|
year = request.query_params.get('year')
|
|
if not year:
|
|
return Response({'error': 'year parameter is required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
plans = Plan.objects.filter(year=year)
|
|
total_area = plans.aggregate(total=Sum('field__area_tan'))['total'] or 0
|
|
|
|
by_crop = {}
|
|
for plan in plans:
|
|
crop_name = plan.crop.name
|
|
if crop_name not in by_crop:
|
|
by_crop[crop_name] = {
|
|
'crop': crop_name,
|
|
'count': 0,
|
|
'area': 0
|
|
}
|
|
by_crop[crop_name]['count'] += 1
|
|
by_crop[crop_name]['area'] += float(plan.field.area_tan)
|
|
|
|
total_fields = Field.objects.count()
|
|
assigned_field_ids = plans.values_list('field_id', flat=True).distinct()
|
|
assigned_count = assigned_field_ids.count()
|
|
unassigned_count = total_fields - assigned_count
|
|
|
|
return Response({
|
|
'year': int(year),
|
|
'total_fields': total_fields,
|
|
'assigned_fields': assigned_count,
|
|
'unassigned_fields': unassigned_count,
|
|
'total_plans': plans.count(),
|
|
'total_area': float(total_area),
|
|
'by_crop': list(by_crop.values())
|
|
})
|
|
|
|
@action(detail=False, methods=['post'])
|
|
def copy_from_previous_year(self, request):
|
|
from_year = request.data.get('from_year')
|
|
to_year = request.data.get('to_year')
|
|
|
|
if not from_year or not to_year:
|
|
return Response({'error': 'from_year and to_year are required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
previous_plans = Plan.objects.filter(year=from_year)
|
|
new_plans = []
|
|
|
|
for plan in previous_plans:
|
|
new_plans.append(Plan(
|
|
field=plan.field,
|
|
year=to_year,
|
|
crop=plan.crop,
|
|
variety=plan.variety,
|
|
notes=plan.notes
|
|
))
|
|
|
|
Plan.objects.bulk_create(new_plans, ignore_conflicts=True)
|
|
|
|
return Response({'message': f'Copied {len(new_plans)} plans from {from_year} to {to_year}'})
|
|
|
|
@action(detail=False, methods=['post'])
|
|
def bulk_update(self, request):
|
|
"""複数圃場の作付け計画を一括更新"""
|
|
field_ids = request.data.get('field_ids', [])
|
|
year = request.data.get('year')
|
|
crop_id = request.data.get('crop')
|
|
variety_id = request.data.get('variety')
|
|
|
|
if not field_ids or not year or not crop_id:
|
|
return Response({'error': 'field_ids, year, crop are required'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
try:
|
|
crop = Crop.objects.get(id=crop_id)
|
|
except Crop.DoesNotExist:
|
|
return Response({'error': 'Crop not found'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
variety = None
|
|
if variety_id:
|
|
try:
|
|
variety = Variety.objects.get(id=variety_id)
|
|
except Variety.DoesNotExist:
|
|
pass
|
|
|
|
updated = 0
|
|
created = 0
|
|
for field_id in field_ids:
|
|
plan, was_created = Plan.objects.update_or_create(
|
|
field_id=field_id,
|
|
year=year,
|
|
defaults={'crop': crop, 'variety': variety}
|
|
)
|
|
if was_created:
|
|
created += 1
|
|
else:
|
|
updated += 1
|
|
|
|
return Response({'created': created, 'updated': updated, 'total': created + updated})
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def get_crops_with_varieties(self, request):
|
|
crops = Crop.objects.prefetch_related('varieties').all()
|
|
return Response(CropSerializer(crops, many=True).data)
|
|
|
|
|
|
class RiceTransplantPlanViewSet(viewsets.ModelViewSet):
|
|
queryset = RiceTransplantPlan.objects.select_related(
|
|
'variety',
|
|
'variety__crop',
|
|
).prefetch_related('entries', 'entries__field')
|
|
|
|
def get_queryset(self):
|
|
queryset = self.queryset
|
|
year = self.request.query_params.get('year')
|
|
if year:
|
|
queryset = queryset.filter(year=year)
|
|
return queryset
|
|
|
|
def get_serializer_class(self):
|
|
if self.action in ['create', 'update', 'partial_update']:
|
|
return RiceTransplantPlanWriteSerializer
|
|
return RiceTransplantPlanSerializer
|
|
|
|
@action(detail=False, methods=['get'])
|
|
def candidate_fields(self, request):
|
|
year = request.query_params.get('year')
|
|
variety_id = request.query_params.get('variety_id')
|
|
if not year or not variety_id:
|
|
return Response(
|
|
{'error': 'year と variety_id が必要です'},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
field_ids = Plan.objects.filter(
|
|
year=year,
|
|
variety_id=variety_id,
|
|
).values_list('field_id', flat=True)
|
|
fields = Field.objects.filter(id__in=field_ids).order_by('display_order', 'id')
|
|
data = [
|
|
{
|
|
'id': field.id,
|
|
'name': field.name,
|
|
'area_tan': str(field.area_tan),
|
|
'area_m2': field.area_m2,
|
|
'group_name': field.group_name,
|
|
}
|
|
for field in fields
|
|
]
|
|
return Response(data)
|