Move rice transplant entries on variety change
This commit is contained in:
@@ -17,7 +17,7 @@ class Migration(migrations.Migration):
|
||||
('year', models.IntegerField(verbose_name='作付年度')),
|
||||
('changed_at', models.DateTimeField(auto_now_add=True, verbose_name='変更日時')),
|
||||
('reason', models.TextField(blank=True, default='', verbose_name='変更理由')),
|
||||
('moved_entry_count', models.IntegerField(default=0, verbose_name='移動エントリ数')),
|
||||
('fertilizer_moved_entry_count', models.IntegerField(default=0, verbose_name='施肥移動エントリ数')),
|
||||
('field', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='plan_variety_changes', to='fields.field', verbose_name='圃場')),
|
||||
('new_variety', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='new_plan_variety_changes', to='plans.variety', verbose_name='変更後品種')),
|
||||
('old_variety', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='old_plan_variety_changes', to='plans.variety', verbose_name='変更前品種')),
|
||||
|
||||
@@ -97,7 +97,7 @@ class PlanVarietyChange(models.Model):
|
||||
blank=True,
|
||||
)
|
||||
reason = models.TextField(blank=True, default='', verbose_name='変更理由')
|
||||
moved_entry_count = models.IntegerField(default=0, verbose_name='移動エントリ数')
|
||||
fertilizer_moved_entry_count = models.IntegerField(default=0, verbose_name='施肥移動エントリ数')
|
||||
|
||||
class Meta:
|
||||
verbose_name = '作付け計画品種変更履歴'
|
||||
|
||||
@@ -60,11 +60,13 @@ def handle_plan_variety_change(plan: Plan, *, old_variety, new_variety, reason:
|
||||
|
||||
def process_plan_variety_change(change: PlanVarietyChange):
|
||||
from apps.fertilizer.services import move_unspread_entries_for_variety_change
|
||||
from .services_rice_transplant import move_rice_transplant_entries_for_variety_change
|
||||
|
||||
moved_count = move_unspread_entries_for_variety_change(change)
|
||||
if moved_count != change.moved_entry_count:
|
||||
change.moved_entry_count = moved_count
|
||||
change.save(update_fields=['moved_entry_count'])
|
||||
move_rice_transplant_entries_for_variety_change(change)
|
||||
if moved_count != change.fertilizer_moved_entry_count:
|
||||
change.fertilizer_moved_entry_count = moved_count
|
||||
change.save(update_fields=['fertilizer_moved_entry_count'])
|
||||
return change
|
||||
|
||||
|
||||
|
||||
46
backend/apps/plans/services_rice_transplant.py
Normal file
46
backend/apps/plans/services_rice_transplant.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from django.db import transaction
|
||||
|
||||
from .models import RiceTransplantEntry, RiceTransplantPlan
|
||||
|
||||
|
||||
@transaction.atomic
|
||||
def move_rice_transplant_entries_for_variety_change(change):
|
||||
old_variety_id = change.old_variety_id
|
||||
new_variety = change.new_variety
|
||||
if old_variety_id is None or new_variety is None:
|
||||
return 0
|
||||
|
||||
old_plans = (
|
||||
RiceTransplantPlan.objects
|
||||
.filter(
|
||||
year=change.year,
|
||||
variety_id=old_variety_id,
|
||||
entries__field_id=change.field_id,
|
||||
)
|
||||
.distinct()
|
||||
.prefetch_related('entries')
|
||||
)
|
||||
|
||||
moved_count = 0
|
||||
for old_plan in old_plans:
|
||||
entries_to_move = list(
|
||||
old_plan.entries.filter(field_id=change.field_id).order_by('id')
|
||||
)
|
||||
if not entries_to_move:
|
||||
continue
|
||||
|
||||
new_plan = RiceTransplantPlan.objects.create(
|
||||
name=f'{change.year}年度 {new_variety.name} 田植え計画(品種変更移動)',
|
||||
year=change.year,
|
||||
variety=new_variety,
|
||||
default_seed_grams_per_box=old_plan.default_seed_grams_per_box,
|
||||
seedling_boxes_per_tan=old_plan.seedling_boxes_per_tan,
|
||||
notes=old_plan.notes,
|
||||
)
|
||||
|
||||
RiceTransplantEntry.objects.filter(
|
||||
id__in=[entry.id for entry in entries_to_move]
|
||||
).update(plan=new_plan)
|
||||
moved_count += len(entries_to_move)
|
||||
|
||||
return moved_count
|
||||
@@ -1,12 +1,20 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
from rest_framework.test import APIRequestFactory, force_authenticate
|
||||
from decimal import Decimal
|
||||
|
||||
from apps.fertilizer.models import FertilizationEntry, FertilizationPlan, Fertilizer
|
||||
from apps.fields.models import Field
|
||||
from apps.materials.models import Material, StockTransaction
|
||||
from apps.materials.stock_service import create_reserves_for_plan
|
||||
from .models import Crop, Plan, PlanVarietyChange, Variety
|
||||
from .models import (
|
||||
Crop,
|
||||
Plan,
|
||||
PlanVarietyChange,
|
||||
RiceTransplantEntry,
|
||||
RiceTransplantPlan,
|
||||
Variety,
|
||||
)
|
||||
from .serializers import PlanSerializer
|
||||
from .views import PlanViewSet
|
||||
|
||||
@@ -64,7 +72,7 @@ class PlanVarietyChangeTests(TestCase):
|
||||
self.assertEqual(change.year, 2026)
|
||||
self.assertEqual(change.old_variety_id, self.old_variety.id)
|
||||
self.assertEqual(change.new_variety_id, self.new_variety.id)
|
||||
self.assertEqual(change.moved_entry_count, 0)
|
||||
self.assertEqual(change.fertilizer_moved_entry_count, 0)
|
||||
|
||||
def test_serializer_update_does_not_create_history_without_variety_change(self):
|
||||
serializer = PlanSerializer(
|
||||
@@ -158,7 +166,7 @@ class PlanVarietyChangeTests(TestCase):
|
||||
serializer.save()
|
||||
|
||||
change = PlanVarietyChange.objects.get(plan=self.plan)
|
||||
self.assertEqual(change.moved_entry_count, 1)
|
||||
self.assertEqual(change.fertilizer_moved_entry_count, 1)
|
||||
|
||||
old_fertilization_plan.refresh_from_db()
|
||||
new_plan = FertilizationPlan.objects.exclude(id=old_fertilization_plan.id).get(
|
||||
@@ -201,3 +209,50 @@ class PlanVarietyChangeTests(TestCase):
|
||||
},
|
||||
)
|
||||
self.assertEqual(new_reserves[0].quantity, unspread_entry.bags)
|
||||
|
||||
def test_serializer_update_moves_rice_transplant_entries_for_target_field(self):
|
||||
old_rice_plan = RiceTransplantPlan.objects.create(
|
||||
name='2026年度 にこまる 田植え計画',
|
||||
year=2026,
|
||||
variety=self.old_variety,
|
||||
default_seed_grams_per_box='200.00',
|
||||
seedling_boxes_per_tan='12.00',
|
||||
notes='旧計画メモ',
|
||||
)
|
||||
target_entry = RiceTransplantEntry.objects.create(
|
||||
plan=old_rice_plan,
|
||||
field=self.field,
|
||||
installed_seedling_boxes='14.40',
|
||||
seed_grams_per_box='200.00',
|
||||
)
|
||||
other_entry = RiceTransplantEntry.objects.create(
|
||||
plan=old_rice_plan,
|
||||
field=self.other_field,
|
||||
installed_seedling_boxes='9.60',
|
||||
seed_grams_per_box='200.00',
|
||||
)
|
||||
|
||||
serializer = PlanSerializer(
|
||||
instance=self.plan,
|
||||
data={'variety': self.new_variety.id},
|
||||
partial=True,
|
||||
)
|
||||
self.assertTrue(serializer.is_valid(), serializer.errors)
|
||||
serializer.save()
|
||||
|
||||
target_entry.refresh_from_db()
|
||||
other_entry.refresh_from_db()
|
||||
|
||||
new_rice_plan = RiceTransplantPlan.objects.exclude(id=old_rice_plan.id).get(
|
||||
year=2026,
|
||||
variety=self.new_variety,
|
||||
)
|
||||
self.assertEqual(
|
||||
new_rice_plan.name,
|
||||
f'2026年度 {self.new_variety.name} 田植え計画(品種変更移動)',
|
||||
)
|
||||
self.assertEqual(new_rice_plan.default_seed_grams_per_box, Decimal('200.00'))
|
||||
self.assertEqual(new_rice_plan.seedling_boxes_per_tan, Decimal('12.00'))
|
||||
self.assertEqual(new_rice_plan.notes, old_rice_plan.notes)
|
||||
self.assertEqual(target_entry.plan_id, new_rice_plan.id)
|
||||
self.assertEqual(other_entry.plan_id, old_rice_plan.id)
|
||||
|
||||
Reference in New Issue
Block a user