v1.0
This commit is contained in:
@@ -3,11 +3,17 @@ import os
|
|||||||
from dotenv import load_dotenv, find_dotenv
|
from dotenv import load_dotenv, find_dotenv
|
||||||
|
|
||||||
load_dotenv(find_dotenv())
|
load_dotenv(find_dotenv())
|
||||||
|
|
||||||
|
# Database
|
||||||
PG_LOGIN = os.environ.get('PG_LOGIN')
|
PG_LOGIN = os.environ.get('PG_LOGIN')
|
||||||
PG_PASSWORD = os.environ.get('PG_PASSWORD')
|
PG_PASSWORD = os.environ.get('PG_PASSWORD')
|
||||||
PG_PORT = os.environ.get('PG_PORT')
|
PG_PORT = os.environ.get('PG_PORT')
|
||||||
PG_HOST = os.environ.get('PG_HOST')
|
PG_HOST = os.environ.get('PG_HOST')
|
||||||
PG_DATABASE = os.environ.get('PG_DATABASE')
|
PG_DATABASE = os.environ.get('PG_DATABASE')
|
||||||
|
|
||||||
|
# Celery
|
||||||
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL')
|
CELERY_BROKER_URL = os.environ.get('CELERY_BROKER_URL')
|
||||||
CELERY_RESULT_BACKEND = os.environ.get('CELERY_RESULT_BACKEND')
|
CELERY_RESULT_BACKEND = os.environ.get('CELERY_RESULT_BACKEND')
|
||||||
|
|
||||||
|
# Yandex
|
||||||
|
YANDEX_CLIENT_ID = os.environ.get('YANDEX_CLIENT_ID')
|
||||||
|
|||||||
@@ -15,8 +15,16 @@ database_url = (
|
|||||||
f"{PG_LOGIN}:{PG_PASSWORD}@"
|
f"{PG_LOGIN}:{PG_PASSWORD}@"
|
||||||
f"{PG_HOST}:{PG_PORT}/{PG_DATABASE}"
|
f"{PG_HOST}:{PG_PORT}/{PG_DATABASE}"
|
||||||
)
|
)
|
||||||
engine = create_async_engine(database_url)
|
engine = create_async_engine(database_url,
|
||||||
session_factory = async_sessionmaker(engine, expire_on_commit=False, autoflush=False, autocommit=False)
|
pool_size=20,
|
||||||
|
max_overflow=10
|
||||||
|
)
|
||||||
|
session_factory = async_sessionmaker(
|
||||||
|
engine,
|
||||||
|
expire_on_commit=False,
|
||||||
|
autoflush=False,
|
||||||
|
autocommit=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
from typing import List, Union
|
||||||
|
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
|
|
||||||
@@ -10,3 +11,15 @@ import background.update
|
|||||||
def process_update(product_ids: list[int]):
|
def process_update(product_ids: list[int]):
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
return loop.run_until_complete(background.update.process_update(product_ids))
|
return loop.run_until_complete(background.update.process_update(product_ids))
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task(name='update_marketplace')
|
||||||
|
def update_marketplace(marketplace_id: int):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
return loop.run_until_complete(background.update.update_marketplace(marketplace_id))
|
||||||
|
|
||||||
|
|
||||||
|
@celery.task(name='update_marketplaces')
|
||||||
|
async def update_marketplaces(marketplace_ids: Union[List[int], None]):
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
return loop.run_until_complete(background.update.update_marketplaces(marketplace_ids))
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
import time
|
from typing import Union, List
|
||||||
|
|
||||||
from backend.session import get_session
|
from backend.session import session_factory
|
||||||
from schemas.general import StockUpdate
|
from schemas.general import StockUpdate
|
||||||
from updaters.stocks_updater import StocksUpdater
|
from updaters.stocks_updater import StocksUpdater
|
||||||
|
|
||||||
|
|
||||||
async def process_update(product_ids: list[int]):
|
async def process_update(product_ids: list[int]):
|
||||||
async for session in get_session():
|
async with session_factory() as session:
|
||||||
updates = [StockUpdate(product_id=product_id) for product_id in product_ids]
|
updates = [StockUpdate(product_id=product_id) for product_id in product_ids]
|
||||||
updater = StocksUpdater(session)
|
updater = StocksUpdater(session)
|
||||||
await updater.update(updates)
|
await updater.update(updates)
|
||||||
await session.close()
|
return {'message': f'Stocks for products [{",".join(map(str, product_ids))}] successfully updated'}
|
||||||
return {'message': f'Stocks for [{",".join(map(str, product_ids))}] successfully updated'}
|
|
||||||
|
|
||||||
|
async def update_marketplace(marketplace_id: int):
|
||||||
|
async with session_factory() as session:
|
||||||
|
updater = StocksUpdater(session)
|
||||||
|
await updater.full_update_marketplace(marketplace_id)
|
||||||
|
return {'message': f'Stocks for marketplace {marketplace_id} successfully updated'}
|
||||||
|
|
||||||
|
|
||||||
|
async def update_marketplaces(marketplace_ids: Union[List[int], None]):
|
||||||
|
async with session_factory() as session:
|
||||||
|
updater = StocksUpdater(session)
|
||||||
|
await updater.full_update_all_marketplaces(marketplace_ids)
|
||||||
|
return {'message': f'Stocks for marketplaces [{",".join(map(str, marketplace_ids))}] successfully updated'}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ class Company(BaseSiproModel):
|
|||||||
is_denco: Mapped[bool] = mapped_column()
|
is_denco: Mapped[bool] = mapped_column()
|
||||||
balance: Mapped[int] = mapped_column()
|
balance: Mapped[int] = mapped_column()
|
||||||
|
|
||||||
|
is_deleted: Mapped[bool] = mapped_column()
|
||||||
|
is_archived: Mapped[bool] = mapped_column()
|
||||||
|
|
||||||
|
|
||||||
class CompanyWarehouse(BaseSiproModel):
|
class CompanyWarehouse(BaseSiproModel):
|
||||||
__tablename__ = 'company_warehouses'
|
__tablename__ = 'company_warehouses'
|
||||||
@@ -49,9 +52,12 @@ class Marketplace(BaseSiproModel):
|
|||||||
sell_blocks: Mapped[bool] = mapped_column()
|
sell_blocks: Mapped[bool] = mapped_column()
|
||||||
sell_warehouse_products: Mapped[bool] = mapped_column()
|
sell_warehouse_products: Mapped[bool] = mapped_column()
|
||||||
sell_from_price: Mapped[bool] = mapped_column()
|
sell_from_price: Mapped[bool] = mapped_column()
|
||||||
|
is_deleted: Mapped[bool] = mapped_column()
|
||||||
|
|
||||||
warehouses: Mapped[List["Warehouse"]] = relationship(secondary=marketplace_warehouses)
|
warehouses: Mapped[List["Warehouse"]] = relationship(secondary=marketplace_warehouses)
|
||||||
warehouse_id: Mapped[str] = mapped_column()
|
warehouse_id: Mapped[str] = mapped_column()
|
||||||
|
|
||||||
company_id: Mapped[int] = mapped_column(ForeignKey('companies.id'))
|
company_id: Mapped[int] = mapped_column(ForeignKey('companies.id'))
|
||||||
company: Mapped["Company"] = relationship()
|
company: Mapped["Company"] = relationship()
|
||||||
|
|
||||||
|
campaign_id: Mapped[str] = mapped_column()
|
||||||
|
|||||||
18
main.py
18
main.py
@@ -8,7 +8,7 @@ from starlette.responses import JSONResponse
|
|||||||
|
|
||||||
import background.tasks
|
import background.tasks
|
||||||
from background.tasks import *
|
from background.tasks import *
|
||||||
from schemas.general import UpdateRequest, UpdateResponse
|
from schemas.general import UpdateRequest, UpdateResponse, UpdateMarketplaceRequest, UpdateMarketplacesRequest
|
||||||
|
|
||||||
auth_schema = HTTPBearer()
|
auth_schema = HTTPBearer()
|
||||||
|
|
||||||
@@ -34,6 +34,22 @@ async def update(
|
|||||||
return UpdateResponse(task_id=task.id)
|
return UpdateResponse(task_id=task.id)
|
||||||
|
|
||||||
|
|
||||||
|
@app.post('/update/marketplace')
|
||||||
|
async def update_marketplace(
|
||||||
|
request: UpdateMarketplaceRequest
|
||||||
|
):
|
||||||
|
task = background.tasks.update_marketplace.delay(request.marketplace_id)
|
||||||
|
return UpdateResponse(task_id=task.id)
|
||||||
|
|
||||||
|
|
||||||
|
@app.post('/update/marketplaces')
|
||||||
|
async def update_marketplace(
|
||||||
|
request: UpdateMarketplacesRequest
|
||||||
|
):
|
||||||
|
task = background.tasks.update_marketplaces.delay(request.marketplace_ids)
|
||||||
|
return UpdateResponse(task_id=task.id)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/tasks/{task_id}")
|
@app.get("/tasks/{task_id}")
|
||||||
def get_status(task_id):
|
def get_status(task_id):
|
||||||
task_result = AsyncResult(task_id)
|
task_result = AsyncResult(task_id)
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class BaseMarketplaceApi(ABC):
|
|||||||
async def _method(self, http_method: Literal['POST', 'GET', 'PATCH', 'PUT', 'DELETE'],
|
async def _method(self, http_method: Literal['POST', 'GET', 'PATCH', 'PUT', 'DELETE'],
|
||||||
method: str,
|
method: str,
|
||||||
data: dict) -> ClientResponse:
|
data: dict) -> ClientResponse:
|
||||||
|
return
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
return await session.request(http_method,
|
return await session.request(http_method,
|
||||||
f'{self.api_url}{method}',
|
f'{self.api_url}{method}',
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from database import Marketplace
|
|||||||
from database.sipro.enums.general import BaseMarketplace
|
from database.sipro.enums.general import BaseMarketplace
|
||||||
from .wildberries import WildberriesMarketplaceApi
|
from .wildberries import WildberriesMarketplaceApi
|
||||||
from .ozon import OzonMarketplaceApi
|
from .ozon import OzonMarketplaceApi
|
||||||
|
from .yandexmarket import YandexmarketMarketplaceApi
|
||||||
|
|
||||||
|
|
||||||
class MarketplaceApiFactory:
|
class MarketplaceApiFactory:
|
||||||
@@ -11,9 +12,12 @@ class MarketplaceApiFactory:
|
|||||||
def get_marketplace_api(marketplace: Marketplace) -> Union[
|
def get_marketplace_api(marketplace: Marketplace) -> Union[
|
||||||
WildberriesMarketplaceApi,
|
WildberriesMarketplaceApi,
|
||||||
OzonMarketplaceApi,
|
OzonMarketplaceApi,
|
||||||
|
YandexmarketMarketplaceApi
|
||||||
]:
|
]:
|
||||||
match marketplace.base_marketplace:
|
match marketplace.base_marketplace:
|
||||||
case BaseMarketplace.OZON:
|
case BaseMarketplace.OZON:
|
||||||
return OzonMarketplaceApi(marketplace)
|
return OzonMarketplaceApi(marketplace)
|
||||||
case BaseMarketplace.WILDBERRIES:
|
case BaseMarketplace.WILDBERRIES:
|
||||||
return WildberriesMarketplaceApi(marketplace)
|
return WildberriesMarketplaceApi(marketplace)
|
||||||
|
case BaseMarketplace.YANDEX_MARKET:
|
||||||
|
return YandexmarketMarketplaceApi(marketplace)
|
||||||
|
|||||||
58
marketplaces/yandexmarket.py
Normal file
58
marketplaces/yandexmarket.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from backend.config import YANDEX_CLIENT_ID
|
||||||
|
from database import Marketplace
|
||||||
|
from limiter import BatchLimiter
|
||||||
|
from marketplaces.base import BaseMarketplaceApi
|
||||||
|
from utils import chunk_list
|
||||||
|
|
||||||
|
|
||||||
|
class YandexmarketMarketplaceApi(BaseMarketplaceApi):
|
||||||
|
def __init__(self, marketplace: Marketplace):
|
||||||
|
self.marketplace = marketplace
|
||||||
|
auth_data = json.loads(marketplace.auth_data)
|
||||||
|
access_token = auth_data.get('accessToken')
|
||||||
|
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'OAuth oauth_token="{access_token}", oauth_client_id="{YANDEX_CLIENT_ID}"'
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_headers(self):
|
||||||
|
return self.headers
|
||||||
|
|
||||||
|
@property
|
||||||
|
def api_url(self):
|
||||||
|
return 'https://api.partner.market.yandex.ru/v2'
|
||||||
|
|
||||||
|
async def update_stocks(self, data: Union[list, dict]):
|
||||||
|
if type(data) is not list:
|
||||||
|
return
|
||||||
|
campaign_id = self.marketplace.campaign_id
|
||||||
|
max_stocks = 2000
|
||||||
|
chunks = chunk_list(data, max_stocks)
|
||||||
|
limiter = BatchLimiter(max_requests=50, period=60)
|
||||||
|
|
||||||
|
async def send_stock_chunk(chunk):
|
||||||
|
try:
|
||||||
|
await limiter.acquire()
|
||||||
|
request_data = {
|
||||||
|
'skus': chunk
|
||||||
|
}
|
||||||
|
response = await self._method('PUT',
|
||||||
|
f'/campaigns/{campaign_id}/offers/stocks',
|
||||||
|
data=request_data)
|
||||||
|
print(request_data)
|
||||||
|
rsp = await response.json()
|
||||||
|
print(rsp)
|
||||||
|
if response.status != 200:
|
||||||
|
logging.warning(
|
||||||
|
f'Error occurred when sending stocks to [{self.marketplace.id}]')
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(
|
||||||
|
f'Exception occurred while sending stocks to marketplace ID [{self.marketplace.id}]: {str(e)}')
|
||||||
|
|
||||||
|
tasks = [send_stock_chunk(chunk) for chunk in chunks]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
@@ -289,10 +289,6 @@ async def get_stocks_data(
|
|||||||
slaves_stock_subquery.c.product_id == MarketplaceProduct.product_id
|
slaves_stock_subquery.c.product_id == MarketplaceProduct.product_id
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
print('-------------------------')
|
|
||||||
print(stmt.compile(compile_kwargs={
|
|
||||||
'literal_binds': True
|
|
||||||
}))
|
|
||||||
result = await session.execute(stmt)
|
result = await session.execute(stmt)
|
||||||
marketplace_products = result.all()
|
marketplace_products = result.all()
|
||||||
response: List[StockData] = []
|
response: List[StockData] = []
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Union, List
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
@@ -13,7 +14,15 @@ class BaseSchema(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class UpdateRequest(BaseSchema):
|
class UpdateRequest(BaseSchema):
|
||||||
product_ids: list[int]
|
product_ids: List[int]
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateMarketplaceRequest(BaseSchema):
|
||||||
|
marketplace_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateMarketplacesRequest(BaseSchema):
|
||||||
|
marketplace_ids: Union[List[int], None] = None
|
||||||
|
|
||||||
|
|
||||||
class UpdateResponse(BaseSchema):
|
class UpdateResponse(BaseSchema):
|
||||||
|
|||||||
514
test.py
514
test.py
@@ -1,7 +1,509 @@
|
|||||||
a = [
|
import asyncio
|
||||||
(1, [1, 4, 5, ]),
|
import time
|
||||||
(2, [1, 2, 3, 4, 5, ]),
|
|
||||||
]
|
|
||||||
|
|
||||||
updates_list = sorted(a, key=lambda x: x[1], reverse=True)
|
from background.update import process_update
|
||||||
print(updates_list)
|
|
||||||
|
A = [46806,
|
||||||
|
50457,
|
||||||
|
5294,
|
||||||
|
50455,
|
||||||
|
1263604,
|
||||||
|
3153,
|
||||||
|
1281166,
|
||||||
|
60075,
|
||||||
|
1266284,
|
||||||
|
1255288,
|
||||||
|
1430906,
|
||||||
|
1430905,
|
||||||
|
1430909,
|
||||||
|
1430911,
|
||||||
|
1430908,
|
||||||
|
1233617,
|
||||||
|
1274809,
|
||||||
|
1269081,
|
||||||
|
1216052,
|
||||||
|
5281,
|
||||||
|
1240583,
|
||||||
|
1215881,
|
||||||
|
1262205,
|
||||||
|
1263362,
|
||||||
|
1260217,
|
||||||
|
1269043,
|
||||||
|
1261160,
|
||||||
|
1262930,
|
||||||
|
1199011,
|
||||||
|
1244985,
|
||||||
|
1256197,
|
||||||
|
1259971,
|
||||||
|
1275109,
|
||||||
|
1277923,
|
||||||
|
1266093,
|
||||||
|
1269905,
|
||||||
|
1262068,
|
||||||
|
1272526,
|
||||||
|
1269918,
|
||||||
|
1272247,
|
||||||
|
14802,
|
||||||
|
1690206,
|
||||||
|
1265012,
|
||||||
|
1268765,
|
||||||
|
1258451,
|
||||||
|
1199922,
|
||||||
|
1264652,
|
||||||
|
1206165,
|
||||||
|
1276134,
|
||||||
|
1276758,
|
||||||
|
1277343,
|
||||||
|
1277346,
|
||||||
|
1262974,
|
||||||
|
1323227,
|
||||||
|
1280821,
|
||||||
|
1276512,
|
||||||
|
1688415,
|
||||||
|
1274390,
|
||||||
|
1273690,
|
||||||
|
1268750,
|
||||||
|
1268054,
|
||||||
|
1266939,
|
||||||
|
1262254,
|
||||||
|
1262238,
|
||||||
|
1261898,
|
||||||
|
1260348,
|
||||||
|
1258610,
|
||||||
|
1256746,
|
||||||
|
1255706,
|
||||||
|
1255696,
|
||||||
|
1255692,
|
||||||
|
1255500,
|
||||||
|
1255496,
|
||||||
|
1677398,
|
||||||
|
1255053,
|
||||||
|
1255052,
|
||||||
|
1255027,
|
||||||
|
1255024,
|
||||||
|
1255020,
|
||||||
|
1254967,
|
||||||
|
1254966,
|
||||||
|
1254964,
|
||||||
|
1254751,
|
||||||
|
1254750,
|
||||||
|
1253996,
|
||||||
|
1253739,
|
||||||
|
1252160,
|
||||||
|
1252157,
|
||||||
|
1242300,
|
||||||
|
1256578,
|
||||||
|
1256194,
|
||||||
|
1255177,
|
||||||
|
1278124,
|
||||||
|
1267797,
|
||||||
|
1266537,
|
||||||
|
1277673,
|
||||||
|
1235438,
|
||||||
|
1256819,
|
||||||
|
62484,
|
||||||
|
1260874,
|
||||||
|
1257620,
|
||||||
|
1273799,
|
||||||
|
53141,
|
||||||
|
1257730,
|
||||||
|
1272776,
|
||||||
|
1268129,
|
||||||
|
1257068,
|
||||||
|
1256919,
|
||||||
|
1234979,
|
||||||
|
1254460,
|
||||||
|
1254578,
|
||||||
|
1258563,
|
||||||
|
1253242,
|
||||||
|
1263602,
|
||||||
|
1254576,
|
||||||
|
1255015,
|
||||||
|
1254981,
|
||||||
|
1253646,
|
||||||
|
1261321,
|
||||||
|
1273813,
|
||||||
|
1255242,
|
||||||
|
1274598,
|
||||||
|
1214897,
|
||||||
|
1273279,
|
||||||
|
2172,
|
||||||
|
1231462,
|
||||||
|
1257310,
|
||||||
|
1253645,
|
||||||
|
1242885,
|
||||||
|
1747377,
|
||||||
|
1233273,
|
||||||
|
1220800,
|
||||||
|
1257333,
|
||||||
|
1256133,
|
||||||
|
1253956,
|
||||||
|
1663,
|
||||||
|
1771,
|
||||||
|
1272628,
|
||||||
|
1270851,
|
||||||
|
57977,
|
||||||
|
1257159,
|
||||||
|
1258366,
|
||||||
|
1274675,
|
||||||
|
1228267,
|
||||||
|
1267046,
|
||||||
|
1277962,
|
||||||
|
1255028,
|
||||||
|
1273500,
|
||||||
|
57994,
|
||||||
|
58014,
|
||||||
|
57995,
|
||||||
|
1425848,
|
||||||
|
1255218,
|
||||||
|
1255032,
|
||||||
|
1257132,
|
||||||
|
1276552,
|
||||||
|
1272983,
|
||||||
|
1272984,
|
||||||
|
1270101,
|
||||||
|
1257311,
|
||||||
|
1266716,
|
||||||
|
1255420,
|
||||||
|
1265283,
|
||||||
|
1269404,
|
||||||
|
1265309,
|
||||||
|
50749,
|
||||||
|
57941,
|
||||||
|
62110,
|
||||||
|
1265942,
|
||||||
|
1255744,
|
||||||
|
52862,
|
||||||
|
1274446,
|
||||||
|
41851,
|
||||||
|
1263009,
|
||||||
|
1253446,
|
||||||
|
4633,
|
||||||
|
21392,
|
||||||
|
1264372,
|
||||||
|
1264231,
|
||||||
|
53052,
|
||||||
|
1264656,
|
||||||
|
1262555,
|
||||||
|
1262009,
|
||||||
|
1265287,
|
||||||
|
1278725,
|
||||||
|
1268653,
|
||||||
|
1268652,
|
||||||
|
1268651,
|
||||||
|
1278044,
|
||||||
|
1353805,
|
||||||
|
1270730,
|
||||||
|
1253802,
|
||||||
|
1255266,
|
||||||
|
1230815,
|
||||||
|
1269405,
|
||||||
|
1274444,
|
||||||
|
1274445,
|
||||||
|
1205670,
|
||||||
|
1268767,
|
||||||
|
1268761,
|
||||||
|
1255679,
|
||||||
|
1252820,
|
||||||
|
1276125,
|
||||||
|
1253954,
|
||||||
|
1268790,
|
||||||
|
1268789,
|
||||||
|
1254508,
|
||||||
|
1254507,
|
||||||
|
1271531,
|
||||||
|
1430596,
|
||||||
|
1430901,
|
||||||
|
1265975,
|
||||||
|
1201855,
|
||||||
|
1237377,
|
||||||
|
1290777,
|
||||||
|
1290779,
|
||||||
|
1290845,
|
||||||
|
1301023,
|
||||||
|
1313042,
|
||||||
|
1313044,
|
||||||
|
1486866,
|
||||||
|
1486865,
|
||||||
|
1482040,
|
||||||
|
1482039,
|
||||||
|
1486868,
|
||||||
|
1677395,
|
||||||
|
1693204,
|
||||||
|
1785113,
|
||||||
|
1730179,
|
||||||
|
1746619,
|
||||||
|
57778,
|
||||||
|
58549,
|
||||||
|
1274911,
|
||||||
|
5238,
|
||||||
|
59939,
|
||||||
|
48130,
|
||||||
|
51725,
|
||||||
|
3324,
|
||||||
|
3315,
|
||||||
|
42937,
|
||||||
|
1250692,
|
||||||
|
1691268,
|
||||||
|
65691,
|
||||||
|
65679,
|
||||||
|
1266715,
|
||||||
|
1261585,
|
||||||
|
1547,
|
||||||
|
58237,
|
||||||
|
5267,
|
||||||
|
13728,
|
||||||
|
57985,
|
||||||
|
1430910,
|
||||||
|
46996,
|
||||||
|
49071,
|
||||||
|
49778,
|
||||||
|
1199528,
|
||||||
|
18420,
|
||||||
|
1357948,
|
||||||
|
13436,
|
||||||
|
1201667,
|
||||||
|
1371508,
|
||||||
|
60577,
|
||||||
|
47106,
|
||||||
|
1213493,
|
||||||
|
62574,
|
||||||
|
46808,
|
||||||
|
51130,
|
||||||
|
3100,
|
||||||
|
47108,
|
||||||
|
52536,
|
||||||
|
1272396,
|
||||||
|
1266321,
|
||||||
|
1280034,
|
||||||
|
1409383,
|
||||||
|
1272575,
|
||||||
|
1246252,
|
||||||
|
1267713,
|
||||||
|
1265479,
|
||||||
|
4726,
|
||||||
|
1268028,
|
||||||
|
1277070,
|
||||||
|
1278743,
|
||||||
|
1254882,
|
||||||
|
1270158,
|
||||||
|
1254749,
|
||||||
|
1255416,
|
||||||
|
1253839,
|
||||||
|
1268655,
|
||||||
|
1750701,
|
||||||
|
3173,
|
||||||
|
1725771,
|
||||||
|
4646,
|
||||||
|
1801937,
|
||||||
|
1837677,
|
||||||
|
1442421,
|
||||||
|
1811379,
|
||||||
|
1821818,
|
||||||
|
1838555,
|
||||||
|
1752948,
|
||||||
|
1579762,
|
||||||
|
61747,
|
||||||
|
1838556,
|
||||||
|
5087,
|
||||||
|
1838552,
|
||||||
|
1270564,
|
||||||
|
1838547,
|
||||||
|
1815657,
|
||||||
|
1821809,
|
||||||
|
1752947,
|
||||||
|
1821806,
|
||||||
|
1546488,
|
||||||
|
1536001,
|
||||||
|
1838554,
|
||||||
|
1752946,
|
||||||
|
1562500,
|
||||||
|
1838698,
|
||||||
|
1821821,
|
||||||
|
1815220,
|
||||||
|
1213805,
|
||||||
|
1821796,
|
||||||
|
1546102,
|
||||||
|
1173684,
|
||||||
|
1849044,
|
||||||
|
1821776,
|
||||||
|
61453,
|
||||||
|
61465,
|
||||||
|
1694439,
|
||||||
|
1548447,
|
||||||
|
1796332,
|
||||||
|
1204445,
|
||||||
|
1266798,
|
||||||
|
1236596,
|
||||||
|
1252685,
|
||||||
|
1252631,
|
||||||
|
1548800,
|
||||||
|
1838561,
|
||||||
|
1810009,
|
||||||
|
1546753,
|
||||||
|
1838562,
|
||||||
|
61439,
|
||||||
|
61466,
|
||||||
|
1811405,
|
||||||
|
1811396,
|
||||||
|
21475,
|
||||||
|
1821764,
|
||||||
|
1812378,
|
||||||
|
1548797,
|
||||||
|
1838553,
|
||||||
|
37,
|
||||||
|
517,
|
||||||
|
49124,
|
||||||
|
1814818,
|
||||||
|
1546149,
|
||||||
|
58180,
|
||||||
|
1837889,
|
||||||
|
4667,
|
||||||
|
61354,
|
||||||
|
1821769,
|
||||||
|
61595,
|
||||||
|
1694473,
|
||||||
|
1821802,
|
||||||
|
4370,
|
||||||
|
48406,
|
||||||
|
1838559,
|
||||||
|
1778238,
|
||||||
|
1546760,
|
||||||
|
1838558,
|
||||||
|
1821752,
|
||||||
|
61429,
|
||||||
|
754,
|
||||||
|
1265,
|
||||||
|
1837956,
|
||||||
|
1821800,
|
||||||
|
1821747,
|
||||||
|
1546834,
|
||||||
|
16675,
|
||||||
|
1214135,
|
||||||
|
1791293,
|
||||||
|
61341,
|
||||||
|
1837887,
|
||||||
|
47168,
|
||||||
|
1224282,
|
||||||
|
1938274,
|
||||||
|
1837886,
|
||||||
|
1254630,
|
||||||
|
1546849,
|
||||||
|
49122,
|
||||||
|
4825,
|
||||||
|
43589,
|
||||||
|
1838560,
|
||||||
|
1687827,
|
||||||
|
1838551,
|
||||||
|
4807,
|
||||||
|
1694419,
|
||||||
|
1548750,
|
||||||
|
53220,
|
||||||
|
2032683,
|
||||||
|
1822337,
|
||||||
|
1821728,
|
||||||
|
1260032,
|
||||||
|
61600,
|
||||||
|
1546423,
|
||||||
|
1811399,
|
||||||
|
49121,
|
||||||
|
519,
|
||||||
|
1821730,
|
||||||
|
1247748,
|
||||||
|
4717,
|
||||||
|
1808931,
|
||||||
|
43583,
|
||||||
|
43584,
|
||||||
|
1838692,
|
||||||
|
1268073,
|
||||||
|
1821741,
|
||||||
|
1845065,
|
||||||
|
1838699,
|
||||||
|
1200388,
|
||||||
|
1937568,
|
||||||
|
4359,
|
||||||
|
45049,
|
||||||
|
66803,
|
||||||
|
1814848,
|
||||||
|
49667,
|
||||||
|
1821737,
|
||||||
|
1821713,
|
||||||
|
4156,
|
||||||
|
1546421,
|
||||||
|
1546419,
|
||||||
|
1789644,
|
||||||
|
1270222,
|
||||||
|
1821717,
|
||||||
|
1812381,
|
||||||
|
1821742,
|
||||||
|
1254254,
|
||||||
|
3691,
|
||||||
|
1546424,
|
||||||
|
1259,
|
||||||
|
1253389,
|
||||||
|
1457,
|
||||||
|
1838557,
|
||||||
|
1224277,
|
||||||
|
1838548,
|
||||||
|
4824,
|
||||||
|
1814870,
|
||||||
|
1562490,
|
||||||
|
1249319,
|
||||||
|
1937717,
|
||||||
|
1838549,
|
||||||
|
4411,
|
||||||
|
1562476,
|
||||||
|
59199,
|
||||||
|
1845056,
|
||||||
|
4028,
|
||||||
|
1822211,
|
||||||
|
47056,
|
||||||
|
1201201,
|
||||||
|
62192,
|
||||||
|
1815646,
|
||||||
|
1694418,
|
||||||
|
1546549,
|
||||||
|
1254472,
|
||||||
|
1814112,
|
||||||
|
1258777,
|
||||||
|
2032682,
|
||||||
|
1546763,
|
||||||
|
1658549,
|
||||||
|
1838546,
|
||||||
|
61758,
|
||||||
|
1744312,
|
||||||
|
1518567,
|
||||||
|
1271323,
|
||||||
|
1814821,
|
||||||
|
4412,
|
||||||
|
1938272,
|
||||||
|
2032521,
|
||||||
|
4196,
|
||||||
|
57643,
|
||||||
|
49126,
|
||||||
|
49127,
|
||||||
|
1815644,
|
||||||
|
50812,
|
||||||
|
1821642,
|
||||||
|
1823200,
|
||||||
|
66933,
|
||||||
|
1268915,
|
||||||
|
1837969,
|
||||||
|
53209,
|
||||||
|
1546794,
|
||||||
|
1272267,
|
||||||
|
47147,
|
||||||
|
43512,
|
||||||
|
1849014,
|
||||||
|
1838550,
|
||||||
|
1368860,
|
||||||
|
2609,
|
||||||
|
1821727,
|
||||||
|
2021536,
|
||||||
|
1276589,
|
||||||
|
1936567,
|
||||||
|
1269506
|
||||||
|
]
|
||||||
|
start = time.time()
|
||||||
|
asyncio.run(process_update(A))
|
||||||
|
print(time.time() - start)
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# Test your FastAPI endpoints
|
|
||||||
|
|
||||||
GET http://127.0.0.1:8000/
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
GET http://127.0.0.1:8000/hello/User
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import time
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
@@ -33,7 +34,17 @@ class BaseMarketplaceUpdater(ABC):
|
|||||||
marketplace=self.marketplace,
|
marketplace=self.marketplace,
|
||||||
product_ids=product_ids
|
product_ids=product_ids
|
||||||
)
|
)
|
||||||
return
|
marketplace_updates = []
|
||||||
|
for stock_data in stock_data_list:
|
||||||
|
marketplace_update = self.get_update_for_marketplace(stock_data)
|
||||||
|
marketplace_updates.append(marketplace_update)
|
||||||
|
await self.marketplace_api.update_stocks(marketplace_updates)
|
||||||
|
|
||||||
|
async def update_all(self):
|
||||||
|
stock_data_list = await queries.general.get_stocks_data(
|
||||||
|
session=self.session,
|
||||||
|
marketplace=self.marketplace,
|
||||||
|
)
|
||||||
marketplace_updates = []
|
marketplace_updates = []
|
||||||
for stock_data in stock_data_list:
|
for stock_data in stock_data_list:
|
||||||
marketplace_update = self.get_update_for_marketplace(stock_data)
|
marketplace_update = self.get_update_for_marketplace(stock_data)
|
||||||
|
|||||||
@@ -6,13 +6,20 @@ from database import Marketplace
|
|||||||
from database.sipro.enums.general import BaseMarketplace
|
from database.sipro.enums.general import BaseMarketplace
|
||||||
from updaters.ozon_updater import OzonUpdater
|
from updaters.ozon_updater import OzonUpdater
|
||||||
from updaters.wildberries_updater import WildberriesUpdater
|
from updaters.wildberries_updater import WildberriesUpdater
|
||||||
|
from updaters.yandexmarket_updater import YandexmarketUpdater
|
||||||
|
|
||||||
|
|
||||||
class UpdaterFactory:
|
class UpdaterFactory:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_updater(session: AsyncSession, marketplace: Marketplace) -> Union[OzonUpdater, WildberriesUpdater]:
|
def get_updater(session: AsyncSession, marketplace: Marketplace) -> Union[
|
||||||
|
OzonUpdater,
|
||||||
|
WildberriesUpdater,
|
||||||
|
YandexmarketUpdater
|
||||||
|
]:
|
||||||
match marketplace.base_marketplace:
|
match marketplace.base_marketplace:
|
||||||
case BaseMarketplace.WILDBERRIES:
|
case BaseMarketplace.WILDBERRIES:
|
||||||
return WildberriesUpdater(marketplace, session)
|
return WildberriesUpdater(marketplace, session)
|
||||||
case BaseMarketplace.OZON:
|
case BaseMarketplace.OZON:
|
||||||
return OzonUpdater(marketplace, session)
|
return OzonUpdater(marketplace, session)
|
||||||
|
case BaseMarketplace.YANDEX_MARKET:
|
||||||
|
return YandexmarketUpdater(marketplace, session)
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from enum import unique, IntEnum
|
from enum import unique, IntEnum
|
||||||
from typing import List
|
from typing import List, Union
|
||||||
|
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select, or_
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload, selectinload
|
||||||
|
|
||||||
|
from backend.session import get_session, session_factory
|
||||||
from database import Marketplace, MarketplaceProduct, Warehouse, Company
|
from database import Marketplace, MarketplaceProduct, Warehouse, Company
|
||||||
|
from database.sipro.enums.general import BaseMarketplace
|
||||||
from schemas.general import StockUpdate
|
from schemas.general import StockUpdate
|
||||||
from updaters.factory import UpdaterFactory
|
from updaters.factory import UpdaterFactory
|
||||||
|
|
||||||
@@ -24,9 +27,59 @@ class StocksUpdater:
|
|||||||
])
|
])
|
||||||
return marketplace
|
return marketplace
|
||||||
|
|
||||||
async def update_marketplace(self, marketplace_id: int, updates: List[StockUpdate]):
|
async def get_marketplaces(self, marketplace_ids: Union[list[int], None] = None) -> List[Marketplace]:
|
||||||
|
if not marketplace_ids:
|
||||||
|
marketplace_ids = []
|
||||||
|
stmt = (
|
||||||
|
select(
|
||||||
|
Marketplace
|
||||||
|
)
|
||||||
|
.join(
|
||||||
|
Company
|
||||||
|
)
|
||||||
|
.options(
|
||||||
|
selectinload(Marketplace.warehouses).selectinload(Warehouse.suppliers),
|
||||||
|
selectinload(Marketplace.warehouses).selectinload(Warehouse.company_warehouses),
|
||||||
|
joinedload(Marketplace.company).joinedload(Company.warehouse)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
Company.is_deleted == False,
|
||||||
|
Company.is_archived == False,
|
||||||
|
Marketplace.is_deleted == False,
|
||||||
|
Marketplace.base_marketplace.in_([
|
||||||
|
BaseMarketplace.OZON,
|
||||||
|
BaseMarketplace.WILDBERRIES,
|
||||||
|
BaseMarketplace.YANDEX_MARKET
|
||||||
|
]),
|
||||||
|
or_(
|
||||||
|
marketplace_ids == [],
|
||||||
|
Marketplace.id.in_(marketplace_ids)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
query_result = await self.session.scalars(stmt)
|
||||||
|
return query_result.all()
|
||||||
|
|
||||||
|
async def full_update_marketplace(self, marketplace_id: int):
|
||||||
marketplace = await self.get_marketplace(marketplace_id)
|
marketplace = await self.get_marketplace(marketplace_id)
|
||||||
updater = UpdaterFactory.get_updater(self.session, marketplace)
|
updater = UpdaterFactory.get_updater(self.session, marketplace)
|
||||||
|
await updater.update_all()
|
||||||
|
|
||||||
|
async def full_update_all_marketplaces(self, marketplace_ids: Union[List[int], None] = None):
|
||||||
|
marketplaces = await self.get_marketplaces(marketplace_ids)
|
||||||
|
|
||||||
|
async def update_marketplace(marketplace):
|
||||||
|
async with session_factory() as session:
|
||||||
|
updater = UpdaterFactory.get_updater(session, marketplace)
|
||||||
|
await updater.update_all()
|
||||||
|
|
||||||
|
tasks = [update_marketplace(marketplace) for marketplace in marketplaces]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
async def update_marketplace(self, marketplace_id: int, updates: List[StockUpdate]):
|
||||||
|
marketplace = await self.get_marketplace(marketplace_id)
|
||||||
|
async with session_factory() as session:
|
||||||
|
updater = UpdaterFactory.get_updater(session, marketplace)
|
||||||
if not updater:
|
if not updater:
|
||||||
return
|
return
|
||||||
await updater.update(updates)
|
await updater.update(updates)
|
||||||
@@ -34,14 +87,17 @@ class StocksUpdater:
|
|||||||
async def update(self, updates: list[StockUpdate]):
|
async def update(self, updates: list[StockUpdate]):
|
||||||
updates_dict = defaultdict(list)
|
updates_dict = defaultdict(list)
|
||||||
for update in updates:
|
for update in updates:
|
||||||
# Working with marketplaces
|
|
||||||
stmt = (
|
stmt = (
|
||||||
select(
|
select(
|
||||||
MarketplaceProduct.marketplace_id.distinct()
|
MarketplaceProduct.marketplace_id.distinct()
|
||||||
)
|
)
|
||||||
|
.join(Marketplace)
|
||||||
|
.join(Company)
|
||||||
.where(
|
.where(
|
||||||
MarketplaceProduct.product_id == update.product_id,
|
MarketplaceProduct.product_id == update.product_id,
|
||||||
MarketplaceProduct.marketplace_id.in_([9, 41])
|
Marketplace.is_deleted == False,
|
||||||
|
Company.is_deleted == False,
|
||||||
|
Company.is_archived == False
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
stmt_result = await self.session.execute(stmt)
|
stmt_result = await self.session.execute(stmt)
|
||||||
@@ -52,7 +108,8 @@ class StocksUpdater:
|
|||||||
updates_dict[marketplace_id].append(update)
|
updates_dict[marketplace_id].append(update)
|
||||||
updates_list = list(updates_dict.items())
|
updates_list = list(updates_dict.items())
|
||||||
updates_list = sorted(updates_list, key=lambda x: len(x[1]))
|
updates_list = sorted(updates_list, key=lambda x: len(x[1]))
|
||||||
|
print(updates_list)
|
||||||
|
return
|
||||||
tasks = []
|
tasks = []
|
||||||
for marketplace_id, marketplace_updates in updates_list:
|
for marketplace_id, marketplace_updates in updates_list:
|
||||||
tasks.append(self.update_marketplace(marketplace_id, marketplace_updates))
|
tasks.append(self.update_marketplace(marketplace_id, marketplace_updates))
|
||||||
|
|||||||
13
updaters/yandexmarket_updater.py
Normal file
13
updaters/yandexmarket_updater.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from queries.general import StockData
|
||||||
|
from updaters.base import BaseMarketplaceUpdater
|
||||||
|
|
||||||
|
|
||||||
|
class YandexmarketUpdater(BaseMarketplaceUpdater):
|
||||||
|
def get_update_for_marketplace(self, stock_data: StockData) -> dict:
|
||||||
|
return {
|
||||||
|
'sku': str(stock_data['article']),
|
||||||
|
'warehouseId': self.marketplace.warehouse_id,
|
||||||
|
'items': [{
|
||||||
|
'count': stock_data['full_stock'],
|
||||||
|
}]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user