From e3182bae9a970f56fe196a8765d5b76a7ec97a82 Mon Sep 17 00:00:00 2001 From: Nathaniel Miller Date: Thu, 12 Sep 2019 19:51:00 -0400 Subject: [PATCH 1/3] Add transactions resource --- CHANGELOG.md | 1 + README.rst | 29 +++++++++++ pybutton/client.py | 2 + pybutton/constants.py | 2 + pybutton/resources/__init__.py | 1 + pybutton/resources/transactions.py | 52 +++++++++++++++++++ pybutton/test/resources/transactions_test.py | 54 ++++++++++++++++++++ 7 files changed, 141 insertions(+) create mode 100644 pybutton/constants.py create mode 100644 pybutton/resources/transactions.py create mode 100644 pybutton/test/resources/transactions_test.py 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..79bc6e4 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.accounts.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..f0c2a0a --- /dev/null +++ b/pybutton/resources/transactions.py @@ -0,0 +1,52 @@ +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. + + + Args: + account_id (str) optional: A Button account id ('acc-XXX') + 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 + + 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') From eddb7a73f0f722665d9624c9bfb7b8c62a7dd779 Mon Sep 17 00:00:00 2001 From: Nathaniel Miller Date: Mon, 23 Sep 2019 13:42:20 -0400 Subject: [PATCH 2/3] PR feedback --- README.rst | 2 +- pybutton/resources/transactions.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 79bc6e4..ae2b7fa 100644 --- a/README.rst +++ b/README.rst @@ -337,7 +337,7 @@ You may pass the following optional arguments: client = Client('sk-XXX') - response = client.accounts.transactions( + response = client.transactions( start='2016-07-15T00:00:00.000Z', end='2016-09-30T00:00:00.000Z', time_field='modified_date', diff --git a/pybutton/resources/transactions.py b/pybutton/resources/transactions.py index f0c2a0a..d68b99a 100644 --- a/pybutton/resources/transactions.py +++ b/pybutton/resources/transactions.py @@ -17,10 +17,12 @@ 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: - account_id (str) optional: A Button account id ('acc-XXX') cursor (str) optional: An opaque string that lets you view a consistent list of transactions. start (ISO-8601 datetime str) optional: Filter out transactions @@ -28,7 +30,7 @@ def all(self, cursor=None, start=None, end=None, time_field=None): 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 + filter on. Defaults to created_date. Raises: pybutton.ButtonClientError From 7b5f960b33d1d0f24967f755c8ebde6beed19305 Mon Sep 17 00:00:00 2001 From: Nathaniel Miller Date: Wed, 25 Sep 2019 16:17:04 -0400 Subject: [PATCH 3/3] Fix docstrings --- pybutton/resources/transactions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pybutton/resources/transactions.py b/pybutton/resources/transactions.py index d68b99a..5230018 100644 --- a/pybutton/resources/transactions.py +++ b/pybutton/resources/transactions.py @@ -7,14 +7,14 @@ class Transactions(Resource): - '''Manages interacting with Button Transactions via the Button API + """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. + """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 @@ -38,7 +38,7 @@ def all(self, cursor=None, start=None, end=None, time_field=None): Returns: (pybutton.Response) The API response - ''' + """ query = {}