APIOperationBase   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 169
Duplicated Lines 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
wmc 30
dl 0
loc 169
rs 10
c 5
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A getenvironment() 0 3 1
A afterexecute() 0 2 1
A validaterequest() 0 3 1
A setenvironment() 0 4 1
A buildrequest() 0 9 1
A __init__() 0 20 2
A getresultcode() 0 5 2
C execute() 0 53 7
A beforeexecute() 0 2 1
A validate() 0 6 1
A setClientId() 0 2 1
A validateandsetmerchantauthentication() 0 8 3
A getmerchantauthentication() 0 3 1
A setmerchantauthentication() 0 4 1
A getmessagetype() 0 5 2
A _getrequest() 0 2 1
A getresponse() 0 3 1
A getprettyxmlrequest() 0 6 1
A __classinitialized() 0 3 1
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