rewritten crap

This commit is contained in:
2025-05-11 07:46:57 +03:00
parent 41a5fb91f3
commit b5110ec69a
20 changed files with 475 additions and 193 deletions

View File

@@ -1,65 +1,131 @@
import time
import json
from abc import ABC, abstractmethod
from typing import List
from typing import List, Optional
import redis.asyncio
from sqlalchemy.ext.asyncio import AsyncSession
import queries.general
from database import Marketplace
from limiter import redis_client
from marketplaces import MarketplaceApiFactory
from marketplaces.base import BaseMarketplaceApi
from queries.general import StockData
from schemas.general import StockUpdate
from sender.base import StockRequest
from sender.factory import SenderFactory
class BaseMarketplaceUpdater(ABC):
marketplace: Marketplace
marketplace_api: BaseMarketplaceApi
session: AsyncSession
lock_key: Optional[str]
cache_key: Optional[str]
redis_client: redis.asyncio.Redis
def __init__(self, marketplace: Marketplace, session: AsyncSession):
self.marketplace = marketplace
self.session = session
self.marketplace_api = MarketplaceApiFactory.get_marketplace_api(marketplace)
self.redis_client = redis_client.get_client()
self.sender = SenderFactory.get_sender(self)
self.cache_key = None
self.lock_key = None
def is_valid_updater(self) -> bool:
if not self.marketplace_api:
return False
return self.marketplace_api.is_valid
@abstractmethod
def get_update_for_marketplace(self,
stock_data: StockData) -> dict:
def get_stock_request(self,
stock_data: StockData) -> StockRequest:
pass
@abstractmethod
def _get_identifier(self) -> str:
raise NotImplementedError()
def __get_base_marketplace_key(self):
base_marketplace = 'wb'
if self.marketplace.base_marketplace == 1:
base_marketplace = 'ozon'
elif self.marketplace.base_marketplace == 2:
base_marketplace = 'yandexmarket'
return base_marketplace
def get_lock_key(self) -> str:
identifier = self._get_identifier()
base_marketplace = self.__get_base_marketplace_key()
return f'{base_marketplace}_{identifier}_lock'
def get_cache_key(self):
identifier = self._get_identifier()
base_marketplace = self.__get_base_marketplace_key()
return f'{base_marketplace}_{self.marketplace.warehouse_id}_{identifier}_cache'
def get_auth_data(self) -> dict:
try:
return json.loads(self.marketplace.auth_data)
except Exception as e:
return {}
async def filter_stocks_data(self, stock_data_list: list[StockData]) -> list[StockData]:
cached_stocks: dict = await self.redis_client.hgetall(self.get_cache_key())
cached_stocks = {int(k): int(v) for k, v in cached_stocks.items()}
result = []
for stock_data in stock_data_list:
cached_stock = cached_stocks.get(stock_data['product_id'])
if cached_stock is not None and cached_stock == stock_data['full_stock']:
continue
result.append(stock_data)
return result
async def after_sender_sent(self, stock_requests: list[StockRequest], invalid_product_ids: list[int]):
stock_requests = list(filter(lambda stock: stock['product_id'] not in invalid_product_ids, stock_requests))
mapping = {stock['product_id']: stock['full_stock'] for stock in stock_requests}
await self.redis_client.hset(self.get_cache_key(), mapping=mapping)
async def get_marketplace_updates(self, stock_data_list: list[StockData]) -> list[StockRequest]:
marketplace_updates = []
for stock_data in stock_data_list:
marketplace_update = self.get_stock_request(stock_data)
marketplace_updates.append(marketplace_update)
return marketplace_updates
async def update(self, updates: List[StockUpdate]):
if not self.marketplace_api:
return
product_ids = list(set([update.product_id for update in updates]))
await self.update_products(product_ids)
async def update_products(self, product_ids: list[int]):
if not self.is_valid_updater():
return
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace,
product_ids=product_ids
)
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)
stock_data_list = await self.filter_stocks_data(stock_data_list)
stock_requests = await self.get_marketplace_updates(stock_data_list)
invalid_product_ids = await self.sender.send(stock_requests)
await self.after_sender_sent(stock_requests, invalid_product_ids)
async def update_all(self):
if not self.marketplace_api:
if not self.is_valid_updater():
return
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace,
)
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)
stock_data_list = await self.filter_stocks_data(stock_data_list)
stock_requests = await self.get_marketplace_updates(stock_data_list)
invalid_product_ids = await self.sender.send(stock_requests)
await self.after_sender_sent(stock_requests, invalid_product_ids)
async def get_all_stocks(self, only_available: bool) -> List[StockData]:
if not self.marketplace_api:
if not self.is_valid_updater():
return []
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
@@ -74,14 +140,11 @@ class BaseMarketplaceUpdater(ABC):
return stock_data_list
async def reset(self):
if not self.marketplace_api:
if not self.is_valid_updater():
return
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace
)
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)
stock_requests = await self.get_marketplace_updates(stock_data_list)
await self.sender.send(stock_requests)

View File

@@ -23,3 +23,4 @@ class UpdaterFactory:
return OzonUpdater(marketplace, session)
case BaseMarketplace.YANDEX_MARKET:
return YandexmarketUpdater(marketplace, session)
raise ValueError()

View File

@@ -1,11 +1,22 @@
from queries.general import StockData
from sender.base import StockRequest
from updaters.base import BaseMarketplaceUpdater
class OzonUpdater(BaseMarketplaceUpdater):
def get_update_for_marketplace(self, data: StockData) -> dict:
def _get_identifier(self) -> str:
auth_data = self.get_auth_data()
client_id = auth_data.get('clientId', -1)
return str(client_id)
def get_stock_request(self, stock_data: StockData) -> StockRequest:
return {
'offer_id': str(data['article']),
'stock': data['full_stock'],
'warehouse_id': self.marketplace.warehouse_id
'request_data': {
'offer_id': str(stock_data['article']),
'stock': stock_data['full_stock'],
'warehouse_id': self.marketplace.warehouse_id
},
'product_id': stock_data['product_id'],
'full_stock': stock_data['full_stock']
}

View File

@@ -1,11 +1,32 @@
import json
import jwt
from celery.backends.database import retry
from queries.general import StockData
from sender.base import StockRequest
from updaters.base import BaseMarketplaceUpdater
class WildberriesUpdater(BaseMarketplaceUpdater):
def get_update_for_marketplace(self, stock_data: StockData) -> dict:
def _get_identifier(self) -> str:
try:
auth_data = self.get_auth_data()
token = auth_data.get('token')
decoded_token = jwt.decode(token, algorithms=["HS256"], options={"verify_signature": False})
sid = decoded_token.get('sid')
return str(sid)
except Exception:
return f'-1'
def get_stock_request(self, stock_data: StockData) -> StockRequest:
return {
'sku': stock_data['marketplace_product'].third_additional_article,
'amount': stock_data['full_stock']
'request_data': {
'sku': stock_data['marketplace_product'].third_additional_article,
'amount': stock_data['full_stock']
},
'product_id': stock_data['product_id'],
'full_stock': stock_data['full_stock']
}

View File

@@ -1,13 +1,23 @@
from queries.general import StockData
from sender.base import StockRequest
from updaters.base import BaseMarketplaceUpdater
class YandexmarketUpdater(BaseMarketplaceUpdater):
def get_update_for_marketplace(self, stock_data: StockData) -> dict:
def _get_identifier(self) -> str:
return str(self.marketplace.campaign_id)
def get_stock_request(self, stock_data: StockData) -> StockRequest:
return {
'sku': str(stock_data['article']),
'warehouseId': self.marketplace.warehouse_id,
'items': [{
'count': stock_data['full_stock'],
}]
'request_data': {
'sku': str(stock_data['article']),
'warehouseId': self.marketplace.warehouse_id,
'items': [{
'count': stock_data['full_stock'],
}]
},
'product_id': stock_data['product_id'],
'full_stock': stock_data['full_stock']
}