diff --git a/CHANGELOG.md b/CHANGELOG.md index 154af5b..79f4bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Current Version - Update flake8 quote linting - Add official support for Python 3.7 - Drop official support for Python 2.6, 3.2, 3.3 + - Added `transactions` resource 2.7.0 June 21, 2018 - Added optional `time_field` argument to `client.accounts.transactions` diff --git a/README.rst b/README.rst index d28adbf..ae2b7fa 100644 --- a/README.rst +++ b/README.rst @@ -96,6 +96,7 @@ We currently expose the following resources to manage: * `Orders`_ * `Customers`_ * `Links`_ +* `Transactions`_ Accounts ~~~~~~~~ @@ -317,6 +318,34 @@ Get print(response) # +Transactions +~~~~~~~~~~~~ + +All +''' + +You may pass the following optional arguments: + +* ``cursor`` (string): An API cursor to fetch a specific set of results. +* ``start`` (ISO-8601 datetime string): Fetch transactions after this time. +* ``end`` (ISO-8601 datetime string): Fetch transactions before this time. +* ``time_field`` (string): Which time field ``start`` and ``end`` filter on. + +.. code:: python + + from pybutton import Client + + client = Client('sk-XXX') + + response = client.transactions( + start='2016-07-15T00:00:00.000Z', + end='2016-09-30T00:00:00.000Z', + time_field='modified_date', + ) + + print(response) + # + Response -------- diff --git a/pybutton/client.py b/pybutton/client.py index 5406cc8..6387722 100644 --- a/pybutton/client.py +++ b/pybutton/client.py @@ -8,6 +8,7 @@ from pybutton.resources import Merchants from pybutton.resources import Orders from pybutton.resources import Links +from pybutton.resources import Transactions from pybutton.error import ButtonClientError @@ -57,6 +58,7 @@ def __init__(self, api_key, config=None): self.merchants = Merchants(api_key, config) self.customers = Customers(api_key, config) self.links = Links(api_key, config) + self.transactions = Transactions(api_key, config) def config_with_defaults(config): diff --git a/pybutton/constants.py b/pybutton/constants.py new file mode 100644 index 0000000..c8e88eb --- /dev/null +++ b/pybutton/constants.py @@ -0,0 +1,2 @@ +TIME_FIELD_CREATED = 'created_date' +TIME_FIELD_MODIFIED = 'modified_date' diff --git a/pybutton/resources/__init__.py b/pybutton/resources/__init__.py index 8c6cd0b..1b6fc99 100644 --- a/pybutton/resources/__init__.py +++ b/pybutton/resources/__init__.py @@ -8,3 +8,4 @@ from pybutton.resources.links import Links # noqa: 401 from pybutton.resources.merchants import Merchants # noqa: 401 from pybutton.resources.orders import Orders # noqa: 401 +from pybutton.resources.transactions import Transactions # noqa: 401 diff --git a/pybutton/resources/transactions.py b/pybutton/resources/transactions.py new file mode 100644 index 0000000..5230018 --- /dev/null +++ b/pybutton/resources/transactions.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from pybutton.resources.resource import Resource + + +class Transactions(Resource): + """Manages interacting with Button Transactions via the Button API + + See Resource for class docstring. + + """ + + def all(self, cursor=None, start=None, end=None, time_field=None): + """Get a list of transactions. + To paginate transactions, pass the result of response.next_cursor() as + the cursor argument. + Unlike Accounts.transactions, which retrieves transactions only for a + single account, Transactions.all retrieves all of an organization's + transactions. + + + Args: + cursor (str) optional: An opaque string that lets you view a + consistent list of transactions. + start (ISO-8601 datetime str) optional: Filter out transactions + created at or after this time. + end (ISO-8601 datetime str) optional: Filter out transactions + created before this time. + time_field (str) optional: Which time field ``start`` and ``end`` + filter on. Defaults to created_date. + + Raises: + pybutton.ButtonClientError + + Returns: + (pybutton.Response) The API response + + """ + + query = {} + + if cursor: + query['cursor'] = cursor + if start: + query['start'] = start + if end: + query['end'] = end + if time_field: + query['time_field'] = time_field + + return self.api_get('/v1/affiliation/transactions', query=query) diff --git a/pybutton/test/resources/transactions_test.py b/pybutton/test/resources/transactions_test.py new file mode 100644 index 0000000..3f26584 --- /dev/null +++ b/pybutton/test/resources/transactions_test.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from unittest import TestCase +from mock import Mock +from mock import patch + +from pybutton import constants +from pybutton.resources import Transactions + +config = { + 'hostname': 'api.usebutton.com', + 'secure': True, + 'port': 443, + 'timeout': None, +} + + +class TransactionsTestCase(TestCase): + + def test_all(self): + transactions = Transactions('sk-XXX', config) + transaction_response = [{'a': 1}, {'b': 2}] + + api_get = Mock() + api_get.return_value = transaction_response + + with patch.object(transactions, 'api_get', api_get): + response = transactions.all( + cursor='abc', + start='2016-09-15T00:00:00.000Z', + end='2016-09-30T00:00:00.000Z' + ) + self.assertEqual( + api_get.call_args[0][0], + '/v1/affiliation/transactions' + ) + self.assertEqual(response, transaction_response) + query = api_get.call_args[1]['query'] + self.assertEqual(query['cursor'], 'abc') + self.assertEqual(query['start'], '2016-09-15T00:00:00.000Z') + self.assertEqual(query['end'], '2016-09-30T00:00:00.000Z') + + response = transactions.all( + cursor='abc', + start='2016-09-15T00:00:00.000Z', + end='2016-09-30T00:00:00.000Z', + time_field=constants.TIME_FIELD_MODIFIED + ) + self.assertEqual(response, transaction_response) + query = api_get.call_args[1]['query'] + self.assertEqual(query['time_field'], 'modified_date')