157 lines
5.8 KiB
Python
157 lines
5.8 KiB
Python
from decimal import Decimal
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import TestCase
|
|
from rest_framework.test import APIClient
|
|
|
|
from apps.fields.models import Field
|
|
from apps.materials.models import Material, StockTransaction
|
|
from apps.materials.stock_service import create_reserves_for_plan
|
|
from apps.plans.models import Crop, Variety
|
|
|
|
from .models import FertilizationEntry, FertilizationPlan, Fertilizer
|
|
|
|
|
|
class FertilizationPlanMergeTests(TestCase):
|
|
def setUp(self):
|
|
self.client = APIClient()
|
|
self.user = get_user_model().objects.create_user(
|
|
username='merge-user',
|
|
password='secret12345',
|
|
)
|
|
self.client.force_authenticate(user=self.user)
|
|
|
|
crop = Crop.objects.create(name='水稲')
|
|
self.variety = Variety.objects.create(crop=crop, name='たちはるか特栽')
|
|
self.field_a = Field.objects.create(
|
|
name='足川北上',
|
|
address='高知県高岡郡',
|
|
area_tan='1.2000',
|
|
area_m2=1200,
|
|
owner_name='吉田',
|
|
group_name='北',
|
|
display_order=1,
|
|
)
|
|
self.field_b = Field.objects.create(
|
|
name='足川南',
|
|
address='高知県高岡郡',
|
|
area_tan='0.8000',
|
|
area_m2=800,
|
|
owner_name='吉田',
|
|
group_name='南',
|
|
display_order=2,
|
|
)
|
|
material_a = Material.objects.create(
|
|
name='高度化成14号',
|
|
material_type=Material.MaterialType.FERTILIZER,
|
|
)
|
|
material_b = Material.objects.create(
|
|
name='分げつ一発',
|
|
material_type=Material.MaterialType.FERTILIZER,
|
|
)
|
|
self.fertilizer_a = Fertilizer.objects.create(name='高度化成14号', material=material_a)
|
|
self.fertilizer_b = Fertilizer.objects.create(name='分げつ一発', material=material_b)
|
|
|
|
def test_merge_into_moves_entries_and_deletes_empty_source_plan(self):
|
|
target_plan = FertilizationPlan.objects.create(
|
|
name='2026年度 たちはるか特栽 元肥',
|
|
year=2026,
|
|
variety=self.variety,
|
|
calc_settings=[{'fertilizer_id': self.fertilizer_a.id, 'method': 'per_tan', 'param': '1.2'}],
|
|
)
|
|
source_plan = FertilizationPlan.objects.create(
|
|
name='2026年度 たちはるか特栽 施肥計画(品種変更移動)',
|
|
year=2026,
|
|
variety=self.variety,
|
|
calc_settings=[{'fertilizer_id': self.fertilizer_b.id, 'method': 'per_tan', 'param': '0.8'}],
|
|
)
|
|
target_entry = FertilizationEntry.objects.create(
|
|
plan=target_plan,
|
|
field=self.field_a,
|
|
fertilizer=self.fertilizer_a,
|
|
bags='3.00',
|
|
actual_bags='1.0000',
|
|
)
|
|
source_entry = FertilizationEntry.objects.create(
|
|
plan=source_plan,
|
|
field=self.field_b,
|
|
fertilizer=self.fertilizer_b,
|
|
bags='2.00',
|
|
actual_bags='2.0000',
|
|
)
|
|
create_reserves_for_plan(target_plan)
|
|
create_reserves_for_plan(source_plan)
|
|
|
|
response = self.client.post(
|
|
f'/api/fertilizer/plans/{source_plan.id}/merge_into/',
|
|
{'target_plan_id': target_plan.id},
|
|
format='json',
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.data['moved_entry_count'], 1)
|
|
self.assertTrue(response.data['deleted_source_plan'])
|
|
|
|
source_entry.refresh_from_db()
|
|
self.assertEqual(source_entry.plan_id, target_plan.id)
|
|
self.assertFalse(FertilizationPlan.objects.filter(id=source_plan.id).exists())
|
|
|
|
target_plan.refresh_from_db()
|
|
self.assertEqual(
|
|
target_plan.calc_settings,
|
|
[
|
|
{'fertilizer_id': self.fertilizer_a.id, 'method': 'per_tan', 'param': '1.2'},
|
|
{'fertilizer_id': self.fertilizer_b.id, 'method': 'per_tan', 'param': '0.8'},
|
|
],
|
|
)
|
|
reserves = list(
|
|
StockTransaction.objects.filter(
|
|
fertilization_plan=target_plan,
|
|
transaction_type=StockTransaction.TransactionType.RESERVE,
|
|
).order_by('material__name')
|
|
)
|
|
self.assertEqual(len(reserves), 2)
|
|
self.assertEqual(
|
|
{(reserve.material_id, reserve.quantity) for reserve in reserves},
|
|
{
|
|
(self.fertilizer_a.material_id, Decimal(str(target_entry.bags))),
|
|
(self.fertilizer_b.material_id, Decimal(str(source_entry.bags))),
|
|
},
|
|
)
|
|
|
|
def test_merge_into_stops_on_field_fertilizer_conflict(self):
|
|
target_plan = FertilizationPlan.objects.create(
|
|
name='2026年度 たちはるか特栽 元肥',
|
|
year=2026,
|
|
variety=self.variety,
|
|
)
|
|
source_plan = FertilizationPlan.objects.create(
|
|
name='2026年度 たちはるか特栽 施肥計画(品種変更移動)',
|
|
year=2026,
|
|
variety=self.variety,
|
|
)
|
|
FertilizationEntry.objects.create(
|
|
plan=target_plan,
|
|
field=self.field_a,
|
|
fertilizer=self.fertilizer_a,
|
|
bags='3.00',
|
|
)
|
|
source_entry = FertilizationEntry.objects.create(
|
|
plan=source_plan,
|
|
field=self.field_a,
|
|
fertilizer=self.fertilizer_a,
|
|
bags='2.00',
|
|
)
|
|
|
|
response = self.client.post(
|
|
f'/api/fertilizer/plans/{source_plan.id}/merge_into/',
|
|
{'target_plan_id': target_plan.id},
|
|
format='json',
|
|
)
|
|
|
|
self.assertEqual(response.status_code, 409)
|
|
self.assertEqual(len(response.data['conflicts']), 1)
|
|
source_entry.refresh_from_db()
|
|
self.assertEqual(source_entry.plan_id, source_plan.id)
|
|
self.assertTrue(FertilizationPlan.objects.filter(id=source_plan.id).exists())
|