feat: ym sync

This commit is contained in:
2025-04-13 13:50:02 +03:00
parent 10683a9a42
commit c08c2c04c4
5 changed files with 344 additions and 5 deletions

View File

@@ -1,6 +1,187 @@
from typing import Optional
from sqlalchemy import select
from sqlalchemy.orm import selectinload
from external.marketplace import YandexMarketplaceApi
from external.marketplace.base.product_synchronizer import BaseProductSynchronizer
from marketplaces.base.core import BaseMarketplaceController
from models import Product, YandexProduct, ProductBarcode, ProductImage
class YandexProductSynchronizer(BaseProductSynchronizer):
api: YandexMarketplaceApi
def _try_get_param(self, offer: dict, param: str) -> Optional[str]:
params = offer.get('params')
if not params:
return None
for p in params:
if p['name'] == param:
return str(p['value'])
return None
def _create_product(self, offer: dict) -> Product:
return Product(
client_id=self.marketplace.client_id,
name=offer['name'],
article=offer['offerId'],
brand=self._try_get_param(offer, 'Бренд'),
size=self._try_get_param(offer, 'Размер'),
color=self._try_get_param(offer, 'Цвет товара'),
composition=self._try_get_param(offer, 'Состав материала'),
)
def _create_barcodes(self, product: Product, offer: dict):
barcodes = []
for sku in offer['barcodes']:
barcode = ProductBarcode(
product=product,
barcode=sku
)
barcodes.append(barcode)
return barcodes
def _create_images(self, product: Product, offer: dict):
product_images = []
images = offer.get('pictures', [])
for image in images[:1]:
product_image = ProductImage(
product=product,
image_url=image
)
product_images.append(product_image)
return product_images
def _create_ym_product(self, product: Product):
return YandexProduct(
marketplace_id=self.marketplace.id,
product=product,
)
async def create_products(self):
self._clear()
synchronized_articles = await self._get_synchronized_products()
async for product in self.api.get_all_products():
try:
offer = product.get('offer')
if not offer:
continue
if offer['offerId'] in synchronized_articles:
continue
product = self._create_product(offer)
self.products.append(product)
barcodes = self._create_barcodes(product, offer)
product.barcodes.extend(barcodes)
images = self._create_images(product, offer)
product.images.extend(images)
ym_product = self._create_ym_product(product)
self.marketplace_products.append(ym_product)
except Exception as e:
print(e)
await self._write()
def _update_barcodes(self, product: Product, offer: dict):
existing_barcodes = {barcode.barcode for barcode in product.barcodes}
new_barcodes = []
for barcode in offer['barcodes']:
if barcode not in existing_barcodes:
barcode = ProductBarcode(
product=product,
barcode=barcode
)
new_barcodes.append(barcode)
return new_barcodes
def _update_images(self, product: Product, offer: dict):
existing_images = {image.image_url for image in product.images}
new_images = []
images = offer.get('pictures', [])
for image in images[:1]:
if image not in existing_images:
product_image = ProductImage(
product=product,
image_url=image
)
new_images.append(product_image)
return new_images
async def _update_product(self, product: Product, offer: dict):
product.name = offer['name']
product.brand = self._try_get_param(offer, 'Бренд')
product.size = self._try_get_param(offer, 'Размер')
product.color = self._try_get_param(offer, 'Цвет товара')
product.composition = self._try_get_param(offer, 'Состав материала')
barcodes = self._update_barcodes(product, offer)
product.barcodes.extend(barcodes)
images = self._update_images(product, offer)
product.images.extend(images)
async def synchronize_products(self):
self._clear()
synchronized_products = (
select(
Product
)
.options(
selectinload(Product.barcodes),
selectinload(Product.images),
)
.select_from(
YandexProduct
)
.join(
Product
)
.where(
YandexProduct.marketplace_id == self.marketplace.id
)
)
result = await self.session.execute(synchronized_products)
synchronized_products = result.scalars().all()
synchronized_products_dict = {product.article: product for product in synchronized_products}
synchronized_articles = list(set(synchronized_products_dict.keys()))
async for product in self.api.get_products_by_offer_ids(synchronized_articles):
try:
offer = product.get('offer')
if not offer:
continue
article = offer['offerId']
if article not in synchronized_articles:
continue
product = synchronized_products_dict[article]
await self._update_product(product, offer)
except Exception as e:
print(f'Error: {e}')
continue
await self._write()
async def _get_synchronized_products(self):
stmt = (
select(
Product.article
)
.select_from(
YandexProduct
)
.join(
Product
)
)
result = await self.session.execute(stmt)
return set(result.scalars().all())
class YandexController(BaseMarketplaceController):
def __init__(self, session, marketplace):
super().__init__(session, marketplace)
self.synchronizer = YandexProductSynchronizer(session, marketplace, self.api)
async def synchronize_products(self):
await self.synchronizer.synchronize_products()
async def create_products(self):
pass
await self.synchronizer.create_products()