feat: a lot of a lot

This commit is contained in:
2024-09-01 01:05:11 +03:00
parent 867dfbe597
commit 4ae03284a3
43 changed files with 700 additions and 13 deletions

View File

@@ -18,3 +18,8 @@ SECRET_KEY = os.environ.get('SECRET_KEY')
S3_API_KEY = os.environ.get('S3_API_KEY') S3_API_KEY = os.environ.get('S3_API_KEY')
BILLING_API_KEY = os.environ.get('BILLING_API_KEY') BILLING_API_KEY = os.environ.get('BILLING_API_KEY')
# Celery
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL')
CELERY_RESULT_BACKEND = os.environ.get('CELERY_RESULT_BACKEND')

0
background/__init__.py Normal file
View File

14
background/celery_app.py Normal file
View File

@@ -0,0 +1,14 @@
from celery import Celery
from backend.config import CELERY_BROKER_URL, CELERY_RESULT_BACKEND
celery = Celery(
__name__,
broker=CELERY_BROKER_URL,
backend=CELERY_RESULT_BACKEND
)
celery.conf.result_backend_transport_options = {
'global_keyprefix': 'crm_'
}
from .tasks import *

View File

@@ -0,0 +1 @@
from .marketplace import synchronize_marketplace

View File

@@ -0,0 +1,20 @@
import time
from random import randint
from background.celery_app import celery
@celery.task(name='synchronize_marketplace')
def synchronize_marketplace(marketplace_id: int):
time.sleep(10)
if randint(0,10) % 2 == 0:
return 1
else:
raise Exception('Some error')
# async with session_maker() as session:
# session: AsyncSession
# marketplace: Optional[Marketplace] = await session.get(Marketplace, marketplace_id)
# if not marketplace:
# return
# controller = MarketplaceControllerFactory.get_controller(session, marketplace)
# await controller.synchronize_products()

View File

@@ -17,7 +17,7 @@ class DefaultBarcodeGenerator(BaseBarcodeGenerator):
if not attribute_getter: if not attribute_getter:
continue continue
value = attribute_getter.get_value(product) value = attribute_getter.get_value(product)
if not value: if not value or not value.strip():
continue continue
attributes[attribute.name] = value attributes[attribute.name] = value
for additional_attribute in template.additional_attributes: for additional_attribute in template.additional_attributes:

0
decorators/__init__.py Normal file
View File

19
decorators/async_utils.py Normal file
View File

@@ -0,0 +1,19 @@
import asyncio
from functools import wraps
def async_to_sync(func):
@wraps(func)
def wrapper(*args, **kwargs):
# Get the current event loop
loop = asyncio.get_event_loop()
# If there is no current event loop, create a new one
if loop.is_closed():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Run the async function until complete and return the result
return loop.run_until_complete(func(*args, **kwargs))
return wrapper

4
external/marketplace/__init__.py vendored Normal file
View File

@@ -0,0 +1,4 @@
from .wildberries import WildberriesMarketplaceApi
from .ozon import OzonMarketplaceApi
from .yandex import YandexMarketplaceApi
from .factory import MarketplaceApiFactory

1
external/marketplace/base/__init__.py vendored Normal file
View File

@@ -0,0 +1 @@
from .core import BaseMarketplaceApi

28
external/marketplace/base/core.py vendored Normal file
View File

@@ -0,0 +1,28 @@
from abc import ABC, abstractmethod
import aiohttp
from models import Marketplace
class BaseMarketplaceApi(ABC):
marketplace: Marketplace
@abstractmethod
def __init__(self, marketplace: Marketplace):
pass
async def _method(self, http_method, method, **kwargs):
async with aiohttp.ClientSession(headers=self.get_headers) as session:
async with session.request(http_method, self.base_url + method, **kwargs) as response:
return await response.json()
@property
@abstractmethod
def get_headers(self) -> dict:
pass
@property
@abstractmethod
def base_url(self) -> str:
pass

19
external/marketplace/factory.py vendored Normal file
View File

@@ -0,0 +1,19 @@
from enums.base_marketplace import BaseMarketplace
from external.marketplace.ozon.core import OzonMarketplaceApi
from external.marketplace.wildberries.core import WildberriesApiUrl, WildberriesMarketplaceApi
from external.marketplace.yandex.core import YandexMarketplaceApi
from models import Marketplace
class MarketplaceApiFactory:
@staticmethod
def get_marketplace_api(marketplace: Marketplace):
match marketplace.base_marketplace_key:
case BaseMarketplace.WILDBERRIES:
return WildberriesMarketplaceApi(marketplace)
case BaseMarketplace.OZON:
return OzonMarketplaceApi(marketplace)
case BaseMarketplace.YANDEX_MARKET:
return YandexMarketplaceApi(marketplace)
case _:
raise ValueError(f"Unsupported marketplace: {marketplace.base_marketplace_key}")

1
external/marketplace/ozon/__init__.py vendored Normal file
View File

@@ -0,0 +1 @@
from .core import OzonMarketplaceApi

15
external/marketplace/ozon/core.py vendored Normal file
View File

@@ -0,0 +1,15 @@
from external.marketplace.base.core import BaseMarketplaceApi
from models import Marketplace
class OzonMarketplaceApi(BaseMarketplaceApi):
def __init__(self, marketplace: Marketplace):
pass
@property
def get_headers(self) -> dict:
return {}
@property
def base_url(self) -> str:
return ""

View File

@@ -0,0 +1 @@
from .core import WildberriesMarketplaceApi

View File

@@ -0,0 +1,86 @@
import time
from enum import StrEnum
from typing import AsyncIterator
from async_timeout import timeout
from external.marketplace.base.core import BaseMarketplaceApi
from models import Marketplace
class WildberriesApiUrl(StrEnum):
CONTENT = 'https://content-api.wildberries.ru'
DISCOUNTS_PRICES = 'https://discounts-prices-api.wildberries.ru'
SUPPLIES = 'https://supplies-api.wildberries.ru'
MARKETPLACE = 'https://marketplace-api.wildberries.ru'
STATISTICS = 'https://statistics-api.wildberries.ru'
SELLER_ANALYTICS = 'https://seller-analytics-api.wildberries.ru'
ADVERT = 'https://advert-api.wildberries.ru'
RECOMMEND = 'https://recommend-api.wildberries.ru'
FEEDBACKS = 'https://feedbacks-api.wildberries.ru'
COMMON = 'https://common-api.wildberries.ru'
BUYER_CHAT = 'https://buyer-chat-api.wildberries.ru'
RETURNS = 'https://returns-api.wildberries.ru'
DOCUMENTS = 'https://documents-api.wildberries.ru'
class WildberriesMarketplaceApi(BaseMarketplaceApi):
def __init__(self, marketplace: Marketplace):
token = marketplace.auth_data.get('Authorization')
if not token:
raise ValueError(
f"Authorization token is missing for Marketplace ID: {marketplace.id}. "
"Please check the marketplace credentials."
)
self.token = token
self.headers = {'Authorization': token}
self.marketplace = marketplace
@property
def get_headers(self) -> dict:
return self.headers
@property
def base_url(self) -> str:
return ""
async def get_products(self, data: dict) -> dict:
method = WildberriesApiUrl.CONTENT + '/content/v2/get/cards/list'
response = await self._method('POST', method, json=data)
return response
async def get_all_products(self) -> AsyncIterator[dict]:
limit = 100
updated_at = None
nm_id = None
while True:
data = {
'settings': {
'cursor': {
'limit': limit,
'updatedAt': updated_at,
'nmID': nm_id
},
'filter': {
'withPhoto': -1
}
}
}
start = time.time()
response = await self.get_products(data)
print(f'Request elapsed: {round(time.time() - start, 2)}')
if not response:
break
cards = response.get('cards')
if not cards:
break
for card in cards:
yield card
cursor = response.get('cursor')
total = cursor.get('total')
if total < limit:
break
updated_at = cursor.get('updatedAt')
nm_id = cursor.get('nmID')

View File

View File

@@ -0,0 +1 @@
from .core import YandexMarketplaceApi

15
external/marketplace/yandex/core.py vendored Normal file
View File

@@ -0,0 +1,15 @@
from external.marketplace.base.core import BaseMarketplaceApi
from models import Marketplace
class YandexMarketplaceApi(BaseMarketplaceApi):
def __init__(self, marketplace: Marketplace):
pass
@property
def get_headers(self) -> dict:
return {}
@property
def base_url(self) -> str:
return ""

View File

@@ -42,7 +42,8 @@ routers_list = [
routers.marketplace_router, routers.marketplace_router,
routers.payroll_router, routers.payroll_router,
routers.time_tracking_router, routers.time_tracking_router,
routers.billing_router routers.billing_router,
routers.task_router,
] ]
for router in routers_list: for router in routers_list:
app.include_router(router) app.include_router(router)

4
marketplaces/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
from .wildberries import WildberriesController
from .ozon import OzonController
from .yandex import YandexController
from .factory import MarketplaceControllerFactory

View File

@@ -0,0 +1 @@
from .core import BaseMarketplaceController

25
marketplaces/base/core.py Normal file
View File

@@ -0,0 +1,25 @@
from abc import ABC, abstractmethod
from typing import Union
from sqlalchemy.ext.asyncio import AsyncSession
from external.marketplace.factory import MarketplaceApiFactory
from external.marketplace.ozon.core import OzonMarketplaceApi
from external.marketplace.wildberries.core import WildberriesMarketplaceApi
from external.marketplace.yandex.core import YandexMarketplaceApi
from models import Marketplace
class BaseMarketplaceController(ABC):
api: Union[WildberriesMarketplaceApi, OzonMarketplaceApi, YandexMarketplaceApi]
marketplace: Marketplace
session: AsyncSession
def __init__(self, session: AsyncSession, marketplace: Marketplace):
self.api = MarketplaceApiFactory.get_marketplace_api(marketplace)
self.marketplace = marketplace
self.session = session
@abstractmethod
async def synchronize_products(self):
pass

28
marketplaces/factory.py Normal file
View File

@@ -0,0 +1,28 @@
from audioop import ratecv
from typing import Union
from sqlalchemy.ext.asyncio import AsyncSession
from enums.base_marketplace import BaseMarketplace
from marketplaces.ozon.core import OzonController
from marketplaces.wildberries.core import WildberriesController
from marketplaces.yandex.core import YandexController
from models import Marketplace
class MarketplaceControllerFactory:
@staticmethod
def get_controller(session: AsyncSession, marketplace: Marketplace) -> Union[
WildberriesController,
OzonController,
YandexController
]:
match marketplace.base_marketplace_key:
case BaseMarketplace.WILDBERRIES:
return WildberriesController(session, marketplace)
case BaseMarketplace.OZON:
return OzonController(session, marketplace)
case BaseMarketplace.YANDEX_MARKET:
return YandexController(session, marketplace)
case _:
raise ValueError(f"Unsupported marketplace: {marketplace.base_marketplace_key}")

View File

@@ -0,0 +1 @@
from .core import OzonController

View File

@@ -0,0 +1,6 @@
from marketplaces.base.core import BaseMarketplaceController
class OzonController(BaseMarketplaceController):
async def synchronize_products(self):
pass

View File

@@ -0,0 +1 @@
from .core import WildberriesController

View File

@@ -0,0 +1,76 @@
import time
from sqlalchemy import select
from external.marketplace.wildberries.core import WildberriesMarketplaceApi
from marketplaces.base.core import BaseMarketplaceController
from models import Product, ProductBarcode, ProductImage, WildberriesProduct
class WildberriesController(BaseMarketplaceController):
api: WildberriesMarketplaceApi
async def synchronize_products(self):
products = []
barcodes = []
images = []
wildberries_products = []
marketplace_id: int = self.marketplace.id
synchronized_nm_uuids = set(
(
await self.session.scalars(
select(
WildberriesProduct.nm_uuid
)
.where(
WildberriesProduct.marketplace_id == marketplace_id
)
)
).all()
)
async for card in self.api.get_all_products():
nm_uuid = card['nmUUID']
if nm_uuid in synchronized_nm_uuids:
continue
sizes: list[dict] = card.get('sizes') or []
for size in sizes:
tech_size = size.get('techSize')
wb_size = size.get('wbSize')
size_value = tech_size or wb_size
product = Product(
client_id=self.marketplace.client_id,
name=card['title'],
article=card['vendorCode'],
size=size_value
)
skus = size.get('skus') or []
for sku in skus:
barcode = ProductBarcode(
product=product,
barcode=sku
)
barcodes.append(barcode)
photos = card.get('photos') or []
for photo in photos:
image = ProductImage(
product=product,
image_url=photo['big']
)
images.append(image)
break
wildberries_product = WildberriesProduct(
marketplace_id=self.marketplace.id,
product=product,
nm_uuid=nm_uuid
)
wildberries_products.append(
wildberries_product
)
products.append(product)
instances = products + wildberries_products + barcodes + images
start = time.time()
self.session.add_all(instances)
await self.session.commit()
print(f'Add and commit elapsed: {time.time() - start}')

View File

@@ -0,0 +1 @@
from .core import YandexController

View File

@@ -0,0 +1,6 @@
from marketplaces.base.core import BaseMarketplaceController
class YandexController(BaseMarketplaceController):
async def synchronize_products(self):
pass

View File

@@ -11,5 +11,6 @@ from .shipping_warehouse import *
from .marketplace import * from .marketplace import *
from .payroll import * from .payroll import *
from .billing import * from .billing import *
from .marketplace_products import *
configure_mappers() configure_mappers()

View File

@@ -1,7 +1,12 @@
from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy import ForeignKey, JSON
from sqlalchemy.orm import Mapped, mapped_column, relationship
from typing_extensions import TYPE_CHECKING
from models import BaseModel from models import BaseModel
if TYPE_CHECKING:
from models import Client
class BaseMarketplace(BaseModel): class BaseMarketplace(BaseModel):
__tablename__ = 'base_marketplaces' __tablename__ = 'base_marketplaces'
@@ -9,3 +14,17 @@ class BaseMarketplace(BaseModel):
name: Mapped[str] = mapped_column() name: Mapped[str] = mapped_column()
icon_url: Mapped[str] = mapped_column() icon_url: Mapped[str] = mapped_column()
class Marketplace(BaseModel):
__tablename__ = 'marketplaces'
id: Mapped[int] = mapped_column(primary_key=True)
base_marketplace_key: Mapped[str] = mapped_column(ForeignKey("base_marketplaces.key"), nullable=False)
base_marketplace: Mapped["BaseMarketplace"] = relationship(lazy="joined")
client_id: Mapped[int] = mapped_column(ForeignKey('clients.id'), nullable=False, comment='ID клиента')
client: Mapped["Client"] = relationship('Client')
name: Mapped[str] = mapped_column(nullable=False)
auth_data: Mapped[dict] = mapped_column(type_=JSON)

View File

@@ -0,0 +1,39 @@
from sqlalchemy import ForeignKey
from sqlalchemy.orm import Mapped, relationship, mapped_column
from models import BaseModel
from models import Marketplace
from models import Product
class WildberriesProduct(BaseModel):
__tablename__ = 'wildberries_products'
marketplace_id: Mapped[int] = mapped_column(ForeignKey('marketplaces.id'), primary_key=True)
marketplace: Mapped["Marketplace"] = relationship()
product_id: Mapped[int] = mapped_column(ForeignKey('products.id'), primary_key=True)
product: Mapped["Product"] = relationship()
nm_uuid: Mapped[str] = mapped_column(nullable=False)
class OzonProduct(BaseModel):
__tablename__ = 'ozon_products'
marketplace_id: Mapped[int] = mapped_column(ForeignKey('marketplaces.id'), primary_key=True)
marketplace: Mapped["Marketplace"] = relationship()
product_id: Mapped[int] = mapped_column(ForeignKey('products.id'), primary_key=True)
product: Mapped["Product"] = relationship()
class YandexProduct(BaseModel):
__tablename__ = 'yandex_products'
marketplace_id: Mapped[int] = mapped_column(ForeignKey('marketplaces.id'), primary_key=True)
marketplace: Mapped["Marketplace"] = relationship()
product_id: Mapped[int] = mapped_column(ForeignKey('products.id'), primary_key=True)
product: Mapped["Product"] = relationship()

View File

@@ -1,8 +1,14 @@
from typing import TYPE_CHECKING
from sqlalchemy import Column, Integer, String, ForeignKey, Sequence from sqlalchemy import Column, Integer, String, ForeignKey, Sequence
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship, Mapped
from sqlalchemy.testing.schema import mapped_column
from models import BaseModel from models import BaseModel
if TYPE_CHECKING:
from models import Marketplace
class Product(BaseModel): class Product(BaseModel):
__tablename__ = 'products' __tablename__ = 'products'
@@ -30,11 +36,12 @@ class Product(BaseModel):
cascade="all, delete-orphan") cascade="all, delete-orphan")
class ProductImage(BaseModel): class ProductImage(BaseModel):
__tablename__ = 'product_images' __tablename__ = 'product_images'
id = Column(Integer, autoincrement=True, primary_key=True, index=True) id = Column(Integer, autoincrement=True, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey('products.id'), nullable=False) product_id = Column(Integer, ForeignKey('products.id'), nullable=False)
product = relationship('Product', back_populates='images') product: Mapped["Product"] = relationship(back_populates='images')
image_url = Column(String, nullable=False) image_url = Column(String, nullable=False)
@@ -42,6 +49,6 @@ class ProductImage(BaseModel):
class ProductBarcode(BaseModel): class ProductBarcode(BaseModel):
__tablename__ = 'product_barcodes' __tablename__ = 'product_barcodes'
product_id = Column(Integer, ForeignKey('products.id'), nullable=False, comment='ID товара', primary_key=True) product_id = Column(Integer, ForeignKey('products.id'), nullable=False, comment='ID товара', primary_key=True)
product = relationship('Product', back_populates='barcodes') product: Mapped["Product"] = relationship(back_populates='barcodes')
barcode = Column(String, nullable=False, index=True, comment='ШК товара', primary_key=True) barcode = Column(String, nullable=False, index=True, comment='ШК товара', primary_key=True)

View File

@@ -22,6 +22,7 @@ aiohttp
aiohttp[speedups] aiohttp[speedups]
openpyxl openpyxl
lexorank-py lexorank-py
celery[redis]
celery
# PDF # PDF
reportlab reportlab

View File

@@ -12,3 +12,4 @@ from .marketplace import marketplace_router
from .payroll import payroll_router from .payroll import payroll_router
from .time_tracking import time_tracking_router from .time_tracking import time_tracking_router
from .billing import billing_router from .billing import billing_router
from .task import task_router

View File

@@ -1,6 +1,6 @@
from typing import Annotated from typing import Annotated
from fastapi import APIRouter, Depends from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from backend.session import get_session from backend.session import get_session
@@ -16,3 +16,11 @@ auth_router = APIRouter(
@auth_router.post('/login', response_model=AuthLoginResponse) @auth_router.post('/login', response_model=AuthLoginResponse)
async def login(request: AuthLoginRequest, session: Annotated[AsyncSession, Depends(get_session)]): async def login(request: AuthLoginRequest, session: Annotated[AsyncSession, Depends(get_session)]):
return await AuthService(session).authenticate(request) return await AuthService(session).authenticate(request)
@auth_router.post('/test')
async def test(
request: Request
):
print(request.headers)
return {'a': "a"}

View File

@@ -16,6 +16,8 @@ client_router = APIRouter(
) )
@client_router.get('/search', operation_id='search_clients') @client_router.get('/search', operation_id='search_clients')
async def search_clients( async def search_clients(
name: str, name: str,
@@ -52,7 +54,7 @@ async def get_all_clients(
@client_router.post( @client_router.post(
'/create', '/create',
operation_id='create_client', operation_id='create_client_api',
response_model=ClientCreateResponse response_model=ClientCreateResponse
) )
async def create_client( async def create_client(

View File

@@ -21,3 +21,51 @@ async def get_all(
session: SessionDependency session: SessionDependency
): ):
return await MarketplaceService(session).get_all_base_marketplaces() return await MarketplaceService(session).get_all_base_marketplaces()
@marketplace_router.post(
'/get',
operation_id='get_client_marketplaces',
response_model=GetClientMarketplacesResponse
)
async def get(
session: SessionDependency,
request: GetClientMarketplacesRequest
):
return await MarketplaceService(session).get_client_marketplaces(request)
@marketplace_router.post(
'/create',
operation_id='create_marketplace',
response_model=CreateMarketplaceResponse
)
async def create(
session: SessionDependency,
request: CreateMarketplaceRequest
):
return await MarketplaceService(session).create_marketplace(request)
@marketplace_router.post(
'/delete',
operation_id='delete_marketplace',
response_model=DeleteMarketplaceResponse
)
async def delete(
session: SessionDependency,
request: DeleteMarketplaceRequest
):
return await MarketplaceService(session).delete_marketplace(request)
@marketplace_router.post(
'/update',
operation_id='update_marketplace',
response_model=UpdateMarketplaceResponse
)
async def update(
session: SessionDependency,
request: UpdateMarketplaceRequest
):
return await MarketplaceService(session).update_marketplace(request)

37
routers/task.py Normal file
View File

@@ -0,0 +1,37 @@
from celery.result import AsyncResult
from fastapi import APIRouter
import background.tasks.marketplace
from background.celery_app import celery
from schemas.task import *
task_router = APIRouter(
prefix='/task',
tags=["task"],
)
@task_router.post(
'/synchronize-marketplace',
operation_id='create_synchronize_marketplace_task',
response_model=CreateTaskResponse
)
async def synchronize_marketplace(
request: SynchronizeMarketplaceRequest
):
marketplace_id = request.marketplace_id
task: AsyncResult = background.tasks.marketplace.synchronize_marketplace.delay(marketplace_id)
return CreateTaskResponse(task_id=task.id)
@task_router.get(
'/info/{task_id}',
operation_id='get_task_info',
response_model=TaskInfoResponse
)
def task_info(task_id: str):
task = AsyncResult(task_id, app=celery)
return TaskInfoResponse(
task_id=task_id,
status=task.status
)

View File

@@ -1,6 +1,7 @@
from typing import List from typing import List
from schemas.base import BaseSchema from schemas.base import BaseSchema, OkMessageSchema
from schemas.client import ClientSchema
# region Entities # region Entities
@@ -10,13 +11,62 @@ class BaseMarketplaceSchema(BaseSchema):
icon_url: str icon_url: str
class MarketplaceMixin(BaseSchema):
name: str
base_marketplace: BaseMarketplaceSchema
client: ClientSchema
auth_data: dict
class MarketplaceCreateSchema(BaseSchema):
name: str
client_id: int
base_marketplace_key: str
auth_data: dict
class MarketplaceSchema(MarketplaceMixin):
id: int
# endregion # endregion
# region Requests # region Requests
class GetClientMarketplacesRequest(BaseSchema):
client_id: int
class CreateMarketplaceRequest(BaseSchema):
marketplace: MarketplaceCreateSchema
class DeleteMarketplaceRequest(BaseSchema):
marketplace_id: int
class UpdateMarketplaceRequest(BaseSchema):
marketplace: MarketplaceSchema
# endregion # endregion
# region Responses # region Responses
class GetAllBaseMarketplacesResponse(BaseSchema): class GetAllBaseMarketplacesResponse(BaseSchema):
base_marketplaces: List[BaseMarketplaceSchema] base_marketplaces: List[BaseMarketplaceSchema]
class GetClientMarketplacesResponse(BaseSchema):
marketplaces: List[MarketplaceSchema]
class CreateMarketplaceResponse(OkMessageSchema):
pass
class DeleteMarketplaceResponse(OkMessageSchema):
pass
class UpdateMarketplaceResponse(OkMessageSchema):
pass
# endregion # endregion

14
schemas/task.py Normal file
View File

@@ -0,0 +1,14 @@
from schemas.base import BaseSchema
class CreateTaskResponse(BaseSchema):
task_id: str
class TaskInfoResponse(BaseSchema):
task_id: str
status: str
class SynchronizeMarketplaceRequest(BaseSchema):
marketplace_id: int

View File

@@ -1,7 +1,9 @@
from sqlalchemy import select from pyexpat.errors import messages
from sqlalchemy import select, insert, delete, update
from sqlalchemy.orm import joinedload
from models import BaseMarketplace from models import BaseMarketplace, Marketplace
from schemas.marketplace import GetAllBaseMarketplacesResponse from schemas.marketplace import *
from services.base import BaseService from services.base import BaseService
@@ -12,3 +14,81 @@ class MarketplaceService(BaseService):
return GetAllBaseMarketplacesResponse( return GetAllBaseMarketplacesResponse(
base_marketplaces=base_marketplaces base_marketplaces=base_marketplaces
) )
async def get_client_marketplaces(self, request: GetClientMarketplacesRequest) -> GetClientMarketplacesResponse:
stmt = (
select(
Marketplace
)
.options(
joinedload(Marketplace.base_marketplace),
joinedload(Marketplace.client)
)
.where(
Marketplace.client_id == request.client_id
)
)
marketplaces = (await self.session.scalars(stmt)).all()
return GetClientMarketplacesResponse(
marketplaces=marketplaces
)
async def create_marketplace(self, request: CreateMarketplaceRequest) -> CreateMarketplaceResponse:
try:
marketplace = request.marketplace
marketplace_dict = marketplace.dict()
stmt = (
insert(Marketplace)
.values(
**marketplace_dict
)
)
await self.session.execute(stmt)
await self.session.commit()
return CreateMarketplaceResponse(ok=True, message='Маркетплейс успешно создан')
except Exception as e:
await self.session.rollback()
return CreateMarketplaceResponse(ok=False, message=str(e))
async def delete_marketplace(self, request: DeleteMarketplaceRequest) -> DeleteMarketplaceResponse:
try:
stmt = (
delete(Marketplace)
.where(
Marketplace.id == request.marketplace_id
)
)
await self.session.execute(stmt)
await self.session.commit()
return DeleteMarketplaceResponse(ok=True, message='Маркетплейс успешно удален')
except Exception as e:
await self.session.rollback()
return DeleteMarketplaceResponse(ok=False, message=str(e))
async def update_marketplace(self, request: UpdateMarketplaceRequest) -> UpdateMarketplaceResponse:
try:
marketplace = request.marketplace
marketplace_dict = marketplace.dict()
del marketplace_dict['id']
del marketplace_dict['base_marketplace']
del marketplace_dict['client']
marketplace_dict['base_marketplace_key'] = marketplace.base_marketplace.key
marketplace_dict['client_id'] = marketplace.client.id
stmt = (
update(
Marketplace
)
.values(
**marketplace_dict
)
.where(
Marketplace.id == marketplace.id
)
)
await self.session.execute(stmt)
await self.session.commit()
return UpdateMarketplaceResponse(ok=True, message='Маркетплейс успешно обновлен')
except Exception as e:
await self.session.rollback()
return UpdateMarketplaceResponse(ok=False, message=str(e))