Add fertilization plan merge workflow
This commit is contained in:
@@ -31,7 +31,12 @@ from .serializers import (
|
||||
SpreadingSessionSerializer,
|
||||
SpreadingSessionWriteSerializer,
|
||||
)
|
||||
from .services import sync_actual_bags_for_pairs
|
||||
from .services import (
|
||||
FertilizationPlanMergeConflict,
|
||||
FertilizationPlanMergeError,
|
||||
merge_fertilization_plan_into,
|
||||
sync_actual_bags_for_pairs,
|
||||
)
|
||||
|
||||
|
||||
class FertilizerViewSet(viewsets.ModelViewSet):
|
||||
@@ -123,6 +128,55 @@ class FertilizationPlanViewSet(viewsets.ModelViewSet):
|
||||
response['Content-Disposition'] = f'attachment; filename="fertilization_{plan.year}_{plan.id}.pdf"'
|
||||
return response
|
||||
|
||||
@action(detail=True, methods=['get'])
|
||||
def merge_targets(self, request, pk=None):
|
||||
source_plan = self.get_object()
|
||||
targets = (
|
||||
FertilizationPlan.objects
|
||||
.filter(year=source_plan.year, variety_id=source_plan.variety_id)
|
||||
.exclude(id=source_plan.id)
|
||||
.prefetch_related('entries')
|
||||
.order_by('-updated_at', 'id')
|
||||
)
|
||||
data = [
|
||||
{
|
||||
'id': plan.id,
|
||||
'name': plan.name,
|
||||
'field_count': plan.entries.values('field').distinct().count(),
|
||||
'planned_total_bags': str(sum((entry.bags or Decimal('0')) for entry in plan.entries.all())),
|
||||
'is_confirmed': plan.is_confirmed,
|
||||
}
|
||||
for plan in targets
|
||||
]
|
||||
return Response(data)
|
||||
|
||||
@action(detail=True, methods=['post'])
|
||||
def merge_into(self, request, pk=None):
|
||||
source_plan = self.get_object()
|
||||
target_plan_id = request.data.get('target_plan_id')
|
||||
if not target_plan_id:
|
||||
return Response({'error': 'target_plan_id が必要です。'}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
try:
|
||||
target_plan = FertilizationPlan.objects.get(id=target_plan_id)
|
||||
except FertilizationPlan.DoesNotExist:
|
||||
return Response({'error': 'マージ先の施肥計画が見つかりません。'}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
try:
|
||||
result = merge_fertilization_plan_into(source_plan, target_plan)
|
||||
except FertilizationPlanMergeConflict as exc:
|
||||
return Response(
|
||||
{
|
||||
'error': '競合する圃場・肥料があるためマージできません。',
|
||||
'conflicts': exc.conflicts,
|
||||
},
|
||||
status=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
except FertilizationPlanMergeError as exc:
|
||||
return Response({'error': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return Response(result)
|
||||
|
||||
class CandidateFieldsView(APIView):
|
||||
"""作付け計画から圃場候補を返す"""
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
Reference in New Issue
Block a user