1
|
|
|
''' |
2
|
|
|
Created on Nov 1, 2015 |
3
|
|
|
|
4
|
|
|
@author: krgupta |
5
|
|
|
''' |
6
|
|
|
import abc |
7
|
|
|
import logging |
8
|
|
|
import pyxb |
9
|
|
|
import sys |
10
|
|
|
import xml.dom.minidom |
11
|
|
|
import requests |
12
|
|
|
from lxml import objectify |
13
|
|
|
|
14
|
|
|
from authorizenet.constants import constants |
15
|
|
|
from authorizenet import apicontractsv1 |
16
|
|
|
from authorizenet import utility |
17
|
|
|
''' |
18
|
|
|
from authorizenet.apicontractsv1 import merchantAuthenticationType |
19
|
|
|
from authorizenet.apicontractsv1 import ANetApiRequest |
20
|
|
|
from authorizenet.apicontractsv1 import ANetApiResponse |
21
|
|
|
''' |
22
|
|
|
|
23
|
|
|
anetLogger = logging.getLogger(constants.defaultLoggerName) |
24
|
|
|
anetLogger.addHandler(logging.NullHandler()) |
25
|
|
|
logging.getLogger('pyxb.binding.content').addHandler(logging.NullHandler()) |
26
|
|
|
|
27
|
|
|
class APIOperationBaseInterface(object): |
28
|
|
|
|
29
|
|
|
__metaclass__ = abc.ABCMeta |
30
|
|
|
|
31
|
|
|
@abc.abstractmethod |
32
|
|
|
def execute(self): |
33
|
|
|
''' |
34
|
|
|
Makes a http-post call. |
35
|
|
|
Uses request xml and response class type to check that the response was of correct type |
36
|
|
|
''' |
37
|
|
|
pass |
38
|
|
|
|
39
|
|
|
@abc.abstractmethod |
40
|
|
|
def getresponseclass(self): |
41
|
|
|
''' Returns the response class ''' |
42
|
|
|
pass |
43
|
|
|
|
44
|
|
|
@abc.abstractmethod |
45
|
|
|
def getrequesttype(self): |
46
|
|
|
''' Returns the request class ''' |
47
|
|
|
pass |
48
|
|
|
|
49
|
|
|
@abc.abstractmethod |
50
|
|
|
def getresponse(self): |
51
|
|
|
''' Returns the de-serialized response''' |
52
|
|
|
pass |
53
|
|
|
|
54
|
|
|
@abc.abstractmethod |
55
|
|
|
def getresultcode(self): |
56
|
|
|
''' Returns the result code from the response ''' |
57
|
|
|
pass |
58
|
|
|
|
59
|
|
|
@abc.abstractmethod |
60
|
|
|
def getmessagetype(self): |
61
|
|
|
''' Returns the message type enum from the response ''' |
62
|
|
|
pass |
63
|
|
|
|
64
|
|
|
@abc.abstractmethod |
65
|
|
|
def afterexecute(self): |
66
|
|
|
'''Returns the message received from binding after processing request''' |
67
|
|
|
pass |
68
|
|
|
|
69
|
|
|
@abc.abstractmethod |
70
|
|
|
def beforeexecute(self): |
71
|
|
|
'''TODO''' |
72
|
|
|
pass |
73
|
|
|
|
74
|
|
|
class APIOperationBase(APIOperationBaseInterface): |
75
|
|
|
|
76
|
|
|
__metaclass__ = abc.ABCMeta |
77
|
|
|
__initialized = False |
78
|
|
|
__merchantauthentication = "null" |
79
|
|
|
__environment = "null" |
80
|
|
|
|
81
|
|
|
@staticmethod |
82
|
|
|
def __classinitialized(): |
83
|
|
|
return APIOperationBase.__initialized |
84
|
|
|
|
85
|
|
|
@abc.abstractmethod |
86
|
|
|
def validaterequest(self): |
87
|
|
|
return |
88
|
|
|
|
89
|
|
|
def validate(self): |
90
|
|
|
anetapirequest = self._getrequest() |
91
|
|
|
self.validateandsetmerchantauthentication() |
92
|
|
|
self.validaterequest() |
93
|
|
|
|
94
|
|
|
return |
95
|
|
|
|
96
|
|
|
def setClientId(self): #protected method |
97
|
|
|
self._request.clientId = constants.clientId |
98
|
|
|
|
99
|
|
|
def _getrequest(self): #protected method |
100
|
|
|
return self._request |
101
|
|
|
|
102
|
|
|
def buildrequest(self): |
103
|
|
|
anetLogger.debug('building request..') |
104
|
|
|
|
105
|
|
|
xmlRequest = self._request.toxml(encoding=constants.xml_encoding, element_name=self.getrequesttype()) |
106
|
|
|
#remove namespaces that toxml() generates |
107
|
|
|
xmlRequest = xmlRequest.replace(constants.nsNamespace1, b'') |
108
|
|
|
xmlRequest = xmlRequest.replace(constants.nsNamespace2, b'') |
109
|
|
|
|
110
|
|
|
return xmlRequest |
111
|
|
|
|
112
|
|
|
def getprettyxmlrequest(self): |
113
|
|
|
xmlRequest = self.buildrequest() |
114
|
|
|
requestDom = xml.dom.minidom.parseString(xmlRequest) |
115
|
|
|
anetLogger.debug('Request is: %s' % requestDom.toprettyxml()) |
116
|
|
|
|
117
|
|
|
return requestDom |
118
|
|
|
|
119
|
|
|
def execute(self): |
120
|
|
|
|
121
|
|
|
self.endpoint = APIOperationBase.__environment |
122
|
|
|
|
123
|
|
|
anetLogger.debug('Executing http post to url: %s', self.endpoint) |
124
|
|
|
|
125
|
|
|
self.beforeexecute() |
126
|
|
|
|
127
|
|
|
proxyDictionary = {'http' : utility.helper.getproperty("http"), |
128
|
|
|
'https' : utility.helper.getproperty("https"), |
129
|
|
|
'ftp' : utility.helper.getproperty("ftp")} |
130
|
|
|
|
131
|
|
|
#requests is http request |
132
|
|
|
try: |
133
|
|
|
self.setClientId() |
134
|
|
|
xmlRequest = self.buildrequest() |
135
|
|
|
self._httpResponse = requests.post(self.endpoint, data=xmlRequest, headers=constants.headers, proxies=proxyDictionary) |
136
|
|
|
except Exception as httpException: |
137
|
|
|
anetLogger.error( 'Error retrieving http response from: %s for request: %s', self.endpoint, self.getprettyxmlrequest()) |
138
|
|
|
anetLogger.error( 'Exception: %s, %s', type(httpException), httpException.args ) |
139
|
|
|
|
140
|
|
|
|
141
|
|
|
if self._httpResponse: |
142
|
|
|
self._httpResponse.encoding = constants.response_encoding |
143
|
|
|
self._httpResponse = self._httpResponse.text[3:] #strip BOM |
144
|
|
|
self.afterexecute() |
145
|
|
|
try: |
146
|
|
|
self._response = apicontractsv1.CreateFromDocument(self._httpResponse) |
147
|
|
|
#objectify code |
148
|
|
|
xmlResponse= self._response.toxml(encoding=constants.xml_encoding, element_name=self.getrequesttype()) |
149
|
|
|
xmlResponse = xmlResponse.replace(constants.nsNamespace1, b'') |
150
|
|
|
xmlResponse = xmlResponse.replace(constants.nsNamespace2, b'') |
151
|
|
|
self._mainObject = objectify.fromstring(xmlResponse) |
152
|
|
|
|
153
|
|
|
except Exception as objectifyexception: |
154
|
|
|
anetLogger.error( 'Create Document Exception: %s, %s', type(objectifyexception), objectifyexception.args ) |
155
|
|
|
responseString = self._httpResponse |
156
|
|
|
|
157
|
|
|
# removing encoding attribute as objectify fails if it is present |
158
|
|
|
responseString = responseString.replace('encoding=\"utf-8\"', '') |
159
|
|
|
self._mainObject = objectify.fromstring(responseString) |
160
|
|
|
else: |
161
|
|
|
if type(self.getresponseclass()) != type(self._mainObject): |
162
|
|
|
if self._response.messages.resultCode == "Error": |
163
|
|
|
anetLogger.debug("Response error") |
164
|
|
|
domResponse = xml.dom.minidom.parseString(self._httpResponse.encode('utf-8')) |
165
|
|
|
anetLogger.debug('Received response: %s' % domResponse.toprettyxml(encoding='utf-8')) |
166
|
|
|
else: |
167
|
|
|
#Need to handle ErrorResponse |
168
|
|
|
anetLogger.debug('Error retrieving response for request: %s' % self._request) |
169
|
|
|
else: |
170
|
|
|
anetLogger.debug("Did not receive http response") |
171
|
|
|
return |
172
|
|
|
|
173
|
|
|
def getresponse(self): |
174
|
|
|
#return self._response #pyxb object |
175
|
|
|
return self._mainObject #objectify object |
176
|
|
|
|
177
|
|
|
def getresultcode(self): |
178
|
|
|
resultcode = 'null' |
179
|
|
|
if self._response: |
180
|
|
|
resultcode = self._response.resultCode |
181
|
|
|
return resultcode |
182
|
|
|
|
183
|
|
|
def getmessagetype(self): |
184
|
|
|
message = 'null' |
185
|
|
|
if self._response: |
186
|
|
|
message = self._response.message |
187
|
|
|
return message |
188
|
|
|
|
189
|
|
|
def afterexecute(self ): |
190
|
|
|
return |
191
|
|
|
|
192
|
|
|
def beforeexecute(self): |
193
|
|
|
return |
194
|
|
|
|
195
|
|
|
@staticmethod |
196
|
|
|
def getmerchantauthentication(self): |
197
|
|
|
return self.__merchantauthentication |
198
|
|
|
|
199
|
|
|
@staticmethod |
200
|
|
|
def setmerchantauthentication(merchantauthentication): |
201
|
|
|
APIOperationBase.__merchantauthentication = merchantauthentication |
202
|
|
|
return |
203
|
|
|
|
204
|
|
|
def validateandsetmerchantauthentication(self): |
205
|
|
|
anetapirequest = apicontractsv1.ANetApiRequest() |
206
|
|
|
if (anetapirequest.merchantAuthentication == "null"): |
207
|
|
|
if (self.getmerchantauthentication() != "null"): |
208
|
|
|
anetapirequest.merchantAuthentication = self.getmerchantauthentication() |
209
|
|
|
else: |
210
|
|
|
raise ValueError('Merchant Authentication can not be null') |
211
|
|
|
return |
212
|
|
|
|
213
|
|
|
@staticmethod |
214
|
|
|
def getenvironment(self): |
215
|
|
|
return APIOperationBase.__environment |
216
|
|
|
|
217
|
|
|
|
218
|
|
|
@staticmethod |
219
|
|
|
def setenvironment(userenvironment): |
220
|
|
|
APIOperationBase.__environment = userenvironment |
221
|
|
|
return |
222
|
|
|
|
223
|
|
|
def __init__(self, apiRequest): |
224
|
|
|
self._httpResponse = None |
225
|
|
|
self._request = None |
226
|
|
|
self._response = None |
227
|
|
|
#objectify variables |
228
|
|
|
self._responseXML = None |
229
|
|
|
self._reponseObject = None |
230
|
|
|
self._mainObject = None |
231
|
|
|
|
232
|
|
|
if None == apiRequest: |
233
|
|
|
raise ValueError('Input request cannot be null') |
234
|
|
|
|
235
|
|
|
self._request = apiRequest |
236
|
|
|
__merchantauthentication = apicontractsv1.merchantAuthenticationType() |
237
|
|
|
APIOperationBase.__environment = constants.SANDBOX |
238
|
|
|
|
239
|
|
|
APIOperationBase.setmerchantauthentication(__merchantauthentication) |
240
|
|
|
self.validate() |
241
|
|
|
|
242
|
|
|
return |
243
|
|
|
|