Files
keinasystem/backend/apps/materials/stock_service.py

98 lines
3.0 KiB
Python

from decimal import Decimal, InvalidOperation
from django.db import transaction
from django.utils import timezone
from .models import StockTransaction
@transaction.atomic
def create_reserves_for_plan(plan):
"""施肥計画の引当を全置換で作り直す。"""
StockTransaction.objects.filter(
fertilization_plan=plan,
transaction_type=StockTransaction.TransactionType.RESERVE,
).delete()
occurred_on = (
plan.updated_at.date() if getattr(plan, 'updated_at', None) else timezone.localdate()
)
for entry in plan.entries.select_related('fertilizer__material'):
material = getattr(entry.fertilizer, 'material', None)
if material is None:
continue
StockTransaction.objects.create(
material=material,
transaction_type=StockTransaction.TransactionType.RESERVE,
quantity=entry.bags,
occurred_on=occurred_on,
note=f'施肥計画「{plan.name}」からの引当',
fertilization_plan=plan,
)
@transaction.atomic
def delete_reserves_for_plan(plan):
"""施肥計画に紐づく引当のみ削除する。"""
StockTransaction.objects.filter(
fertilization_plan=plan,
transaction_type=StockTransaction.TransactionType.RESERVE,
).delete()
@transaction.atomic
def confirm_spreading(plan, actual_entries):
"""引当を使用実績へ変換して施肥計画を確定済みにする。"""
from apps.fertilizer.models import Fertilizer
delete_reserves_for_plan(plan)
for entry_data in actual_entries:
actual_bags = _to_decimal(entry_data.get('actual_bags'))
if actual_bags <= 0:
continue
fertilizer = (
Fertilizer.objects.select_related('material')
.filter(id=entry_data['fertilizer_id'])
.first()
)
if fertilizer is None or fertilizer.material is None:
continue
StockTransaction.objects.create(
material=fertilizer.material,
transaction_type=StockTransaction.TransactionType.USE,
quantity=actual_bags,
occurred_on=timezone.localdate(),
note=f'施肥計画「{plan.name}」散布確定',
fertilization_plan=plan,
)
plan.is_confirmed = True
plan.confirmed_at = timezone.now()
plan.save(update_fields=['is_confirmed', 'confirmed_at'])
@transaction.atomic
def unconfirm_spreading(plan):
"""散布確定を取り消し、USE トランザクションを削除して引当を再作成する。"""
StockTransaction.objects.filter(
fertilization_plan=plan,
transaction_type=StockTransaction.TransactionType.USE,
).delete()
plan.is_confirmed = False
plan.confirmed_at = None
plan.save(update_fields=['is_confirmed', 'confirmed_at'])
create_reserves_for_plan(plan)
def _to_decimal(value):
try:
return Decimal(str(value))
except (InvalidOperation, TypeError, ValueError):
return Decimal('0')