feat: ozon sync
This commit is contained in:
@@ -1,6 +1,190 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
from external.marketplace import OzonMarketplaceApi
|
||||
from external.marketplace.base.product_synchronizer import BaseProductSynchronizer
|
||||
from marketplaces.base.core import BaseMarketplaceController
|
||||
from models import OzonProduct, ProductImage, ProductBarcode, Product
|
||||
from utils.list_utils import chunk_list
|
||||
|
||||
|
||||
class OzonProductSynchronizer(BaseProductSynchronizer):
|
||||
api: OzonMarketplaceApi
|
||||
marketplace_products: list[OzonProduct]
|
||||
|
||||
def _create_product(self, product_info):
|
||||
return Product(
|
||||
client_id=self.marketplace.client_id,
|
||||
name=product_info['name'],
|
||||
article=product_info['offer_id'],
|
||||
)
|
||||
|
||||
def _create_barcodes(self, product, param):
|
||||
barcodes = []
|
||||
for sku in param:
|
||||
barcode = ProductBarcode(
|
||||
product=product,
|
||||
barcode=sku
|
||||
)
|
||||
barcodes.append(barcode)
|
||||
return barcodes
|
||||
|
||||
def _create_images(self, product, product_info):
|
||||
primary_image = product_info.get('primary_image')
|
||||
if primary_image:
|
||||
image = ProductImage(
|
||||
product=product,
|
||||
image_url=primary_image
|
||||
)
|
||||
return [image]
|
||||
product_images = []
|
||||
images = product_info.get('images') or []
|
||||
for image in images[:1]:
|
||||
product_image = ProductImage(
|
||||
product=product,
|
||||
image_url=image
|
||||
)
|
||||
product_images.append(product_image)
|
||||
return product_images
|
||||
|
||||
def _create_ozon_product(self, product, product_info):
|
||||
return OzonProduct(
|
||||
marketplace_id=self.marketplace.id,
|
||||
product=product,
|
||||
ozon_product_id=product_info['id'],
|
||||
)
|
||||
|
||||
def _process_product(self, product_info):
|
||||
product = self._create_product(product_info)
|
||||
barcodes = self._create_barcodes(product, product_info['barcodes'])
|
||||
images = self._create_images(product, product_info)
|
||||
ozon_product = self._create_ozon_product(product, product_info)
|
||||
|
||||
self.products.append(product)
|
||||
self.barcodes.extend(barcodes)
|
||||
self.images.extend(images)
|
||||
self.marketplace_products.append(ozon_product)
|
||||
|
||||
async def create_products(self):
|
||||
self._clear()
|
||||
product_ids = []
|
||||
|
||||
async for product in self.api.get_all_products():
|
||||
product_ids.append(product['product_id'])
|
||||
if len(product_ids) > 100:
|
||||
break
|
||||
max_products = 1000
|
||||
for chunk in chunk_list(product_ids, max_products):
|
||||
data = {
|
||||
'product_id': chunk
|
||||
}
|
||||
products_info = await self.api.get_products_info(data)
|
||||
if not products_info:
|
||||
continue
|
||||
result = products_info.get('result')
|
||||
if not result:
|
||||
continue
|
||||
items = result.get('items')
|
||||
for product_info in items:
|
||||
product = self._create_product(product_info)
|
||||
self.products.append(product)
|
||||
barcodes = self._create_barcodes(product, product_info['barcodes'])
|
||||
self.barcodes.extend(barcodes)
|
||||
images = self._create_images(product, product_info)
|
||||
self.images.extend(images)
|
||||
ozon_product = self._create_ozon_product(product, product_info)
|
||||
self.marketplace_products.append(ozon_product)
|
||||
|
||||
await self._write()
|
||||
|
||||
async def synchronize_products(self):
|
||||
self._clear()
|
||||
synchronized_products_stmt = (
|
||||
select(
|
||||
Product
|
||||
)
|
||||
.join(
|
||||
OzonProduct
|
||||
).options(
|
||||
selectinload(Product.barcodes),
|
||||
selectinload(Product.ozon_products)
|
||||
)
|
||||
.where(
|
||||
OzonProduct.marketplace_id == self.marketplace.id
|
||||
)
|
||||
)
|
||||
synchronized_products = await self.session.execute(synchronized_products_stmt)
|
||||
synchronized_products = synchronized_products.scalars().all()
|
||||
synchronized_products_ozon_id_dict = defaultdict(list)
|
||||
for product in synchronized_products:
|
||||
for ozon_product in product.ozon_products:
|
||||
synchronized_products_ozon_id_dict[ozon_product.ozon_product_id].append(product)
|
||||
synchronized_ozon_ids = list(synchronized_products_ozon_id_dict.keys())
|
||||
max_products = 1000
|
||||
for chunk in chunk_list(synchronized_ozon_ids, max_products):
|
||||
data = {
|
||||
'product_id': chunk
|
||||
}
|
||||
products_info = await self.api.get_products_info(data)
|
||||
if not products_info:
|
||||
continue
|
||||
result = products_info.get('result')
|
||||
if not result:
|
||||
continue
|
||||
items = result.get('items')
|
||||
for product_info in items:
|
||||
ozon_id = product_info['id']
|
||||
if ozon_id not in synchronized_ozon_ids:
|
||||
continue
|
||||
products = synchronized_products_ozon_id_dict.get(ozon_id)
|
||||
if not products:
|
||||
continue
|
||||
product = products[0]
|
||||
await self._update_product_info(product, product_info)
|
||||
await self._write()
|
||||
|
||||
async def _update_product_info(self, product, product_info):
|
||||
product.name = product_info['name']
|
||||
product.article = product_info['offer_id']
|
||||
barcodes = self._update_barcodes(product, product_info['barcodes'])
|
||||
self.barcodes.extend(barcodes)
|
||||
images = self._update_images(product, product_info)
|
||||
self.images.extend(images)
|
||||
|
||||
def _update_barcodes(self, product, param):
|
||||
existing_barcodes = {barcode.barcode for barcode in product.barcodes}
|
||||
barcodes = []
|
||||
for sku in param:
|
||||
if sku not in existing_barcodes:
|
||||
barcode = ProductBarcode(
|
||||
product=product,
|
||||
barcode=sku
|
||||
)
|
||||
barcodes.append(barcode)
|
||||
return barcodes
|
||||
|
||||
def _update_images(self, product, product_info):
|
||||
existing_images = {image.image_url for image in product.images}
|
||||
primary_image = product_info.get('primary_image')
|
||||
if primary_image and primary_image not in existing_images:
|
||||
image = ProductImage(
|
||||
product=product,
|
||||
image_url=primary_image
|
||||
)
|
||||
return [image]
|
||||
return []
|
||||
|
||||
|
||||
|
||||
class OzonController(BaseMarketplaceController):
|
||||
def __init__(self, session, marketplace):
|
||||
super().__init__(session, marketplace)
|
||||
self.product_synchronizer = OzonProductSynchronizer(session, marketplace, self.api)
|
||||
|
||||
async def synchronize_products(self):
|
||||
await self.product_synchronizer.synchronize_products()
|
||||
|
||||
async def create_products(self):
|
||||
pass
|
||||
await self.product_synchronizer.create_products()
|
||||
|
||||
Reference in New Issue
Block a user