Files
suite/connector_amazon_sp/components/api/amazon.py
2022-02-04 13:25:45 -08:00

183 lines
5.8 KiB
Python

# © 2021 Hibou Corp.
# imports for Client and CredentialProvider patch
from os import environ
import json
from requests import request
import boto3
from botocore.config import Config as BotoConfig
from sp_api.base.client import Client
from sp_api.base.config import CredentialProvider
from sp_api.base.ApiResponse import ApiResponse
from sp_api.base.marketplaces import Marketplaces
from sp_api.auth import AccessTokenClient
from requests.exceptions import HTTPError
# imports for Wrapping
from sp_api.api import Orders, \
Shipping, \
MerchantFulfillment, \
Feeds
from sp_api.base.exceptions import SellingApiException, \
SellingApiForbiddenException
amz_proxy_endpoint = environ.get('AMAZON_SP_ENDPOINT', 'https://amz-proxy.hibou.io')
PROXY_ENDPOINT = amz_proxy_endpoint
PROXY = amz_proxy_endpoint.split('//')[1]
class RequestRateError(Exception):
def __init__(self, message, exception=None):
super().__init__(message)
self.exception = exception
class WrappedAPI:
SellingApiException = SellingApiException
SellingApiForbiddenException = SellingApiForbiddenException
def __init__(self, env, refresh_token, lwa_client_id, lwa_client_secret, aws_access_key, aws_secret_key, role_arn):
self.env = env
get_param = env['ir.config_parameter'].sudo().get_param
self.credentials = {
'refresh_token': refresh_token,
'lwa_app_id': lwa_client_id,
'lwa_client_secret': lwa_client_secret,
'aws_access_key': aws_access_key,
'aws_secret_key': aws_secret_key,
'role_arn': role_arn,
# 'db_uid': get_param('database.uuid', ''),
# 'pro_code': get_param('database.hibou_professional_code', ''),
}
def orders(self):
return Orders(credentials=self.credentials)
def shipping(self):
return Shipping(credentials=self.credentials)
def merchant_fulfillment(self):
return MerchantFulfillment(credentials=self.credentials)
def feeds(self):
return Feeds(credentials=self.credentials)
# patch the Client
def __init__(
self,
marketplace: Marketplaces = Marketplaces.US,
*,
refresh_token=None,
account='default',
credentials=None
):
super(Client, self).__init__(account, credentials)
self.boto3_client = boto3.client(
'sts',
# aws_access_key_id=self.credentials.aws_access_key,
# aws_secret_access_key=self.credentials.aws_secret_key
config=BotoConfig(proxies={'http': PROXY, 'https': PROXY})
)
self.endpoint = marketplace.endpoint
self.marketplace_id = marketplace.marketplace_id
self.region = marketplace.region
self._auth = AccessTokenClient(refresh_token=refresh_token, account=account, credentials=credentials)
def _sign_request(self):
return None
def _request(self, path: str, *, data: dict = None, params: dict = None, headers=None,
add_marketplace=True) -> ApiResponse:
if params is None:
params = {}
if data is None:
data = {}
self.method = params.pop('method', data.pop('method', 'GET'))
if add_marketplace:
self._add_marketplaces(data if self.method in ('POST', 'PUT') else params)
# auth=None because we don't sign the request anymore
# proxy setup...
# url = self.endpoint + path
url = PROXY_ENDPOINT + path
headers = headers or self.headers
headers['x-orig-host'] = headers['host']
del headers['host']
headers['x-db-uuid'] = self.credentials.db_uid
headers['x-pro-code'] = self.credentials.pro_code
res = request(self.method, url, params=params,
data=json.dumps(data) if data and self.method in ('POST', 'PUT') else None, headers=headers,
auth=self._sign_request())
try:
res.raise_for_status() # proxy does not return json errors
except HTTPError as e:
status_code = e.response.status_code
if str(status_code) == '429':
raise RequestRateError('HTTP 429', exception=e)
raise e
return self._check_response(res)
# Patch _request to have timeout, not signing differences above.
def _request(self, path: str, *, data: dict = None, params: dict = None, headers=None,
add_marketplace=True) -> ApiResponse:
if params is None:
params = {}
if data is None:
data = {}
self.method = params.pop('method', data.pop('method', 'GET'))
if add_marketplace:
self._add_marketplaces(data if self.method in ('POST', 'PUT') else params)
res = request(self.method, self.endpoint + path, params=params,
data=json.dumps(data) if data and self.method in ('POST', 'PUT') else None, headers=headers or self.headers,
auth=self._sign_request(),
timeout=60)
return self._check_response(res)
# Client.__init__ = __init__
# Client._sign_request = _sign_request
Client._request = _request
# patch the CredentialProvider
class Config:
def __init__(self,
refresh_token,
lwa_app_id,
lwa_client_secret,
aws_access_key,
aws_secret_key,
role_arn,
db_uid,
pro_code,
):
self.refresh_token = refresh_token
self.lwa_app_id = lwa_app_id
self.lwa_client_secret = lwa_client_secret
self.aws_access_key = aws_access_key
self.aws_secret_key = aws_secret_key
self.role_arn = role_arn
self.db_uid = db_uid
self.pro_code = pro_code
def check_config(self):
errors = []
for k, v in self.__dict__.items():
if not v and k != 'refresh_token':
errors.append(k)
return errors
# CredentialProvider.Config = Config