Skip to content

Commit f9584db

Browse files
author
Craig Christenson
committed
Adding support for 2Checkout Purchase API
1 parent 3a5c382 commit f9584db

5 files changed

Lines changed: 220 additions & 26 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
*.lock
33
*.DS_Store
44
*.swp
5-
*.out
5+
*.out
6+
*.idea
7+
*.pyc
8+
*build

README.md

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,105 @@ import twocheckout
3030

3131
Full documentation for each binding will be provided in the [Wiki](https://github.com/2checkout/2checkout-python/wiki).
3232

33+
Example Purchase API Usage
34+
-----------------
35+
36+
*Example Usage:*
37+
38+
```python
39+
import twocheckout
40+
41+
42+
twocheckout.Api.auth_credentials({
43+
'private_key': '9999999',
44+
'seller_id': '532001',
45+
'mode': 'production'
46+
})
47+
48+
params = {
49+
'merchantOrderId': '123',
50+
'token': 'ODAxZjUzMDEtOWU0MC00NzA3LWFmMDctYmY1NTQ3MDhmZDFh',
51+
'currency': 'USD',
52+
'total': '1.00',
53+
'billingAddr': {
54+
'name': 'Testing Tester',
55+
'addrLine1': '123 Test St',
56+
'city': 'Columbus',
57+
'state': 'OH',
58+
'zipCode': '43123',
59+
'country': 'USA',
60+
'email': 'cchristenson@2co.com',
61+
'phoneNumber': '555-555-5555'
62+
}
63+
}
64+
65+
try:
66+
result = twocheckout.Charge.authorize(params)
67+
print result.responseCode
68+
except TwocheckoutError as error:
69+
print error.msg
70+
71+
```
72+
73+
*Example Response:*
74+
75+
```python
76+
{
77+
'lineItems': [
78+
{
79+
'tangible': 'N',
80+
'name': '123',
81+
'price': '1.00',
82+
'description': '',
83+
'recurrence': None,
84+
'duration': None,
85+
'startupFee': None,
86+
'productId': '',
87+
'type': 'product',
88+
'options': [
89+
90+
],
91+
'quantity': '1'
92+
}
93+
],
94+
'responseMsg': 'Successfully authorized the provided creditcard',
95+
'recurrentInstallmentId': None,
96+
'shippingAddr': {
97+
'city': None,
98+
'phoneExtension': None,
99+
'country': None,
100+
'addrLine2': None,
101+
'zipCode': None,
102+
'addrLine1': None,
103+
'state': None,
104+
'phoneNumber': None,
105+
'email': None,
106+
'name': None
107+
},
108+
'orderNumber': '205180784763',
109+
'currencyCode': 'USD',
110+
'merchantOrderId': '123',
111+
'errors': None,
112+
'responseCode': 'APPROVED',
113+
'transactionId': '205180784772',
114+
'total': '1.00',
115+
'type': 'AuthResponse',
116+
'billingAddr': {
117+
'city': 'Columbus',
118+
'phoneExtension': None,
119+
'country': 'USA',
120+
'addrLine2': None,
121+
'zipCode': '43123',
122+
'addrLine1': '123 Test St',
123+
'state': 'OH',
124+
'phoneNumber': '555-555-5555',
125+
'email': 'cchristenson@2co.com',
126+
'name': 'Testing Tester'
127+
}
128+
}
129+
```
33130

34-
Example API Usage
131+
Example Admin API Usage
35132
-----------------
36133

37134
*Example Usage:*

test/test_twocheckout.py

100644100755
Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
EXAMPLE_PRODUCT = {
1515
'name': 'Example Product',
16-
'price': 1.00,
16+
'price': 1.00
1717
}
1818

1919
EXAMPLE_OPTION = {
@@ -28,12 +28,12 @@
2828
}
2929

3030
EXAMPLE_SALE = {
31-
'sale_id': 4774380224,
31+
'sale_id': 4774380224
3232
}
3333

3434
EXAMPLE_COMMENT = {
35-
'sale_comment': "test",
36-
}
35+
'sale_comment': "test"
36+
}
3737

3838
EXAMPLE_REFUND = {
3939
'comment': "test",
@@ -60,11 +60,37 @@
6060
'secret': 'tango'
6161
}
6262

63+
EXAMPLE_AUTH = {
64+
'merchantOrderId': '123',
65+
'token': 'ZDBiNGFkYzMtZGIzNi00MDMwLWIwMTctNTAzOGFhOTU1ODJm',
66+
'currency': 'USD',
67+
'total': '1.00',
68+
'billingAddr': {
69+
'name': 'Testing Tester',
70+
'addrLine1': '123 Test St',
71+
'city': 'Columbus',
72+
'state': 'OH',
73+
'zipCode': '43123',
74+
'country': 'USA',
75+
'email': 'cchristenson@2co.com',
76+
'phoneNumber': '555-555-5555'
77+
}
78+
}
79+
6380
class TwocheckoutTestCase(unittest.TestCase):
6481
def setUp(self):
6582
super(TwocheckoutTestCase, self).setUp()
6683

67-
twocheckout.Api.credentials({'username':'APIuser1817037', 'password':'APIpass1817037'})
84+
twocheckout.Api.credentials({
85+
'username': 'APIuser1817037',
86+
'password': 'APIpass1817037'
87+
})
88+
89+
twocheckout.Api.auth_credentials({
90+
'private_key': '9999999',
91+
'seller_id': '532001',
92+
'mode': 'production'
93+
})
6894

6995
class SaleTest(TwocheckoutTestCase):
7096
def setUp(self):
@@ -277,5 +303,17 @@ def test_1_check(self):
277303
result = twocheckout.Notification.check(params)
278304
self.assertEqual(result.response_code, "SUCCESS")
279305

306+
class AuthorizationTest(TwocheckoutTestCase):
307+
def setUp(self):
308+
super(AuthorizationTest, self).setUp()
309+
310+
def test_1_auth(self):
311+
params = EXAMPLE_AUTH
312+
try:
313+
result = twocheckout.Charge.authorize(params)
314+
self.assertEqual(result.responseCode, "APPROVED")
315+
except TwocheckoutError as error:
316+
self.assertEqual(error.msg, "Unauthorized")
317+
280318
if __name__ == '__main__':
281319
unittest.main()

twocheckout/api_request.py

100644100755
Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,82 @@
66

77
class Api:
88

9-
username = []
10-
password = []
9+
username = None
10+
password = None
11+
private_key = None
12+
seller_id = None
13+
mode = None
14+
version = '1'
1115

1216
@classmethod
1317
def credentials(cls, credentials):
1418
Api.username = credentials['username']
1519
Api.password = credentials['password']
1620

21+
@classmethod
22+
def auth_credentials(cls, credentials):
23+
Api.private_key = credentials['private_key']
24+
Api.seller_id = credentials['seller_id']
25+
Api.mode = credentials['mode']
26+
1727
@classmethod
1828
def call(cls, method, params=None):
19-
username = cls.username
20-
password = cls.password
21-
headers = {'Accept': 'application/json',
22-
'User-Agent': '2Checkout Python/0.1.0/%s'
23-
}
24-
base_url = 'https://www.2checkout.com/api/'
25-
url = base_url + method
26-
data = urllib.urlencode(params)
27-
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
28-
password_manager.add_password(
29-
None, 'https://www.2checkout.com', username, password
30-
)
31-
auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
32-
opener = urllib2.build_opener(auth_handler)
33-
urllib2.install_opener(opener)
29+
data = cls.set_opts(method, params)
30+
url = cls.build_url(method)
31+
headers = cls.build_headers(method)
3432
try:
3533
req = urllib2.Request(url, data, headers)
3634
result = urllib2.urlopen(req).read()
3735
return json.loads(result)
3836
except urllib2.HTTPError, e:
3937
exception = json.loads(e.read())
40-
raise TwocheckoutError(exception['errors'][0]['code'], exception['errors'][0]['message'])
38+
if method == 'authService':
39+
raise TwocheckoutError(exception['exception']['errorCode'], exception['exception']['errorMsg'])
40+
else:
41+
raise TwocheckoutError(exception['errors'][0]['code'], exception['errors'][0]['message'])
42+
43+
@classmethod
44+
def set_opts(cls, method, params=None):
45+
if method == 'authService':
46+
params['sellerId'] = cls.seller_id
47+
params['privateKey'] = cls.private_key
48+
data = json.dumps(params)
49+
else:
50+
username = cls.username
51+
password = cls.password
52+
data = urllib.urlencode(params)
53+
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
54+
password_manager.add_password(
55+
None, 'https://www.2checkout.com', username, password
56+
)
57+
auth_handler = urllib2.HTTPBasicAuthHandler(password_manager)
58+
opener = urllib2.build_opener(auth_handler)
59+
urllib2.install_opener(opener)
60+
return data
61+
62+
@classmethod
63+
def build_headers(cls, method):
64+
if method == 'authService':
65+
headers = {
66+
'Accept': 'application/json',
67+
'User-Agent': '2Checkout Python/0.1.0/%s',
68+
'Content-Type': 'application/JSON'
69+
}
70+
else:
71+
headers = {
72+
'Accept': 'application/json',
73+
'User-Agent': '2Checkout Python/0.1.0/%s'
74+
}
75+
return headers
76+
77+
@classmethod
78+
def build_url(cls, method):
79+
if method == 'authService':
80+
if cls.mode == 'sandbox':
81+
url = 'https://sandbox.2checkout.com/checkout/api/'
82+
else:
83+
url = 'https://www.2checkout.com/checkout/api/'
84+
url += cls.version + '/' + cls.seller_id + '/rs/' + method
85+
else:
86+
url = 'https://www.2checkout.com/api/' + method
87+
return url

twocheckout/charge.py

100644100755
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import urllib
2+
from api_request import Api
3+
from twocheckout import Twocheckout
24

35

4-
class Charge:
6+
class Charge(Twocheckout):
7+
def __init__(self, dict_):
8+
super(self.__class__, self).__init__(dict_)
59

610
@classmethod
711
def form(cls, params=None):
@@ -39,3 +43,8 @@ def link(cls, params=None, url="https://www.2checkout.com/checkout/purchase?"):
3943
param = urllib.urlencode(params)
4044
url = url.endswith('?') and (url + param)
4145
return url
46+
47+
@classmethod
48+
def authorize(cls, params=None):
49+
response = Charge(Api.call('authService', params))
50+
return response.response

0 commit comments

Comments
 (0)