Skip to content

Commit 24edd45

Browse files
committed
3.23.0
1 parent b915742 commit 24edd45

File tree

11 files changed

+97
-77
lines changed

11 files changed

+97
-77
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 3.23.0
2+
* Add better defaults to client token generation when using an access token by consolidating client token defaults into ClientTokenGateway
3+
* Add PaymentMethodGateway#revoke
4+
15
## 3.22.0
26
* Add VenmoAccount
37
* Add support for Set Transaction Context supplementary data.

braintree/client_token.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,9 @@ class ClientToken(object):
1010

1111
@staticmethod
1212
def generate(params={}, gateway=None):
13-
1413
if gateway is None:
1514
gateway = Configuration.gateway().client_token
1615

17-
if "options" in params and not "customer_id" in params:
18-
for option in ["verify_card", "make_default", "fail_on_duplicate_payment_method"]:
19-
if option in params["options"]:
20-
raise exceptions.InvalidSignatureError("cannot specify %s without a customer_id" % option)
21-
22-
if "version" not in params:
23-
params["version"] = 2
24-
2516
return gateway.generate(params)
2617

2718
@staticmethod

braintree/client_token_gateway.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import braintree
2-
from braintree.client_token import ClientToken
32
from braintree.resource import Resource
3+
from braintree.client_token import ClientToken
44
from braintree import exceptions
55

66
class ClientTokenGateway(object):
@@ -9,10 +9,17 @@ def __init__(self, gateway):
99
self.config = gateway.config
1010

1111

12-
def generate(self, params):
13-
if params:
14-
Resource.verify_keys(params, ClientToken.generate_signature())
15-
params = {'client_token': params}
12+
def generate(self, params={}):
13+
if "options" in params and not "customer_id" in params:
14+
for option in ["verify_card", "make_default", "fail_on_duplicate_payment_method"]:
15+
if option in params["options"]:
16+
raise exceptions.InvalidSignatureError("cannot specify %s without a customer_id" % option)
17+
18+
if "version" not in params:
19+
params["version"] = 2
20+
21+
Resource.verify_keys(params, ClientToken.generate_signature())
22+
params = {'client_token': params}
1623

1724
response = self.config.http().post(self.config.base_merchant_path() + "/client_token", params)
1825

braintree/payment_method_gateway.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,28 +58,45 @@ def grant(self, payment_method_token, allow_vaulting):
5858
raise ValueError
5959

6060
try:
61-
response = self._post(
61+
return self._post(
6262
"/payment_methods/grant",
6363
{
6464
"payment_method": {
6565
"shared_payment_method_token": payment_method_token,
6666
"allow_vaulting": allow_vaulting
6767
}
6868
},
69-
parse_response=False
69+
"payment_method_nonce"
7070
)
71+
except NotFoundError:
72+
raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found")
7173

72-
return PaymentMethodNonce(self.gateway, response["payment_method_nonce"])
74+
def revoke(self, payment_method_token):
75+
if payment_method_token is None or not str(payment_method_token).strip():
76+
raise ValueError
77+
78+
try:
79+
return self._post(
80+
"/payment_methods/revoke",
81+
{
82+
"payment_method": {
83+
"shared_payment_method_token": payment_method_token
84+
}
85+
},
86+
None
87+
)
7388
except NotFoundError:
7489
raise NotFoundError("payment method with payment_method_token " + repr(payment_method_token) + " not found")
7590

76-
def _post(self, url, params={}, parse_response=True):
91+
def _post(self, url, params={}, result_key="payment_method"):
7792
response = self.config.http().post(self.config.base_merchant_path() + url, params)
7893
if "api_error_response" in response:
7994
return ErrorResult(self.gateway, response["api_error_response"])
80-
elif parse_response:
95+
elif result_key is None:
96+
return SuccessfulResult()
97+
else:
8198
payment_method = self._parse_payment_method(response)
82-
return SuccessfulResult({"payment_method": payment_method})
99+
return SuccessfulResult({result_key: payment_method})
83100
return response
84101

85102
def _put(self, url, params={}):
@@ -107,6 +124,10 @@ def _parse_payment_method(self, response):
107124
return CoinbaseAccount(self.gateway, response["coinbase_account"])
108125
elif "venmo_account" in response:
109126
return VenmoAccount(self.gateway, response["venmo_account"])
127+
elif "payment_method_nonce" in response:
128+
return PaymentMethodNonce(self.gateway, response["payment_method_nonce"])
129+
elif "success" in response:
130+
return None
110131
else:
111132
name = list(response)[0]
112133
return UnknownPaymentMethod(self.gateway, response[name])

braintree/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Version = "3.22.0"
1+
Version = "3.23.0"

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from distutils.core import setup
22
setup(
33
name="braintree",
4-
version="3.22.0",
4+
version="3.23.0",
55
description="Braintree Python Library",
66
author="Braintree",
77
author_email="support@braintreepayments.com",

tests/integration/test_payment_method.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -911,21 +911,26 @@ def test_update_updates_a_paypal_accounts_token(self):
911911
self.assertTrue(updated_result.is_success == False)
912912
self.assertTrue(updated_result.errors.deep_errors[0].code == "92906")
913913

914+
def test_payment_method_grant_raises_on_non_existent_tokens(self):
915+
granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures()
916+
self.assertRaises(NotFoundError, granting_gateway.payment_method.grant, "non-existant-token", False)
917+
914918
def test_payment_method_grant_returns_one_time_nonce(self):
915919
"""
916920
Payment method grant returns a nonce that is transactable by a partner merchant exactly once
917921
"""
918922
granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures()
919923
grant_result = granting_gateway.payment_method.grant(credit_card.token, False)
924+
self.assertTrue(grant_result.is_success)
920925

921926
result = Transaction.sale({
922-
"payment_method_nonce": grant_result.nonce,
923-
"amount": TransactionAmounts.Authorize,
927+
"payment_method_nonce": grant_result.payment_method_nonce.nonce,
928+
"amount": TransactionAmounts.Authorize
924929
})
925930
self.assertTrue(result.is_success)
926931
result = Transaction.sale({
927-
"payment_method_nonce": grant_result.nonce,
928-
"amount": TransactionAmounts.Authorize,
932+
"payment_method_nonce": grant_result.payment_method_nonce.nonce,
933+
"amount": TransactionAmounts.Authorize
929934
})
930935
self.assertFalse(result.is_success)
931936

@@ -936,7 +941,7 @@ def test_payment_method_grant_returns_a_nonce_that_is_not_vaultable(self):
936941

937942
result = PaymentMethod.create({
938943
"customer_id": customer_id,
939-
"payment_method_nonce": grant_result.nonce
944+
"payment_method_nonce": grant_result.payment_method_nonce.nonce
940945
})
941946
self.assertFalse(result.is_success)
942947

@@ -947,10 +952,27 @@ def test_payment_method_grant_returns_a_nonce_that_is_vaultable(self):
947952

948953
result = PaymentMethod.create({
949954
"customer_id": customer_id,
950-
"payment_method_nonce": grant_result.nonce
955+
"payment_method_nonce": grant_result.payment_method_nonce.nonce
951956
})
952957
self.assertTrue(result.is_success)
953958

959+
def test_payment_method_revoke_renders_a_granted_nonce_unusable(self):
960+
granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures()
961+
grant_result = granting_gateway.payment_method.grant(credit_card.token, False)
962+
963+
revoke_result = granting_gateway.payment_method.revoke(credit_card.token)
964+
self.assertTrue(revoke_result.is_success)
965+
966+
result = Transaction.sale({
967+
"payment_method_nonce": grant_result.payment_method_nonce.nonce,
968+
"amount": TransactionAmounts.Authorize
969+
})
970+
self.assertFalse(result.is_success)
971+
972+
def test_payment_method_revoke_raises_on_non_existent_tokens(self):
973+
granting_gateway, credit_card = TestHelper.create_payment_method_grant_fixtures()
974+
self.assertRaises(NotFoundError, granting_gateway.payment_method.revoke, "non-existant-token")
975+
954976
class CreditCardForwardingTest(unittest.TestCase):
955977
def setUp(self):
956978
braintree.Configuration.configure(

tests/integration/test_settlement_batch_summary.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ def test_generate_returns_transactions_settled_on_a_given_day(self):
3434
self.assertTrue(result.is_success)
3535
visa_records = [row for row in result.settlement_batch_summary.records if row['card_type'] == 'Visa'][0]
3636
count = int(visa_records['count'])
37-
self.assertEquals(float(visa_records['amount_settled']), float(TransactionAmounts.Authorize) * count)
37+
self.assertGreaterEqual(count, 1)
38+
self.assertGreaterEqual(float(visa_records['amount_settled']), float(TransactionAmounts.Authorize))
3839

3940
def test_generate_can_be_grouped_by_a_custom_field(self):
4041
result = Transaction.sale({

tests/integration/test_transaction.py

Lines changed: 4 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,52 +1622,6 @@ def test_submit_for_settlement_with_invalid_params(self):
16221622
except KeyError as e:
16231623
self.assertEquals("'Invalid keys: invalid_param'", str(e))
16241624

1625-
def test_submit_for_settlement_with_order_id_on_unsupported_processor(self):
1626-
transaction = Transaction.sale({
1627-
"merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id,
1628-
"amount": TransactionAmounts.Authorize,
1629-
"credit_card": {
1630-
"number": CreditCardNumbers.AmexPayWithPoints.Success,
1631-
"expiration_date": "05/2009"
1632-
}
1633-
}).transaction
1634-
1635-
params = { "order_id": "ABC123" }
1636-
1637-
result = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params)
1638-
1639-
self.assertFalse(result.is_success)
1640-
self.assertEquals(
1641-
ErrorCodes.Transaction.ProcessorDoesNotSupportUpdatingOrderId,
1642-
result.errors.for_object("transaction").on("base")[0].code
1643-
)
1644-
1645-
def test_submit_for_settlement_with_descriptor_on_unsupported_processor(self):
1646-
transaction = Transaction.sale({
1647-
"merchant_account_id": TestHelper.fake_amex_direct_merchant_account_id,
1648-
"amount": TransactionAmounts.Authorize,
1649-
"credit_card": {
1650-
"number": CreditCardNumbers.AmexPayWithPoints.Success,
1651-
"expiration_date": "05/2009"
1652-
}
1653-
}).transaction
1654-
1655-
params = {
1656-
"descriptor": {
1657-
"name": "123*123456789012345678",
1658-
"phone": "3334445555",
1659-
"url": "ebay.com"
1660-
}
1661-
}
1662-
1663-
result = Transaction.submit_for_settlement(transaction.id, Decimal("900"), params)
1664-
1665-
self.assertFalse(result.is_success)
1666-
self.assertEquals(
1667-
ErrorCodes.Transaction.ProcessorDoesNotSupportUpdatingDescriptor ,
1668-
result.errors.for_object("transaction").on("base")[0].code
1669-
)
1670-
16711625
def test_submit_for_settlement_with_validation_error(self):
16721626
transaction = Transaction.sale({
16731627
"amount": TransactionAmounts.Authorize,
@@ -2392,6 +2346,9 @@ def test_find_exposes_disputes(self):
23922346
self.assertEquals(Dispute.Reason.Fraud, dispute.reason)
23932347
self.assertEquals("disputedtransaction", dispute.transaction_details.id)
23942348
self.assertEquals(Decimal("1000.00"), dispute.transaction_details.amount)
2349+
self.assertEquals(Dispute.Kind.Chargeback, dispute.kind)
2350+
self.assertEquals(date(2014, 3, 1), dispute.date_opened)
2351+
self.assertEquals(date(2014, 3, 7), dispute.date_won)
23952352

23962353
def test_find_exposes_three_d_secure_info(self):
23972354
transaction = Transaction.find("threedsecuredtransaction")
@@ -2928,7 +2885,7 @@ def test_transaction_facilitator(self):
29282885
grant_result = granting_gateway.payment_method.grant(credit_card.token, False)
29292886

29302887
result = Transaction.sale({
2931-
"payment_method_nonce": grant_result.nonce,
2888+
"payment_method_nonce": grant_result.payment_method_nonce.nonce,
29322889
"amount": TransactionAmounts.Authorize,
29332890
})
29342891
self.assertTrue(result.transaction.facilitator_details is not None)

tests/unit/test_dispute.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ def test_constructor(self):
1616
"received_date": date(2013, 4, 10),
1717
"reply_by_date": date(2013, 4, 10),
1818
"reason": "fraud",
19-
"transaction_ids": ["asdf", "qwer"]
19+
"transaction_ids": ["asdf", "qwer"],
20+
"date_opened": date(2013, 4, 1),
21+
"date_won": date(2013, 4, 2),
22+
"kind": "chargeback",
2023
}
2124

2225
dispute = Dispute(attributes)
@@ -28,3 +31,6 @@ def test_constructor(self):
2831
self.assertEquals(dispute.status, Dispute.Status.Open)
2932
self.assertEquals(dispute.transaction_details.id, "transaction_id")
3033
self.assertEquals(dispute.transaction_details.amount, Decimal("100.00"))
34+
self.assertEquals(dispute.date_opened, date(2013, 4, 1))
35+
self.assertEquals(dispute.date_won, date(2013, 4, 2))
36+
self.assertEquals(dispute.kind, Dispute.Kind.Chargeback)

0 commit comments

Comments
 (0)