hesabixArc/hesabixAPI/app/services/price_list_service.py

140 lines
5.9 KiB
Python

from __future__ import annotations
from typing import Dict, Any, Optional
from sqlalchemy.orm import Session
from sqlalchemy import and_
from app.core.responses import ApiError
from adapters.db.repositories.price_list_repository import PriceListRepository, PriceItemRepository
from adapters.db.models.price_list import PriceList, PriceItem
from adapters.api.v1.schema_models.price_list import PriceListCreateRequest, PriceListUpdateRequest, PriceItemUpsertRequest
from adapters.db.models.product import Product
def create_price_list(db: Session, business_id: int, payload: PriceListCreateRequest) -> Dict[str, Any]:
repo = PriceListRepository(db)
# یکتایی نام در هر کسب‌وکار
dup = db.query(PriceList).filter(and_(PriceList.business_id == business_id, PriceList.name == payload.name.strip())).first()
if dup:
raise ApiError("DUPLICATE_PRICE_LIST_NAME", "نام لیست قیمت تکراری است", http_status=400)
obj = repo.create(
business_id=business_id,
name=payload.name.strip(),
is_active=payload.is_active,
)
return {"message": "PRICE_LIST_CREATED", "data": _pl_to_dict(obj)}
def list_price_lists(db: Session, business_id: int, query: Dict[str, Any]) -> Dict[str, Any]:
repo = PriceListRepository(db)
take = int(query.get("take", 20) or 20)
skip = int(query.get("skip", 0) or 0)
sort_by = query.get("sort_by")
sort_desc = bool(query.get("sort_desc", True))
search = query.get("search")
return repo.search(business_id=business_id, take=take, skip=skip, sort_by=sort_by, sort_desc=sort_desc, search=search)
def get_price_list(db: Session, business_id: int, id: int) -> Optional[Dict[str, Any]]:
obj = db.get(PriceList, id)
if not obj or obj.business_id != business_id:
return None
return _pl_to_dict(obj)
def update_price_list(db: Session, business_id: int, id: int, payload: PriceListUpdateRequest) -> Optional[Dict[str, Any]]:
repo = PriceListRepository(db)
obj = db.get(PriceList, id)
if not obj or obj.business_id != business_id:
return None
if payload.name is not None and payload.name.strip() and payload.name.strip() != obj.name:
dup = db.query(PriceList).filter(and_(PriceList.business_id == business_id, PriceList.name == payload.name.strip(), PriceList.id != id)).first()
if dup:
raise ApiError("DUPLICATE_PRICE_LIST_NAME", "نام لیست قیمت تکراری است", http_status=400)
updated = repo.update(id, name=payload.name.strip() if isinstance(payload.name, str) else None, is_active=payload.is_active)
if not updated:
return None
return {"message": "PRICE_LIST_UPDATED", "data": _pl_to_dict(updated)}
def delete_price_list(db: Session, business_id: int, id: int) -> bool:
repo = PriceListRepository(db)
obj = db.get(PriceList, id)
if not obj or obj.business_id != business_id:
return False
return repo.delete(id)
def list_price_items(db: Session, business_id: int, price_list_id: int, take: int = 50, skip: int = 0, product_id: int | None = None, currency_id: int | None = None) -> Dict[str, Any]:
# مالکیت را از روی price_list بررسی می‌کنیم
pl = db.get(PriceList, price_list_id)
if not pl or pl.business_id != business_id:
raise ApiError("NOT_FOUND", "لیست قیمت یافت نشد", http_status=404)
repo = PriceItemRepository(db)
return repo.list_for_price_list(price_list_id=price_list_id, take=take, skip=skip, product_id=product_id, currency_id=currency_id)
def upsert_price_item(db: Session, business_id: int, price_list_id: int, payload: PriceItemUpsertRequest) -> Dict[str, Any]:
pl = db.get(PriceList, price_list_id)
if not pl or pl.business_id != business_id:
raise ApiError("NOT_FOUND", "لیست قیمت یافت نشد", http_status=404)
# صحت وجود محصول
pr = db.get(Product, payload.product_id)
if not pr or pr.business_id != business_id:
raise ApiError("NOT_FOUND", "کالا/خدمت یافت نشد", http_status=404)
# اگر unit_id داده شده و با واحدهای محصول سازگار نباشد، خطا بده
if payload.unit_id is not None and payload.unit_id not in [pr.main_unit, pr.secondary_unit]:
raise ApiError("INVALID_UNIT", "واحد انتخابی با واحدهای محصول همخوانی ندارد", http_status=400)
repo = PriceItemRepository(db)
obj = repo.upsert(
price_list_id=price_list_id,
product_id=payload.product_id,
unit_id=payload.unit_id,
currency_id=payload.currency_id,
tier_name=(payload.tier_name.strip() if isinstance(payload.tier_name, str) and payload.tier_name.strip() else 'پیش‌فرض'),
min_qty=payload.min_qty,
price=payload.price,
)
return {"message": "PRICE_ITEM_UPSERTED", "data": _pi_to_dict(obj)}
def delete_price_item(db: Session, business_id: int, id: int) -> bool:
repo = PriceItemRepository(db)
pi = db.get(PriceItem, id)
if not pi:
return False
# بررسی مالکیت از طریق price_list
pl = db.get(PriceList, pi.price_list_id)
if not pl or pl.business_id != business_id:
return False
return repo.delete(id)
def _pl_to_dict(obj: PriceList) -> Dict[str, Any]:
return {
"id": obj.id,
"business_id": obj.business_id,
"name": obj.name,
"is_active": obj.is_active,
"created_at": obj.created_at,
"updated_at": obj.updated_at,
}
def _pi_to_dict(obj: PriceItem) -> Dict[str, Any]:
return {
"id": obj.id,
"price_list_id": obj.price_list_id,
"product_id": obj.product_id,
"unit_id": obj.unit_id,
"currency_id": obj.currency_id,
"tier_name": obj.tier_name,
"min_qty": obj.min_qty,
"price": obj.price,
"created_at": obj.created_at,
"updated_at": obj.updated_at,
}