Files
Sipro-Stocks/updaters/base.py
2025-05-11 07:46:57 +03:00

151 lines
5.9 KiB
Python

import json
from abc import ABC, abstractmethod
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_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]):
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
)
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.is_valid_updater():
return
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace,
)
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.is_valid_updater():
return []
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace
)
if only_available:
stock_data_list = list(filter(lambda x: x["full_stock"] > 0, stock_data_list))
for idx, stock_data in enumerate(stock_data_list):
stock_data['product_id'] = stock_data['marketplace_product'].product_id
del stock_data["marketplace_product"]
stock_data_list[idx] = stock_data
return stock_data_list
async def reset(self):
if not self.is_valid_updater():
return
stock_data_list = await queries.general.get_stocks_data(
session=self.session,
marketplace=self.marketplace
)
stock_requests = await self.get_marketplace_updates(stock_data_list)
await self.sender.send(stock_requests)