82 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import asyncio
 | 
						|
import json
 | 
						|
import logging
 | 
						|
from typing import Union
 | 
						|
 | 
						|
import jwt
 | 
						|
 | 
						|
import utils
 | 
						|
from database import Marketplace
 | 
						|
from limiter import BatchLimiter
 | 
						|
from marketplaces.base import BaseMarketplaceApi
 | 
						|
 | 
						|
 | 
						|
class WildberriesMarketplaceApi(BaseMarketplaceApi):
 | 
						|
    def __init__(self, marketplace: Marketplace):
 | 
						|
        self.marketplace = marketplace
 | 
						|
        auth_data = json.loads(marketplace.auth_data)
 | 
						|
        token = auth_data.get('token')
 | 
						|
        self.is_valid = True
 | 
						|
        try:
 | 
						|
            decoded_token = jwt.decode(token, algorithms=["HS256"], options={"verify_signature": False})
 | 
						|
        except Exception:
 | 
						|
            logging.error(f"Couldn't decode token for {marketplace.id}")
 | 
						|
            self.is_valid = False
 | 
						|
            return
 | 
						|
        self.limiter_key = str(marketplace.company_id) + str(decoded_token.get('sid'))
 | 
						|
 | 
						|
        self.headers = {
 | 
						|
            'Authorization': token,
 | 
						|
            'Content-Type': 'application/json'
 | 
						|
        }
 | 
						|
 | 
						|
    def get_headers(self):
 | 
						|
        return self.headers
 | 
						|
 | 
						|
    @property
 | 
						|
    def api_url(self):
 | 
						|
        return 'https://suppliers-api.wildberries.ru'
 | 
						|
 | 
						|
    async def update_stocks(self, data: Union[list, dict]):
 | 
						|
        if type(data) is not list:
 | 
						|
            return
 | 
						|
        if not self.is_valid:
 | 
						|
            logging.warning(f'Skipping marketplace [{self.marketplace.id}] because of invalid token')
 | 
						|
            return
 | 
						|
        max_stocks = 1000
 | 
						|
        chunks = utils.chunk_list(data, max_stocks)
 | 
						|
        if not chunks:
 | 
						|
            return
 | 
						|
        self.init_session()
 | 
						|
        limiter = BatchLimiter()
 | 
						|
 | 
						|
        async def send_stock_chunk(chunk):
 | 
						|
            try:
 | 
						|
                await limiter.acquire_wildberries(self.limiter_key)
 | 
						|
                request_data = {'stocks': chunk}
 | 
						|
                response = await self._method('PUT', f'/api/v3/stocks/{self.marketplace.warehouse_id}',
 | 
						|
                                              data=request_data)
 | 
						|
                if response.status not in [204, 409]:
 | 
						|
                    response = await response.json()
 | 
						|
                    error_message = response.get('message')
 | 
						|
                    error_code = response.get('code')
 | 
						|
                    logging.warning(
 | 
						|
                        f'Error occurred when sending stocks to [{self.marketplace.id}]: {error_message} ({error_code})')
 | 
						|
                    return False
 | 
						|
                return True
 | 
						|
            except Exception as e:
 | 
						|
                logging.error(
 | 
						|
                    f'Exception occurred while sending stocks to marketplace ID [{self.marketplace.id}]: {str(e)}')
 | 
						|
                return False
 | 
						|
 | 
						|
        tasks = [send_stock_chunk(chunk) for chunk in chunks]
 | 
						|
        first_request = tasks[0]
 | 
						|
        first_response = await first_request
 | 
						|
        if not first_response:
 | 
						|
            logging.error(f'Skipping marketplace [{self.marketplace.id}] because first request was unsuccessful')
 | 
						|
            await self.session.close()
 | 
						|
            return
 | 
						|
 | 
						|
        await asyncio.gather(*tasks[1:])
 | 
						|
        await self.session.close()
 |