source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/contrib/AuthorizeNet.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 10.5 KB
Line 
1"""
2AIM class to credit card payment with authorize.net
3
4Fork of authnet code written by John Conde
5http://www.johnconde.net/blog/integrate-the-authorizenet-aim-api-with-python-3-2/
6BSDv3 License
7
8Modifed by Massimo Di Pierro
9
10- ported from Python 3.x run on Python 2.4+
11- fixed a couple of bugs
12- merged with test so single file
13- namedtuple from http://code.activestate.com/recipes/500261/
14
15"""
16from __future__ import print_function
17
18__all__ = ['AIM']
19
20from operator import itemgetter
21from gluon._compat import urlopen, urlencode, FancyURLopener
22
23_known_tuple_types = {}
24
25
26class NamedTupleBase(tuple):
27    """Base class for named tuples with the __new__ operator set, named tuples
28       yielded by the namedtuple() function will subclass this and add
29       properties."""
30    def __new__(cls, *args, **kws):
31        """Create a new instance of this fielded tuple"""
32        # May need to unpack named field values here
33        if kws:
34            values = list(args) + [None] * (len(cls._fields) - len(args))
35            fields = dict((val, idx) for idx, val in enumerate(cls._fields))
36            for kw, val in kws.iteritems():
37                assert kw in kws, "%r not in field list" % kw
38                values[fields[kw]] = val
39            args = tuple(values)
40        return tuple.__new__(cls, args)
41
42
43def namedtuple(typename, fieldnames):
44    """
45    >>> import namedtuples
46    >>> tpl = namedtuples.namedtuple(['a', 'b', 'c'])
47    >>> tpl(1, 2, 3)
48    (1, 2, 3)
49    >>> tpl(1, 2, 3).b
50    2
51    >>> tpl(c=1, a=2, b=3)
52    (2, 3, 1)
53    >>> tpl(c=1, a=2, b=3).b
54    3
55    >>> tpl(c='pads with nones')
56    (None, None, 'pads with nones')
57    >>> tpl(b='pads with nones')
58    (None, 'pads with nones', None)
59    >>>
60    """
61    # Split up a string, some people do this
62    if isinstance(fieldnames, basestring):
63        fieldnames = fieldnames.replace(',', ' ').split()
64    # Convert anything iterable that enumerates fields to a tuple now
65    fieldname_tuple = tuple(str(field) for field in fieldnames)
66    # See if we've cached this
67    if fieldname_tuple in _known_tuple_types:
68        return _known_tuple_types[fieldname_tuple]
69    # Make the type
70    new_tuple_type = type(typename, (NamedTupleBase,), {})
71    # Set the hidden field
72    new_tuple_type._fields = fieldname_tuple
73    # Add the getters
74    for i, field in enumerate(fieldname_tuple):
75        setattr(new_tuple_type, field, property(itemgetter(i)))
76    # Cache
77    _known_tuple_types[fieldname_tuple] = new_tuple_type
78    # Done
79    return new_tuple_type
80
81
82class AIM:
83
84    class AIMError(Exception):
85        def __init__(self, value):
86            self.parameter = value
87
88        def __str__(self):
89            return str(self.parameter)
90
91    def __init__(self, login, transkey, testmode=False):
92        if str(login).strip() == '' or login is None:
93            raise AIM.AIMError('No login name provided')
94        if str(transkey).strip() == '' or transkey is None:
95            raise AIM.AIMError('No transaction key provided')
96        if testmode != True and testmode != False:
97            raise AIM.AIMError('Invalid value for testmode. Must be True or False. "{0}" given.'.format(testmode))
98
99        self.testmode = testmode
100        self.proxy = None
101        self.delimiter = '|'
102        self.results = []
103        self.error = True
104        self.success = False
105        self.declined = False
106
107        self.parameters = {}
108        self.setParameter('x_delim_data', 'true')
109        self.setParameter('x_delim_char', self.delimiter)
110        self.setParameter('x_relay_response', 'FALSE')
111        self.setParameter('x_url', 'FALSE')
112        self.setParameter('x_version', '3.1')
113        self.setParameter('x_method', 'CC')
114        self.setParameter('x_type', 'AUTH_CAPTURE')
115        self.setParameter('x_login', login)
116        self.setParameter('x_tran_key', transkey)
117
118    def process(self):
119        encoded_args = urlencode(self.parameters)
120        if self.testmode == True:
121            url = 'https://test.authorize.net/gateway/transact.dll'
122        else:
123            url = 'https://secure.authorize.net/gateway/transact.dll'
124
125        if self.proxy is None:
126            self.results += str(urlopen(
127                url, encoded_args).read()).split(self.delimiter)
128        else:
129            opener = FancyURLopener(self.proxy)
130            opened = opener.open(url, encoded_args)
131            try:
132                self.results += str(opened.read()).split(self.delimiter)
133            finally:
134                opened.close()
135        Results = namedtuple('Results', 'ResultResponse ResponseSubcode ResponseCode ResponseText AuthCode \
136                                          AVSResponse TransactionID InvoiceNumber Description Amount PaymentMethod \
137                                          TransactionType CustomerID CHFirstName CHLastName Company BillingAddress \
138                                          BillingCity BillingState BillingZip BillingCountry Phone Fax Email ShippingFirstName \
139                                          ShippingLastName ShippingCompany ShippingAddress ShippingCity ShippingState \
140                                          ShippingZip ShippingCountry TaxAmount DutyAmount FreightAmount TaxExemptFlag \
141                                          PONumber MD5Hash CVVResponse CAVVResponse')
142        self.response = Results(*tuple(r for r in self.results)[0:40])
143
144        if self.getResultResponseFull() == 'Approved':
145            self.error = False
146            self.success = True
147            self.declined = False
148        elif self.getResultResponseFull() == 'Declined':
149            self.error = False
150            self.success = False
151            self.declined = True
152        else:
153            raise AIM.AIMError(self.response.ResponseText)
154
155    def setTransaction(self, creditcard, expiration, total, cvv=None, tax=None, invoice=None):
156        if str(creditcard).strip() == '' or creditcard is None:
157            raise AIM.AIMError('No credit card number passed to setTransaction(): {0}'.format(creditcard))
158        if str(expiration).strip() == '' or expiration is None:
159            raise AIM.AIMError('No expiration number to setTransaction(): {0}'.format(expiration))
160        if str(total).strip() == '' or total is None:
161            raise AIM.AIMError('No total amount passed to setTransaction(): {0}'.format(total))
162
163        self.setParameter('x_card_num', creditcard)
164        self.setParameter('x_exp_date', expiration)
165        self.setParameter('x_amount', total)
166        if cvv is not None:
167            self.setParameter('x_card_code', cvv)
168        if tax is not None:
169            self.setParameter('x_tax', tax)
170        if invoice is not None:
171            self.setParameter('x_invoice_num', invoice)
172
173    def setTransactionType(self, transtype=None):
174        types = ['AUTH_CAPTURE', 'AUTH_ONLY', 'PRIOR_AUTH_CAPTURE',
175                 'CREDIT', 'CAPTURE_ONLY', 'VOID']
176        if transtype.upper() not in types:
177            raise AIM.AIMError('Incorrect Transaction Type passed to setTransactionType(): {0}'.format(transtype))
178        self.setParameter('x_type', transtype.upper())
179
180    def setProxy(self, proxy=None):
181        if str(proxy).strip() == '' or proxy is None:
182            raise AIM.AIMError('No proxy passed to setProxy()')
183        self.proxy = {'http': str(proxy).strip()}
184
185    def setParameter(self, key=None, value=None):
186        if key is not None and value is not None and str(key).strip() != '' and str(value).strip() != '':
187            self.parameters[key] = str(value).strip()
188        else:
189            raise AIM.AIMError('Incorrect parameters passed to setParameter(): {0}:{1}'.format(key, value))
190
191    def isApproved(self):
192        return self.success
193
194    def isDeclined(self):
195        return self.declined
196
197    def isError(self):
198        return self.error
199
200    def getResultResponseFull(self):
201        responses = ['', 'Approved', 'Declined', 'Error']
202        return responses[int(self.results[0])]
203
204
205def process(creditcard, expiration, total, cvv=None, tax=None, invoice=None,
206            login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
207    payment = AIM(login, transkey, testmode)
208    expiration = expiration.replace('/', '')
209    payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
210    try:
211        payment.process()
212        return payment.isApproved()
213    except AIM.AIMError:
214        return False
215
216
217def test():
218    import socket
219    import sys
220    from time import time
221
222    creditcard = '4427802641004797'
223    expiration = '122012'
224    total = '1.00'
225    cvv = '123'
226    tax = '0.00'
227    invoice = str(time())[4:10]  # get a random invoice number
228
229    try:
230        payment = AIM('cnpdev4289', 'SR2P8g4jdEn7vFLQ', True)
231        payment.setTransaction(
232            creditcard, expiration, total, cvv, tax, invoice)
233        payment.setParameter(
234            'x_duplicate_window', 180)  # three minutes duplicate windows
235        payment.setParameter('x_cust_id', '1324')       # customer ID
236        payment.setParameter('x_first_name', 'John')
237        payment.setParameter('x_last_name', 'Conde')
238        payment.setParameter('x_company', 'Test Company')
239        payment.setParameter('x_address', '1234 Main Street')
240        payment.setParameter('x_city', 'Townsville')
241        payment.setParameter('x_state', 'NJ')
242        payment.setParameter('x_zip', '12345')
243        payment.setParameter('x_country', 'US')
244        payment.setParameter('x_phone', '800-555-1234')
245        payment.setParameter('x_description', 'Test Transaction')
246        payment.setParameter(
247            'x_customer_ip', socket.gethostbyname(socket.gethostname()))
248        payment.setParameter('x_email', 'john@example.com')
249        payment.setParameter('x_email_customer', False)
250        payment.process()
251        if payment.isApproved():
252            print('Response Code: ', payment.response.ResponseCode)
253            print('Response Text: ', payment.response.ResponseText)
254            print('Response: ', payment.getResultResponseFull())
255            print('Transaction ID: ', payment.response.TransactionID)
256            print('CVV Result: ', payment.response.CVVResponse)
257            print('Approval Code: ', payment.response.AuthCode)
258            print('AVS Result: ', payment.response.AVSResponse)
259        elif payment.isDeclined():
260            print('Your credit card was declined by your bank')
261        elif payment.isError():
262            raise AIM.AIMError('An uncaught error occurred')
263    except AIM.AIMError as e:
264        print("Exception thrown:", e)
265        print('An error occured')
266    print('approved', payment.isApproved())
267    print('declined', payment.isDeclined())
268    print('error', payment.isError())
269
270if __name__ == '__main__':
271    test()
Note: See TracBrowser for help on using the repository browser.