feat: modules, products, services, services kits

This commit is contained in:
2025-09-16 10:54:10 +04:00
parent be8052848c
commit 276626d6f7
55 changed files with 1791 additions and 34 deletions

View 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

View 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()

View 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()

View 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)

View 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()

View 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)

View 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)