importir
Errorunknown
python
3 years ago
19 kB
4
Indexable
import json import re import requests import traceback from typing import Dict, List from requests.exceptions import ConnectionError, Timeout from django.conf import settings from django.utils import timezone from apps.utils.logger import create_mongo_logger from apps.utils.image import get_image_url from apps.utils.cache import cache_wrapper from apps.helpers import currency, getSetting, updateOrCreateSetting from apps.models_helper.setting_tb import SettingTb from sentry_sdk import capture_exception CONFIG_INCOMPLETE = 'Incomplete configuration for importir API.' CONNECTION_FAILED = 'Failed connecting to importir.org' def get_file_name(cd): """ Get filename from content-disposition """ if not cd: return None fname = re.findall('filename=(.+)', cd) if len(fname) == 0: return None return fname[0] class ImportirAPI: # docs: https://importir.docs.apiary.io/ def __init__(self): self.retry_count = 0 self.base_url = getattr(settings, "IMPORTIR_BASE_URL", None) self.is_demo = getattr(settings, "IMPORTIR_IS_DEMO", True) self.timeout = getattr(settings, "IMPORTIR_TIMEOUT", 20) self.api_token = None setting_token = SettingTb.objects.filter(setting_key='importir_api_token')\ .first() if setting_token is None: token_response = self.generate_token() if token_response.get('action'): self.api_token = token_response.get('result')\ .get('message', {})\ .get('token', '') SettingTb.objects.create( setting_desc='Importir API Token', setting_key='importir_api_token', setting_title='Importir API Token', setting_value=self.api_token ) else: self.api_token = setting_token.setting_value setting_token.last_used_at = timezone.now() setting_token.save(update_fields=['last_used_at']) def generate_token(self): """ Generate auth token for importir API """ ret = {'action': False, 'status_code': 500, 'result': None, 'message': ''} endpoint = '/api/vendor/generate-token' api_url = self.base_url + endpoint user_email = getattr(settings, 'IMPORTIR_USER_EMAIL', None) api_key = getattr(settings, 'IMPORTIR_API_KEY', None) if not user_email or not api_key: ret['message'] = CONFIG_INCOMPLETE return ret request_params = {'email': user_email, 'api_key': api_key} try: response = requests.get(api_url, params=request_params) ret['status_code'] = response.status_code if response.status_code == 200: ret['action'] = True ret['result'] = response.json() if isinstance(ret['result'], dict) and ret.get('result').get('status', True) == False: ret['action'] = False except (ConnectionError, Timeout) as err: ret['message'] = CONNECTION_FAILED except Exception as err: capture_exception(traceback.format_exc()) log_data = { 'METHOD': 'GET', 'URL': api_url, 'STATUS_CODE': ret['status_code'], 'REQUEST_PARAMETERS': request_params, 'RESPONSE_DATA': ret } # logger = create_mongo_logger('importir', collection_name="mongolog-request") # logger.info(log_data) return ret def send(self, method, endpoint, request_data={}, request_files={}, request_params={}, request_headers={}, is_json=False): ret = {'action': False, 'status_code': 500, 'message': '', 'result': None} if not all([self.base_url, self.api_token]): ret['message'] = CONFIG_INCOMPLETE return ret api_headers = { # 'Content-Type': content_type, 'Authorization': 'Bearer ' + self.api_token } api_headers.update({**request_headers}) api_url = self.base_url + endpoint log_data = { 'METHOD': method, 'HEADERS': api_headers, 'REQUEST_DATA': request_data, 'URL': api_url } try: if method in ['post', 'POST']: # print("request data: ", request_data) # print("request files: ", request_files) if is_json: response = requests.post(api_url, headers=api_headers, data=json.dumps(request_data), timeout=7) # files=request_files else: response = requests.post(api_url, headers=api_headers, data=request_data, files=request_files, timeout=7) elif method in ['get', 'GET']: response = requests.get(api_url, headers=api_headers, params=request_params, timeout=self.timeout) log_data['STATUS_CODE'] = response.status_code log_data['FULL_URL'] = response.request.url ret['status_code'] = response.status_code if response.status_code == 200: ret['result'] = response.json() ret['action'] = True if isinstance(ret['result'], dict): # validasi api create shipping if ret.get('result').get('status', True) == False: ret['action'] = False # validasi api product 1688 & checkout importir_success_status = ['success_product_feeds_200', 'success_product_detail_200', 'success_product_description_view_200', 'success_checkout_200', 'success_categories_200', 'success_category_detail_200'] if ret.get('result').get('body') and ret.get('result').get('body').get('status_code') not in importir_success_status: ret['action'] = False except (ConnectionError, Timeout) as err: ret['message'] = CONNECTION_FAILED except Exception as err: capture_exception(traceback.format_exc()) log_data['RESPONSE_DATA'] = ret # logger = create_mongo_logger('importir', collection_name="mongolog-request") # logger.info(log_data) # If response is `Token is Expired`, retry request with new token if self.retry_count == 0 and isinstance(ret.get('result'), dict) and ret.get('result').get('data') == 'Token is Expired': self.retry_count += 1 token_response = self.generate_token() if token_response.get('action'): self.api_token = token_response.get('result')\ .get('message', {})\ .get('token', '') _ = updateOrCreateSetting('importir_api_token', self.api_token, 'Importir API Token') return self.send(method, endpoint, request_data, request_files, request_params, request_headers, is_json) return ret def get_file(self, file_url): """ Return response and filename """ response = None try: response = requests.get(file_url, allow_redirects=True) if response.status_code == 200: file_name = get_file_name(response.headers.get('content-disposition')) or file_url.rsplit('/', 1)[1] return response, file_name except (ConnectionError, Timeout) as err: pass except Exception as err: response = None print("Exception get_file: ", str(err)) return response, None def create_shipping_step_one(self, cart_tk: "CartTitipkirimin"): endpoint = '/api/shipping/step/1' estimation_weight = cart_tk.estimation_weight estimation_weight_kg = estimation_weight / 1000 if estimation_weight else 0 request_data = { 'freight': 10, # Laut LCL 'volume': cart_tk.estimation_volume, 'weight': estimation_weight_kg, 'is_demo': 1 if self.is_demo else 0, 'use_wood': 1 if cart_tk.is_wood else 0, 'wood_note': cart_tk.wood_note } request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_headers=request_headers) def create_shipping_step_two(self, shipping_id: int): endpoint = '/api/shipping/step/2' request_data = { 'id': shipping_id, # `shipping_id` from step 1 'other_price_rmb': '', } request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_headers=request_headers) def create_shipping_step_three(self, shipping_id: int, cart_tk: "CartTitipkirimin"): endpoint = '/api/shipping/step/3' request_data = { 'id': shipping_id, # `shipping_id` from step 1 'supplier_email': cart_tk.shipper_email, 'supplier_phone': cart_tk.shipper_phone_number, 'wechat_id': '' } request_files = { # 'supplier_bank_info': '', # 'invoice_file': '', # 'packing_ist_file': '' } # content_type = 'application/x-www-form-urlencoded' if cart_tk.invoice_file: response, filename = self.get_file(get_image_url(cart_tk.invoice_file)) if response: request_files.update({'invoice_file': (filename, response.content, response.headers.get('Content-Type'))}) # content_type = 'multipart/form-data' request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_files, request_headers=request_headers) def create_shipping_step_four(self, shipping_id: int): endpoint = '/api/shipping/step/4' request_data = { 'id': shipping_id, # `shipping_id` from step 1 'note': '' } request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_headers=request_headers) def shipping_save_product(self, shipping_id: int, cart_detail: "CartDetail"): endpoint = '/api/shipping/save-product/{}'.format(shipping_id) product_type = cart_detail.get_product_type product_price = cart_detail.price_original \ if cart_detail.currency == 'CNY' \ else currency(cart_detail.price_original, from_money=cart_detail.currency, to_money='CNY') price_per_unit = product_price / cart_detail.quantity is_lartas = 1 if cart_detail.additional_document == 'laporan' else 0 hscode = cart_detail.hscode # object hscode_number = '' if hscode is not None: hscode_number = (hscode.hscode).replace('.', '') request_data = { 'product_name': cart_detail.product.product_title, 'hscode': hscode_number, 'is_lartas': is_lartas, 'quantity': cart_detail.quantity, 'price_per_unit': price_per_unit, 'category[]': product_type.name } request_files = { # 'cover_product': '' } if cart_detail.product.image_file: response, filename = self.get_file(get_image_url(cart_detail.product.image_file)) if response: request_files.update({'cover_product': (filename, response.content, response.headers.get('Content-Type'))}) request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_files, request_headers=request_headers) def chat_list(self, shipping_id: int): """ Get chat list from Importir API Args: shipping_id (int): Importir shipping ID (see: Cart.additional_json) """ endpoint = '/api/shipping-chat/detail/{}'.format(shipping_id) request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('GET', endpoint, request_headers=request_headers) def post_chat(self, shipping_id: int, message: str): """ Send chat to Importir API Args: shipping_id (int): Importir shipping ID (see: Cart.additional_json) """ endpoint = '/api/shipping-chat/send-message/{}'.format(shipping_id) request_data = { 'message': message } request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data, request_headers=request_headers) def get_shipping_detail(self, shipping_id: int): """ Get shipping detail from ImportirAPI Args: shipping_id (int): Importir Shipping ID """ endpoint = '/api/shipping/detail/{}'.format(shipping_id) request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('GET', endpoint, request_headers=request_headers) def get_shipping_status(self, shipping_id: int): """ Get shipping status from ImportirAPI Args: shipping_id (int): Importir Shipping ID """ endpoint = '/api/shipping-status/{}'.format(shipping_id) request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('GET', endpoint, request_headers=request_headers) def get_product_feeds(self, query_params: Dict={}) -> Dict: """ Get 1688 product feeds from importir Args: query_params (Dict): request query parameters Returns: Dict: Json response from importir """ endpoint = '/api/product/feeds' if not isinstance(query_params, dict): query_params = {} def cache_validator(response): if response.get('action'): return True return False return cache_wrapper(key='importir:1688_product_feeds', timeout=3600, validator=cache_validator)(self.send)(method='GET', endpoint=endpoint, request_params=query_params, request_data={}, request_files={}, request_headers={}, is_json=False) def get_product_detail(self, product_id) -> Dict: """ Get 1688 product detail from importir Args: product_id (int): 1688 product ID Returns: Dict: Json response from importir """ if not product_id: ret = {'action': False, 'status_code': 500, 'message': 'Invalid product ID'} return ret endpoint = '/api/product/detail/1688/%s' % product_id return self.send('GET', endpoint) def get_product_description(self, product_id: int) -> Dict: """ Get 1688 product description from importir Args: product_id (int): 1688 product ID Returns: Dict: Json response from importir """ if not product_id or not isinstance(product_id, int): ret = {'action': False, 'status_code': 500, 'message': 'Invalid product ID'} return ret endpoint = '/product/description-view/%s' % product_id return self.send('GET', endpoint) def get_categories(self) -> Dict: """ Get product categories from importir """ endpoint = '/api/category/categories' return self.send('GET', endpoint) def get_sub_categories(self, category_slug: str) -> Dict: """ Get list sub categories from importir Args: category_slug (str): category slug """ endpoint = '/api/category/detail' request_params = { 'slug': category_slug } return self.send('GET', endpoint, request_params=request_params) def checkout(self, product_id: int, cart_details) -> Dict: """ Checkout Importir """ endpoint = '/api/cart/order-vendor' quantity = subtotal = weight = 0 is_multi_price = False spec_list = [] price_multiple_desc_list = [] cart_details = cart_details first_cart_detail = cart_details.first() for cart_detail in cart_details: quantity += cart_detail.quantity weight += cart_detail.weight product_type = cart_detail.product_type margin_percent = product_type.get_1688_margin(cart_detail.customer) margin = (100 + margin_percent) / 100 subtotal += (cart_detail.sub_total / margin) additional_info = cart_detail.get_additional_information() if additional_info.get('spec_id') and additional_info.get('sku_id'): spec_price = cart_detail.price / margin spec_list.append({'quantity': cart_detail.quantity, 'price': str(spec_price), 'specId': additional_info.get('spec_id')}) price_multiple_desc_list.append({'id': str(additional_info.get('sku_id')), 'qty': cart_detail.quantity}) if not is_multi_price: is_multi_price = additional_info.get('is_multi_price') == 1 request_data = { 'product_id': product_id, 'specIds': spec_list, 'note': first_cart_detail.product.product_title if first_cart_detail else '', 'note_ori': first_cart_detail.product.product_title if first_cart_detail else '', 'quantity': quantity, 'price': str(subtotal), 'freight': 'air' if first_cart_detail.package_track == 'udara' else 'sea', 'is_parse': 0, 'is_multiple_price': 1 if not is_multi_price else 0, 'price_type': 'RANGE' if is_multi_price else 'OTHERS', 'price_multiple_desc': price_multiple_desc_list, 'weight': weight, 'cbm': 0 } request_headers = { 'Content-Type': 'application/json', 'lang': 'id', 'currency': 'idr' } return self.send('POST', endpoint, request_data=request_data, request_headers=request_headers, is_json=True) def get_official_order_status(self, order_id: int) -> Dict: """ Get official 1688 order status from importir Args: order_id (int): Importir order ID """ endpoint = '/api/vendor/tracking/official-last-status' request_params = { 'order_id': order_id } request_headers = { 'lang': 'id', 'currency': 'idr' } return self.send('GET', endpoint, request_params=request_params, request_headers=request_headers)
Editor is loading...