from typing import List, Optional from datetime import date, timedelta from sqlalchemy.ext.asyncio import AsyncSession from app.models.batch import Batch from app.schemas.batch import BatchCreate, BatchUpdate from app.repositories.batch import BatchRepository from app.services.audit import AuditService class BatchService: def __init__(self, db: AsyncSession): self.db = db self.repo = BatchRepository(db) self.audit_service = AuditService(db) async def get_batches_by_medicine(self, medicine_id: int) -> List[Batch]: return await self.repo.get_by_medicine_id(medicine_id) async def get_batch(self, batch_id: int) -> Optional[Batch]: return await self.repo.get_by_id(batch_id) async def create_batch(self, medicine_id: int, data: BatchCreate) -> Batch: batch_data = data.model_dump() batch_data['medicine_id'] = medicine_id return await self.repo.create(batch_data) async def update_batch(self, batch_id: int, data: BatchUpdate) -> Optional[Batch]: update_data = data.model_dump(exclude_unset=True) return await self.repo.update(batch_id, update_data) async def delete_batch(self, batch_id: int) -> bool: return await self.repo.delete(batch_id) async def dispense(self, batch_id: int, quantity: int, user_id: int) -> Optional[Batch]: batch = await self.repo.get_by_id(batch_id) if not batch: raise ValueError("批次不存在") if batch.quantity < quantity: raise ValueError("库存不足") await self.audit_service.log_action( medicine_id=batch.medicine_id, batch_id=batch_id, user_id=user_id, action="dispense", quantity_change=-quantity, quantity_after=batch.quantity - quantity ) batch.quantity -= quantity await self.db.commit() return batch async def add_stock(self, batch_id: int, quantity: int, user_id: int) -> Optional[Batch]: batch = await self.repo.get_by_id(batch_id) if not batch: raise ValueError("批次不存在") await self.audit_service.log_action( medicine_id=batch.medicine_id, batch_id=batch_id, user_id=user_id, action="add_stock", quantity_change=quantity, quantity_after=batch.quantity + quantity ) batch.quantity += quantity await self.db.commit() return batch async def check_expiring_batches(self, warning_days: List[int]) -> List[dict]: expiring = [] today = date.today() for days in warning_days: target_date = today + timedelta(days=days) batches = await self.repo.get_expiring_before(target_date) for batch in batches: expiring.append({ 'batch': batch, 'days_until_expiry': days }) return expiring