Files
Fulfillment-Backend/services/residues.py
2025-01-14 21:35:39 +04:00

193 lines
9.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import HTTPException
from sqlalchemy import select
from sqlalchemy.orm import selectinload, joinedload
from starlette import status
from models import ResidualPallet, ResidualBox, ResidualProduct, Client, Product
from schemas.residues import *
from services.base import BaseService
class ResiduesService(BaseService):
async def _get_pallet_by_id(self, pallet_id: int) -> Optional[ResidualPallet]:
stmt = (
select(ResidualPallet)
.options(
selectinload(ResidualPallet.boxes)
.selectinload(ResidualBox.residual_products)
.selectinload(ResidualProduct.product)
.noload(Product.barcodes),
joinedload(ResidualPallet.client),
selectinload(ResidualPallet.residual_products)
.selectinload(ResidualProduct.product)
.noload(Product.barcodes),
)
.where(ResidualPallet.id == pallet_id)
)
pallet = (await self.session.execute(stmt)).one_or_none()
return pallet[0] if pallet else None
async def get_pallet(self, pallet_id: int) -> GetResidualPalletResponse:
pallet = await self._get_pallet_by_id(pallet_id)
if not pallet:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f'Паллет с ID:{pallet_id} не найден')
return GetResidualPalletResponse(pallet=pallet, client_id=pallet.client_id)
async def create_pallet(self, request: CreateResidualPalletRequest) -> CreateResidualPalletResponse:
client = await self.session.get(Client, request.client_id)
if not client:
return CreateResidualPalletResponse(ok=False, message=f'Клиент с ID:{request.client_id} не найден')
pallet = ResidualPallet(client_id=request.client_id, created_at=datetime.now())
self.session.add(pallet)
await self.session.commit()
return CreateResidualPalletResponse(ok=True, message='Паллет успешно создан')
async def delete_pallet(self, pallet_id: int) -> DeleteResidualPalletResponse:
pallet = await self.session.get(ResidualPallet, pallet_id)
if not pallet:
return DeleteResidualPalletResponse(ok=False, message='Паллет не найден')
await self.session.delete(pallet)
await self.session.commit()
return DeleteResidualPalletResponse(ok=True, message='Паллет успешно удален')
async def _get_box_by_id(self, box_id: int) -> Optional[ResidualBox]:
stmt = (
select(ResidualBox)
.options(
selectinload(ResidualBox.pallet)
.noload(ResidualPallet.boxes),
selectinload(ResidualBox.pallet)
.joinedload(ResidualPallet.client),
selectinload(ResidualBox.residual_products)
.selectinload(ResidualProduct.product)
.noload(Product.barcodes),
)
.where(ResidualBox.id == box_id)
)
box = (await self.session.execute(stmt)).one_or_none()
return box[0] if box else None
async def get_box(self, box_id: int) -> GetResidualBoxResponse:
box = await self._get_box_by_id(box_id)
if not box:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f'Короб с ID:{box_id} не найден')
if box.client_id:
client_id = box.client_id
else:
pallet = await self._get_pallet_by_id(box.pallet_id)
client_id = pallet.client_id
return GetResidualBoxResponse(box=box, client_id=client_id)
async def create_box(self, request: CreateResidualBoxRequest) -> CreateResidualBoxResponse:
if request.client_id:
client = await self.session.get(Client, request.client_id)
if not client:
return CreateResidualBoxResponse(ok=False, message=f'Клиент с ID:{request.client_id} не найден')
else:
pallet = await self.session.get(ResidualPallet, request.pallet_id)
if not pallet:
return CreateResidualBoxResponse(ok=False, message=f'Паллет с ID:{request.pallet_id} не найден')
box = ResidualBox(created_at=datetime.now(), **request.model_dump())
self.session.add(box)
await self.session.commit()
return CreateResidualBoxResponse(ok=True, message='Короб успешно создан')
async def delete_box(self, box_id: int) -> DeleteResidualBoxResponse:
box = await self.session.get(ResidualBox, box_id)
if not box:
return DeleteResidualBoxResponse(ok=False, message=f'Короб с ID:{box_id} не найден')
await self.session.delete(box)
await self.session.commit()
return DeleteResidualBoxResponse(ok=True, message='Короб успешно удален')
async def _create_residual_product(
self,
obj: ResidualBox | ResidualPallet,
request: CreateResidualProductRequest,
) -> tuple[bool, str]:
try:
existing_residual = next(p for p in obj.residual_products if p.product_id == request.data.product_id)
existing_residual.quantity += request.data.quantity
self.session.add(existing_residual)
except StopIteration:
residual_product = ResidualProduct(**request.data.model_dump())
self.session.add(residual_product)
await self.session.commit()
return True, "Товар успешно добавлен"
async def create_residual_product(self, request: CreateResidualProductRequest) -> CreateResidualProductResponse:
if request.data.box_id:
obj = await self._get_box_by_id(request.data.box_id)
if not obj:
return CreateResidualProductResponse(ok=False, message=f'Короб с ID:{request.data.box_id} не найден')
else:
obj = await self.session.get(ResidualPallet, request.data.pallet_id)
if not obj:
return CreateResidualProductResponse(
ok=False, message=f'Паллет с ID:{request.data.pallet_id} не найден',
)
ok, message = await self._create_residual_product(obj, request)
return CreateResidualProductResponse(ok=ok, message=message)
async def update_residual_product(
self,
request: UpdateResidualProductRequest,
residual_product_id: int
) -> UpdateResidualProductResponse:
residual_product = await self.session.get(ResidualProduct, residual_product_id)
residual_product.product_id = request.data.product_id
residual_product.quantity = request.data.quantity
await self.session.commit()
return UpdateResidualProductResponse(ok=True, message='Запись о товаре на паллете успешно изменена')
async def delete_residual_product(self, residual_product_id: int) -> DeleteResidualProductResponse:
residual_product = await self.session.get(ResidualProduct, residual_product_id)
if not residual_product:
return DeleteResidualProductResponse(ok=False, message=f'Запись для данного паллета и товара не найдена')
await self.session.delete(residual_product)
await self.session.commit()
return DeleteResidualProductResponse(ok=True, message='Запись о товаре на паллете успешно удалена')
async def load_receipt(self, request: LoadReceiptRequest) -> LoadReceiptResponse:
if not await self.session.get(Client, request.client_id):
return LoadReceiptResponse(ok=False, message=f'Клиент с ID {request.client_id}')
await self._load_receipt_boxes(request.boxes, request.client_id)
await self._load_receipt_pallets(request.pallets, request.client_id)
await self.session.commit()
return LoadReceiptResponse(ok=True, message='Приемка успешно завершена')
async def _load_receipt_boxes(self, boxes: list[ReceiptBoxSchema], client_id: int = None, pallet_id: int = None):
for receipt_box in boxes:
box = ResidualBox(client_id=client_id, pallet_id=pallet_id, created_at=datetime.now())
self.session.add(box)
await self.session.flush()
await self._load_receipt_products(receipt_box.products, box_id=box.id)
async def _load_receipt_pallets(self, pallets: list[ReceiptPalletSchema], client_id: int):
for receipt_pallet in pallets:
pallet = ResidualPallet(client_id=client_id, created_at=datetime.now())
self.session.add(pallet)
await self.session.flush()
await self._load_receipt_boxes(receipt_pallet.boxes, pallet.id)
await self._load_receipt_products(receipt_pallet.products, pallet_id=pallet.id)
async def _load_receipt_products(
self,
products: list[ReceiptPalletSchema],
box_id: int = None,
pallet_id: int = None,
):
for receipt_product in products:
product = ResidualProduct(box_id=box_id, pallet_id=pallet_id, **receipt_product.model_dump())
self.session.add(product)