feat: modules, products, services, services kits
This commit is contained in:
0
modules/fulfillment_base/__init__.py
Normal file
0
modules/fulfillment_base/__init__.py
Normal file
1
modules/fulfillment_base/enums/__init__.py
Normal file
1
modules/fulfillment_base/enums/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .service import *
|
||||
7
modules/fulfillment_base/enums/service.py
Normal file
7
modules/fulfillment_base/enums/service.py
Normal file
@ -0,0 +1,7 @@
|
||||
from enum import IntEnum, unique
|
||||
|
||||
|
||||
@unique
|
||||
class ServiceType(IntEnum):
|
||||
DEAL_SERVICE = 0
|
||||
PRODUCT_SERVICE = 1
|
||||
6
modules/fulfillment_base/models/__init__.py
Normal file
6
modules/fulfillment_base/models/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .deal_product import DealProduct as DealProduct, DealProductService as DealProductService
|
||||
from .deal_service import (
|
||||
DealService as DealService,
|
||||
)
|
||||
from .product import Product as Product
|
||||
from .service import Service as Service
|
||||
60
modules/fulfillment_base/models/deal_product.py
Normal file
60
modules/fulfillment_base/models/deal_product.py
Normal file
@ -0,0 +1,60 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey, ForeignKeyConstraint
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from models.base import BaseModel
|
||||
from models.mixins import PriceMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models import Deal, Service, Product
|
||||
|
||||
|
||||
class DealProduct(BaseModel):
|
||||
__tablename__ = "fulfillment_base_deal_products"
|
||||
|
||||
deal_id: Mapped[int] = mapped_column(ForeignKey("deals.id"), primary_key=True)
|
||||
product_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("fulfillment_base_products.id"), primary_key=True
|
||||
)
|
||||
|
||||
quantity: Mapped[int] = mapped_column(default=1)
|
||||
comment: Mapped[str] = mapped_column(comment="Комментарий к товару")
|
||||
|
||||
deal: Mapped["Deal"] = relationship(backref="deal_products")
|
||||
product: Mapped["Product"] = relationship()
|
||||
|
||||
product_services: Mapped[list["DealProductService"]] = relationship(
|
||||
back_populates="deal_product",
|
||||
primaryjoin="and_(DealProduct.deal_id==DealProductService.deal_id, DealProduct.product_id==DealProductService.product_id)",
|
||||
)
|
||||
|
||||
|
||||
class DealProductService(BaseModel, PriceMixin):
|
||||
__tablename__ = "fulfillment_base_deal_products_services"
|
||||
|
||||
deal_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
product_id: Mapped[int] = mapped_column(primary_key=True)
|
||||
service_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("fulfillment_base_services.id"), primary_key=True
|
||||
)
|
||||
|
||||
is_fixed_price: Mapped[bool] = mapped_column(
|
||||
default=False, server_default="0", comment="Фиксированная цена"
|
||||
)
|
||||
|
||||
deal_product: Mapped["DealProduct"] = relationship(
|
||||
back_populates="product_services",
|
||||
primaryjoin="and_(DealProductService.deal_id==DealProduct.deal_id, DealProductService.product_id==DealProduct.product_id)",
|
||||
)
|
||||
service: Mapped["Service"] = relationship()
|
||||
|
||||
__table_args__ = (
|
||||
ForeignKeyConstraint(
|
||||
["deal_id", "product_id"],
|
||||
[
|
||||
"fulfillment_base_deal_products.deal_id",
|
||||
"fulfillment_base_deal_products.product_id",
|
||||
],
|
||||
),
|
||||
)
|
||||
28
modules/fulfillment_base/models/deal_service.py
Normal file
28
modules/fulfillment_base/models/deal_service.py
Normal file
@ -0,0 +1,28 @@
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from models.base import BaseModel
|
||||
from models.mixins import PriceMixin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models import Deal
|
||||
from modules.fulfillment_base.models import Service
|
||||
|
||||
|
||||
class DealService(BaseModel, PriceMixin):
|
||||
__tablename__ = "fulfillment_base_deal_services"
|
||||
|
||||
deal_id: Mapped[int] = mapped_column(ForeignKey("deals.id"), primary_key=True)
|
||||
deal: Mapped["Deal"] = relationship(backref="deal_services")
|
||||
|
||||
service_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("fulfillment_base_services.id"), primary_key=True
|
||||
)
|
||||
service: Mapped["Service"] = relationship()
|
||||
|
||||
quantity: Mapped[int] = mapped_column(default=1)
|
||||
is_fixed_price: Mapped[bool] = mapped_column(
|
||||
default=False, server_default="0", comment="Фиксированная цена"
|
||||
)
|
||||
40
modules/fulfillment_base/models/product.py
Normal file
40
modules/fulfillment_base/models/product.py
Normal file
@ -0,0 +1,40 @@
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from models.base import BaseModel
|
||||
from models.mixins import IdMixin, SoftDeleteMixin
|
||||
|
||||
|
||||
class Product(BaseModel, IdMixin, SoftDeleteMixin):
|
||||
__tablename__ = "fulfillment_base_products"
|
||||
|
||||
name: Mapped[str] = mapped_column()
|
||||
article: Mapped[str] = mapped_column(index=True)
|
||||
factory_article: Mapped[str] = mapped_column(
|
||||
index=True, default="", server_default=""
|
||||
)
|
||||
brand: Mapped[Optional[str]] = mapped_column(comment="Бренд")
|
||||
color: Mapped[Optional[str]] = mapped_column(comment="Цвет")
|
||||
composition: Mapped[Optional[str]] = mapped_column(comment="Состав")
|
||||
size: Mapped[Optional[str]] = mapped_column(comment="Размер")
|
||||
additional_info: Mapped[Optional[str]] = mapped_column(
|
||||
comment="Дополнительная информация"
|
||||
)
|
||||
|
||||
images: Mapped[list["ProductImage"]] = relationship(
|
||||
"ProductImage",
|
||||
back_populates="product",
|
||||
lazy="selectin",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
|
||||
class ProductImage(BaseModel, IdMixin):
|
||||
__tablename__ = "fulfillment_base_product_images"
|
||||
|
||||
product_id: Mapped[int] = mapped_column(ForeignKey("fulfillment_base_products.id"))
|
||||
product: Mapped["Product"] = relationship(back_populates="images")
|
||||
|
||||
image_url: Mapped[str] = mapped_column(nullable=False)
|
||||
73
modules/fulfillment_base/models/service.py
Normal file
73
modules/fulfillment_base/models/service.py
Normal file
@ -0,0 +1,73 @@
|
||||
from sqlalchemy import ForeignKey, Table, Column
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from models.base import BaseModel
|
||||
from models.mixins import IdMixin, SoftDeleteMixin, CostMixin, PriceMixin
|
||||
from modules.fulfillment_base import enums
|
||||
|
||||
services_kit_services = Table(
|
||||
"fulfillment_base_services_kit_services",
|
||||
BaseModel.metadata,
|
||||
Column("services_kit_id", ForeignKey("fulfillment_base_services_kits.id")),
|
||||
Column("service_id", ForeignKey("fulfillment_base_services.id")),
|
||||
)
|
||||
|
||||
|
||||
class Service(BaseModel, IdMixin, SoftDeleteMixin, PriceMixin, CostMixin):
|
||||
__tablename__ = "fulfillment_base_services"
|
||||
|
||||
name: Mapped[str] = mapped_column(index=True)
|
||||
|
||||
price_ranges: Mapped[list["ServicePriceRange"]] = relationship(
|
||||
back_populates="service",
|
||||
lazy="selectin",
|
||||
order_by="asc(ServicePriceRange.from_quantity)",
|
||||
cascade="all, delete-orphan",
|
||||
)
|
||||
|
||||
category_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("fulfillment_base_service_categories.id"),
|
||||
comment="ID категории услуги",
|
||||
)
|
||||
category: Mapped["ServiceCategory"] = relationship("ServiceCategory", lazy="joined")
|
||||
|
||||
service_type: Mapped[int] = mapped_column(
|
||||
server_default=f"{enums.service.ServiceType.DEAL_SERVICE}",
|
||||
comment="Тип услуги",
|
||||
)
|
||||
lexorank: Mapped[str] = mapped_column(comment="Ранг услуги")
|
||||
|
||||
|
||||
class ServiceCategory(BaseModel, IdMixin):
|
||||
__tablename__ = "fulfillment_base_service_categories"
|
||||
|
||||
name: Mapped[str] = mapped_column()
|
||||
is_deleted: Mapped[bool] = mapped_column(
|
||||
default=False, comment="Удалена ли категория"
|
||||
)
|
||||
|
||||
deal_service_rank: Mapped[str] = mapped_column(comment="Ранг услуги для сделки")
|
||||
product_service_rank: Mapped[str] = mapped_column(comment="Ранг услуги для товара")
|
||||
|
||||
|
||||
class ServicesKit(BaseModel, IdMixin):
|
||||
__tablename__ = "fulfillment_base_services_kits"
|
||||
|
||||
name: Mapped[str] = mapped_column()
|
||||
service_type: Mapped[int] = mapped_column(
|
||||
server_default=f"{enums.ServiceType.DEAL_SERVICE}",
|
||||
comment="Тип услуги",
|
||||
)
|
||||
services: Mapped[list["Service"]] = relationship(
|
||||
secondary=services_kit_services, lazy="selectin"
|
||||
)
|
||||
|
||||
|
||||
class ServicePriceRange(BaseModel, IdMixin, PriceMixin):
|
||||
__tablename__ = "fulfillment_base_service_price_ranges"
|
||||
|
||||
service_id: Mapped[int] = mapped_column(ForeignKey("fulfillment_base_services.id"))
|
||||
service: Mapped[Service] = relationship(back_populates="price_ranges")
|
||||
|
||||
from_quantity: Mapped[int] = mapped_column(comment="От количества")
|
||||
to_quantity: Mapped[int] = mapped_column(comment="До количества")
|
||||
6
modules/fulfillment_base/repositories/__init__.py
Normal file
6
modules/fulfillment_base/repositories/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .deal_product import DealProductRepository as DealProductRepository
|
||||
from .product_service import ProductServiceRepository as ProductServiceRepository
|
||||
from .deal_service import DealServiceRepository as DealServiceRepository
|
||||
from .product import ProductRepository as ProductRepository
|
||||
from .service import ServiceRepository as ServiceRepository
|
||||
from .services_kit import ServicesKitRepository as ServicesKitRepository
|
||||
71
modules/fulfillment_base/repositories/deal_product.py
Normal file
71
modules/fulfillment_base/repositories/deal_product.py
Normal file
@ -0,0 +1,71 @@
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Select, select
|
||||
from sqlalchemy.orm import joinedload, selectinload
|
||||
|
||||
from modules.fulfillment_base.models import DealProductService
|
||||
from modules.fulfillment_base.models.deal_product import DealProduct
|
||||
from modules.fulfillment_base.models.service import ServicesKit
|
||||
from modules.fulfillment_base.schemas.deal_product import (
|
||||
UpdateDealProductSchema,
|
||||
CreateDealProductSchema,
|
||||
)
|
||||
from repositories.base import BaseRepository
|
||||
from repositories.mixins import RepGetAllMixin, RepUpdateMixin
|
||||
|
||||
|
||||
class DealProductRepository(
|
||||
BaseRepository,
|
||||
RepGetAllMixin[DealProduct],
|
||||
RepUpdateMixin[DealProduct, UpdateDealProductSchema],
|
||||
):
|
||||
entity_class = DealProduct
|
||||
|
||||
def _process_get_all_stmt_with_args(self, stmt: Select, *args) -> Select:
|
||||
deal_id = args[0]
|
||||
return (
|
||||
stmt.options(
|
||||
joinedload(DealProduct.product),
|
||||
selectinload(DealProduct.product_services).joinedload(
|
||||
DealProductService.service
|
||||
),
|
||||
)
|
||||
.where(DealProduct.deal_id == deal_id)
|
||||
.order_by(DealProduct.product_id)
|
||||
)
|
||||
|
||||
async def get_by_id(self, deal_id: int, product_id: int) -> Optional[DealProduct]:
|
||||
stmt = (
|
||||
select(DealProduct)
|
||||
.options(
|
||||
joinedload(DealProduct.product),
|
||||
selectinload(DealProduct.product_services).joinedload(
|
||||
DealProductService.service
|
||||
),
|
||||
)
|
||||
.where(DealProduct.deal_id == deal_id, DealProduct.product_id == product_id)
|
||||
)
|
||||
result = await self.session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def create(self, data: CreateDealProductSchema):
|
||||
deal_product = DealProduct(**data.model_dump())
|
||||
self.session.add(deal_product)
|
||||
await self.session.commit()
|
||||
|
||||
async def delete(self, obj: DealProduct):
|
||||
await self.session.delete(obj)
|
||||
await self.session.commit()
|
||||
|
||||
async def add_services_kit(
|
||||
self, deal_product: DealProduct, services_kit: ServicesKit
|
||||
):
|
||||
for service in services_kit.services:
|
||||
deal_product_service = DealProductService(
|
||||
deal_id=deal_product.deal_id,
|
||||
product_id=deal_product.product_id,
|
||||
service_id=service.id,
|
||||
price=service.price,
|
||||
)
|
||||
self.session.add(deal_product_service)
|
||||
await self.session.commit()
|
||||
48
modules/fulfillment_base/repositories/deal_service.py
Normal file
48
modules/fulfillment_base/repositories/deal_service.py
Normal file
@ -0,0 +1,48 @@
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import Select, select
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from modules.fulfillment_base.models import DealService
|
||||
from modules.fulfillment_base.schemas.deal_service import (
|
||||
UpdateDealServiceSchema,
|
||||
CreateDealServiceSchema,
|
||||
)
|
||||
from repositories.base import BaseRepository
|
||||
from repositories.mixins import RepGetAllMixin, RepUpdateMixin
|
||||
|
||||
|
||||
class DealServiceRepository(
|
||||
BaseRepository,
|
||||
RepGetAllMixin[DealService],
|
||||
RepUpdateMixin[DealService, UpdateDealServiceSchema],
|
||||
):
|
||||
entity_class = DealService
|
||||
|
||||
def _process_get_all_stmt_with_args(self, stmt: Select, *args) -> Select:
|
||||
deal_id = args[0]
|
||||
return (
|
||||
stmt.options(
|
||||
joinedload(DealService.service),
|
||||
)
|
||||
.where(DealService.deal_id == deal_id)
|
||||
.order_by(DealService.service_id)
|
||||
)
|
||||
|
||||
async def get_by_id(self, deal_id: int, service_id: int) -> Optional[DealService]:
|
||||
stmt = (
|
||||
select(DealService)
|
||||
.options(joinedload(DealService.service))
|
||||
.where(DealService.deal_id == deal_id, DealService.service_id == service_id)
|
||||
)
|
||||
result = await self.session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def create(self, data: CreateDealServiceSchema):
|
||||
deal_service = DealService(**data.model_dump())
|
||||
self.session.add(deal_service)
|
||||
await self.session.commit()
|
||||
|
||||
async def delete(self, obj: DealService):
|
||||
await self.session.delete(obj)
|
||||
await self.session.commit()
|
||||
33
modules/fulfillment_base/repositories/product.py
Normal file
33
modules/fulfillment_base/repositories/product.py
Normal file
@ -0,0 +1,33 @@
|
||||
from modules.fulfillment_base.models import Product
|
||||
from modules.fulfillment_base.schemas.product import (
|
||||
CreateProductSchema,
|
||||
UpdateProductSchema,
|
||||
)
|
||||
from repositories.mixins import *
|
||||
from schemas.base import PaginationSchema
|
||||
|
||||
|
||||
class ProductRepository(
|
||||
BaseRepository,
|
||||
RepGetAllMixin[Product],
|
||||
RepDeleteMixin[Product],
|
||||
RepCreateMixin[Product, CreateProductSchema],
|
||||
RepUpdateMixin[Product, UpdateProductSchema],
|
||||
RepGetByIdMixin[Product],
|
||||
):
|
||||
entity_class = Product
|
||||
|
||||
def _process_get_all_stmt_with_args(self, stmt: Select, *args) -> Select:
|
||||
search_input = args[0]
|
||||
pagination: PaginationSchema = args[1]
|
||||
if search_input:
|
||||
stmt = stmt.where(Product.name.ilike(f"%{search_input}%"))
|
||||
if pagination.items_per_page and pagination.page:
|
||||
stmt = self._apply_pagination(
|
||||
stmt, pagination.page, pagination.items_per_page
|
||||
)
|
||||
|
||||
return stmt
|
||||
|
||||
async def update(self, product: Product, data: UpdateProductSchema) -> Product:
|
||||
return await self._apply_update_data_to_model(product, data, True)
|
||||
84
modules/fulfillment_base/repositories/product_service.py
Normal file
84
modules/fulfillment_base/repositories/product_service.py
Normal file
@ -0,0 +1,84 @@
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import select, delete
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import joinedload
|
||||
|
||||
from modules.fulfillment_base.models import DealProductService
|
||||
from modules.fulfillment_base.schemas.product_service import *
|
||||
from repositories.base import BaseRepository
|
||||
from repositories.mixins import RepUpdateMixin
|
||||
|
||||
|
||||
class ProductServiceRepository(
|
||||
BaseRepository,
|
||||
RepUpdateMixin[DealProductService, UpdateProductServiceSchema],
|
||||
):
|
||||
entity_class = DealProductService
|
||||
session: AsyncSession
|
||||
|
||||
async def get_by_id(
|
||||
self, deal_id: int, product_id: int, service_id: int
|
||||
) -> Optional[DealProductService]:
|
||||
stmt = (
|
||||
select(DealProductService)
|
||||
.options(
|
||||
joinedload(DealProductService.service),
|
||||
)
|
||||
.where(
|
||||
DealProductService.deal_id == deal_id,
|
||||
DealProductService.product_id == product_id,
|
||||
DealProductService.service_id == service_id,
|
||||
)
|
||||
)
|
||||
result = await self.session.execute(stmt)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
async def create(self, data: CreateProductServiceSchema):
|
||||
deal_product_service = DealProductService(**data.model_dump())
|
||||
self.session.add(deal_product_service)
|
||||
await self.session.commit()
|
||||
|
||||
async def delete(self, obj: DealProductService):
|
||||
await self.session.delete(obj)
|
||||
await self.session.commit()
|
||||
|
||||
async def get_product_services(
|
||||
self, deal_id: int, product_id: int
|
||||
) -> list[DealProductService]:
|
||||
stmt = (
|
||||
select(DealProductService)
|
||||
.options(
|
||||
joinedload(DealProductService.service),
|
||||
)
|
||||
.where(
|
||||
DealProductService.deal_id == deal_id,
|
||||
DealProductService.product_id == product_id,
|
||||
)
|
||||
)
|
||||
return list(await self.session.scalars(stmt))
|
||||
|
||||
async def delete_product_services(self, deal_id: int, product_ids: list[int]):
|
||||
stmt = delete(DealProductService).where(
|
||||
DealProductService.deal_id == deal_id,
|
||||
DealProductService.product_id.in_(product_ids),
|
||||
)
|
||||
await self.session.execute(stmt)
|
||||
await self.session.flush()
|
||||
|
||||
async def duplicate_services(
|
||||
self, deal_id: int, product_ids: list[int], services: list[DealProductService]
|
||||
):
|
||||
await self.delete_product_services(deal_id, product_ids)
|
||||
|
||||
for product_id in product_ids:
|
||||
for prod_service in services:
|
||||
product_service = DealProductService(
|
||||
deal_id=deal_id,
|
||||
product_id=product_id,
|
||||
service_id=prod_service.service.id,
|
||||
price=prod_service.price,
|
||||
is_fixed_price=prod_service.is_fixed_price,
|
||||
)
|
||||
self.session.add(product_service)
|
||||
await self.session.commit()
|
||||
20
modules/fulfillment_base/repositories/service.py
Normal file
20
modules/fulfillment_base/repositories/service.py
Normal file
@ -0,0 +1,20 @@
|
||||
from modules.fulfillment_base.models import Service
|
||||
from modules.fulfillment_base.schemas.service import (
|
||||
CreateServiceSchema,
|
||||
UpdateServiceSchema,
|
||||
)
|
||||
from repositories.mixins import *
|
||||
|
||||
|
||||
class ServiceRepository(
|
||||
BaseRepository,
|
||||
RepGetAllMixin[Service],
|
||||
RepDeleteMixin[Service],
|
||||
RepCreateMixin[Service, CreateServiceSchema],
|
||||
RepUpdateMixin[Service, UpdateServiceSchema],
|
||||
RepGetByIdMixin[Service],
|
||||
):
|
||||
entity_class = Service
|
||||
|
||||
async def update(self, service: Service, data: UpdateServiceSchema) -> Service:
|
||||
return await self._apply_update_data_to_model(service, data, True)
|
||||
22
modules/fulfillment_base/repositories/services_kit.py
Normal file
22
modules/fulfillment_base/repositories/services_kit.py
Normal file
@ -0,0 +1,22 @@
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from modules.fulfillment_base.models.service import ServicesKit
|
||||
from modules.fulfillment_base.schemas.services_kit import (
|
||||
CreateServicesKitSchema,
|
||||
UpdateServicesKitSchema,
|
||||
)
|
||||
from repositories.mixins import *
|
||||
|
||||
|
||||
class ServicesKitRepository(
|
||||
RepCrudMixin[ServicesKit, CreateServicesKitSchema, UpdateServicesKitSchema],
|
||||
):
|
||||
entity_class = ServicesKit
|
||||
|
||||
def _process_get_by_id_stmt(self, stmt: Select) -> Select:
|
||||
return stmt.options(selectinload(ServicesKit.services))
|
||||
|
||||
async def update(
|
||||
self, service: ServicesKit, data: UpdateServicesKitSchema
|
||||
) -> ServicesKit:
|
||||
return await self._apply_update_data_to_model(service, data, True)
|
||||
0
modules/fulfillment_base/routers/__init__.py
Normal file
0
modules/fulfillment_base/routers/__init__.py
Normal file
137
modules/fulfillment_base/routers/deal_product.py
Normal file
137
modules/fulfillment_base/routers/deal_product.py
Normal file
@ -0,0 +1,137 @@
|
||||
from fastapi import APIRouter, Path
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from modules.fulfillment_base.schemas.deal_product import *
|
||||
from modules.fulfillment_base.schemas.product_service import *
|
||||
from modules.fulfillment_base.services import DealProductService, ProductServiceService
|
||||
|
||||
router = APIRouter(tags=["deal-product"])
|
||||
|
||||
# region DealProduct
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{dealId}",
|
||||
response_model=GetDealProductsResponse,
|
||||
operation_id="get_deal_products",
|
||||
)
|
||||
async def get_deal_products(
|
||||
session: SessionDependency,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
):
|
||||
return await DealProductService(session).get_all(deal_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response_model=CreateDealProductResponse,
|
||||
operation_id="create_deal_product",
|
||||
)
|
||||
async def create_deal_product(
|
||||
session: SessionDependency,
|
||||
request: CreateDealProductRequest,
|
||||
):
|
||||
return await DealProductService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{dealId}/product/{productId}",
|
||||
response_model=UpdateDealProductResponse,
|
||||
operation_id="update_deal_product",
|
||||
)
|
||||
async def update_deal_product(
|
||||
session: SessionDependency,
|
||||
request: UpdateDealProductRequest,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
product_id: int = Path(alias="productId"),
|
||||
):
|
||||
return await DealProductService(session).update(deal_id, product_id, request)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{dealId}/product/{productId}",
|
||||
response_model=DeleteDealProductResponse,
|
||||
operation_id="delete_deal_product",
|
||||
)
|
||||
async def delete_deal_product(
|
||||
session: SessionDependency,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
product_id: int = Path(alias="productId"),
|
||||
):
|
||||
return await DealProductService(session).delete(deal_id, product_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/add-services-kit",
|
||||
response_model=DealProductAddKitResponse,
|
||||
operation_id="add_kit_to_deal_product",
|
||||
)
|
||||
async def add_kit_to_deal_product(
|
||||
session: SessionDependency,
|
||||
request: DealProductAddKitRequest,
|
||||
):
|
||||
return await DealProductService(session).add_services_kit(request)
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
# region DealProductService
|
||||
|
||||
|
||||
@router.post(
|
||||
"/service",
|
||||
response_model=CreateProductServiceResponse,
|
||||
operation_id="create_deal_product_service",
|
||||
)
|
||||
async def create_deal_product_service(
|
||||
session: SessionDependency,
|
||||
request: CreateProductServiceRequest,
|
||||
):
|
||||
return await ProductServiceService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{dealId}/product/{productId}/service/{serviceId}",
|
||||
response_model=UpdateProductServiceResponse,
|
||||
operation_id="update_deal_product_service",
|
||||
)
|
||||
async def update_deal_product_service(
|
||||
session: SessionDependency,
|
||||
request: UpdateProductServiceRequest,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
product_id: int = Path(alias="productId"),
|
||||
service_id: int = Path(alias="serviceId"),
|
||||
):
|
||||
return await ProductServiceService(session).update(
|
||||
deal_id, product_id, service_id, request
|
||||
)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{dealId}/product/{productId}/service/{serviceId}",
|
||||
response_model=DeleteProductServiceResponse,
|
||||
operation_id="delete_deal_product_service",
|
||||
)
|
||||
async def delete_deal_product_service(
|
||||
session: SessionDependency,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
product_id: int = Path(alias="productId"),
|
||||
service_id: int = Path(alias="serviceId"),
|
||||
):
|
||||
return await ProductServiceService(session).delete(deal_id, product_id, service_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/services/duplicate",
|
||||
response_model=ProductServicesDuplicateResponse,
|
||||
operation_id="duplicate_product_services",
|
||||
)
|
||||
async def copy_product_services(
|
||||
session: SessionDependency,
|
||||
request: ProductServicesDuplicateRequest,
|
||||
):
|
||||
return await ProductServiceService(session).duplicate_product_services(request)
|
||||
|
||||
|
||||
# endregion
|
||||
58
modules/fulfillment_base/routers/deal_service.py
Normal file
58
modules/fulfillment_base/routers/deal_service.py
Normal file
@ -0,0 +1,58 @@
|
||||
from fastapi import APIRouter, Path
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from modules.fulfillment_base.schemas.deal_service import *
|
||||
from modules.fulfillment_base.services import DealServiceService
|
||||
|
||||
router = APIRouter(tags=["deal-service"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{dealId}",
|
||||
response_model=GetDealServicesResponse,
|
||||
operation_id="get_deal_services",
|
||||
)
|
||||
async def get_deal_services(
|
||||
session: SessionDependency,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
):
|
||||
return await DealServiceService(session).get_all(deal_id)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response_model=CreateDealServiceResponse,
|
||||
operation_id="create_deal_service",
|
||||
)
|
||||
async def create_deal_service(
|
||||
session: SessionDependency,
|
||||
request: CreateDealServiceRequest,
|
||||
):
|
||||
return await DealServiceService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{dealId}/service/{serviceId}",
|
||||
response_model=UpdateDealServiceResponse,
|
||||
operation_id="update_deal_service",
|
||||
)
|
||||
async def update_deal_service(
|
||||
session: SessionDependency,
|
||||
request: UpdateDealServiceRequest,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
service_id: int = Path(alias="serviceId"),
|
||||
):
|
||||
return await DealServiceService(session).update(deal_id, service_id, request)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{dealId}/service/{serviceId}",
|
||||
response_model=DeleteDealServiceResponse,
|
||||
operation_id="delete_deal_service",
|
||||
)
|
||||
async def delete_deal_service(
|
||||
session: SessionDependency,
|
||||
deal_id: int = Path(alias="dealId"),
|
||||
service_id: int = Path(alias="serviceId"),
|
||||
):
|
||||
return await DealServiceService(session).delete(deal_id, service_id)
|
||||
57
modules/fulfillment_base/routers/product.py
Normal file
57
modules/fulfillment_base/routers/product.py
Normal file
@ -0,0 +1,57 @@
|
||||
from fastapi import APIRouter, Path, Query
|
||||
|
||||
from backend.dependecies import SessionDependency, PaginationDependency
|
||||
from modules.fulfillment_base.schemas.product import *
|
||||
from modules.fulfillment_base.services import ProductService
|
||||
|
||||
router = APIRouter(tags=["product"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
response_model=GetProductsResponse,
|
||||
operation_id="get_products",
|
||||
)
|
||||
async def get_products(
|
||||
session: SessionDependency,
|
||||
pagination: PaginationDependency,
|
||||
search_input: Optional[str] = Query(alias="searchInput", default=None),
|
||||
):
|
||||
return await ProductService(session).get_all(search_input, pagination)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response_model=CreateProductResponse,
|
||||
operation_id="create_product",
|
||||
)
|
||||
async def create_product(
|
||||
session: SessionDependency,
|
||||
request: CreateProductRequest,
|
||||
):
|
||||
return await ProductService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{pk}",
|
||||
response_model=UpdateProductResponse,
|
||||
operation_id="update_product",
|
||||
)
|
||||
async def update_product(
|
||||
session: SessionDependency,
|
||||
request: UpdateProductRequest,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ProductService(session).update(pk, request)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{pk}",
|
||||
response_model=DeleteProductResponse,
|
||||
operation_id="delete_product",
|
||||
)
|
||||
async def delete_product(
|
||||
session: SessionDependency,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ProductService(session).delete(pk)
|
||||
55
modules/fulfillment_base/routers/service.py
Normal file
55
modules/fulfillment_base/routers/service.py
Normal file
@ -0,0 +1,55 @@
|
||||
from fastapi import APIRouter, Path
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from modules.fulfillment_base.schemas.service import *
|
||||
from modules.fulfillment_base.services import ServiceModelService
|
||||
|
||||
router = APIRouter(tags=["service"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
response_model=GetServicesResponse,
|
||||
operation_id="get_services",
|
||||
)
|
||||
async def get_services(
|
||||
session: SessionDependency,
|
||||
):
|
||||
return await ServiceModelService(session).get_all()
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response_model=CreateServiceResponse,
|
||||
operation_id="create_service",
|
||||
)
|
||||
async def create_service(
|
||||
session: SessionDependency,
|
||||
request: CreateServiceRequest,
|
||||
):
|
||||
return await ServiceModelService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{pk}",
|
||||
response_model=UpdateServiceResponse,
|
||||
operation_id="update_service",
|
||||
)
|
||||
async def update_service(
|
||||
session: SessionDependency,
|
||||
request: UpdateServiceRequest,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ServiceModelService(session).update(pk, request)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{pk}",
|
||||
response_model=DeleteServiceResponse,
|
||||
operation_id="delete_service",
|
||||
)
|
||||
async def delete_service(
|
||||
session: SessionDependency,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ServiceModelService(session).delete(pk)
|
||||
55
modules/fulfillment_base/routers/services_kit.py
Normal file
55
modules/fulfillment_base/routers/services_kit.py
Normal file
@ -0,0 +1,55 @@
|
||||
from fastapi import APIRouter, Path
|
||||
|
||||
from backend.dependecies import SessionDependency
|
||||
from modules.fulfillment_base.schemas.services_kit import *
|
||||
from modules.fulfillment_base.services import ServicesKitService
|
||||
|
||||
router = APIRouter(tags=["services-kit"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
response_model=GetServicesKitResponse,
|
||||
operation_id="get_services_kits",
|
||||
)
|
||||
async def get_services_kits(
|
||||
session: SessionDependency,
|
||||
):
|
||||
return await ServicesKitService(session).get_all()
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response_model=CreateServicesKitResponse,
|
||||
operation_id="create_services_kit",
|
||||
)
|
||||
async def create_services_kit(
|
||||
session: SessionDependency,
|
||||
request: CreateServicesKitRequest,
|
||||
):
|
||||
return await ServicesKitService(session).create(request)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{pk}",
|
||||
response_model=UpdateServicesKitResponse,
|
||||
operation_id="update_services_kit",
|
||||
)
|
||||
async def update_services_kit(
|
||||
session: SessionDependency,
|
||||
request: UpdateServicesKitRequest,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ServicesKitService(session).update(pk, request)
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{pk}",
|
||||
response_model=DeleteServicesKitResponse,
|
||||
operation_id="delete_services_kit",
|
||||
)
|
||||
async def delete_services_kit(
|
||||
session: SessionDependency,
|
||||
pk: int = Path(),
|
||||
):
|
||||
return await ServicesKitService(session).delete(pk)
|
||||
74
modules/fulfillment_base/schemas/deal_product.py
Normal file
74
modules/fulfillment_base/schemas/deal_product.py
Normal file
@ -0,0 +1,74 @@
|
||||
from modules.fulfillment_base.schemas.product import ProductSchema
|
||||
from modules.fulfillment_base.schemas.product_service import ProductServiceSchema
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class DealProductSchema(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
product: ProductSchema
|
||||
quantity: int
|
||||
comment: str
|
||||
product_services: list[ProductServiceSchema]
|
||||
|
||||
|
||||
class CreateDealProductSchema(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
quantity: int
|
||||
comment: str
|
||||
|
||||
|
||||
class UpdateDealProductSchema(BaseSchema):
|
||||
quantity: int
|
||||
comment: str
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateDealProductRequest(BaseSchema):
|
||||
entity: CreateDealProductSchema
|
||||
|
||||
|
||||
class UpdateDealProductRequest(BaseSchema):
|
||||
entity: UpdateDealProductSchema
|
||||
|
||||
|
||||
class DealProductAddKitRequest(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
kit_id: int
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class GetDealProductsResponse(BaseSchema):
|
||||
items: list[DealProductSchema]
|
||||
|
||||
|
||||
class CreateDealProductResponse(BaseResponse):
|
||||
entity: DealProductSchema
|
||||
|
||||
|
||||
class UpdateDealProductResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteDealProductResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DealProductAddKitResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
64
modules/fulfillment_base/schemas/deal_service.py
Normal file
64
modules/fulfillment_base/schemas/deal_service.py
Normal file
@ -0,0 +1,64 @@
|
||||
from modules.fulfillment_base.schemas.service import ServiceSchema
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class DealServiceSchema(BaseSchema):
|
||||
deal_id: int
|
||||
service_id: int
|
||||
service: ServiceSchema
|
||||
quantity: int
|
||||
price: float
|
||||
is_fixed_price: bool
|
||||
|
||||
|
||||
class CreateDealServiceSchema(BaseSchema):
|
||||
deal_id: int
|
||||
service_id: int
|
||||
quantity: int
|
||||
price: float
|
||||
|
||||
|
||||
class UpdateDealServiceSchema(BaseSchema):
|
||||
quantity: int
|
||||
price: float
|
||||
is_fixed_price: bool
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateDealServiceRequest(BaseSchema):
|
||||
entity: CreateDealServiceSchema
|
||||
|
||||
|
||||
class UpdateDealServiceRequest(BaseSchema):
|
||||
entity: UpdateDealServiceSchema
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class GetDealServicesResponse(BaseSchema):
|
||||
items: list[DealServiceSchema]
|
||||
|
||||
|
||||
class CreateDealServiceResponse(BaseResponse):
|
||||
entity: DealServiceSchema
|
||||
|
||||
|
||||
class UpdateDealServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteDealServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
77
modules/fulfillment_base/schemas/product.py
Normal file
77
modules/fulfillment_base/schemas/product.py
Normal file
@ -0,0 +1,77 @@
|
||||
from typing import Optional
|
||||
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class ProductImageSchema(BaseSchema):
|
||||
id: int
|
||||
product_id: int
|
||||
image_url: str
|
||||
|
||||
|
||||
class CreateProductSchema(BaseSchema):
|
||||
name: str
|
||||
article: str
|
||||
factory_article: str
|
||||
brand: Optional[str]
|
||||
color: Optional[str]
|
||||
composition: Optional[str]
|
||||
size: Optional[str]
|
||||
additional_info: Optional[str]
|
||||
|
||||
|
||||
class ProductSchema(CreateProductSchema):
|
||||
id: int
|
||||
|
||||
|
||||
class UpdateProductSchema(BaseSchema):
|
||||
name: Optional[str] = None
|
||||
article: Optional[str] = None
|
||||
factory_article: Optional[str] = None
|
||||
brand: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
composition: Optional[str] = None
|
||||
size: Optional[str] = None
|
||||
additional_info: Optional[str] = None
|
||||
|
||||
images: list[ProductImageSchema] | None = []
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateProductRequest(BaseSchema):
|
||||
entity: CreateProductSchema
|
||||
|
||||
|
||||
class UpdateProductRequest(BaseSchema):
|
||||
entity: UpdateProductSchema
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class GetProductsResponse(BaseSchema):
|
||||
items: list[ProductSchema]
|
||||
|
||||
|
||||
class CreateProductResponse(BaseResponse):
|
||||
entity: ProductSchema
|
||||
|
||||
|
||||
class UpdateProductResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteProductResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
69
modules/fulfillment_base/schemas/product_service.py
Normal file
69
modules/fulfillment_base/schemas/product_service.py
Normal file
@ -0,0 +1,69 @@
|
||||
from modules.fulfillment_base.schemas.service import ServiceSchema
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class ProductServiceSchema(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
service_id: int
|
||||
service: ServiceSchema
|
||||
price: float
|
||||
is_fixed_price: bool
|
||||
|
||||
|
||||
class CreateProductServiceSchema(BaseSchema):
|
||||
deal_id: int
|
||||
product_id: int
|
||||
service_id: int
|
||||
price: float
|
||||
|
||||
|
||||
class UpdateProductServiceSchema(BaseSchema):
|
||||
price: float
|
||||
is_fixed_price: bool
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateProductServiceRequest(BaseSchema):
|
||||
entity: CreateProductServiceSchema
|
||||
|
||||
|
||||
class UpdateProductServiceRequest(BaseSchema):
|
||||
entity: UpdateProductServiceSchema
|
||||
|
||||
|
||||
class ProductServicesDuplicateRequest(BaseSchema):
|
||||
deal_id: int
|
||||
source_deal_product_id: int
|
||||
target_deal_product_ids: list[int]
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class CreateProductServiceResponse(BaseResponse):
|
||||
entity: ProductServiceSchema
|
||||
|
||||
|
||||
class UpdateProductServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteProductServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class ProductServicesDuplicateResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
76
modules/fulfillment_base/schemas/service.py
Normal file
76
modules/fulfillment_base/schemas/service.py
Normal file
@ -0,0 +1,76 @@
|
||||
from typing import Optional
|
||||
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class ServicePriceRangeSchema(BaseSchema):
|
||||
id: int | None
|
||||
from_quantity: int
|
||||
to_quantity: int
|
||||
price: float
|
||||
|
||||
|
||||
class ServiceCategorySchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
deal_service_rank: str
|
||||
product_service_rank: str
|
||||
|
||||
|
||||
class ServiceSchema(BaseSchema):
|
||||
id: int
|
||||
name: str
|
||||
category: ServiceCategorySchema
|
||||
price: float
|
||||
service_type: int
|
||||
price_ranges: list[ServicePriceRangeSchema]
|
||||
cost: Optional[float]
|
||||
lexorank: str
|
||||
|
||||
|
||||
class UpdateServiceSchema(ServiceSchema):
|
||||
pass
|
||||
|
||||
|
||||
class CreateServiceSchema(ServiceSchema):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateServiceRequest(BaseSchema):
|
||||
entity: CreateServiceSchema
|
||||
|
||||
|
||||
class UpdateServiceRequest(BaseSchema):
|
||||
entity: UpdateServiceSchema
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class GetServicesResponse(BaseSchema):
|
||||
items: list[ServiceSchema]
|
||||
|
||||
|
||||
class CreateServiceResponse(BaseResponse):
|
||||
entity: ServiceSchema
|
||||
|
||||
|
||||
class UpdateServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteServiceResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
60
modules/fulfillment_base/schemas/services_kit.py
Normal file
60
modules/fulfillment_base/schemas/services_kit.py
Normal file
@ -0,0 +1,60 @@
|
||||
from modules.fulfillment_base.schemas.service import ServiceSchema
|
||||
from schemas.base import BaseSchema, BaseResponse
|
||||
|
||||
|
||||
# region Entity
|
||||
|
||||
|
||||
class BaseServicesKitSchema(BaseSchema):
|
||||
name: str
|
||||
service_type: int
|
||||
|
||||
|
||||
class ServicesKitSchema(BaseServicesKitSchema):
|
||||
id: int
|
||||
services: list[ServiceSchema]
|
||||
|
||||
|
||||
class CreateServicesKitSchema(BaseServicesKitSchema):
|
||||
services_ids: list[int]
|
||||
|
||||
|
||||
class UpdateServicesKitSchema(BaseServicesKitSchema):
|
||||
services_ids: list[int]
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Request
|
||||
|
||||
|
||||
class CreateServicesKitRequest(BaseSchema):
|
||||
entity: CreateServicesKitSchema
|
||||
|
||||
|
||||
class UpdateServicesKitRequest(BaseSchema):
|
||||
entity: UpdateServicesKitSchema
|
||||
|
||||
|
||||
# endregion
|
||||
|
||||
# region Response
|
||||
|
||||
|
||||
class GetServicesKitResponse(BaseSchema):
|
||||
items: list[ServicesKitSchema]
|
||||
|
||||
|
||||
class CreateServicesKitResponse(BaseResponse):
|
||||
entity: ServicesKitSchema
|
||||
|
||||
|
||||
class UpdateServicesKitResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
class DeleteServicesKitResponse(BaseResponse):
|
||||
pass
|
||||
|
||||
|
||||
# endregion
|
||||
6
modules/fulfillment_base/services/__init__.py
Normal file
6
modules/fulfillment_base/services/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .deal_product import DealProductService as DealProductService
|
||||
from .deal_service import DealServiceService as DealServiceService
|
||||
from .product import ProductService as ProductService
|
||||
from .product_service import ProductServiceService as ProductServiceService
|
||||
from .service import ServiceModelService as ServiceModelService
|
||||
from .services_kit import ServicesKitService as ServicesKitService
|
||||
72
modules/fulfillment_base/services/deal_product.py
Normal file
72
modules/fulfillment_base/services/deal_product.py
Normal file
@ -0,0 +1,72 @@
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from modules.fulfillment_base.models import DealProduct
|
||||
from modules.fulfillment_base.repositories import (
|
||||
DealProductRepository,
|
||||
ServicesKitRepository,
|
||||
ProductServiceRepository,
|
||||
)
|
||||
from modules.fulfillment_base.schemas.deal_product import *
|
||||
from services.mixins import ServiceGetAllMixin
|
||||
|
||||
|
||||
class DealProductService(ServiceGetAllMixin[DealProduct, DealProductSchema]):
|
||||
schema_class = DealProductSchema
|
||||
entity_not_found_msg = "Связь товара со сделкой не найдена"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = DealProductRepository(session)
|
||||
|
||||
async def create(
|
||||
self, request: CreateDealProductRequest
|
||||
) -> CreateDealProductResponse:
|
||||
await self.repository.create(request.entity)
|
||||
deal_product = await self.repository.get_by_id(
|
||||
request.entity.deal_id, request.entity.product_id
|
||||
)
|
||||
return CreateDealProductResponse(
|
||||
entity=DealProductSchema.model_validate(deal_product),
|
||||
message="Товар добавлен в сделку",
|
||||
)
|
||||
|
||||
async def update(
|
||||
self, deal_id: int, product_id: int, data: UpdateDealProductRequest
|
||||
) -> UpdateDealProductResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, product_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.update(entity, data.entity)
|
||||
return UpdateDealProductResponse(message="Товар сделки обновлен")
|
||||
|
||||
async def delete(self, deal_id: int, product_id: int) -> DeleteDealProductResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, product_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.delete(entity)
|
||||
return DeleteDealProductResponse(message="Товар удален из сделки")
|
||||
|
||||
async def add_services_kit(
|
||||
self, request: DealProductAddKitRequest
|
||||
) -> DealProductAddKitResponse:
|
||||
services_kit_repo = ServicesKitRepository(self.repository.session)
|
||||
services_kit = await services_kit_repo.get_by_id(request.kit_id)
|
||||
if not services_kit:
|
||||
raise HTTPException(status_code=404, detail="Набор услуг не найден")
|
||||
|
||||
deal_product = await self.repository.get_by_id(
|
||||
request.deal_id, request.product_id
|
||||
)
|
||||
if not deal_product:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
product_service_repo = ProductServiceRepository(self.repository.session)
|
||||
await product_service_repo.delete_product_services(
|
||||
request.deal_id, [request.product_id]
|
||||
)
|
||||
|
||||
await self.repository.add_services_kit(deal_product, services_kit)
|
||||
|
||||
return DealProductAddKitResponse(message="Комплект добавлен в товар")
|
||||
45
modules/fulfillment_base/services/deal_service.py
Normal file
45
modules/fulfillment_base/services/deal_service.py
Normal file
@ -0,0 +1,45 @@
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from modules.fulfillment_base.models import DealService
|
||||
from modules.fulfillment_base.repositories import DealServiceRepository
|
||||
from modules.fulfillment_base.schemas.deal_service import *
|
||||
from services.mixins import ServiceGetAllMixin
|
||||
|
||||
|
||||
class DealServiceService(ServiceGetAllMixin[DealService, DealServiceSchema]):
|
||||
schema_class = DealServiceSchema
|
||||
entity_not_found_msg = "Связь услуги со сделкой не найдена"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = DealServiceRepository(session)
|
||||
|
||||
async def create(
|
||||
self, request: CreateDealServiceRequest
|
||||
) -> CreateDealServiceResponse:
|
||||
await self.repository.create(request.entity)
|
||||
deal_service = await self.repository.get_by_id(
|
||||
request.entity.deal_id, request.entity.service_id
|
||||
)
|
||||
return CreateDealServiceResponse(
|
||||
entity=DealServiceSchema.model_validate(deal_service),
|
||||
message="Услуга добавлена в сделку",
|
||||
)
|
||||
|
||||
async def update(
|
||||
self, deal_id: int, service_id: int, data: UpdateDealServiceRequest
|
||||
) -> UpdateDealServiceResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, service_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.update(entity, data.entity)
|
||||
return UpdateDealServiceResponse(message="Услуга сделки обновлена")
|
||||
|
||||
async def delete(self, deal_id: int, service_id: int) -> DeleteDealServiceResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, service_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.delete(entity)
|
||||
return DeleteDealServiceResponse(message="Услуга удалена из сделки")
|
||||
27
modules/fulfillment_base/services/product.py
Normal file
27
modules/fulfillment_base/services/product.py
Normal file
@ -0,0 +1,27 @@
|
||||
from modules.fulfillment_base.models import Product
|
||||
from modules.fulfillment_base.repositories import ProductRepository
|
||||
from modules.fulfillment_base.schemas.product import (
|
||||
CreateProductRequest,
|
||||
ProductSchema,
|
||||
UpdateProductRequest,
|
||||
)
|
||||
from services.mixins import *
|
||||
|
||||
|
||||
class ProductService(
|
||||
ServiceGetAllMixin[Product, ProductSchema],
|
||||
ServiceCreateMixin[Product, CreateProductRequest, ProductSchema],
|
||||
ServiceUpdateMixin[Product, UpdateProductRequest],
|
||||
ServiceDeleteMixin[Product],
|
||||
):
|
||||
schema_class = ProductSchema
|
||||
entity_not_found_msg = "Товар не найден"
|
||||
entity_deleted_msg = "Товар успешно удален"
|
||||
entity_updated_msg = "Товар успешно обновлен"
|
||||
entity_created_msg = "Товар успешно создан"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = ProductRepository(session)
|
||||
|
||||
async def is_soft_delete(self, product: ProductSchema) -> bool:
|
||||
return True
|
||||
66
modules/fulfillment_base/services/product_service.py
Normal file
66
modules/fulfillment_base/services/product_service.py
Normal file
@ -0,0 +1,66 @@
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from modules.fulfillment_base.models import DealProductService
|
||||
from modules.fulfillment_base.repositories import ProductServiceRepository
|
||||
from modules.fulfillment_base.schemas.product_service import *
|
||||
|
||||
|
||||
class ProductServiceService:
|
||||
schema_class = ProductServiceSchema
|
||||
entity_not_found_msg = "Связь услуги с товаром не найдена"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = ProductServiceRepository(session)
|
||||
|
||||
async def create(
|
||||
self, request: CreateProductServiceRequest
|
||||
) -> CreateProductServiceResponse:
|
||||
await self.repository.create(request.entity)
|
||||
deal_product = await self.repository.get_by_id(
|
||||
request.entity.deal_id,
|
||||
request.entity.product_id,
|
||||
request.entity.service_id,
|
||||
)
|
||||
return CreateProductServiceResponse(
|
||||
entity=ProductServiceSchema.model_validate(deal_product),
|
||||
message="Услуга добавлена к товару",
|
||||
)
|
||||
|
||||
async def update(
|
||||
self,
|
||||
deal_id: int,
|
||||
product_id: int,
|
||||
service_id: int,
|
||||
data: UpdateProductServiceRequest,
|
||||
) -> UpdateProductServiceResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, product_id, service_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.update(entity, data.entity)
|
||||
return UpdateProductServiceResponse(message="Услуга обновлена")
|
||||
|
||||
async def delete(
|
||||
self, deal_id: int, product_id: int, service_id: int
|
||||
) -> DeleteProductServiceResponse:
|
||||
entity = await self.repository.get_by_id(deal_id, product_id, service_id)
|
||||
if not entity:
|
||||
raise HTTPException(status_code=404, detail=self.entity_not_found_msg)
|
||||
|
||||
await self.repository.delete(entity)
|
||||
return DeleteProductServiceResponse(message="Товар удален из сделки")
|
||||
|
||||
async def duplicate_product_services(
|
||||
self, request: ProductServicesDuplicateRequest
|
||||
) -> ProductServicesDuplicateResponse:
|
||||
services_to_copy: list[
|
||||
DealProductService
|
||||
] = await self.repository.get_product_services(
|
||||
request.deal_id, request.source_deal_product_id
|
||||
)
|
||||
|
||||
await self.repository.duplicate_services(
|
||||
request.deal_id, request.target_deal_product_ids, services_to_copy
|
||||
)
|
||||
return ProductServicesDuplicateResponse(message="Услуги продублированы")
|
||||
27
modules/fulfillment_base/services/service.py
Normal file
27
modules/fulfillment_base/services/service.py
Normal file
@ -0,0 +1,27 @@
|
||||
from modules.fulfillment_base.models import Service
|
||||
from modules.fulfillment_base.repositories import ServiceRepository
|
||||
from modules.fulfillment_base.schemas.service import (
|
||||
ServiceSchema,
|
||||
CreateServiceRequest,
|
||||
UpdateServiceRequest,
|
||||
)
|
||||
from services.mixins import *
|
||||
|
||||
|
||||
class ServiceModelService(
|
||||
ServiceGetAllMixin[Service, ServiceSchema],
|
||||
ServiceCreateMixin[Service, CreateServiceRequest, ServiceSchema],
|
||||
ServiceUpdateMixin[Service, UpdateServiceRequest],
|
||||
ServiceDeleteMixin[Service],
|
||||
):
|
||||
schema_class = ServiceSchema
|
||||
entity_not_found_msg = "Услуга не найдена"
|
||||
entity_deleted_msg = "Услуга успешно удалена"
|
||||
entity_updated_msg = "Услуга успешно обновлена"
|
||||
entity_created_msg = "Услуга успешно создана"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = ServiceRepository(session)
|
||||
|
||||
async def is_soft_delete(self, service: ServiceSchema) -> bool:
|
||||
return True
|
||||
24
modules/fulfillment_base/services/services_kit.py
Normal file
24
modules/fulfillment_base/services/services_kit.py
Normal file
@ -0,0 +1,24 @@
|
||||
from modules.fulfillment_base.models.service import ServicesKit
|
||||
from modules.fulfillment_base.repositories import ServicesKitRepository
|
||||
from modules.fulfillment_base.schemas.services_kit import (
|
||||
ServicesKitSchema,
|
||||
CreateServicesKitRequest,
|
||||
UpdateServicesKitRequest,
|
||||
)
|
||||
from services.mixins import *
|
||||
|
||||
|
||||
class ServicesKitService(
|
||||
ServiceCrudMixin[ServicesKit, ServicesKitSchema, CreateServicesKitRequest, UpdateServicesKitRequest]
|
||||
):
|
||||
schema_class = ServicesKitSchema
|
||||
entity_not_found_msg = "Набор услуг не найден"
|
||||
entity_deleted_msg = "Набор услуг успешно удален"
|
||||
entity_updated_msg = "Набор услуг успешно обновлен"
|
||||
entity_created_msg = "Набор услуг успешно создан"
|
||||
|
||||
def __init__(self, session: AsyncSession):
|
||||
self.repository = ServicesKitRepository(session)
|
||||
|
||||
async def is_soft_delete(self, service: ServicesKitSchema) -> bool:
|
||||
return False
|
||||
Reference in New Issue
Block a user