Skip to content

Instantly share code, notes, and snippets.

@levivm
Created July 20, 2018 04:43
Show Gist options
  • Save levivm/cf898a45f095f2d8d00e799c031454e8 to your computer and use it in GitHub Desktop.
Save levivm/cf898a45f095f2d8d00e799c031454e8 to your computer and use it in GitHub Desktop.
from zeep import Client
from zeep.helpers import serialize_object
from rest_framework import status
import traceback
import sys
from mo_integration.communication import services as communication_service
from .exceptions import (
CriticalBSAPIResponse,
ServiceBSUnavailable,
MerchantNotFound,
OtherBSException,
BSMalformedResponse
)
from .mixins import (
ParseXMLResponseMixin,
RenameResponseAttributesMixin
)
from ..constants import (
PARTNER_API_URL,
PARTNER_API_USERNAME,
PARTNER_API_PASSWORD,
SENSITIVE_PARTNER_API_URL,
SENSITIVE_PARTNER_API_USERNAME,
SENSITIVE_PARTNER_API_PASSWORD,
BlackstoneResponseCode
)
from ..utils import (
convert_dict_values_to_str
)
from mo_security.security.mixins import (
KinesisLogViewMixin
)
class BlackstoneAPI(
ParseXMLResponseMixin,
RenameResponseAttributesMixin,
KinesisLogViewMixin
):
WSDL_URL = None
soap_client = None
BLACKSTONE_USERNAME = None
BLACKSTONE_PASSWORD = None
def __init__(self, wsdl_url, username, password):
if not self.soap_client:
self.WSDL_URL = wsdl_url
self.BLACKSTONE_USERNAME = username
self.BLACKSTONE_PASSWORD = password
self.soap_client = self.get_soap_client()
def get_soap_client(self):
"""
:return: client: Client
"""
try:
client = Client(self.WSDL_URL)
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
msg = ServiceBSUnavailable.default_detail\
.format(type(e).__name__, e.args)
trace = repr(traceback.extract_tb(exc_traceback))
communication_service\
.alert_error_communication_with_partner(msg, trace)
exp = ServiceBSUnavailable(msg)
data_to_log = dict(response_detail=exp.get_full_details())
self.log_kinesis_partner_connection(data_to_log)
raise exp
return client
@classmethod
def parse_xml_response(cls, xml_response):
"""
Parse and validate the response dict
:param xml_response: dict
:return: dict
"""
parsed_response = cls.parse_xml_raw_response(
xml_response
)
cls.validate_response(parsed_response)
parsed_response_content = cls.parse_xml_raw_content(xml_response)
return parsed_response_content
@classmethod
def parse_response(cls, response):
"""
:param response: json
:return: parsed_response: dict
"""
if not cls.is_complex_response(response):
serialized_object = serialize_object(response)
cls.validate_response(serialized_object)
return serialized_object
try:
parsed_response = cls.parse_xml_response(
response
)
except AttributeError as exception:
raise BSMalformedResponse
return parsed_response
@classmethod
def validate_response(cls, parsed_response):
"""
Validate the response code from parsed response
if is not valid raise an exception
:param parsed_response:
"""
if not parsed_response.get('ErrorCode') is None:
code = parsed_response.get('ErrorCode')
message = parsed_response.get('ErrorDescription')
else:
code = parsed_response.get('response')\
.get('response_code')
message = parsed_response.get('response')\
.get('response_description')
if BlackstoneResponseCode.is_critical_response(code):
exception = BlackstoneResponseCode.get_api_exception_by_code(
code
)
raise exception(
"Error code: {0} \nError message: {1}"
.format(
code,
message
)
)
if not BlackstoneResponseCode.is_success_response(code):
exception = BlackstoneResponseCode.get_api_exception_by_code(
code
)
if exception.status_code == status.HTTP_404_NOT_FOUND:
raise exception
raise exception({
'non_field_errors': [message]
})
@classmethod
def alert_invalid_response_code(
cls,
request_data,
service_name,
exception,
receivers=None
):
"""
Alert the invalid response code received from BS
:param request_data: dict
:param service_name: str
:param exception: Exception
:param receivers: list
:return:
"""
del request_data['credential']
request_data = convert_dict_values_to_str(request_data)
communication_service.alert_invalid_response_code_from_partner(
service_name=service_name,
data_sent=request_data,
exception_message=exception.get_full_details(),
receivers=receivers
)
def send_unauthorized_request(self, service_name, data=None):
""""
:param service_name: str
:param data: dict
:return: res
"""
soap_method = getattr(
self.soap_client.service,
service_name,
None
)
request_data = {
'request': data
} if data else {}
return self.call_request_method(
soap_method,
request_data,
service_name
)
def send_request(self, service_name, data=None):
"""
:param service_name: str
:param data: dict
:return: res
"""
soap_method = getattr(
self.soap_client.service,
service_name,
None
)
request_data = {
'credential': {
'Username': self.BLACKSTONE_USERNAME,
'Password': self.BLACKSTONE_PASSWORD
},
'request': data
}
return self.call_request_method(
soap_method,
request_data,
service_name
).get(
'content',
)
def call_request_method(self, soap_method, request_data, service_name):
"""
:param soap_method: function
:param request_data: dict
:param service_name: str
:return: dict
"""
parsed_response = {}
data_to_log = dict(
service_name=service_name,
request_data=request_data,
response_detail=""
)
try:
response = soap_method(**request_data)
parsed_response = self.parse_response(response)
data_to_log.update(dict(
response_detail=u'Transaction success',
))
except CriticalBSAPIResponse as critical_exception:
self.alert_invalid_response_code(
request_data,
service_name,
critical_exception
)
data_to_log.update(dict(
response_detail=critical_exception.get_full_details())
)
self.log_kinesis_partner_request(data_to_log)
raise critical_exception
except MerchantNotFound as merchant_not_found_exception:
receivers = [
'[email protected]',
'[email protected]',
'[email protected]'
]
self.alert_invalid_response_code(
request_data,
service_name,
merchant_not_found_exception,
receivers
)
data_to_log.update(
dict(
response_detail=merchant_not_found_exception
.get_full_details()
)
)
self.log_kinesis_partner_request(data_to_log)
raise merchant_not_found_exception
except OtherBSException as other_bs_exception:
self.alert_invalid_response_code(
request_data,
service_name,
other_bs_exception
)
data_to_log.update(
dict(
response_detail=other_bs_exception.get_full_details()
)
)
self.log_kinesis_partner_request(data_to_log)
raise other_bs_exception
except BSMalformedResponse as bs_malformed_response:
self.alert_invalid_response_code(
request_data,
service_name,
bs_malformed_response
)
data_to_log.update(
dict(response_detail=bs_malformed_response)
)
communication_service.alert_error_communication_with_partner(
bs_malformed_response.get_full_details()
)
self.log_kinesis_partner_request(data_to_log)
raise BSMalformedResponse(
dict(
non_field_errors=[
bs_malformed_response.error_display_message
]
)
)
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
trace = repr(traceback.extract_tb(exc_traceback))
error_message = ServiceBSUnavailable.default_detail.format(
type(e).__name__,
e.args
)
communication_service.alert_error_communication_with_partner(
error_message,
trace
)
exp = ServiceBSUnavailable(error_message)
data_to_log.update(
dict(
response_detail=exp.get_full_details()
)
)
self.log_kinesis_partner_request(data_to_log)
raise exp
self.log_kinesis_partner_request(data_to_log)
return parsed_response
class PublicBlackstoneAPI(BlackstoneAPI):
API_URL = PARTNER_API_URL
USERNAME = PARTNER_API_USERNAME
PASSWORD = PARTNER_API_PASSWORD
def __init__(self):
super(PublicBlackstoneAPI, self).__init__(
self.API_URL,
self.USERNAME,
self.PASSWORD
)
def get_merchants_info_from_phone_or_email(
self,
phone_number=None,
email=None
):
"""
Verify merchant's email or phone number
US_ID = 571
:param phone_number: str
:param email: str
:return: external_id: str
"""
SERVICE_NAME = 'VerifyMerchant'
data = {
'merchant_emailaddress': email
} if email else {
'merchant_phonenumber': phone_number
}
response = self.send_request(
SERVICE_NAME,
data
)
renamed_response = self.rename_response_attributes(
response,
[
('merchant_fk', 'merchant_id'),
('merchant_busphone', 'phone_number'),
('merchant_BusinessName', 'merchant_name'),
('merchant_email', 'email'),
]
)
return renamed_response
def get_merchants_data_by_date(
self,
from_date=None,
to_date=None
):
"""
Get the anonymous information for merchants
US_ID = 567
:param from_date: str
:param to_date: str
:return: dict
"""
SERVICE_NAME = 'Retrievemerchants'
data = dict(
dateTo=to_date,
dateFrom=from_date
)
return self.send_request(
SERVICE_NAME,
data
)
def update_merchant_amount_cash_advance(
self,
merchant_pk=None,
merchant_mcaa=None,
merchant_mo_status=None
):
"""
Notify BS the Merchants Maximum Amount of Cash Advance (ACA) and
MO status
US_ID = 569
:param merchant_pk: int
:param merchant_mcaa: decimal
:param merchant_mo_status: str
:return: dict
"""
SERVICE_NAME = 'UpdateMCAAStatus'
data = dict(
merchant_pk=merchant_pk,
merchant_MCAA=merchant_mcaa,
merchant_MO_Status=merchant_mo_status
)
response = self.send_request(
SERVICE_NAME,
data
)
return response
def retrieve_all_merchants_status(self, dateFrom, dateTo):
"""
service US_ID = 577
:param dateFrom: str
:param dateTo: str
:return: dict
"""
data = dict(
dateFrom=dateFrom,
dateTo=dateTo
)
service = "Retrievestatusupdates"
return self.send_request(service, data)
def notify_merchant_registration(
self,
merchant_id=None
):
"""
Notify BS that a new merchant was registered
US_ID = 572
:param merchant_id:
:return: dict
"""
SERVICE_NAME = 'RegisterMerchant'
data = dict(
merchant_pk=str(merchant_id),
)
response = self.send_request(
SERVICE_NAME,
data
)
return response
def echo(self):
"""
Echo service
US_ID = 578
:return:
"""
SERVICE_NAME = 'Echo'
response = self.send_unauthorized_request(
SERVICE_NAME
)
return response
class PrivateBlackstoneAPI(BlackstoneAPI):
API_URL = SENSITIVE_PARTNER_API_URL
USERNAME = SENSITIVE_PARTNER_API_USERNAME
PASSWORD = SENSITIVE_PARTNER_API_PASSWORD
def __init__(self):
super(PrivateBlackstoneAPI, self).__init__(
self.API_URL,
self.USERNAME,
self.PASSWORD
)
def update_merchant_basic_information(self, merchant_id):
"""
service US_ID = 573
:param merchant_id: int
:return: dict
"""
data = dict(
merchant_pk=merchant_id,
)
service = "Retrievemerchantbankupdte"
return self.send_request(service, data)
def get_merchant_basic_information(self, merchant_id):
"""
service US_ID = 570
:param merchant_id: int
:return: dict
"""
data = dict(
merchant_pk=merchant_id,
)
service = "RetrieveMerchantinformation"
return self.send_request(service, data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment