feat: a lot of a lot
This commit is contained in:
		@@ -18,3 +18,8 @@ SECRET_KEY = os.environ.get('SECRET_KEY')
 | 
			
		||||
S3_API_KEY = os.environ.get('S3_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
									
								
							
							
						
						
									
										0
									
								
								background/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										14
									
								
								background/celery_app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								background/celery_app.py
									
									
									
									
									
										Normal 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 *
 | 
			
		||||
							
								
								
									
										1
									
								
								background/tasks/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								background/tasks/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .marketplace import synchronize_marketplace
 | 
			
		||||
							
								
								
									
										20
									
								
								background/tasks/marketplace.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								background/tasks/marketplace.py
									
									
									
									
									
										Normal 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()
 | 
			
		||||
@@ -17,7 +17,7 @@ class DefaultBarcodeGenerator(BaseBarcodeGenerator):
 | 
			
		||||
            if not attribute_getter:
 | 
			
		||||
                continue
 | 
			
		||||
            value = attribute_getter.get_value(product)
 | 
			
		||||
            if not value:
 | 
			
		||||
            if not value or not value.strip():
 | 
			
		||||
                continue
 | 
			
		||||
            attributes[attribute.name] = value
 | 
			
		||||
        for additional_attribute in template.additional_attributes:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										0
									
								
								decorators/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								decorators/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										19
									
								
								decorators/async_utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								decorators/async_utils.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										4
									
								
								external/marketplace/__init__.py
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										1
									
								
								external/marketplace/base/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import BaseMarketplaceApi
 | 
			
		||||
							
								
								
									
										28
									
								
								external/marketplace/base/core.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								external/marketplace/base/core.py
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										19
									
								
								external/marketplace/factory.py
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										1
									
								
								external/marketplace/ozon/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import OzonMarketplaceApi
 | 
			
		||||
							
								
								
									
										15
									
								
								external/marketplace/ozon/core.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								external/marketplace/ozon/core.py
									
									
									
									
										vendored
									
									
										Normal 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 ""
 | 
			
		||||
							
								
								
									
										1
									
								
								external/marketplace/wildberries/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								external/marketplace/wildberries/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import WildberriesMarketplaceApi
 | 
			
		||||
							
								
								
									
										86
									
								
								external/marketplace/wildberries/core.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								external/marketplace/wildberries/core.py
									
									
									
									
										vendored
									
									
										Normal 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')
 | 
			
		||||
							
								
								
									
										0
									
								
								external/marketplace/wildberries/schemas.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								external/marketplace/wildberries/schemas.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								external/marketplace/yandex/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								external/marketplace/yandex/__init__.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import YandexMarketplaceApi
 | 
			
		||||
							
								
								
									
										15
									
								
								external/marketplace/yandex/core.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								external/marketplace/yandex/core.py
									
									
									
									
										vendored
									
									
										Normal 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 ""
 | 
			
		||||
							
								
								
									
										3
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								main.py
									
									
									
									
									
								
							@@ -42,7 +42,8 @@ routers_list = [
 | 
			
		||||
    routers.marketplace_router,
 | 
			
		||||
    routers.payroll_router,
 | 
			
		||||
    routers.time_tracking_router,
 | 
			
		||||
    routers.billing_router
 | 
			
		||||
    routers.billing_router,
 | 
			
		||||
    routers.task_router,
 | 
			
		||||
]
 | 
			
		||||
for router in routers_list:
 | 
			
		||||
    app.include_router(router)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								marketplaces/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								marketplaces/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
from .wildberries import WildberriesController
 | 
			
		||||
from .ozon import OzonController
 | 
			
		||||
from .yandex import YandexController
 | 
			
		||||
from .factory import MarketplaceControllerFactory
 | 
			
		||||
							
								
								
									
										1
									
								
								marketplaces/base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								marketplaces/base/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import BaseMarketplaceController
 | 
			
		||||
							
								
								
									
										25
									
								
								marketplaces/base/core.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								marketplaces/base/core.py
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										28
									
								
								marketplaces/factory.py
									
									
									
									
									
										Normal 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}")
 | 
			
		||||
							
								
								
									
										1
									
								
								marketplaces/ozon/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								marketplaces/ozon/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import OzonController
 | 
			
		||||
							
								
								
									
										6
									
								
								marketplaces/ozon/core.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								marketplaces/ozon/core.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
from marketplaces.base.core import BaseMarketplaceController
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OzonController(BaseMarketplaceController):
 | 
			
		||||
    async def synchronize_products(self):
 | 
			
		||||
        pass
 | 
			
		||||
							
								
								
									
										1
									
								
								marketplaces/wildberries/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								marketplaces/wildberries/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import WildberriesController
 | 
			
		||||
							
								
								
									
										76
									
								
								marketplaces/wildberries/core.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								marketplaces/wildberries/core.py
									
									
									
									
									
										Normal 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}')
 | 
			
		||||
							
								
								
									
										1
									
								
								marketplaces/yandex/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								marketplaces/yandex/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
from .core import YandexController
 | 
			
		||||
							
								
								
									
										6
									
								
								marketplaces/yandex/core.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								marketplaces/yandex/core.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
from marketplaces.base.core import BaseMarketplaceController
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class YandexController(BaseMarketplaceController):
 | 
			
		||||
    async def synchronize_products(self):
 | 
			
		||||
        pass
 | 
			
		||||
@@ -11,5 +11,6 @@ from .shipping_warehouse import *
 | 
			
		||||
from .marketplace import *
 | 
			
		||||
from .payroll import *
 | 
			
		||||
from .billing import *
 | 
			
		||||
from .marketplace_products import *
 | 
			
		||||
 | 
			
		||||
configure_mappers()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
if TYPE_CHECKING:
 | 
			
		||||
    from models import Client
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseMarketplace(BaseModel):
 | 
			
		||||
    __tablename__ = 'base_marketplaces'
 | 
			
		||||
@@ -9,3 +14,17 @@ class BaseMarketplace(BaseModel):
 | 
			
		||||
    name: 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)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										39
									
								
								models/marketplace_products.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								models/marketplace_products.py
									
									
									
									
									
										Normal 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()
 | 
			
		||||
@@ -1,8 +1,14 @@
 | 
			
		||||
from typing import TYPE_CHECKING
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
if TYPE_CHECKING:
 | 
			
		||||
    from models import Marketplace
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Product(BaseModel):
 | 
			
		||||
    __tablename__ = 'products'
 | 
			
		||||
@@ -30,11 +36,12 @@ class Product(BaseModel):
 | 
			
		||||
                          cascade="all, delete-orphan")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProductImage(BaseModel):
 | 
			
		||||
    __tablename__ = 'product_images'
 | 
			
		||||
    id = Column(Integer, autoincrement=True, primary_key=True, index=True)
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
@@ -42,6 +49,6 @@ class ProductImage(BaseModel):
 | 
			
		||||
class ProductBarcode(BaseModel):
 | 
			
		||||
    __tablename__ = 'product_barcodes'
 | 
			
		||||
    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)
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@ aiohttp
 | 
			
		||||
aiohttp[speedups]
 | 
			
		||||
openpyxl
 | 
			
		||||
lexorank-py
 | 
			
		||||
 | 
			
		||||
celery[redis]
 | 
			
		||||
celery
 | 
			
		||||
# PDF
 | 
			
		||||
reportlab
 | 
			
		||||
@@ -12,3 +12,4 @@ from .marketplace import marketplace_router
 | 
			
		||||
from .payroll import payroll_router
 | 
			
		||||
from .time_tracking import time_tracking_router
 | 
			
		||||
from .billing import billing_router
 | 
			
		||||
from .task import task_router
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
from typing import Annotated
 | 
			
		||||
 | 
			
		||||
from fastapi import APIRouter, Depends
 | 
			
		||||
from fastapi import APIRouter, Depends, Request
 | 
			
		||||
from sqlalchemy.ext.asyncio import AsyncSession
 | 
			
		||||
 | 
			
		||||
from backend.session import get_session
 | 
			
		||||
@@ -16,3 +16,11 @@ auth_router = APIRouter(
 | 
			
		||||
@auth_router.post('/login', response_model=AuthLoginResponse)
 | 
			
		||||
async def login(request: AuthLoginRequest, session: Annotated[AsyncSession, Depends(get_session)]):
 | 
			
		||||
    return await AuthService(session).authenticate(request)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@auth_router.post('/test')
 | 
			
		||||
async def test(
 | 
			
		||||
        request: Request
 | 
			
		||||
):
 | 
			
		||||
    print(request.headers)
 | 
			
		||||
    return {'a': "a"}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,8 @@ client_router = APIRouter(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@client_router.get('/search', operation_id='search_clients')
 | 
			
		||||
async def search_clients(
 | 
			
		||||
        name: str,
 | 
			
		||||
@@ -52,7 +54,7 @@ async def get_all_clients(
 | 
			
		||||
 | 
			
		||||
@client_router.post(
 | 
			
		||||
    '/create',
 | 
			
		||||
    operation_id='create_client',
 | 
			
		||||
    operation_id='create_client_api',
 | 
			
		||||
    response_model=ClientCreateResponse
 | 
			
		||||
)
 | 
			
		||||
async def create_client(
 | 
			
		||||
 
 | 
			
		||||
@@ -21,3 +21,51 @@ async def get_all(
 | 
			
		||||
        session: SessionDependency
 | 
			
		||||
):
 | 
			
		||||
    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
									
								
							
							
						
						
									
										37
									
								
								routers/task.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
    )
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
from typing import List
 | 
			
		||||
 | 
			
		||||
from schemas.base import BaseSchema
 | 
			
		||||
from schemas.base import BaseSchema, OkMessageSchema
 | 
			
		||||
from schemas.client import ClientSchema
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# region Entities
 | 
			
		||||
@@ -10,13 +11,62 @@ class BaseMarketplaceSchema(BaseSchema):
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
# region Responses
 | 
			
		||||
class GetAllBaseMarketplacesResponse(BaseSchema):
 | 
			
		||||
    base_marketplaces: List[BaseMarketplaceSchema]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GetClientMarketplacesResponse(BaseSchema):
 | 
			
		||||
    marketplaces: List[MarketplaceSchema]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CreateMarketplaceResponse(OkMessageSchema):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DeleteMarketplaceResponse(OkMessageSchema):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
class UpdateMarketplaceResponse(OkMessageSchema):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
# endregion
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								schemas/task.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								schemas/task.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -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 schemas.marketplace import GetAllBaseMarketplacesResponse
 | 
			
		||||
from models import BaseMarketplace, Marketplace
 | 
			
		||||
from schemas.marketplace import *
 | 
			
		||||
from services.base import BaseService
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -12,3 +14,81 @@ class MarketplaceService(BaseService):
 | 
			
		||||
        return GetAllBaseMarketplacesResponse(
 | 
			
		||||
            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))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user