""" This file holds the functions necesary to: - Connect to seller's shop API - Load information on seller [??] - Load product information """ import logging from io import BytesIO import datetime from woocommerce import API import requests from PIL import Image from django.core.files import File from bs4 import BeautifulSoup from companies.models import Company from products.models import Product from products.serializers import ProductSerializer from history.models import HistorySync logging.basicConfig( filename='logs/woocommerce.log', filemode='w', format='%(levelname)s:%(message)s', level=logging.INFO, ) PRODUCT_FIELDS = [f.name for f in Product._meta.get_fields()] def get_wcapi_instance(url, key, secret, version="wc/v3"): wcapi = API( url=url, consumer_key=key, consumer_secret=secret, wp_api=True, version=version ) return wcapi def create_imported_product(info, company, history, user): # extract m2m field data tags = [t.get('name') for t in info.pop('tags')] attributes = [t.get('name') for t in info.pop('attributes')] # prepare instance data instance_data = { 'company':company.id, 'creator': user.id if user is not None else None, 'history': history.id, 'url': info.get('permalink'), 'stock': info.get('stock_quantity'), 'name': info.get('name'), 'description': BeautifulSoup(info.get('description', ''), "lxml").text, 'sku': info.get('sku'), 'price': None if info.get('price') == '' else info.get('price'), } # alternative method serializer = ProductSerializer(data=instance_data) if serializer.is_valid(): try: new = Product.objects.create(**serializer.validated_data) new.tags = tags new.attributes = attributes new.save() except Exception as e: logging.error(f"Could not create product instance: {str(e)}") return None if len(info['images']) > 0: try: # get image headers={"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"} image_url = info['images'][0]['src'] response = requests.get(image_url, stream=True, headers=headers) assert(response.status_code==200) response.raw.decode_content = True image = Image.open(response.raw) # save using File object img_io = BytesIO() image.save(img_io, format=image.format) new.image.save(f"{new.name}-{new.sku}.jpg", File(img_io), save=False) new.save() except AssertionError as e: logging.error(f"Source image [{info['images'][0]['src']}] not reachable: {response.status_code}") except Exception as e: logging.error(f"Could not add image to product {new.sku} from [{info['images'][0]['src']}]: {str(e)}") else: logging.info(f"No image for Product {new.name}") return new else: logging.error(f"{serializer.errors}") return None def migrate_shop_products(url, key, secret, user=None, version="wc/v3"): """Tries to connect to WooCommerce site @ url with given credentials If succesful, returns list of Product instances created """ # get wcapi wcapi = get_wcapi_instance(url, key, secret, version) consumer_key = 'ck_565539bb25b472b1ff7a209eb157ca11c0a26397' consumer_secret = 'cs_9c1690ba5da0dd70f51d61c395628fa14d1a104c' # get company fom url company = Company.objects.filter(web_link=url).first() if not company: logging.error(f"Could not find Company with URL: {url}") print(f"Could not find Company with URL: {url}") return None new_products = [] page = 1 # list products while True: try: response = wcapi.get('products/', params={'per_page': 10, 'page': page}) page += 1 if response.status_code == 200: products = response.json() elif response.status_code == 401: logging.error(f"{response.status_code} [{response.url}]: {response.json()}") return None else: logging.error(f"Could not load products from {response.url}: [{response.status_code}]") print(f"Could not load products fom {response.url}: [{response.status_code}]") return None except requests.exceptions.ReadTimeout as e: logging.error(f"Timeout reading backend: {str(e)}") # skip and try next continue # exit loop if no more products if not products: break # create HistorySync instance and link to every product created history = HistorySync.objects.create( company=company, sync_date=datetime.datetime.now(), ) counter = 0 for product in products: # check if exists if product['sku'] and Product.objects.filter(sku=product['sku']).exists(): # product already registered logging.info(f"Product with sku [{product['sku']}] already registered") print(f"Product with sku [{product['sku']}] already registered") # TODO: UPDATE instance?? continue new = create_imported_product(product, company, history, user) if new is not None: new_products.append(new) counter += 1 logging.info(f"Product '{new.name}' created") print(f"Product '{new.name}' created") # update history.quantity history.quantity = counter history.save() print(f"Products created: {len(new_products)}") return new_products