382 lines
19 KiB
Python
382 lines
19 KiB
Python
import lexorank
|
||
from lexorank import Bucket, middle
|
||
from sqlalchemy import select, update, insert, delete, desc
|
||
from sqlalchemy.orm import joinedload
|
||
|
||
from enums.service import ServiceType
|
||
from models import Service, ServiceCategory, ServicePriceRange, ServicesKit, services_kit_services, \
|
||
ServiceCategoryPrice, ServicePriceCategory
|
||
from schemas.service import *
|
||
from services.base import BaseService
|
||
from utils.list_utils import previous_current_next
|
||
|
||
|
||
class ServiceService(BaseService):
|
||
async def get_all(self) -> ServiceGetAllResponse:
|
||
query = await (
|
||
self.session
|
||
.scalars(select(Service)
|
||
.options(joinedload(Service.category))
|
||
.order_by(Service.rank)
|
||
)
|
||
)
|
||
services = []
|
||
for service in query.all():
|
||
services.append(ServiceSchema.model_validate(service))
|
||
return ServiceGetAllResponse(services=services)
|
||
|
||
async def get_latest_rank_in_category(self, category_id: int, service_type: ServiceType) -> str:
|
||
stmt = (
|
||
select(Service.rank)
|
||
.where(Service.category_id == category_id)
|
||
.where(Service.service_type == service_type)
|
||
.order_by(desc(Service.rank))
|
||
.limit(1)
|
||
)
|
||
return await self.session.scalar(stmt) or ''
|
||
|
||
async def create(self, request: ServiceCreateRequest) -> ServiceCreateResponse:
|
||
try:
|
||
raw_service = request.service
|
||
service_dict = raw_service.model_dump()
|
||
service_dict['category_id'] = raw_service.category.id
|
||
del service_dict['id']
|
||
del service_dict['category']
|
||
del service_dict['price_ranges']
|
||
del service_dict['category_prices']
|
||
service_type = ServiceType(raw_service.service_type)
|
||
category_id = raw_service.category.id
|
||
|
||
latest_rank = await self.get_latest_rank_in_category(category_id, service_type)
|
||
if not latest_rank:
|
||
latest_rank = middle(Bucket.BUCEKT_0)
|
||
else:
|
||
latest_rank = lexorank.parse(latest_rank)
|
||
service_rank = str(latest_rank.next())
|
||
service_dict['rank'] = service_rank
|
||
service = Service(**service_dict)
|
||
self.session.add(service)
|
||
await self.session.flush()
|
||
price_ranges = request.service.price_ranges
|
||
for price_range in price_ranges:
|
||
price_range_dict = price_range.model_dump()
|
||
price_range_dict['service_id'] = service.id
|
||
del price_range_dict['id']
|
||
price_range_obj = ServicePriceRange(**price_range_dict)
|
||
self.session.add(price_range_obj)
|
||
category_prices = request.service.category_prices
|
||
for category_price in category_prices:
|
||
category_price_dict = category_price.model_dump()
|
||
category_price_dict['service_id'] = service.id
|
||
category_price_dict['category_id'] = category_price.category.id
|
||
|
||
del category_price_dict['category']
|
||
category_price_obj = ServiceCategoryPrice(**category_price_dict)
|
||
self.session.add(category_price_obj)
|
||
await self.session.commit()
|
||
return ServiceCreateResponse(ok=True, message="Услуга успешно создана")
|
||
except Exception as e:
|
||
return ServiceCreateResponse(ok=False, message=f"Неудалось создать услугу, ошибка: {e}")
|
||
|
||
async def update(self, request: ServiceUpdateRequest) -> ServiceUpdateResponse:
|
||
try:
|
||
raw_service = request.data
|
||
service = await (self.session.get(Service, raw_service.id))
|
||
if not service:
|
||
return ServiceUpdateResponse(ok=False, message="Услуга не найдена")
|
||
|
||
service_dict = raw_service.dict()
|
||
service_dict['category_id'] = raw_service.category.id
|
||
del service_dict['category']
|
||
del service_dict['price_ranges']
|
||
del service_dict['category_prices']
|
||
await self.session.execute(
|
||
update(Service)
|
||
.where(Service.id == raw_service.id)
|
||
.values(**service_dict)
|
||
)
|
||
# checking if old price ranges are still in the request
|
||
request_price_range_ids = [price_range.id for price_range in raw_service.price_ranges if price_range.id]
|
||
price_ranges_to_delete = []
|
||
for price_range in service.price_ranges:
|
||
if price_range.id not in request_price_range_ids:
|
||
price_ranges_to_delete.append(price_range)
|
||
for price_range in price_ranges_to_delete:
|
||
await self.session.delete(price_range)
|
||
await self.session.flush()
|
||
for price_range in raw_service.price_ranges:
|
||
price_range_dict = price_range.dict()
|
||
price_range_dict['service_id'] = raw_service.id
|
||
if price_range.id:
|
||
await self.session.execute(
|
||
update(ServicePriceRange)
|
||
.where(ServicePriceRange.id == price_range.id)
|
||
.values(**price_range_dict)
|
||
)
|
||
else:
|
||
del price_range_dict['id']
|
||
price_range_obj = ServicePriceRange(**price_range_dict)
|
||
self.session.add(price_range_obj)
|
||
|
||
# deleting previouse category prices
|
||
stmt = (
|
||
delete(
|
||
ServiceCategoryPrice
|
||
).where(
|
||
ServiceCategoryPrice.service_id == service.id
|
||
)
|
||
)
|
||
await self.session.execute(stmt)
|
||
await self.session.flush()
|
||
# inserting new category prices
|
||
for category_price in raw_service.category_prices:
|
||
category_price_dict = category_price.dict()
|
||
category_price_dict['service_id'] = raw_service.id
|
||
category_price_dict['category_id'] = category_price.category.id
|
||
del category_price_dict['category']
|
||
category_price_obj = ServiceCategoryPrice(**category_price_dict)
|
||
self.session.add(category_price_obj)
|
||
|
||
await self.session.commit()
|
||
return ServiceUpdateResponse(ok=True, message="Услуга успешно обновлена")
|
||
except Exception as e:
|
||
return ServiceUpdateResponse(ok=False, message=f"Неудалось обновить услугу, ошибка: {e}")
|
||
|
||
async def delete(self, request: ServiceDeleteRequest) -> ServiceDeleteResponse:
|
||
try:
|
||
service = await (self.session
|
||
.scalar(select(Service)
|
||
.filter(Service.id == request.service_id)))
|
||
if not service:
|
||
return ServiceDeleteResponse(ok=False, message="Услуга не найдена")
|
||
await self.session.delete(service)
|
||
await self.session.commit()
|
||
return ServiceDeleteResponse(ok=True, message="Услуга успешно удалена")
|
||
except Exception as e:
|
||
return ServiceDeleteResponse(ok=False, message=f"Неудалось удалить услугу, ошибка: {e}")
|
||
|
||
async def create_category(self, request: ServiceCreateCategoryRequest) -> ServiceCreateCategoryResponse:
|
||
try:
|
||
raw_category = request.category
|
||
category_dict = raw_category.model_dump()
|
||
del category_dict['id']
|
||
category = ServiceCategory(**category_dict)
|
||
self.session.add(category)
|
||
await self.session.commit()
|
||
return ServiceCreateCategoryResponse(ok=True, message="Категория успешно создана")
|
||
|
||
except Exception as e:
|
||
return ServiceCreateCategoryResponse(ok=False, message=f"Неудалось создать категорию, ошибка: {e}")
|
||
|
||
async def get_all_categories(self) -> ServiceGetAllCategoriesResponse:
|
||
query = await (self.session
|
||
.scalars(select(ServiceCategory)
|
||
.order_by(ServiceCategory.id)))
|
||
categories = []
|
||
for category in query.all():
|
||
categories.append(ServiceCategorySchema.model_validate(category))
|
||
return ServiceGetAllCategoriesResponse(categories=categories)
|
||
|
||
async def get_kit_by_name(self, name: str) -> Optional[ServicesKit]:
|
||
return await self.session.scalar(select(ServicesKit).where(ServicesKit.name == name))
|
||
|
||
async def get_kit_by_id(self, kit_id: int) -> Optional[ServicesKit]:
|
||
return await self.session.scalar(select(ServicesKit).where(ServicesKit.id == kit_id))
|
||
|
||
async def get_all_kits(self) -> GetAllServicesKitsResponse:
|
||
stmt = (
|
||
select(
|
||
ServicesKit
|
||
)
|
||
.order_by(
|
||
ServicesKit.id.desc()
|
||
)
|
||
)
|
||
kits = (await self.session.scalars(stmt)).all()
|
||
kits_schemas = GetServiceKitSchema.from_orm_list(kits)
|
||
return GetAllServicesKitsResponse(services_kits=kits_schemas)
|
||
|
||
async def create_kit(self, request: CreateServicesKitRequest) -> CreateServicesKitResponse:
|
||
try:
|
||
if await self.get_kit_by_name(request.data.name):
|
||
return CreateServicesKitResponse(ok=False, message='Набор услуг с таким названием уже существует')
|
||
base_fields = request.data.model_dump_parent()
|
||
kit = ServicesKit(**base_fields)
|
||
self.session.add(kit)
|
||
await self.session.flush()
|
||
# Appending services
|
||
insert_data = []
|
||
for service_id in request.data.services_ids:
|
||
insert_data.append({
|
||
'service_id': service_id,
|
||
'services_kit_id': kit.id
|
||
})
|
||
if insert_data:
|
||
await self.session.execute(
|
||
insert(services_kit_services),
|
||
insert_data
|
||
)
|
||
await self.session.flush()
|
||
await self.session.commit()
|
||
return CreateServicesKitResponse(ok=True, message='Набор услуг успешно создан')
|
||
|
||
except Exception as e:
|
||
return CreateServicesKitResponse(ok=False, message=str(e))
|
||
|
||
async def update_kit(self, request: UpdateServicesKitRequest) -> UpdateServicesKitResponse:
|
||
try:
|
||
kit = await self.get_kit_by_id(request.data.id)
|
||
if not kit:
|
||
return UpdateServicesKitResponse(ok=False, message='Указанный набор услуг не существует')
|
||
base_fields = request.data.model_dump_parent()
|
||
stmt = update(ServicesKit).values(**base_fields).where(ServicesKit.id == request.data.id)
|
||
await self.session.execute(stmt)
|
||
await self.session.flush()
|
||
|
||
# Deleting previous services
|
||
stmt = (
|
||
delete(
|
||
services_kit_services
|
||
).where(
|
||
services_kit_services.c.services_kit_id == kit.id
|
||
)
|
||
)
|
||
await self.session.execute(stmt)
|
||
await self.session.flush()
|
||
|
||
insert_data = []
|
||
for service_id in request.data.services_ids:
|
||
insert_data.append({
|
||
'service_id': service_id,
|
||
'services_kit_id': kit.id
|
||
})
|
||
if insert_data:
|
||
await self.session.execute(
|
||
insert(services_kit_services),
|
||
insert_data
|
||
)
|
||
await self.session.flush()
|
||
await self.session.commit()
|
||
return UpdateServicesKitResponse(ok=True, message='Набор услуг успешно обновлен')
|
||
|
||
except Exception as e:
|
||
return UpdateServicesKitResponse(ok=False, message=str(e))
|
||
|
||
async def get_all_price_categories(self) -> GetAllPriceCategoriesResponse:
|
||
query = await (self.session
|
||
.scalars(select(ServicePriceCategory)
|
||
.order_by(ServicePriceCategory.id)))
|
||
price_categories = []
|
||
for category in query.all():
|
||
price_categories.append(ServicePriceCategorySchema.model_validate(category))
|
||
return GetAllPriceCategoriesResponse(price_categories=price_categories)
|
||
|
||
async def create_price_category(self, request: CreatePriceCategoryRequest) -> ServiceCreateCategoryResponse:
|
||
try:
|
||
raw_category = request.name
|
||
category = ServicePriceCategory(name=raw_category)
|
||
self.session.add(category)
|
||
await self.session.commit()
|
||
return ServiceCreateCategoryResponse(ok=True, message="Категория цен успешно создана")
|
||
except Exception as e:
|
||
return ServiceCreateCategoryResponse(ok=False, message=f"Неудалось создать категорию цен, ошибка: {e}")
|
||
|
||
async def update_price_category(self, request: UpdatePriceCategoryRequest) -> ServiceUpdateResponse:
|
||
try:
|
||
raw_category = request.name
|
||
category = await (self.session.get(ServicePriceCategory, request.id))
|
||
if not category:
|
||
return ServiceUpdateResponse(ok=False, message="Категория цен не найдена")
|
||
await self.session.execute(
|
||
update(ServicePriceCategory)
|
||
.where(ServicePriceCategory.id == request.id)
|
||
.values(name=raw_category)
|
||
)
|
||
await self.session.commit()
|
||
return ServiceUpdateResponse(ok=True, message="Категория цен успешно обновлена")
|
||
except Exception as e:
|
||
return ServiceUpdateResponse(ok=False, message=f"Неудалось обновить категорию цен, ошибка: {e}")
|
||
|
||
async def delete_price_category(self, request: DeletePriceCategoryRequest) -> ServiceDeleteResponse:
|
||
try:
|
||
category = await (
|
||
self.session
|
||
.scalar(
|
||
select(
|
||
ServicePriceCategory
|
||
)
|
||
.filter(
|
||
ServicePriceCategory.id == request.id
|
||
)
|
||
)
|
||
)
|
||
if not category:
|
||
return ServiceDeleteResponse(ok=False, message="Категория цен не найдена")
|
||
|
||
await self.session.delete(category)
|
||
await self.session.commit()
|
||
return ServiceDeleteResponse(ok=True, message="Категория цен успешно удалена")
|
||
except Exception as e:
|
||
return ServiceDeleteResponse(ok=False, message=f"Неудалось удалить категорию цен, ошибка: {e}")
|
||
|
||
async def reorder(self, request: ServiceReorderRequest) -> ServiceReorderResponse:
|
||
try:
|
||
draining_service = await (self.session.get(Service, request.draining_service_id))
|
||
hovered_service = await (self.session.get(Service, request.hovered_service_id))
|
||
if not draining_service or not hovered_service:
|
||
return ServiceReorderResponse(ok=False, message="Услуга не найдена")
|
||
if draining_service.category_id == hovered_service.category_id:
|
||
temp = draining_service.rank
|
||
draining_service.rank = hovered_service.rank
|
||
hovered_service.rank = temp
|
||
else:
|
||
return ServiceReorderResponse(ok=False, message="Нельзя перемещать услуги между категориями")
|
||
await self.session.commit()
|
||
return ServiceReorderResponse(ok=True, message="Услуги успешно пересортированы")
|
||
except Exception as e:
|
||
return ServiceReorderResponse(ok=False, message=f"Неудалось найти услугу, ошибка: {e}")
|
||
|
||
async def reorder_category(self, request: ServiceCategoryReorderRequest) -> ServiceCategoryReorderResponse:
|
||
try:
|
||
if request.move_down and request.move_up:
|
||
return ServiceCategoryReorderResponse(ok=False,
|
||
message="Невозможно выполнить два действия одновременно")
|
||
if not request.move_down and not request.move_up:
|
||
return ServiceCategoryReorderResponse(ok=False, message="Не указано действие")
|
||
if request.service_type == ServiceType.DEAL_SERVICE:
|
||
order_by = ServiceCategory.deal_service_rank
|
||
rank_field = 'deal_service_rank'
|
||
else:
|
||
order_by = ServiceCategory.product_service_rank
|
||
rank_field = 'product_service_rank'
|
||
service_categories = await (
|
||
self.session
|
||
.scalars(select(ServiceCategory)
|
||
.order_by(order_by))
|
||
)
|
||
service_categories = service_categories.all()
|
||
for prv, cur, nxt in previous_current_next(service_categories):
|
||
if request.category_id == cur.id:
|
||
if request.move_down:
|
||
if nxt:
|
||
temp = getattr(cur, rank_field)
|
||
# cur.rank = nxt.rank
|
||
setattr(cur, rank_field, getattr(nxt, rank_field))
|
||
# nxt.rank = temp
|
||
setattr(nxt, rank_field, temp)
|
||
else:
|
||
return ServiceCategoryReorderResponse(ok=False, message="Невозможно переместить вниз")
|
||
elif request.move_up:
|
||
if prv:
|
||
temp = getattr(cur, rank_field)
|
||
# cur.rank = prv.rank
|
||
setattr(cur, rank_field, getattr(prv, rank_field))
|
||
# prv.rank = temp
|
||
setattr(prv, rank_field, temp)
|
||
else:
|
||
return ServiceCategoryReorderResponse(ok=False, message="Невозможно переместить вверх")
|
||
await self.session.commit()
|
||
return ServiceCategoryReorderResponse(ok=True, message="Категории успешно пересортированы")
|
||
except Exception as e:
|
||
return ServiceCategoryReorderResponse(ok=False, message=f"Неудалось пересортировать категорию, ошибка: {e}")
|