diff --git a/.travis.yml b/.travis.yml index 4075b4230..bc4b34d2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ cache: env: global: # If changing this number, please also change it in `tests/conftest.py`. - - STRIPE_MOCK_VERSION=0.57.0 + - STRIPE_MOCK_VERSION=0.58.0 before_install: # Unpack and start stripe-mock so that the test suite can talk to it diff --git a/stripe/api_resources/__init__.py b/stripe/api_resources/__init__.py index ff3a1cae3..3078b5b94 100644 --- a/stripe/api_resources/__init__.py +++ b/stripe/api_resources/__init__.py @@ -29,6 +29,9 @@ from stripe.api_resources.coupon import Coupon from stripe.api_resources.credit_note import CreditNote from stripe.api_resources.customer import Customer +from stripe.api_resources.customer_balance_transaction import ( + CustomerBalanceTransaction, +) from stripe.api_resources.dispute import Dispute from stripe.api_resources.ephemeral_key import EphemeralKey from stripe.api_resources.event import Event diff --git a/stripe/api_resources/customer.py b/stripe/api_resources/customer.py index 76f5db86e..f843876dc 100644 --- a/stripe/api_resources/customer.py +++ b/stripe/api_resources/customer.py @@ -16,6 +16,9 @@ @nested_resource_class_methods( "tax_id", operations=["create", "retrieve", "delete", "list"] ) +@nested_resource_class_methods( + "balance_transaction", operations=["create", "retrieve", "update", "list"] +) class Customer( CreateableAPIResource, DeletableAPIResource, diff --git a/stripe/api_resources/customer_balance_transaction.py b/stripe/api_resources/customer_balance_transaction.py new file mode 100644 index 000000000..a3625764a --- /dev/null +++ b/stripe/api_resources/customer_balance_transaction.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import, division, print_function + +from stripe import util +from stripe.api_resources.customer import Customer +from stripe.api_resources.abstract import APIResource +from stripe.six.moves.urllib.parse import quote_plus + + +class CustomerBalanceTransaction(APIResource): + OBJECT_NAME = "customer_balance_transaction" + + def instance_url(self): + token = util.utf8(self.id) + customer = util.utf8(self.customer) + base = Customer.class_url() + cust_extn = quote_plus(customer) + extn = quote_plus(token) + return "%s/%s/balance_transactions/%s" % (base, cust_extn, extn) + + @classmethod + def retrieve(cls, id, api_key=None, **params): + raise NotImplementedError( + "Can't retrieve a Customer Balance Transaction without a Customer ID. " + "Use Customer.retrieve_customer_balance_transaction('cus_123', 'cbtxn_123')" + ) diff --git a/tests/api_resources/test_customer.py b/tests/api_resources/test_customer.py index 0450845f1..f9f879d51 100644 --- a/tests/api_resources/test_customer.py +++ b/tests/api_resources/test_customer.py @@ -7,6 +7,7 @@ TEST_SUB_ID = "sub_123" TEST_SOURCE_ID = "ba_123" TEST_TAX_ID_ID = "txi_123" +TEST_TRANSACTION_ID = "cbtxn_123" class TestCustomer(object): @@ -141,3 +142,30 @@ def test_is_listable(self, request_mock): "get", "/v1/customers/%s/tax_ids" % TEST_RESOURCE_ID ) assert isinstance(resources.data, list) + + +class TestCustomerTransactions(object): + def test_is_creatable(self, request_mock): + stripe.Customer.create_balance_transaction( + TEST_RESOURCE_ID, amount=1234, currency="usd" + ) + request_mock.assert_requested( + "post", "/v1/customers/%s/balance_transactions" % TEST_RESOURCE_ID + ) + + def test_is_retrievable(self, request_mock): + stripe.Customer.retrieve_balance_transaction( + TEST_RESOURCE_ID, TEST_TRANSACTION_ID + ) + request_mock.assert_requested( + "get", + "/v1/customers/%s/balance_transactions/%s" + % (TEST_RESOURCE_ID, TEST_TRANSACTION_ID), + ) + + def test_is_listable(self, request_mock): + resources = stripe.Customer.list_balance_transactions(TEST_RESOURCE_ID) + request_mock.assert_requested( + "get", "/v1/customers/%s/balance_transactions" % TEST_RESOURCE_ID + ) + assert isinstance(resources.data, list) diff --git a/tests/api_resources/test_customer_balance_transaction.py b/tests/api_resources/test_customer_balance_transaction.py new file mode 100644 index 000000000..eeaf32cb2 --- /dev/null +++ b/tests/api_resources/test_customer_balance_transaction.py @@ -0,0 +1,32 @@ +from __future__ import absolute_import, division, print_function + +import pytest + +import stripe + + +TEST_RESOURCE_ID = "cbtxn_123" + + +class TestCustomerBalanceTransaction(object): + def construct_resource(self): + tax_id_dict = { + "id": TEST_RESOURCE_ID, + "object": "customer_balance_transaction", + "customer": "cus_123", + } + return stripe.CustomerBalanceTransaction.construct_from( + tax_id_dict, stripe.api_key + ) + + def test_has_instance_url(self, request_mock): + resource = self.construct_resource() + assert ( + resource.instance_url() + == "/v1/customers/cus_123/balance_transactions/%s" + % TEST_RESOURCE_ID + ) + + def test_is_not_retrievable(self, request_mock): + with pytest.raises(NotImplementedError): + stripe.CustomerBalanceTransaction.retrieve(TEST_RESOURCE_ID) diff --git a/tests/conftest.py b/tests/conftest.py index 922a5953e..28e739c55 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,7 +16,7 @@ # When changing this number, don't forget to change it in `.travis.yml` too. -MOCK_MINIMUM_VERSION = "0.57.0" +MOCK_MINIMUM_VERSION = "0.58.0" # Starts stripe-mock if an OpenAPI spec override is found in `openapi/`, and # otherwise fall back to `STRIPE_MOCK_PORT` or 12111.