From def7044bb453c8d56021867c8d43ab7e944c3a96 Mon Sep 17 00:00:00 2001 From: "gocardless-ci-robot[bot]" <123969075+gocardless-ci-robot[bot]@users.noreply.github.com> Date: Fri, 1 May 2026 09:05:16 +0000 Subject: [PATCH] Changes generated by 8b11b29c01bad5a3e25ac50c5641547d4c0311ed This commit was automatically created from gocardless/client-library-templates@8b11b29c01bad5a3e25ac50c5641547d4c0311ed by the `push-files` action. Workflow run: https://github.com/gocardless/client-library-templates/actions/runs/25208955170 --- README.rst | 28 +++ gocardless_pro/client.py | 8 + gocardless_pro/resources/__init__.py | 4 + gocardless_pro/resources/export.py | 7 + .../resources/outbound_payment_import.py | 133 ++++++++++++ .../outbound_payment_import_entry.py | 119 +++++++++++ gocardless_pro/services/__init__.py | 2 + ...outbound_payment_import_entries_service.py | 45 ++++ .../outbound_payment_imports_service.py | 96 +++++++++ tests/client_test.py | 6 + tests/fixtures/exports.json | 2 +- .../outbound_payment_import_entries.json | 10 + tests/fixtures/outbound_payment_imports.json | 22 ++ tests/integration/exports_integration_test.py | 2 + ...payment_import_entries_integration_test.py | 87 ++++++++ ...tbound_payment_imports_integration_test.py | 200 ++++++++++++++++++ 16 files changed, 770 insertions(+), 1 deletion(-) create mode 100644 gocardless_pro/resources/outbound_payment_import.py create mode 100644 gocardless_pro/resources/outbound_payment_import_entry.py create mode 100644 gocardless_pro/services/outbound_payment_import_entries_service.py create mode 100644 gocardless_pro/services/outbound_payment_imports_service.py create mode 100644 tests/fixtures/outbound_payment_import_entries.json create mode 100644 tests/fixtures/outbound_payment_imports.json create mode 100644 tests/integration/outbound_payment_import_entries_integration_test.py create mode 100644 tests/integration/outbound_payment_imports_integration_test.py diff --git a/README.rst b/README.rst index e0b152d6..9e505381 100644 --- a/README.rst +++ b/README.rst @@ -531,6 +531,34 @@ Outbound payments # Outbound payment statistics client.outbound_payments.stats(params={...}) +Outbound payment imports +'''''''''''''''''''''''''''''''''''''''''' + +.. code:: python + + # Create an outbound payment import + client.outbound_payment_imports.create(params={...}) + + # Get an outbound payment import + client.outbound_payment_imports.get('IM123', params={...}) + + # List outbound payment imports + client.outbound_payment_imports.list(params={...}) + + # Iterate through all outbound_payment_imports + client.outbound_payment_imports.all(params={...}) + +Outbound payment import entries +'''''''''''''''''''''''''''''''''''''''''' + +.. code:: python + + # List outbound payment import entries + client.outbound_payment_import_entries.list(params={...}) + + # Iterate through all outbound_payment_import_entries + client.outbound_payment_import_entries.all(params={...}) + Payer authorisations '''''''''''''''''''''''''''''''''''''''''' diff --git a/gocardless_pro/client.py b/gocardless_pro/client.py index b37e1788..5f0a45f6 100644 --- a/gocardless_pro/client.py +++ b/gocardless_pro/client.py @@ -149,6 +149,14 @@ def negative_balance_limits(self): def outbound_payments(self): return services.OutboundPaymentsService(self._api_client, 3, 0.5, self._raise_on_idempotency_conflict) + @property + def outbound_payment_imports(self): + return services.OutboundPaymentImportsService(self._api_client, 3, 0.5, self._raise_on_idempotency_conflict) + + @property + def outbound_payment_import_entries(self): + return services.OutboundPaymentImportEntriesService(self._api_client, 3, 0.5, self._raise_on_idempotency_conflict) + @property def payer_authorisations(self): return services.PayerAuthorisationsService(self._api_client, 3, 0.5, self._raise_on_idempotency_conflict) diff --git a/gocardless_pro/resources/__init__.py b/gocardless_pro/resources/__init__.py index 33b68e06..26ffdad7 100644 --- a/gocardless_pro/resources/__init__.py +++ b/gocardless_pro/resources/__init__.py @@ -59,6 +59,10 @@ from .outbound_payment import OutboundPayment +from .outbound_payment_import import OutboundPaymentImport + +from .outbound_payment_import_entry import OutboundPaymentImportEntry + from .payer_authorisation import PayerAuthorisation from .payer_theme import PayerTheme diff --git a/gocardless_pro/resources/export.py b/gocardless_pro/resources/export.py index 95a503df..b90c4f14 100644 --- a/gocardless_pro/resources/export.py +++ b/gocardless_pro/resources/export.py @@ -31,6 +31,11 @@ def download_url(self): return self.attributes.get('download_url') + @property + def error_message(self): + return self.attributes.get('error_message') + + @property def export_type(self): return self.attributes.get('export_type') @@ -52,3 +57,5 @@ def id(self): + + diff --git a/gocardless_pro/resources/outbound_payment_import.py b/gocardless_pro/resources/outbound_payment_import.py new file mode 100644 index 00000000..6d01c571 --- /dev/null +++ b/gocardless_pro/resources/outbound_payment_import.py @@ -0,0 +1,133 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +class OutboundPaymentImport(object): + """A thin wrapper around a outbound_payment_import, providing easy access to its + attributes. + + Example: + outbound_payment_import = client.outbound_payment_imports.get() + outbound_payment_import.id + """ + + def __init__(self, attributes, api_response): + self.attributes = attributes + self.api_response = api_response + + @property + def amount_sum(self): + return self.attributes.get('amount_sum') + + + @property + def authorisation_url(self): + return self.attributes.get('authorisation_url') + + + @property + def created_at(self): + return self.attributes.get('created_at') + + + @property + def currency(self): + return self.attributes.get('currency') + + + @property + def entry_counts(self): + return self.EntryCounts(self.attributes.get('entry_counts')) + + + @property + def id(self): + return self.attributes.get('id') + + + @property + def links(self): + return self.Links(self.attributes.get('links')) + + + @property + def status(self): + return self.attributes.get('status') + + + + + + + + + + + + + class EntryCounts(object): + """Wrapper for the response's 'entry_counts' attribute.""" + + def __init__(self, attributes): + self.attributes = attributes + + @property + def failed_to_process(self): + return self.attributes.get('failed_to_process') + + @property + def invalid(self): + return self.attributes.get('invalid') + + @property + def processed(self): + return self.attributes.get('processed') + + @property + def total(self): + return self.attributes.get('total') + + @property + def valid(self): + return self.attributes.get('valid') + + @property + def verified(self): + return self.attributes.get('verified') + + @property + def verified_with_full_match(self): + return self.attributes.get('verified_with_full_match') + + @property + def verified_with_no_match(self): + return self.attributes.get('verified_with_no_match') + + @property + def verified_with_partial_match(self): + return self.attributes.get('verified_with_partial_match') + + @property + def verified_with_unable_to_match(self): + return self.attributes.get('verified_with_unable_to_match') + + + + + + + class Links(object): + """Wrapper for the response's 'links' attribute.""" + + def __init__(self, attributes): + self.attributes = attributes + + @property + def creditor(self): + return self.attributes.get('creditor') + + + + + diff --git a/gocardless_pro/resources/outbound_payment_import_entry.py b/gocardless_pro/resources/outbound_payment_import_entry.py new file mode 100644 index 00000000..12ccb1a1 --- /dev/null +++ b/gocardless_pro/resources/outbound_payment_import_entry.py @@ -0,0 +1,119 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +class OutboundPaymentImportEntry(object): + """A thin wrapper around a outbound_payment_import_entry, providing easy access to its + attributes. + + Example: + outbound_payment_import_entry = client.outbound_payment_import_entries.get() + outbound_payment_import_entry.id + """ + + def __init__(self, attributes, api_response): + self.attributes = attributes + self.api_response = api_response + + @property + def amount(self): + return self.attributes.get('amount') + + + @property + def created_at(self): + return self.attributes.get('created_at') + + + @property + def id(self): + return self.attributes.get('id') + + + @property + def links(self): + return self.Links(self.attributes.get('links')) + + + @property + def metadata(self): + return self.attributes.get('metadata') + + + @property + def processed_at(self): + return self.attributes.get('processed_at') + + + @property + def reference(self): + return self.attributes.get('reference') + + + @property + def scheme(self): + return self.attributes.get('scheme') + + + @property + def validation_errors(self): + return self.ValidationErrors(self.attributes.get('validation_errors')) + + + @property + def verification_result(self): + return self.attributes.get('verification_result') + + + + + + + + + + + class Links(object): + """Wrapper for the response's 'links' attribute.""" + + def __init__(self, attributes): + self.attributes = attributes + + @property + def outbound_payment(self): + return self.attributes.get('outbound_payment') + + @property + def outbound_payment_import(self): + return self.attributes.get('outbound_payment_import') + + @property + def recipient_bank_account(self): + return self.attributes.get('recipient_bank_account') + + + + + + + + + + + + + class ValidationErrors(object): + """Wrapper for the response's 'validation_errors' attribute.""" + + def __init__(self, attributes): + self.attributes = attributes + + @property + def outbound_payment(self): + return self.attributes.get('outbound_payment') + + + + + diff --git a/gocardless_pro/services/__init__.py b/gocardless_pro/services/__init__.py index ea2bd910..41afc263 100644 --- a/gocardless_pro/services/__init__.py +++ b/gocardless_pro/services/__init__.py @@ -31,6 +31,8 @@ from .mandate_pdfs_service import MandatePdfsService from .negative_balance_limits_service import NegativeBalanceLimitsService from .outbound_payments_service import OutboundPaymentsService +from .outbound_payment_imports_service import OutboundPaymentImportsService +from .outbound_payment_import_entries_service import OutboundPaymentImportEntriesService from .payer_authorisations_service import PayerAuthorisationsService from .payer_themes_service import PayerThemesService from .payments_service import PaymentsService diff --git a/gocardless_pro/services/outbound_payment_import_entries_service.py b/gocardless_pro/services/outbound_payment_import_entries_service.py new file mode 100644 index 00000000..80fcf9e2 --- /dev/null +++ b/gocardless_pro/services/outbound_payment_import_entries_service.py @@ -0,0 +1,45 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +from . import base_service +from .. import resources +from ..paginator import Paginator +from .. import errors + +class OutboundPaymentImportEntriesService(base_service.BaseService): + """Service class that provides access to the outbound_payment_import_entries + endpoints of the GoCardless Pro API. + """ + + RESOURCE_CLASS = resources.OutboundPaymentImportEntry + RESOURCE_NAME = 'outbound_payment_import_entries' + + + def list(self,params=None, headers=None): + """List outbound payment import entries. + + Returns a [cursor-paginated](#api-usage-cursor-pagination) list of the + entries for a given outbound payment import. + + Args: + params (dict, optional): Query string parameters. + + Returns: + ListResponse of OutboundPaymentImportEntry instances + """ + path = '/outbound_payment_import_entries' + + + response = self._perform_request('GET', path, params, headers, + retry_failures=True) + return self._resource_for(response) + + def all(self,params=None): + if params is None: + params = {} + return Paginator(self, params, identity_params={ + }) + + diff --git a/gocardless_pro/services/outbound_payment_imports_service.py b/gocardless_pro/services/outbound_payment_imports_service.py new file mode 100644 index 00000000..07ed3ce2 --- /dev/null +++ b/gocardless_pro/services/outbound_payment_imports_service.py @@ -0,0 +1,96 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +from . import base_service +from .. import resources +from ..paginator import Paginator +from .. import errors + +class OutboundPaymentImportsService(base_service.BaseService): + """Service class that provides access to the outbound_payment_imports + endpoints of the GoCardless Pro API. + """ + + RESOURCE_CLASS = resources.OutboundPaymentImport + RESOURCE_NAME = 'outbound_payment_imports' + + + def create(self,params=None, headers=None): + """Create an outbound payment import. + + + + Args: + params (dict, optional): Request body. + + Returns: + OutboundPaymentImport + """ + path = '/outbound_payment_imports' + + if params is not None: + params = {self._envelope_key(): params} + + try: + response = self._perform_request('POST', path, params, headers, + retry_failures=True) + except errors.IdempotentCreationConflictError as err: + if self.raise_on_idempotency_conflict: + raise err + return self.get(identity=err.conflicting_resource_id, + params=params, + headers=headers) + return self._resource_for(response) + + + def get(self,identity,params=None, headers=None): + """Get an outbound payment import. + + Returns a single outbound payment import. + + Args: + identity (string): Unique identifier, beginning with "IM". + params (dict, optional): Query string parameters. + + Returns: + OutboundPaymentImport + """ + path = self._sub_url_params('/outbound_payment_imports/:identity', { + + 'identity': identity, + }) + + + response = self._perform_request('GET', path, params, headers, + retry_failures=True) + return self._resource_for(response) + + + def list(self,params=None, headers=None): + """List outbound payment imports. + + Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your + outbound payment imports. + + Args: + params (dict, optional): Query string parameters. + + Returns: + ListResponse of OutboundPaymentImport instances + """ + path = '/outbound_payment_imports' + + + response = self._perform_request('GET', path, params, headers, + retry_failures=True) + return self._resource_for(response) + + def all(self,params=None): + if params is None: + params = {} + return Paginator(self, params, identity_params={ + }) + + diff --git a/tests/client_test.py b/tests/client_test.py index f73911d9..2bf4e80f 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -101,6 +101,12 @@ def test_negative_balance_limits_returns_service(): def test_outbound_payments_returns_service(): assert isinstance(client.outbound_payments, services.OutboundPaymentsService) +def test_outbound_payment_imports_returns_service(): + assert isinstance(client.outbound_payment_imports, services.OutboundPaymentImportsService) + +def test_outbound_payment_import_entries_returns_service(): + assert isinstance(client.outbound_payment_import_entries, services.OutboundPaymentImportEntriesService) + def test_payer_authorisations_returns_service(): assert isinstance(client.payer_authorisations, services.PayerAuthorisationsService) diff --git a/tests/fixtures/exports.json b/tests/fixtures/exports.json index b45737ca..f762f966 100644 --- a/tests/fixtures/exports.json +++ b/tests/fixtures/exports.json @@ -5,7 +5,7 @@ "method": "GET", "path_template": "/exports/:identity", "url_params": ["EX123"], - "body": {"exports":{"created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","download_url":"example download_url 101","export_type":"payments_index","id":"EX123"}} + "body": {"exports":{"created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","download_url":"example download_url 101","error_message":"example error_message 101","export_type":"payments_index","id":"EX123"}} }, "list": { "method": "GET", diff --git a/tests/fixtures/outbound_payment_import_entries.json b/tests/fixtures/outbound_payment_import_entries.json new file mode 100644 index 00000000..e5890d71 --- /dev/null +++ b/tests/fixtures/outbound_payment_import_entries.json @@ -0,0 +1,10 @@ +{ + + + "list": { + "method": "GET", + "path_template": "/outbound_payment_import_entries", + "url_params": [], + "body": {"meta":{"cursors":{"after":"example after 101","before":"example before 101"},"limit":50},"outbound_payment_import_entries":[{"amount":1000,"created_at":"2014-01-01T12:00:00.000Z","id":"IE123","links":{"outbound_payment":"OUT123","outbound_payment_import":"IM123","recipient_bank_account":"BA123"},"metadata":{},"processed_at":"2014-01-01T12:00:00.000Z","reference":"Invoice 12345","scheme":"faster_payments","validation_errors":{"outbound_payment":{"amount":["example amount 101"],"recipient_bank_account":["example recipient_bank_account 101"],"reference":["example reference 101"],"scheme":"faster_payments"}},"verification_result":"full_match"},{"amount":1000,"created_at":"2014-01-01T12:00:00.000Z","id":"IE123","links":{"outbound_payment":"OUT123","outbound_payment_import":"IM123","recipient_bank_account":"BA123"},"metadata":{},"processed_at":"2014-01-01T12:00:00.000Z","reference":"Invoice 12345","scheme":"faster_payments","validation_errors":{"outbound_payment":{"amount":["example amount 102"],"recipient_bank_account":["example recipient_bank_account 102"],"reference":["example reference 102"],"scheme":"faster_payments"}},"verification_result":"full_match"}]} + } +} diff --git a/tests/fixtures/outbound_payment_imports.json b/tests/fixtures/outbound_payment_imports.json new file mode 100644 index 00000000..77bcfb1b --- /dev/null +++ b/tests/fixtures/outbound_payment_imports.json @@ -0,0 +1,22 @@ +{ + + + "create": { + "method": "POST", + "path_template": "/outbound_payment_imports", + "url_params": [], + "body": {"outbound_payment_imports":{"amount_sum":1000,"authorisation_url":"https://manage.gocardless.com/imports/IM123","created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","entry_counts":{"failed_to_process":0,"invalid":0,"processed":1000,"total":1000,"valid":1000,"verified":0,"verified_with_full_match":0,"verified_with_no_match":0,"verified_with_partial_match":0,"verified_with_unable_to_match":0},"id":"IM123","links":{"creditor":"CR123"},"status":"created"}} + }, + "get": { + "method": "GET", + "path_template": "/outbound_payment_imports/:identity", + "url_params": ["IM123"], + "body": {"outbound_payment_imports":{"amount_sum":1000,"authorisation_url":"https://manage.gocardless.com/imports/IM123","created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","entry_counts":{"failed_to_process":0,"invalid":0,"processed":1000,"total":1000,"valid":1000,"verified":0,"verified_with_full_match":0,"verified_with_no_match":0,"verified_with_partial_match":0,"verified_with_unable_to_match":0},"id":"IM123","links":{"creditor":"CR123"},"status":"created"}} + }, + "list": { + "method": "GET", + "path_template": "/outbound_payment_imports", + "url_params": [], + "body": {"meta":{"cursors":{"after":"example after 101","before":"example before 101"},"limit":50},"outbound_payment_imports":[{"amount_sum":1000,"authorisation_url":"https://manage.gocardless.com/imports/IM123","created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","entry_counts":{"failed_to_process":0,"invalid":0,"processed":1000,"total":1000,"valid":1000,"verified":0,"verified_with_full_match":0,"verified_with_no_match":0,"verified_with_partial_match":0,"verified_with_unable_to_match":0},"id":"IM123","links":{"creditor":"CR123"},"status":"created"},{"amount_sum":1000,"authorisation_url":"https://manage.gocardless.com/imports/IM123","created_at":"2014-01-01T12:00:00.000Z","currency":"GBP","entry_counts":{"failed_to_process":0,"invalid":0,"processed":1000,"total":1000,"valid":1000,"verified":0,"verified_with_full_match":0,"verified_with_no_match":0,"verified_with_partial_match":0,"verified_with_unable_to_match":0},"id":"IM123","links":{"creditor":"CR123"},"status":"created"}]} + } +} diff --git a/tests/integration/exports_integration_test.py b/tests/integration/exports_integration_test.py index f49d3d09..9e32be4c 100644 --- a/tests/integration/exports_integration_test.py +++ b/tests/integration/exports_integration_test.py @@ -30,6 +30,7 @@ def test_exports_get(): assert response.created_at == body.get('created_at') assert response.currency == body.get('currency') assert response.download_url == body.get('download_url') + assert response.error_message == body.get('error_message') assert response.export_type == body.get('export_type') assert response.id == body.get('id') @@ -71,6 +72,7 @@ def test_exports_list(): assert [r.created_at for r in response.records] == [b.get('created_at') for b in body] assert [r.currency for r in response.records] == [b.get('currency') for b in body] assert [r.download_url for r in response.records] == [b.get('download_url') for b in body] + assert [r.error_message for r in response.records] == [b.get('error_message') for b in body] assert [r.export_type for r in response.records] == [b.get('export_type') for b in body] assert [r.id for r in response.records] == [b.get('id') for b in body] diff --git a/tests/integration/outbound_payment_import_entries_integration_test.py b/tests/integration/outbound_payment_import_entries_integration_test.py new file mode 100644 index 00000000..9583b236 --- /dev/null +++ b/tests/integration/outbound_payment_import_entries_integration_test.py @@ -0,0 +1,87 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +import json + +import pytest +import requests +import responses + +from gocardless_pro.errors import MalformedResponseError +from gocardless_pro import resources +from gocardless_pro import list_response + +from .. import helpers + +@responses.activate +def test_outbound_payment_import_entries_list(): + fixture = helpers.load_fixture('outbound_payment_import_entries')['list'] + helpers.stub_response(fixture) + response = helpers.client.outbound_payment_import_entries.list(*fixture['url_params']) + if fixture['body'].get('outbound_payment_import_entries') is not None and isinstance(fixture['body'].get('outbound_payment_import_entries'), (dict, list)): + body = fixture['body']['outbound_payment_import_entries'] + else: + body = fixture['body'] + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImportEntry) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + assert responses.calls[-1].request.headers.get('Idempotency-Key') is None + assert [r.amount for r in response.records] == [b.get('amount') for b in body] + assert [r.created_at for r in response.records] == [b.get('created_at') for b in body] + assert [r.id for r in response.records] == [b.get('id') for b in body] + assert [r.metadata for r in response.records] == [b.get('metadata') for b in body] + assert [r.processed_at for r in response.records] == [b.get('processed_at') for b in body] + assert [r.reference for r in response.records] == [b.get('reference') for b in body] + assert [r.scheme for r in response.records] == [b.get('scheme') for b in body] + assert [r.verification_result for r in response.records] == [b.get('verification_result') for b in body] + +@responses.activate +def test_timeout_outbound_payment_import_entries_list_retries(): + fixture = helpers.load_fixture('outbound_payment_import_entries')['list'] + with helpers.stub_timeout_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_import_entries.list(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImportEntry) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + +def test_502_outbound_payment_import_entries_list_retries(): + fixture = helpers.load_fixture('outbound_payment_import_entries')['list'] + with helpers.stub_502_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_import_entries.list(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImportEntry) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + +@responses.activate +def test_outbound_payment_import_entries_all(): + fixture = helpers.load_fixture('outbound_payment_import_entries')['list'] + + def callback(request): + if 'after=123' in request.url: + fixture['body']['meta']['cursors']['after'] = None + else: + fixture['body']['meta']['cursors']['after'] = '123' + return [200, {}, json.dumps(fixture['body'])] + + url_pattern = helpers.url_pattern_for(fixture) + responses.add_callback(fixture['method'], url_pattern, callback) + + all_records = list(helpers.client.outbound_payment_import_entries.all(*fixture['url_params'])) + assert len(all_records) == len(fixture['body']['outbound_payment_import_entries']) * 2 + for record in all_records: + assert isinstance(record, resources.OutboundPaymentImportEntry) diff --git a/tests/integration/outbound_payment_imports_integration_test.py b/tests/integration/outbound_payment_imports_integration_test.py new file mode 100644 index 00000000..79ceed06 --- /dev/null +++ b/tests/integration/outbound_payment_imports_integration_test.py @@ -0,0 +1,200 @@ +# WARNING: Do not edit by hand, this file was generated by Crank: +# +# https://github.com/gocardless/crank +# + +import json + +import pytest +import requests +import responses + +from gocardless_pro.errors import MalformedResponseError +from gocardless_pro import resources +from gocardless_pro import list_response + +from .. import helpers + +@responses.activate +def test_outbound_payment_imports_create(): + fixture = helpers.load_fixture('outbound_payment_imports')['create'] + helpers.stub_response(fixture) + response = helpers.client.outbound_payment_imports.create(*fixture['url_params']) + if fixture['body'].get('outbound_payment_imports') is not None and isinstance(fixture['body'].get('outbound_payment_imports'), (dict, list)): + body = fixture['body']['outbound_payment_imports'] + else: + body = fixture['body'] + + assert isinstance(response, resources.OutboundPaymentImport) + assert responses.calls[-1].request.headers.get('Idempotency-Key') is not None + assert response.amount_sum == body.get('amount_sum') + assert response.authorisation_url == body.get('authorisation_url') + assert response.created_at == body.get('created_at') + assert response.currency == body.get('currency') + assert response.id == body.get('id') + assert response.status == body.get('status') + assert response.entry_counts.failed_to_process == body.get('entry_counts')['failed_to_process'] + assert response.entry_counts.invalid == body.get('entry_counts')['invalid'] + assert response.entry_counts.processed == body.get('entry_counts')['processed'] + assert response.entry_counts.total == body.get('entry_counts')['total'] + assert response.entry_counts.valid == body.get('entry_counts')['valid'] + assert response.entry_counts.verified == body.get('entry_counts')['verified'] + assert response.entry_counts.verified_with_full_match == body.get('entry_counts')['verified_with_full_match'] + assert response.entry_counts.verified_with_no_match == body.get('entry_counts')['verified_with_no_match'] + assert response.entry_counts.verified_with_partial_match == body.get('entry_counts')['verified_with_partial_match'] + assert response.entry_counts.verified_with_unable_to_match == body.get('entry_counts')['verified_with_unable_to_match'] + assert response.links.creditor == body.get('links')['creditor'] + +@responses.activate +def test_outbound_payment_imports_create_new_idempotency_key_for_each_call(): + fixture = helpers.load_fixture('outbound_payment_imports')['create'] + helpers.stub_response(fixture) + helpers.client.outbound_payment_imports.create(*fixture['url_params']) + helpers.client.outbound_payment_imports.create(*fixture['url_params']) + assert responses.calls[0].request.headers.get('Idempotency-Key') != responses.calls[1].request.headers.get('Idempotency-Key') + +def test_timeout_outbound_payment_imports_create_idempotency_conflict(): + create_fixture = helpers.load_fixture('outbound_payment_imports')['create'] + get_fixture = helpers.load_fixture('outbound_payment_imports')['get'] + with helpers.stub_timeout_then_idempotency_conflict(create_fixture, get_fixture) as rsps: + response = helpers.client.outbound_payment_imports.create(*create_fixture['url_params']) + assert len(rsps.calls) == 2 + + assert isinstance(response, resources.OutboundPaymentImport) + +@responses.activate +def test_timeout_outbound_payment_imports_create_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['create'] + with helpers.stub_timeout_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.create(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, resources.OutboundPaymentImport) + +def test_502_outbound_payment_imports_create_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['create'] + with helpers.stub_502_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.create(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, resources.OutboundPaymentImport) + +@responses.activate +def test_outbound_payment_imports_get(): + fixture = helpers.load_fixture('outbound_payment_imports')['get'] + helpers.stub_response(fixture) + response = helpers.client.outbound_payment_imports.get(*fixture['url_params']) + if fixture['body'].get('outbound_payment_imports') is not None and isinstance(fixture['body'].get('outbound_payment_imports'), (dict, list)): + body = fixture['body']['outbound_payment_imports'] + else: + body = fixture['body'] + + assert isinstance(response, resources.OutboundPaymentImport) + assert responses.calls[-1].request.headers.get('Idempotency-Key') is None + assert response.amount_sum == body.get('amount_sum') + assert response.authorisation_url == body.get('authorisation_url') + assert response.created_at == body.get('created_at') + assert response.currency == body.get('currency') + assert response.id == body.get('id') + assert response.status == body.get('status') + assert response.entry_counts.failed_to_process == body.get('entry_counts')['failed_to_process'] + assert response.entry_counts.invalid == body.get('entry_counts')['invalid'] + assert response.entry_counts.processed == body.get('entry_counts')['processed'] + assert response.entry_counts.total == body.get('entry_counts')['total'] + assert response.entry_counts.valid == body.get('entry_counts')['valid'] + assert response.entry_counts.verified == body.get('entry_counts')['verified'] + assert response.entry_counts.verified_with_full_match == body.get('entry_counts')['verified_with_full_match'] + assert response.entry_counts.verified_with_no_match == body.get('entry_counts')['verified_with_no_match'] + assert response.entry_counts.verified_with_partial_match == body.get('entry_counts')['verified_with_partial_match'] + assert response.entry_counts.verified_with_unable_to_match == body.get('entry_counts')['verified_with_unable_to_match'] + assert response.links.creditor == body.get('links')['creditor'] + +@responses.activate +def test_timeout_outbound_payment_imports_get_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['get'] + with helpers.stub_timeout_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.get(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, resources.OutboundPaymentImport) + +def test_502_outbound_payment_imports_get_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['get'] + with helpers.stub_502_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.get(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, resources.OutboundPaymentImport) + +@responses.activate +def test_outbound_payment_imports_list(): + fixture = helpers.load_fixture('outbound_payment_imports')['list'] + helpers.stub_response(fixture) + response = helpers.client.outbound_payment_imports.list(*fixture['url_params']) + if fixture['body'].get('outbound_payment_imports') is not None and isinstance(fixture['body'].get('outbound_payment_imports'), (dict, list)): + body = fixture['body']['outbound_payment_imports'] + else: + body = fixture['body'] + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImport) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + assert responses.calls[-1].request.headers.get('Idempotency-Key') is None + assert [r.amount_sum for r in response.records] == [b.get('amount_sum') for b in body] + assert [r.authorisation_url for r in response.records] == [b.get('authorisation_url') for b in body] + assert [r.created_at for r in response.records] == [b.get('created_at') for b in body] + assert [r.currency for r in response.records] == [b.get('currency') for b in body] + assert [r.id for r in response.records] == [b.get('id') for b in body] + assert [r.status for r in response.records] == [b.get('status') for b in body] + +@responses.activate +def test_timeout_outbound_payment_imports_list_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['list'] + with helpers.stub_timeout_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.list(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImport) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + +def test_502_outbound_payment_imports_list_retries(): + fixture = helpers.load_fixture('outbound_payment_imports')['list'] + with helpers.stub_502_then_response(fixture) as rsps: + response = helpers.client.outbound_payment_imports.list(*fixture['url_params']) + assert len(rsps.calls) == 2 + assert rsps.calls[0].request.headers.get('Idempotency-Key') == rsps.calls[1].request.headers.get('Idempotency-Key') + + assert isinstance(response, list_response.ListResponse) + assert isinstance(response.records[0], resources.OutboundPaymentImport) + + assert response.before == fixture['body']['meta']['cursors']['before'] + assert response.after == fixture['body']['meta']['cursors']['after'] + +@responses.activate +def test_outbound_payment_imports_all(): + fixture = helpers.load_fixture('outbound_payment_imports')['list'] + + def callback(request): + if 'after=123' in request.url: + fixture['body']['meta']['cursors']['after'] = None + else: + fixture['body']['meta']['cursors']['after'] = '123' + return [200, {}, json.dumps(fixture['body'])] + + url_pattern = helpers.url_pattern_for(fixture) + responses.add_callback(fixture['method'], url_pattern, callback) + + all_records = list(helpers.client.outbound_payment_imports.all(*fixture['url_params'])) + assert len(all_records) == len(fixture['body']['outbound_payment_imports']) * 2 + for record in all_records: + assert isinstance(record, resources.OutboundPaymentImport)