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): await self.synchronizer.create_products()