diff --git a/.travis.yml b/.travis.yml index 14be293eb..816960625 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ cache: env: global: - - STRIPE_MOCK_VERSION=0.19.0 + - STRIPE_MOCK_VERSION=0.23.0 before_install: # Unpack and start stripe-mock so that the test suite can talk to it diff --git a/stripe/__init__.py b/stripe/__init__.py index 2035362e0..ffe44a51b 100644 --- a/stripe/__init__.py +++ b/stripe/__init__.py @@ -25,6 +25,7 @@ # API resources from stripe.api_resources import * # noqa +from stripe.api_resources import issuing # noqa # OAuth from stripe.oauth import OAuth # noqa diff --git a/stripe/api_resources/issuing/__init__.py b/stripe/api_resources/issuing/__init__.py new file mode 100644 index 000000000..614fd5dac --- /dev/null +++ b/stripe/api_resources/issuing/__init__.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import, division, print_function + +# flake8: noqa + +from stripe.api_resources.issuing.authorization import Authorization +from stripe.api_resources.issuing.card import Card +from stripe.api_resources.issuing.card_details import CardDetails +from stripe.api_resources.issuing.cardholder import Cardholder +from stripe.api_resources.issuing.dispute import Dispute +from stripe.api_resources.issuing.transaction import Transaction diff --git a/stripe/api_resources/issuing/authorization.py b/stripe/api_resources/issuing/authorization.py new file mode 100644 index 000000000..852f4a67f --- /dev/null +++ b/stripe/api_resources/issuing/authorization.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import, division, print_function + +from stripe import util +from stripe.api_resources.abstract import UpdateableAPIResource +from stripe.api_resources.abstract import ListableAPIResource + + +class Authorization(ListableAPIResource, UpdateableAPIResource): + OBJECT_NAME = 'issuing.authorization' + + def approve(self, idempotency_key=None, **params): + url = self.instance_url() + '/approve' + headers = util.populate_headers(idempotency_key) + self.refresh_from(self.request('post', url, params, headers)) + return self + + def decline(self, idempotency_key=None, **params): + url = self.instance_url() + '/decline' + headers = util.populate_headers(idempotency_key) + self.refresh_from(self.request('post', url, params, headers)) + return self diff --git a/stripe/api_resources/issuing/card.py b/stripe/api_resources/issuing/card.py new file mode 100644 index 000000000..bcd4c05bf --- /dev/null +++ b/stripe/api_resources/issuing/card.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function + +from stripe.api_resources.abstract import CreateableAPIResource +from stripe.api_resources.abstract import UpdateableAPIResource +from stripe.api_resources.abstract import ListableAPIResource + + +class Card(CreateableAPIResource, ListableAPIResource, + UpdateableAPIResource): + OBJECT_NAME = 'issuing.card' + + def details(self, idempotency_key=None, **params): + return self.request( + 'get', self.instance_url() + '/details', params) diff --git a/stripe/api_resources/issuing/card_details.py b/stripe/api_resources/issuing/card_details.py new file mode 100644 index 000000000..a59711a5d --- /dev/null +++ b/stripe/api_resources/issuing/card_details.py @@ -0,0 +1,7 @@ +from __future__ import absolute_import, division, print_function + +from stripe.stripe_object import StripeObject + + +class CardDetails(StripeObject): + OBJECT_NAME = 'issuing.card_details' diff --git a/stripe/api_resources/issuing/cardholder.py b/stripe/api_resources/issuing/cardholder.py new file mode 100644 index 000000000..af956421c --- /dev/null +++ b/stripe/api_resources/issuing/cardholder.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import, division, print_function + +from stripe.api_resources.abstract import CreateableAPIResource +from stripe.api_resources.abstract import UpdateableAPIResource +from stripe.api_resources.abstract import ListableAPIResource + + +class Cardholder(CreateableAPIResource, ListableAPIResource, + UpdateableAPIResource): + OBJECT_NAME = 'issuing.cardholder' diff --git a/stripe/api_resources/issuing/dispute.py b/stripe/api_resources/issuing/dispute.py new file mode 100644 index 000000000..24e32fc97 --- /dev/null +++ b/stripe/api_resources/issuing/dispute.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import, division, print_function + +from stripe.api_resources.abstract import CreateableAPIResource +from stripe.api_resources.abstract import UpdateableAPIResource +from stripe.api_resources.abstract import ListableAPIResource + + +class Dispute(CreateableAPIResource, ListableAPIResource, + UpdateableAPIResource): + OBJECT_NAME = 'issuing.dispute' diff --git a/stripe/api_resources/issuing/transaction.py b/stripe/api_resources/issuing/transaction.py new file mode 100644 index 000000000..f2a85791e --- /dev/null +++ b/stripe/api_resources/issuing/transaction.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import, division, print_function + +from stripe.api_resources.abstract import UpdateableAPIResource +from stripe.api_resources.abstract import ListableAPIResource + + +class Transaction(ListableAPIResource, UpdateableAPIResource): + OBJECT_NAME = 'issuing.transaction' diff --git a/stripe/util.py b/stripe/util.py index 0cc86caf0..2b4f2cc2c 100644 --- a/stripe/util.py +++ b/stripe/util.py @@ -169,6 +169,17 @@ def load_object_classes(): api_resources.InvoiceLineItem, api_resources.IssuerFraudRecord.OBJECT_NAME: api_resources.IssuerFraudRecord, + api_resources.issuing.Authorization.OBJECT_NAME: + api_resources.issuing.Authorization, + api_resources.issuing.Card.OBJECT_NAME: api_resources.issuing.Card, + api_resources.issuing.CardDetails.OBJECT_NAME: + api_resources.issuing.CardDetails, + api_resources.issuing.Cardholder.OBJECT_NAME: + api_resources.issuing.Cardholder, + api_resources.issuing.Dispute.OBJECT_NAME: + api_resources.issuing.Dispute, + api_resources.issuing.Transaction.OBJECT_NAME: + api_resources.issuing.Transaction, api_resources.LoginLink.OBJECT_NAME: api_resources.LoginLink, api_resources.Order.OBJECT_NAME: api_resources.Order, api_resources.OrderReturn.OBJECT_NAME: api_resources.OrderReturn, diff --git a/tests/api_resources/issuing/test_authorization.py b/tests/api_resources/issuing/test_authorization.py new file mode 100644 index 000000000..12f7728eb --- /dev/null +++ b/tests/api_resources/issuing/test_authorization.py @@ -0,0 +1,67 @@ +from __future__ import absolute_import, division, print_function + +import stripe + + +TEST_RESOURCE_ID = 'iauth_123' + + +class TestAuthorization(object): + def test_is_listable(self, request_mock): + resources = stripe.issuing.Authorization.list() + request_mock.assert_requested( + 'get', + '/v1/issuing/authorizations' + ) + assert isinstance(resources.data, list) + assert isinstance(resources.data[0], stripe.issuing.Authorization) + + def test_is_modifiable(self, request_mock): + resource = stripe.issuing.Authorization.modify( + TEST_RESOURCE_ID, + metadata={'key': 'value'} + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/authorizations/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Authorization) + + def test_is_retrievable(self, request_mock): + resource = stripe.issuing.Authorization.retrieve(TEST_RESOURCE_ID) + request_mock.assert_requested( + 'get', + '/v1/issuing/authorizations/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Authorization) + + def test_is_saveable(self, request_mock): + resource = stripe.issuing.Authorization.retrieve(TEST_RESOURCE_ID) + resource.metadata['key'] = 'value' + authorization = resource.save() + request_mock.assert_requested( + 'post', + '/v1/issuing/authorizations/%s' % resource.id + ) + assert isinstance(resource, stripe.issuing.Authorization) + assert resource is authorization + + def test_is_approveable(self, request_mock): + resource = stripe.issuing.Authorization.retrieve(TEST_RESOURCE_ID) + authorization = resource.approve() + request_mock.assert_requested( + 'post', + '/v1/issuing/authorizations/%s/approve' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Authorization) + assert resource is authorization + + def test_is_declineable(self, request_mock): + resource = stripe.issuing.Authorization.retrieve(TEST_RESOURCE_ID) + authorization = resource.decline() + request_mock.assert_requested( + 'post', + '/v1/issuing/authorizations/%s/decline' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Authorization) + assert resource is authorization diff --git a/tests/api_resources/issuing/test_card.py b/tests/api_resources/issuing/test_card.py new file mode 100644 index 000000000..65ac8dd27 --- /dev/null +++ b/tests/api_resources/issuing/test_card.py @@ -0,0 +1,67 @@ +from __future__ import absolute_import, division, print_function + +import stripe + + +TEST_RESOURCE_ID = 'ic_123' + + +class TestCard(object): + def test_is_creatable(self, request_mock): + resource = stripe.issuing.Card.create( + currency='usd', + type='physical' + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/cards' + ) + assert isinstance(resource, stripe.issuing.Card) + + def test_is_listable(self, request_mock): + resources = stripe.issuing.Card.list() + request_mock.assert_requested( + 'get', + '/v1/issuing/cards' + ) + assert isinstance(resources.data, list) + assert isinstance(resources.data[0], stripe.issuing.Card) + + def test_is_modifiable(self, request_mock): + resource = stripe.issuing.Card.modify( + TEST_RESOURCE_ID, + metadata={'key': 'value'} + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/cards/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Card) + + def test_is_retrievable(self, request_mock): + resource = stripe.issuing.Card.retrieve(TEST_RESOURCE_ID) + request_mock.assert_requested( + 'get', + '/v1/issuing/cards/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Card) + + def test_is_saveable(self, request_mock): + resource = stripe.issuing.Card.retrieve(TEST_RESOURCE_ID) + resource.metadata['key'] = 'value' + card = resource.save() + request_mock.assert_requested( + 'post', + '/v1/issuing/cards/%s' % resource.id + ) + assert isinstance(resource, stripe.issuing.Card) + assert resource is card + + def test_can_retrieve_details(self, request_mock): + resource = stripe.issuing.Card.retrieve(TEST_RESOURCE_ID) + card_details = resource.details() + request_mock.assert_requested( + 'get', + '/v1/issuing/cards/%s/details' % resource.id + ) + assert isinstance(card_details, stripe.issuing.CardDetails) diff --git a/tests/api_resources/issuing/test_cardholder.py b/tests/api_resources/issuing/test_cardholder.py new file mode 100644 index 000000000..0b00681f3 --- /dev/null +++ b/tests/api_resources/issuing/test_cardholder.py @@ -0,0 +1,66 @@ +from __future__ import absolute_import, division, print_function + +import stripe + + +TEST_RESOURCE_ID = 'ich_123' + + +class TestCardholder(object): + def test_is_creatable(self, request_mock): + resource = stripe.issuing.Cardholder.create( + billing={ + 'address': { + 'city': 'city', + 'country': 'US', + 'line1': 'line1', + 'postal_code': 'postal_code', + }, + }, + name='Jenny Rosen', + type='individual' + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/cardholders' + ) + assert isinstance(resource, stripe.issuing.Cardholder) + + def test_is_listable(self, request_mock): + resources = stripe.issuing.Cardholder.list() + request_mock.assert_requested( + 'get', + '/v1/issuing/cardholders' + ) + assert isinstance(resources.data, list) + assert isinstance(resources.data[0], stripe.issuing.Cardholder) + + def test_is_modifiable(self, request_mock): + resource = stripe.issuing.Cardholder.modify( + TEST_RESOURCE_ID, + metadata={'key': 'value'} + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/cardholders/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Cardholder) + + def test_is_retrievable(self, request_mock): + resource = stripe.issuing.Cardholder.retrieve(TEST_RESOURCE_ID) + request_mock.assert_requested( + 'get', + '/v1/issuing/cardholders/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Cardholder) + + def test_is_saveable(self, request_mock): + resource = stripe.issuing.Cardholder.retrieve(TEST_RESOURCE_ID) + resource.metadata['key'] = 'value' + cardholder = resource.save() + request_mock.assert_requested( + 'post', + '/v1/issuing/cardholders/%s' % resource.id + ) + assert isinstance(resource, stripe.issuing.Cardholder) + assert resource is cardholder diff --git a/tests/api_resources/issuing/test_dispute.py b/tests/api_resources/issuing/test_dispute.py new file mode 100644 index 000000000..548e4088a --- /dev/null +++ b/tests/api_resources/issuing/test_dispute.py @@ -0,0 +1,58 @@ +from __future__ import absolute_import, division, print_function + +import stripe + + +TEST_RESOURCE_ID = 'idp_123' + + +class TestDispute(object): + def test_is_creatable(self, request_mock): + resource = stripe.issuing.Dispute.create( + reason='fraudulent', + transaction='ipi_123' + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/disputes' + ) + assert isinstance(resource, stripe.issuing.Dispute) + + def test_is_listable(self, request_mock): + resources = stripe.issuing.Dispute.list() + request_mock.assert_requested( + 'get', + '/v1/issuing/disputes' + ) + assert isinstance(resources.data, list) + assert isinstance(resources.data[0], stripe.issuing.Dispute) + + def test_is_modifiable(self, request_mock): + resource = stripe.issuing.Dispute.modify( + TEST_RESOURCE_ID, + metadata={'key': 'value'} + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/disputes/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Dispute) + + def test_is_retrievable(self, request_mock): + resource = stripe.issuing.Dispute.retrieve(TEST_RESOURCE_ID) + request_mock.assert_requested( + 'get', + '/v1/issuing/disputes/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Dispute) + + def test_is_saveable(self, request_mock): + resource = stripe.issuing.Dispute.retrieve(TEST_RESOURCE_ID) + resource.metadata['key'] = 'value' + dispute = resource.save() + request_mock.assert_requested( + 'post', + '/v1/issuing/disputes/%s' % resource.id + ) + assert isinstance(resource, stripe.issuing.Dispute) + assert resource is dispute diff --git a/tests/api_resources/issuing/test_transaction.py b/tests/api_resources/issuing/test_transaction.py new file mode 100644 index 000000000..6eab5aa20 --- /dev/null +++ b/tests/api_resources/issuing/test_transaction.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import, division, print_function + +import stripe + + +TEST_RESOURCE_ID = 'ipi_123' + + +class TestTransaction(object): + def test_is_listable(self, request_mock): + resources = stripe.issuing.Transaction.list() + request_mock.assert_requested( + 'get', + '/v1/issuing/transactions' + ) + assert isinstance(resources.data, list) + assert isinstance(resources.data[0], stripe.issuing.Transaction) + + def test_is_modifiable(self, request_mock): + resource = stripe.issuing.Transaction.modify( + TEST_RESOURCE_ID, + metadata={'key': 'value'} + ) + request_mock.assert_requested( + 'post', + '/v1/issuing/transactions/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Transaction) + + def test_is_retrievable(self, request_mock): + resource = stripe.issuing.Transaction.retrieve(TEST_RESOURCE_ID) + request_mock.assert_requested( + 'get', + '/v1/issuing/transactions/%s' % TEST_RESOURCE_ID + ) + assert isinstance(resource, stripe.issuing.Transaction) + + def test_is_saveable(self, request_mock): + resource = stripe.issuing.Transaction.retrieve(TEST_RESOURCE_ID) + resource.metadata['key'] = 'value' + transaction = resource.save() + request_mock.assert_requested( + 'post', + '/v1/issuing/transactions/%s' % resource.id + ) + assert isinstance(resource, stripe.issuing.Transaction) + assert resource is transaction diff --git a/tests/conftest.py b/tests/conftest.py index 08c8c0ca5..abd791a3c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,7 @@ from tests.request_mock import RequestMock -MOCK_MINIMUM_VERSION = '0.19.0' +MOCK_MINIMUM_VERSION = '0.23.0' MOCK_PORT = os.environ.get('STRIPE_MOCK_PORT', 12111)