From 99d1a957fe853d7d385650dadf57b1453c82876d Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Thu, 17 Aug 2023 14:58:37 +0200 Subject: [PATCH 01/11] Split objectlist into 2 --- mollie/api/objects/list.py | 91 ++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 23 deletions(-) diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index a1919553..95f208f2 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -1,29 +1,14 @@ +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Type from .base import ObjectBase +if TYPE_CHECKING: + from mollie.api.resources.base import ResourceBase -class UnknownObject(ObjectBase): - """Mock object for empty lists.""" - @classmethod - def get_object_name(cls): - return "unknown" - - -class ObjectList(ObjectBase): +class ListBase(ObjectBase, ABC): current = None - def __init__(self, result, object_type, client=None): - # If an empty dataset was injected, we mock the structure that the remainder of the clas expects. - # TODO: it would be better if the ObjectList was initiated with a list of results, rather than with - # the full datastructure as it is now, so we can remove all this mucking around with fake data, - # mocked result objects, and loads of lengthy accessor workarounds everywhere in the ObjectList. - if result == {}: - result = {"_embedded": {"unknown": []}, "count": 0} - object_type = UnknownObject - - super().__init__(result, client) - self.object_type = object_type - def __len__(self): """Return the count field.""" return self.count @@ -66,7 +51,7 @@ def __getitem__(self, key): }, "count": len(sliced_data), } - return ObjectList(sliced_result, self.object_type, self.client) + return ObjectList(sliced_result, self._parent, self.client) return super().__getitem__(key) @@ -84,16 +69,76 @@ def has_previous(self): """Return True if the ObjectList contains an url for the previous set.""" return self._get_link("previous") is not None + @abstractmethod + def get_next(self): + pass + + @abstractmethod + def get_previous(self): + pass + + @property + @abstractmethod + def object_type(self): + pass + + +class PaginationList(ObjectBase): + _parent: "ResourceBase" + + def __init__(self, result, parent: "ResourceBase", client=None): + # If an empty dataset was injected, we mock the structure that the remainder of the clas expects. + # TODO: it would be better if the ObjectList was initiated with a list of results, rather than with + # the full datastructure as it is now, so we can remove all this mucking around with fake data, + # mocked result objects, and loads of lengthy accessor workarounds everywhere in the ObjectList. + self._parent = parent + + if result == {}: + result = {"_embedded": {f"{self._parent.object_type.get_object_name()}": []}, "count": 0} + + super().__init__(result, client) + def get_next(self): """Return the next set of objects in an ObjectList.""" url = self._get_link("next") resource = self.object_type.get_resource_class(self.client) resp = resource.perform_api_call(resource.REST_READ, url) - return ObjectList(resp, self.object_type, self.client) + return ObjectList(resp, self._parent, self.client) def get_previous(self): """Return the previous set of objects in an ObjectList.""" url = self._get_link("previous") resource = self.object_type.get_resource_class(self.client) resp = resource.perform_api_call(resource.REST_READ, url) - return ObjectList(resp, self.object_type, self.client) + return ObjectList(resp, self._parent, self.client) + + @property + def object_type(self): + return self._parent.object_type + + +class ObjectList(ObjectBase): + _object_type: Type[ObjectBase] + + def __init__(self, result, object_type: Type[ObjectBase], client=None): + # If an empty dataset was injected, we mock the structure that the remainder of the clas expects. + # TODO: it would be better if the ObjectList was initiated with a list of results, rather than with + # the full datastructure as it is now, so we can remove all this mucking around with fake data, + # mocked result objects, and loads of lengthy accessor workarounds everywhere in the ObjectList. + self._object_type = object_type + + if result == {}: + result = {"_embedded": {f"{self._object_type.get_object_name()}": []}, "count": 0} + + super().__init__(result, client) + + def get_next(self): + """Return the next set of objects in an ObjectList.""" + return None + + def get_previous(self): + return None + + @property + def object_type(self): + return self._object_type From 78c9b971a4864619b30be17d37e512f4191041af Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Thu, 17 Aug 2023 14:58:46 +0200 Subject: [PATCH 02/11] Fix tests --- tests/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/utils.py b/tests/utils.py index d37430a4..a7f1a7b5 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,9 +1,9 @@ -from mollie.api.objects.list import ObjectList +from mollie.api.objects.list import ListBase def assert_list_object(obj, object_type, count=None): """Assert that a List object is correctly working, and has sane contents.""" - assert isinstance(obj, ObjectList), f"Object {obj} is not a ObjectList instance." + assert isinstance(obj, ListBase), f"Object {obj} is not a ObjectList instance." assert isinstance(obj.count, int), "ObjectList count is not an integer." if count is not None: assert obj.count == count, "ObjectList does not contain the expected number of items." From d13dafb32cb1c44c20892fc473b12ea0867e1ba2 Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Thu, 17 Aug 2023 15:09:20 +0200 Subject: [PATCH 03/11] Add object_types to resources --- mollie/api/objects/list.py | 4 ++-- mollie/api/resources/balances.py | 3 +++ mollie/api/resources/base.py | 20 ++++++++++++-------- mollie/api/resources/captures.py | 1 + mollie/api/resources/chargebacks.py | 1 + mollie/api/resources/clients.py | 1 + mollie/api/resources/customers.py | 1 + mollie/api/resources/invoices.py | 1 + mollie/api/resources/mandates.py | 1 + mollie/api/resources/methods.py | 10 ++++++---- mollie/api/resources/onboarding.py | 1 + mollie/api/resources/order_lines.py | 7 ++++--- mollie/api/resources/orders.py | 1 + mollie/api/resources/organizations.py | 1 + mollie/api/resources/payment_links.py | 1 + mollie/api/resources/payments.py | 1 + mollie/api/resources/permissions.py | 2 ++ mollie/api/resources/profiles.py | 1 + mollie/api/resources/refunds.py | 4 +--- mollie/api/resources/settlements.py | 1 + mollie/api/resources/shipments.py | 1 + mollie/api/resources/subscriptions.py | 1 + tests/utils.py | 2 +- 23 files changed, 46 insertions(+), 21 deletions(-) diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index 95f208f2..10427fc2 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -83,7 +83,7 @@ def object_type(self): pass -class PaginationList(ObjectBase): +class PaginationList(ListBase): _parent: "ResourceBase" def __init__(self, result, parent: "ResourceBase", client=None): @@ -117,7 +117,7 @@ def object_type(self): return self._parent.object_type -class ObjectList(ObjectBase): +class ObjectList(ListBase): _object_type: Type[ObjectBase] def __init__(self, result, object_type: Type[ObjectBase], client=None): diff --git a/mollie/api/resources/balances.py b/mollie/api/resources/balances.py index 61438234..1170175e 100644 --- a/mollie/api/resources/balances.py +++ b/mollie/api/resources/balances.py @@ -11,6 +11,7 @@ class Balances(ResourceGetMixin, ResourceListMixin): RESOURCE_ID_PREFIX: str = "bal_" + object_type = Balance @classmethod def validate_resource_id(cls, resource_id: str, name: str = "", message: str = "") -> None: @@ -43,6 +44,7 @@ def get(self, resource_id: str, **params: Any) -> Balance: class BalanceReports(ResourceBase): _balance: "Balance" + object_type = BalanceReport def __init__(self, client: "Client", balance: "Balance") -> None: self._balance = balance @@ -64,6 +66,7 @@ def get_report(self, **params: Any) -> BalanceReport: class BalanceTransactions(ResourceListMixin): _balance: "Balance" + object_type = BalanceTransaction def __init__(self, client: "Client", balance: "Balance") -> None: self._balance = balance diff --git a/mollie/api/resources/base.py b/mollie/api/resources/base.py index aa1303d9..c6bc6c95 100644 --- a/mollie/api/resources/base.py +++ b/mollie/api/resources/base.py @@ -1,9 +1,11 @@ import logging import uuid -from typing import TYPE_CHECKING, Any, Dict, Optional +from typing import TYPE_CHECKING, Any, Dict, Optional, Type + +from mollie.api.objects.base import ObjectBase from ..error import IdentifierError, ResponseError, ResponseHandlingError -from ..objects.list import ObjectList +from ..objects.list import PaginationList if TYPE_CHECKING: from ..client import Client @@ -20,6 +22,8 @@ class ResourceBase: RESOURCE_ID_PREFIX: str = "" + object_type: Type[ObjectBase] + def __init__(self, client: "Client") -> None: self.client = client @@ -92,7 +96,7 @@ def create(self, data: Optional[Dict[str, Any]] = None, idempotency_key: str = " idempotency_key = idempotency_key or self._generate_idempotency_key() path = self.get_resource_path() result = self.perform_api_call(self.REST_CREATE, path, data, params, idempotency_key=idempotency_key) - return self.get_resource_object(result) + return self.object_type(result, self.client) class ResourceGetMixin(ResourceBase): @@ -100,7 +104,7 @@ def get(self, resource_id: str, **params: Any) -> Any: resource_path = self.get_resource_path() path = f"{resource_path}/{resource_id}" result = self.perform_api_call(self.REST_READ, path, params=params) - return self.get_resource_object(result) + return self.object_type(result, self.client) def from_url(self, url: str, params: Optional[Dict[str, Any]] = None) -> Any: """Utility method to return an object from a full URL (such as from _links). @@ -108,14 +112,14 @@ def from_url(self, url: str, params: Optional[Dict[str, Any]] = None) -> Any: This method always does a GET request and returns a single Object. """ result = self.perform_api_call(self.REST_READ, url, params=params) - return self.get_resource_object(result) + return self.object_type(result, self.client) class ResourceListMixin(ResourceBase): - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: path = self.get_resource_path() result = self.perform_api_call(self.REST_LIST, path, params=params) - return ObjectList(result, self.get_resource_object({}).__class__, self.client) + return PaginationList(result, self, self.client) class ResourceUpdateMixin(ResourceBase): @@ -126,7 +130,7 @@ def update( resource_path = self.get_resource_path() path = f"{resource_path}/{resource_id}" result = self.perform_api_call(self.REST_UPDATE, path, data, params, idempotency_key=idempotency_key) - return self.get_resource_object(result) + return self.object_type(result, self.client) class ResourceDeleteMixin(ResourceBase): diff --git a/mollie/api/resources/captures.py b/mollie/api/resources/captures.py index 4a3af95e..5cfec88e 100644 --- a/mollie/api/resources/captures.py +++ b/mollie/api/resources/captures.py @@ -16,6 +16,7 @@ class CapturesBase(ResourceBase): RESOURCE_ID_PREFIX: str = "cpt_" + object_type = Capture def get_resource_object(self, result: dict) -> Capture: return Capture(result, self.client) diff --git a/mollie/api/resources/chargebacks.py b/mollie/api/resources/chargebacks.py index 7e8cb166..1bac798e 100644 --- a/mollie/api/resources/chargebacks.py +++ b/mollie/api/resources/chargebacks.py @@ -20,6 +20,7 @@ class ChargebacksBase(ResourceBase): RESOURCE_ID_PREFIX: str = "chb_" + object_type = Chargeback def get_resource_object(self, result: dict) -> Chargeback: return Chargeback(result, self.client) diff --git a/mollie/api/resources/clients.py b/mollie/api/resources/clients.py index f48c466f..c1532c47 100644 --- a/mollie/api/resources/clients.py +++ b/mollie/api/resources/clients.py @@ -16,6 +16,7 @@ class Clients(ResourceListMixin, ResourceGetMixin): """ RESOURCE_ID_PREFIX: str = "org_" + object_type = Client def get_resource_object(self, result: dict) -> Client: return Client(result, self.client) diff --git a/mollie/api/resources/customers.py b/mollie/api/resources/customers.py index 3eddd945..ba21b753 100644 --- a/mollie/api/resources/customers.py +++ b/mollie/api/resources/customers.py @@ -8,6 +8,7 @@ class Customers(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Reso """Resource handler for the `/customers` endpoint.""" RESOURCE_ID_PREFIX: str = "cst_" + object_type = Customer def get_resource_object(self, result: dict) -> Customer: return Customer(result, self.client) diff --git a/mollie/api/resources/invoices.py b/mollie/api/resources/invoices.py index 69bec70b..e28c2e43 100644 --- a/mollie/api/resources/invoices.py +++ b/mollie/api/resources/invoices.py @@ -12,6 +12,7 @@ class Invoices(ResourceGetMixin, ResourceListMixin): """Resource handler for the `/invoices` endpoint.""" RESOURCE_ID_PREFIX: str = "inv_" + object_type = Invoice def get_resource_object(self, result: dict) -> Invoice: return Invoice(result, self.client) diff --git a/mollie/api/resources/mandates.py b/mollie/api/resources/mandates.py index 779be3f8..8ebb25a9 100644 --- a/mollie/api/resources/mandates.py +++ b/mollie/api/resources/mandates.py @@ -19,6 +19,7 @@ class CustomerMandates(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixi RESOURCE_ID_PREFIX = "mdt_" _customer: Customer + object_type = Mandate def __init__(self, client: "Client", customer: Customer) -> None: self._customer = customer diff --git a/mollie/api/resources/methods.py b/mollie/api/resources/methods.py index 2b1c064e..6141ab2b 100644 --- a/mollie/api/resources/methods.py +++ b/mollie/api/resources/methods.py @@ -2,7 +2,7 @@ from ..error import IdentifierError from ..objects.issuer import Issuer -from ..objects.list import ObjectList +from ..objects.list import PaginationList from ..objects.method import Method from .base import ResourceBase, ResourceGetMixin, ResourceListMixin @@ -18,6 +18,8 @@ class MethodsBase(ResourceBase): + object_type = Method + def get_resource_object(self, result: dict) -> Method: return Method(result, self.client) @@ -25,12 +27,12 @@ def get_resource_object(self, result: dict) -> Method: class Methods(MethodsBase, ResourceGetMixin, ResourceListMixin): """Resource handler for the `/methods` endpoint.""" - def all(self, **params: Any) -> ObjectList: + def all(self, **params: Any) -> PaginationList: """List all mollie payment methods, including methods that aren't activated in your profile.""" resource_path = self.get_resource_path() path = f"{resource_path}/all" result = self.perform_api_call(self.REST_LIST, path, params=params) - return ObjectList(result, Method, self.client) + return PaginationList(result, self, self.client) class ProfileMethods(MethodsBase): @@ -85,7 +87,7 @@ def disable(self, method_id: str, **params: Any) -> Method: result = self.perform_api_call(self.REST_DELETE, path, params=params) return self.get_resource_object(result) - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: """List the payment methods for the profile.""" params.update({"profileId": self._profile.id}) # Divert the API call to the general Methods resource diff --git a/mollie/api/resources/onboarding.py b/mollie/api/resources/onboarding.py index 97d2fc8f..98783da5 100644 --- a/mollie/api/resources/onboarding.py +++ b/mollie/api/resources/onboarding.py @@ -12,6 +12,7 @@ class Onboarding(ResourceGetMixin): """Resource handler for the `/onboarding` endpoint.""" + object_type = OnboardingObject def get_resource_object(self, result: dict) -> OnboardingObject: return OnboardingObject(result, self.client) diff --git a/mollie/api/resources/order_lines.py b/mollie/api/resources/order_lines.py index e99ab010..04c375ff 100644 --- a/mollie/api/resources/order_lines.py +++ b/mollie/api/resources/order_lines.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Any, Dict, Optional from ..error import DataConsistencyError -from ..objects.list import ObjectList +from ..objects.list import PaginationList from ..objects.order_line import OrderLine from .base import ResourceBase @@ -25,6 +25,7 @@ class OrderLines(ResourceBase): """ RESOURCE_ID_PREFIX: str = "odl_" + object_type = OrderLine _order: "Order" @@ -102,7 +103,7 @@ def update(self, order_line_id: str, data: Optional[Dict[str, Any]] = None, **pa raise DataConsistencyError(f"OrderLine with id '{order_line_id}' not found in response.") - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: """Return the orderline data from the related order.""" lines = self._order._get_property("lines") or [] data = { @@ -111,4 +112,4 @@ def list(self, **params: Any) -> ObjectList: }, "count": len(lines), } - return ObjectList(data, OrderLine, self.client) + return PaginationList(data, self, self.client) diff --git a/mollie/api/resources/orders.py b/mollie/api/resources/orders.py index 70bac22d..6f5aa3e1 100644 --- a/mollie/api/resources/orders.py +++ b/mollie/api/resources/orders.py @@ -12,6 +12,7 @@ class Orders(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Resourc """Resource handler for the `/orders` endpoint.""" RESOURCE_ID_PREFIX: str = "ord_" + object_type = Order def get_resource_object(self, result: dict) -> Order: return Order(result, self.client) diff --git a/mollie/api/resources/organizations.py b/mollie/api/resources/organizations.py index a64d9eba..a779dc6c 100644 --- a/mollie/api/resources/organizations.py +++ b/mollie/api/resources/organizations.py @@ -12,6 +12,7 @@ class Organizations(ResourceGetMixin): """Resource handler for the `/organizations` endpoint.""" RESOURCE_ID_PREFIX: str = "org_" + object_type = Organization def get_resource_object(self, result: dict) -> Organization: return Organization(result, self.client) diff --git a/mollie/api/resources/payment_links.py b/mollie/api/resources/payment_links.py index 94579e8d..a5abca92 100644 --- a/mollie/api/resources/payment_links.py +++ b/mollie/api/resources/payment_links.py @@ -12,6 +12,7 @@ class PaymentLinks(ResourceCreateMixin, ResourceGetMixin, ResourceListMixin): """Resource handler for the `/payment_links` endpoint.""" RESOURCE_ID_PREFIX: str = "pl_" + object_type = PaymentLink def get_resource_path(self) -> str: return "payment-links" diff --git a/mollie/api/resources/payments.py b/mollie/api/resources/payments.py index fe005048..61bd524f 100644 --- a/mollie/api/resources/payments.py +++ b/mollie/api/resources/payments.py @@ -31,6 +31,7 @@ class PaymentsBase(ResourceBase): RESOURCE_ID_PREFIX: str = "tr_" + object_type = Payment def get_resource_object(self, result: dict) -> Payment: from ..objects.payment import Payment diff --git a/mollie/api/resources/permissions.py b/mollie/api/resources/permissions.py index 0ba84425..a2ec5a61 100644 --- a/mollie/api/resources/permissions.py +++ b/mollie/api/resources/permissions.py @@ -13,6 +13,8 @@ class Permissions(ResourceGetMixin, ResourceListMixin): """Resource handler for the `/permissions` endpoint.""" + object_type = Permission + def get_resource_object(self, result: dict) -> Permission: return Permission(result, self.client) diff --git a/mollie/api/resources/profiles.py b/mollie/api/resources/profiles.py index 85e7f36e..48df9ed8 100644 --- a/mollie/api/resources/profiles.py +++ b/mollie/api/resources/profiles.py @@ -12,6 +12,7 @@ class Profiles(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Resou """Resource handler for the `/profiles` endpoint.""" RESOURCE_ID_PREFIX: str = "pfl_" + object_type = Profile def get_resource_object(self, result: dict) -> Profile: return Profile(result, self.client) diff --git a/mollie/api/resources/refunds.py b/mollie/api/resources/refunds.py index 3d25eccc..3996bcc6 100644 --- a/mollie/api/resources/refunds.py +++ b/mollie/api/resources/refunds.py @@ -22,9 +22,7 @@ class RefundsBase(ResourceBase): RESOURCE_ID_PREFIX: str = "re_" - - def get_resource_object(self, result: dict) -> Refund: - return Refund(result, self.client) + object_type = Refund class Refunds(RefundsBase, ResourceListMixin): diff --git a/mollie/api/resources/settlements.py b/mollie/api/resources/settlements.py index 71787fa4..0bd2365c 100644 --- a/mollie/api/resources/settlements.py +++ b/mollie/api/resources/settlements.py @@ -9,6 +9,7 @@ class Settlements(ResourceGetMixin, ResourceListMixin): """Resource handler for the `/settlements` endpoint.""" RESOURCE_ID_PREFIX: str = "stl_" + object_type = Settlement # According to Mollie, the bank reference is formatted as: # - The Mollie merchant ID, 4 to 8 digits, might grow when the number of merchants increases diff --git a/mollie/api/resources/shipments.py b/mollie/api/resources/shipments.py index f1c9ca6e..00a8ff73 100644 --- a/mollie/api/resources/shipments.py +++ b/mollie/api/resources/shipments.py @@ -16,6 +16,7 @@ class OrderShipments(ResourceCreateMixin, ResourceGetMixin, ResourceListMixin, R """Resource handler for the `/orders/:order_id:/shipments` endpoint.""" RESOURCE_ID_PREFIX: str = "shp_" + object_type = Shipment _order: Order diff --git a/mollie/api/resources/subscriptions.py b/mollie/api/resources/subscriptions.py index 2d9dd93a..63f3360b 100644 --- a/mollie/api/resources/subscriptions.py +++ b/mollie/api/resources/subscriptions.py @@ -22,6 +22,7 @@ class SubscriptionsBase(ResourceBase): RESOURCE_ID_PREFIX: str = "sub_" + object_type = Subscription def get_resource_object(self, result: dict) -> Subscription: return Subscription(result, self.client) diff --git a/tests/utils.py b/tests/utils.py index a7f1a7b5..f01c99ef 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -3,7 +3,7 @@ def assert_list_object(obj, object_type, count=None): """Assert that a List object is correctly working, and has sane contents.""" - assert isinstance(obj, ListBase), f"Object {obj} is not a ObjectList instance." + assert isinstance(obj, ListBase), f"Object {obj} is not a ListBase instance." assert isinstance(obj.count, int), "ObjectList count is not an integer." if count is not None: assert obj.count == count, "ObjectList does not contain the expected number of items." From ec868dacfbeef3abdf6fa7d6a044ff55a01b1b21 Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Thu, 17 Aug 2023 15:20:04 +0200 Subject: [PATCH 04/11] Fixes, all tests succeed --- mollie/api/objects/list.py | 23 +++++++++++++++++------ tests/test_list.py | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index 10427fc2..f6f96bdd 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -51,7 +51,7 @@ def __getitem__(self, key): }, "count": len(sliced_data), } - return ObjectList(sliced_result, self._parent, self.client) + return self.new(sliced_result) return super().__getitem__(key) @@ -71,16 +71,21 @@ def has_previous(self): @abstractmethod def get_next(self): - pass + ... @abstractmethod def get_previous(self): - pass + ... @property @abstractmethod def object_type(self): - pass + ... + + @abstractmethod + def new(self, result): + ... + class PaginationList(ListBase): @@ -103,18 +108,21 @@ def get_next(self): url = self._get_link("next") resource = self.object_type.get_resource_class(self.client) resp = resource.perform_api_call(resource.REST_READ, url) - return ObjectList(resp, self._parent, self.client) + return PaginationList(resp, self._parent, self.client) def get_previous(self): """Return the previous set of objects in an ObjectList.""" url = self._get_link("previous") resource = self.object_type.get_resource_class(self.client) resp = resource.perform_api_call(resource.REST_READ, url) - return ObjectList(resp, self._parent, self.client) + return PaginationList(resp, self._parent, self.client) @property def object_type(self): return self._parent.object_type + + def new(self, result): + return PaginationList(result, self._parent, self.client) class ObjectList(ListBase): @@ -142,3 +150,6 @@ def get_previous(self): @property def object_type(self): return self._object_type + + def new(self, result): + return ObjectList(result, self._object_type, self.client) diff --git a/tests/test_list.py b/tests/test_list.py index 8c410730..29db795a 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -1,6 +1,6 @@ import pytest -from mollie.api.objects.list import ObjectList +from mollie.api.objects.list import PaginationList from mollie.api.objects.method import Method from .utils import assert_list_object @@ -11,7 +11,7 @@ def test_list_iterator_behaviour(client, response): response.get("https://api.mollie.com/v2/methods", "methods_list") methods = client.methods.list() - assert isinstance(methods, ObjectList) + assert isinstance(methods, PaginationList) # walk the list using next() iterated = 0 From 1a92806056176daa19073e84853fab15497d28da Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Thu, 17 Aug 2023 15:25:44 +0200 Subject: [PATCH 05/11] Remove all get_resource_object references --- mollie/api/resources/balances.py | 17 +---------------- mollie/api/resources/base.py | 9 --------- mollie/api/resources/captures.py | 3 --- mollie/api/resources/chargebacks.py | 3 --- mollie/api/resources/clients.py | 3 --- mollie/api/resources/customers.py | 3 --- mollie/api/resources/invoices.py | 3 --- mollie/api/resources/mandates.py | 3 --- mollie/api/resources/methods.py | 7 ++----- mollie/api/resources/onboarding.py | 5 +---- mollie/api/resources/order_lines.py | 5 +---- mollie/api/resources/orders.py | 5 +---- mollie/api/resources/organizations.py | 3 --- mollie/api/resources/payment_links.py | 3 --- mollie/api/resources/payments.py | 7 +------ mollie/api/resources/permissions.py | 3 --- mollie/api/resources/profiles.py | 3 --- mollie/api/resources/settlements.py | 3 --- mollie/api/resources/shipments.py | 3 --- mollie/api/resources/subscriptions.py | 5 +---- 20 files changed, 8 insertions(+), 88 deletions(-) diff --git a/mollie/api/resources/balances.py b/mollie/api/resources/balances.py index 1170175e..b342c437 100644 --- a/mollie/api/resources/balances.py +++ b/mollie/api/resources/balances.py @@ -32,11 +32,6 @@ def validate_resource_id(cls, resource_id: str, name: str = "", message: str = " else: super().validate_resource_id(resource_id, message=exc_message) - def get_resource_object(self, result: dict) -> Balance: - from ..objects.balance import Balance - - return Balance(result, self.client) - def get(self, resource_id: str, **params: Any) -> Balance: self.validate_resource_id(resource_id) return super().get(resource_id, **params) @@ -50,18 +45,13 @@ def __init__(self, client: "Client", balance: "Balance") -> None: self._balance = balance super().__init__(client) - def get_resource_object(self, result: dict) -> BalanceReport: - from ..objects.balance_report import BalanceReport - - return BalanceReport(result, self.client) - def get_resource_path(self) -> str: return f"balances/{self._balance.id}/report" def get_report(self, **params: Any) -> BalanceReport: path = self.get_resource_path() result = self.perform_api_call(self.REST_READ, path, params=params) - return self.get_resource_object(result) + return BalanceReport(result, self.client) class BalanceTransactions(ResourceListMixin): @@ -72,10 +62,5 @@ def __init__(self, client: "Client", balance: "Balance") -> None: self._balance = balance super().__init__(client) - def get_resource_object(self, result: dict) -> BalanceTransaction: - from ..objects.balance_transaction import BalanceTransaction - - return BalanceTransaction(result, self.client) - def get_resource_path(self) -> str: return f"balances/{self._balance.id}/transactions" diff --git a/mollie/api/resources/base.py b/mollie/api/resources/base.py index c6bc6c95..7b10983e 100644 --- a/mollie/api/resources/base.py +++ b/mollie/api/resources/base.py @@ -27,15 +27,6 @@ class ResourceBase: def __init__(self, client: "Client") -> None: self.client = client - def get_resource_object(self, result: dict) -> Any: - """ - Return an instantiated result class for this resource. Should be overriden by a subclass. - - :param result: The API response that the object should hold. - :type result: dict - """ - raise NotImplementedError() # pragma: no cover - def get_resource_path(self) -> str: """Return the base URL path in the API for this resource.""" return self.__class__.__name__.lower() diff --git a/mollie/api/resources/captures.py b/mollie/api/resources/captures.py index 5cfec88e..132b12ac 100644 --- a/mollie/api/resources/captures.py +++ b/mollie/api/resources/captures.py @@ -18,9 +18,6 @@ class CapturesBase(ResourceBase): RESOURCE_ID_PREFIX: str = "cpt_" object_type = Capture - def get_resource_object(self, result: dict) -> Capture: - return Capture(result, self.client) - class PaymentCaptures(CapturesBase, ResourceGetMixin, ResourceListMixin, ResourceCreateMixin): """Resource handler for the `/payments/:payment_id:/captures` endpoint.""" diff --git a/mollie/api/resources/chargebacks.py b/mollie/api/resources/chargebacks.py index 1bac798e..cd8d5353 100644 --- a/mollie/api/resources/chargebacks.py +++ b/mollie/api/resources/chargebacks.py @@ -22,9 +22,6 @@ class ChargebacksBase(ResourceBase): RESOURCE_ID_PREFIX: str = "chb_" object_type = Chargeback - def get_resource_object(self, result: dict) -> Chargeback: - return Chargeback(result, self.client) - class Chargebacks(ChargebacksBase, ResourceListMixin): """Resource handler for the `/chargebacks` endpoint.""" diff --git a/mollie/api/resources/clients.py b/mollie/api/resources/clients.py index c1532c47..8a29af8e 100644 --- a/mollie/api/resources/clients.py +++ b/mollie/api/resources/clients.py @@ -18,9 +18,6 @@ class Clients(ResourceListMixin, ResourceGetMixin): RESOURCE_ID_PREFIX: str = "org_" object_type = Client - def get_resource_object(self, result: dict) -> Client: - return Client(result, self.client) - def get(self, resource_id: str, **params: Any) -> Client: """Retrieve a single client, linked to your partner account, by its ID.""" self.validate_resource_id(resource_id, "client ID") diff --git a/mollie/api/resources/customers.py b/mollie/api/resources/customers.py index ba21b753..14b54443 100644 --- a/mollie/api/resources/customers.py +++ b/mollie/api/resources/customers.py @@ -10,9 +10,6 @@ class Customers(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Reso RESOURCE_ID_PREFIX: str = "cst_" object_type = Customer - def get_resource_object(self, result: dict) -> Customer: - return Customer(result, self.client) - def get(self, resource_id: str, **params: Any) -> Customer: self.validate_resource_id(resource_id, "customer ID") return super().get(resource_id, **params) diff --git a/mollie/api/resources/invoices.py b/mollie/api/resources/invoices.py index e28c2e43..6f798455 100644 --- a/mollie/api/resources/invoices.py +++ b/mollie/api/resources/invoices.py @@ -14,9 +14,6 @@ class Invoices(ResourceGetMixin, ResourceListMixin): RESOURCE_ID_PREFIX: str = "inv_" object_type = Invoice - def get_resource_object(self, result: dict) -> Invoice: - return Invoice(result, self.client) - def get(self, resource_id: str, **params: Any) -> Invoice: self.validate_resource_id(resource_id, "invoice ID") return super().get(resource_id, **params) diff --git a/mollie/api/resources/mandates.py b/mollie/api/resources/mandates.py index 8ebb25a9..90412a7a 100644 --- a/mollie/api/resources/mandates.py +++ b/mollie/api/resources/mandates.py @@ -28,9 +28,6 @@ def __init__(self, client: "Client", customer: Customer) -> None: def get_resource_path(self) -> str: return f"customers/{self._customer.id}/mandates" - def get_resource_object(self, result: dict) -> Mandate: - return Mandate(result, self.client) - def get(self, resource_id: str, **params: Any) -> Mandate: self.validate_resource_id(resource_id, "mandate ID") return super().get(resource_id, **params) diff --git a/mollie/api/resources/methods.py b/mollie/api/resources/methods.py index 6141ab2b..d74b8405 100644 --- a/mollie/api/resources/methods.py +++ b/mollie/api/resources/methods.py @@ -20,9 +20,6 @@ class MethodsBase(ResourceBase): object_type = Method - def get_resource_object(self, result: dict) -> Method: - return Method(result, self.client) - class Methods(MethodsBase, ResourceGetMixin, ResourceListMixin): """Resource handler for the `/methods` endpoint.""" @@ -68,7 +65,7 @@ def enable(self, method_id: str, **params: Any) -> Method: resource_path = self.get_resource_path() path = f"{resource_path}/{method_id}" result = self.perform_api_call(self.REST_CREATE, path, params=params) - return self.get_resource_object(result) + return Method(result, self.client) def disable(self, method_id: str, **params: Any) -> Method: """ @@ -85,7 +82,7 @@ def disable(self, method_id: str, **params: Any) -> Method: resource_path = self.get_resource_path() path = f"{resource_path}/{method_id}" result = self.perform_api_call(self.REST_DELETE, path, params=params) - return self.get_resource_object(result) + return Method(result, self.client) def list(self, **params: Any) -> PaginationList: """List the payment methods for the profile.""" diff --git a/mollie/api/resources/onboarding.py b/mollie/api/resources/onboarding.py index 98783da5..d6c4b6b2 100644 --- a/mollie/api/resources/onboarding.py +++ b/mollie/api/resources/onboarding.py @@ -14,9 +14,6 @@ class Onboarding(ResourceGetMixin): """Resource handler for the `/onboarding` endpoint.""" object_type = OnboardingObject - def get_resource_object(self, result: dict) -> OnboardingObject: - return OnboardingObject(result, self.client) - def get(self, resource_id: str, **params: Any) -> OnboardingObject: if resource_id != "me": raise IdentifierError(f"Invalid onboarding ID: '{resource_id}'. The onboarding ID should be 'me'.") @@ -32,4 +29,4 @@ def create(self, data: Dict[str, Any], **params: Any) -> OnboardingObject: resource_path = self.get_resource_path() path = f"{resource_path}/me" result = self.perform_api_call(self.REST_CREATE, path, data, params) - return self.get_resource_object(result) + return OnboardingObject(result, self.client) diff --git a/mollie/api/resources/order_lines.py b/mollie/api/resources/order_lines.py index 04c375ff..55f0893c 100644 --- a/mollie/api/resources/order_lines.py +++ b/mollie/api/resources/order_lines.py @@ -36,9 +36,6 @@ def __init__(self, client: "Client", order: "Order") -> None: def get_resource_path(self) -> str: return f"orders/{self._order.id}/lines" - def get_resource_object(self, result: dict) -> OrderLine: - return OrderLine(result, self.client) - def delete_lines(self, data: Optional[Dict[str, Any]] = None, **params: Any) -> dict: """ Cancel multiple orderlines. @@ -99,7 +96,7 @@ def update(self, order_line_id: str, data: Optional[Dict[str, Any]] = None, **pa for line in result["lines"]: if line["id"] == order_line_id: - return self.get_resource_object(line) + return OrderLine(line, self.client) raise DataConsistencyError(f"OrderLine with id '{order_line_id}' not found in response.") diff --git a/mollie/api/resources/orders.py b/mollie/api/resources/orders.py index 6f5aa3e1..7e552ead 100644 --- a/mollie/api/resources/orders.py +++ b/mollie/api/resources/orders.py @@ -14,9 +14,6 @@ class Orders(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Resourc RESOURCE_ID_PREFIX: str = "ord_" object_type = Order - def get_resource_object(self, result: dict) -> Order: - return Order(result, self.client) - def get(self, resource_id: str, **params: Any) -> Order: self.validate_resource_id(resource_id, "order ID") return super().get(resource_id, **params) @@ -29,7 +26,7 @@ def delete(self, resource_id: str, idempotency_key: str = "", **params: Any) -> """ self.validate_resource_id(resource_id, "order ID") result = super().delete(resource_id, **params) - return self.get_resource_object(result) + return Order(result, self.client) def update( self, resource_id: str, data: Optional[Dict[str, Any]] = None, idempotency_key: str = "", **params: Any diff --git a/mollie/api/resources/organizations.py b/mollie/api/resources/organizations.py index a779dc6c..b9756d23 100644 --- a/mollie/api/resources/organizations.py +++ b/mollie/api/resources/organizations.py @@ -14,9 +14,6 @@ class Organizations(ResourceGetMixin): RESOURCE_ID_PREFIX: str = "org_" object_type = Organization - def get_resource_object(self, result: dict) -> Organization: - return Organization(result, self.client) - def get(self, resource_id: str, **params: Any) -> Organization: if resource_id != "me": self.validate_resource_id(resource_id, "organization ID") diff --git a/mollie/api/resources/payment_links.py b/mollie/api/resources/payment_links.py index a5abca92..dfe3ebd7 100644 --- a/mollie/api/resources/payment_links.py +++ b/mollie/api/resources/payment_links.py @@ -17,9 +17,6 @@ class PaymentLinks(ResourceCreateMixin, ResourceGetMixin, ResourceListMixin): def get_resource_path(self) -> str: return "payment-links" - def get_resource_object(self, result: dict) -> PaymentLink: - return PaymentLink(result, self.client) - def get(self, resource_id: str, **params: Any) -> PaymentLink: self.validate_resource_id(resource_id, "payment link ID") return super().get(resource_id, **params) diff --git a/mollie/api/resources/payments.py b/mollie/api/resources/payments.py index 61bd524f..0878d819 100644 --- a/mollie/api/resources/payments.py +++ b/mollie/api/resources/payments.py @@ -33,11 +33,6 @@ class PaymentsBase(ResourceBase): RESOURCE_ID_PREFIX: str = "tr_" object_type = Payment - def get_resource_object(self, result: dict) -> Payment: - from ..objects.payment import Payment - - return Payment(result, self.client) - class Payments( PaymentsBase, ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, ResourceListMixin, ResourceUpdateMixin @@ -56,7 +51,7 @@ def delete(self, resource_id: str, idempotency_key: str = "", **params: Any) -> """ self.validate_resource_id(resource_id, "payment ID") result = super().delete(resource_id, idempotency_key, **params) - return self.get_resource_object(result) + return Payment(result, self.client) def update( self, resource_id: str, data: Optional[Dict[str, Any]] = None, idempotency_key: str = "", **params: Any diff --git a/mollie/api/resources/permissions.py b/mollie/api/resources/permissions.py index a2ec5a61..7159743e 100644 --- a/mollie/api/resources/permissions.py +++ b/mollie/api/resources/permissions.py @@ -15,9 +15,6 @@ class Permissions(ResourceGetMixin, ResourceListMixin): object_type = Permission - def get_resource_object(self, result: dict) -> Permission: - return Permission(result, self.client) - @staticmethod def validate_permission_id(permission_id: str) -> None: if not permission_id or not bool(re.match(r"^[a-z]+\.[a-z]+$", permission_id)): diff --git a/mollie/api/resources/profiles.py b/mollie/api/resources/profiles.py index 48df9ed8..35952da7 100644 --- a/mollie/api/resources/profiles.py +++ b/mollie/api/resources/profiles.py @@ -14,9 +14,6 @@ class Profiles(ResourceCreateMixin, ResourceDeleteMixin, ResourceGetMixin, Resou RESOURCE_ID_PREFIX: str = "pfl_" object_type = Profile - def get_resource_object(self, result: dict) -> Profile: - return Profile(result, self.client) - def get(self, resource_id: str, **params: Any) -> Profile: if resource_id != "me": self.validate_resource_id(resource_id, "profile ID") diff --git a/mollie/api/resources/settlements.py b/mollie/api/resources/settlements.py index 0bd2365c..8282c30e 100644 --- a/mollie/api/resources/settlements.py +++ b/mollie/api/resources/settlements.py @@ -18,9 +18,6 @@ class Settlements(ResourceGetMixin, ResourceListMixin): # The components are separated by a dot. BANK_REFERENCE_REGEX: Pattern[str] = re.compile(r"^\d{4,}\.\d{4}\.\d{2}$", re.ASCII) - def get_resource_object(self, result: dict) -> Settlement: - return Settlement(result, self.client) - @classmethod def validate_resource_id(cls, resource_id: str, name: str = "", message: str = "") -> None: """ diff --git a/mollie/api/resources/shipments.py b/mollie/api/resources/shipments.py index 00a8ff73..ca28f62b 100644 --- a/mollie/api/resources/shipments.py +++ b/mollie/api/resources/shipments.py @@ -24,9 +24,6 @@ def __init__(self, client: "Client", order: Order) -> None: self._order = order super().__init__(client) - def get_resource_object(self, result: dict) -> Shipment: - return Shipment(result, self.client) - def get_resource_path(self) -> str: return f"orders/{self._order.id}/shipments" diff --git a/mollie/api/resources/subscriptions.py b/mollie/api/resources/subscriptions.py index 63f3360b..bdca20cb 100644 --- a/mollie/api/resources/subscriptions.py +++ b/mollie/api/resources/subscriptions.py @@ -24,9 +24,6 @@ class SubscriptionsBase(ResourceBase): RESOURCE_ID_PREFIX: str = "sub_" object_type = Subscription - def get_resource_object(self, result: dict) -> Subscription: - return Subscription(result, self.client) - class Subscriptions(SubscriptionsBase, ResourceListMixin): """Resource handler for the `/subscriptions` endpoint.""" @@ -66,4 +63,4 @@ def update( def delete(self, resource_id: str, idempotency_key: str = "", **params: Any) -> dict: self.validate_resource_id(resource_id, "subscription ID") resp = super().delete(resource_id, idempotency_key, **params) - return self.get_resource_object(resp) + return Subscription(resp, self.client) From e5e64a5fea486c889a2e0c35856020bc0f8d116d Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Mon, 18 Sep 2023 10:44:03 +0200 Subject: [PATCH 06/11] Remove all get_resource_class references --- mollie/api/objects/balance.py | 6 ------ mollie/api/objects/balance_report.py | 13 ------------- mollie/api/objects/balance_transaction.py | 13 ------------- mollie/api/objects/base.py | 9 --------- mollie/api/objects/capture.py | 13 ------------- mollie/api/objects/chargeback.py | 6 ------ mollie/api/objects/client.py | 6 ------ mollie/api/objects/customer.py | 6 ------ mollie/api/objects/invoice.py | 6 ------ mollie/api/objects/list.py | 14 ++++++++------ mollie/api/objects/mandate.py | 13 ------------- mollie/api/objects/method.py | 6 ------ mollie/api/objects/onboarding.py | 6 ------ mollie/api/objects/order.py | 6 ------ mollie/api/objects/order_line.py | 13 ------------- mollie/api/objects/organization.py | 6 ------ mollie/api/objects/payment.py | 6 ------ mollie/api/objects/payment_link.py | 6 ------ mollie/api/objects/permission.py | 6 ------ mollie/api/objects/profile.py | 6 ------ mollie/api/objects/refund.py | 6 ------ mollie/api/objects/settlement.py | 6 ------ mollie/api/objects/subscription.py | 7 ------- 23 files changed, 8 insertions(+), 177 deletions(-) diff --git a/mollie/api/objects/balance.py b/mollie/api/objects/balance.py index 501908d8..fd3367a6 100644 --- a/mollie/api/objects/balance.py +++ b/mollie/api/objects/balance.py @@ -6,12 +6,6 @@ class Balance(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Balances - - return Balances(client) - @property def resource(self): return self._get_property("resource") diff --git a/mollie/api/objects/balance_report.py b/mollie/api/objects/balance_report.py index 5b2adf93..dd88147b 100644 --- a/mollie/api/objects/balance_report.py +++ b/mollie/api/objects/balance_report.py @@ -1,20 +1,7 @@ -from typing import TYPE_CHECKING, Any - from .base import ObjectBase -if TYPE_CHECKING: - from ..client import Client - from ..resources import BalanceReports - class BalanceReport(ObjectBase): - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> "BalanceReports": - from ..resources import BalanceReports - - balance = kwargs["balance"] - return BalanceReports(client, balance) - @property def resource(self): return self._get_property("resource") diff --git a/mollie/api/objects/balance_transaction.py b/mollie/api/objects/balance_transaction.py index e3730d44..3af09447 100644 --- a/mollie/api/objects/balance_transaction.py +++ b/mollie/api/objects/balance_transaction.py @@ -1,20 +1,7 @@ -from typing import TYPE_CHECKING, Any - from .base import ObjectBase -if TYPE_CHECKING: - from ..client import Client - from ..resources import BalanceTransactions - class BalanceTransaction(ObjectBase): - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> "BalanceTransactions": - from ..resources import BalanceTransactions - - balance = kwargs["balance"] - return BalanceTransactions(client, balance) - @classmethod def get_object_name(cls): # Overwrite get_object_name since BalanceTransactions gets returned by Mollie as balance_transactions. diff --git a/mollie/api/objects/base.py b/mollie/api/objects/base.py index 856d6615..ac8493a0 100644 --- a/mollie/api/objects/base.py +++ b/mollie/api/objects/base.py @@ -1,10 +1,5 @@ -from typing import TYPE_CHECKING, Any - from ..error import EmbedNotFound -if TYPE_CHECKING: - from ..client import Client - class ObjectBase(dict): def __init__(self, data, client): @@ -45,7 +40,3 @@ def get_embedded(self, name: str) -> dict: def get_object_name(cls): name = cls.__name__.lower() return f"{name}s" - - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> Any: - raise NotImplementedError # pragma: no cover diff --git a/mollie/api/objects/capture.py b/mollie/api/objects/capture.py index 331aeafb..d040f405 100644 --- a/mollie/api/objects/capture.py +++ b/mollie/api/objects/capture.py @@ -1,20 +1,7 @@ -from typing import TYPE_CHECKING, Any - from .base import ObjectBase -if TYPE_CHECKING: - from ..client import Client - from ..resources import PaymentCaptures - class Capture(ObjectBase): - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> "PaymentCaptures": - from ..resources import PaymentCaptures - - payment = kwargs["payment"] - return PaymentCaptures(client, payment) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/chargeback.py b/mollie/api/objects/chargeback.py index 40f1d6e9..52643975 100644 --- a/mollie/api/objects/chargeback.py +++ b/mollie/api/objects/chargeback.py @@ -4,12 +4,6 @@ class Chargeback(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Chargebacks - - return Chargebacks(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/client.py b/mollie/api/objects/client.py index e9908eb8..7e7928f0 100644 --- a/mollie/api/objects/client.py +++ b/mollie/api/objects/client.py @@ -2,12 +2,6 @@ class Client(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Clients - - return Clients(client) - # Documented properties @property diff --git a/mollie/api/objects/customer.py b/mollie/api/objects/customer.py index 2a52876b..fe3602fc 100644 --- a/mollie/api/objects/customer.py +++ b/mollie/api/objects/customer.py @@ -2,12 +2,6 @@ class Customer(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Customers - - return Customers(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/invoice.py b/mollie/api/objects/invoice.py index e01f9f66..4f6d2070 100644 --- a/mollie/api/objects/invoice.py +++ b/mollie/api/objects/invoice.py @@ -2,12 +2,6 @@ class Invoice(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Invoices - - return Invoices(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index f6f96bdd..85f62c01 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -106,21 +106,23 @@ def __init__(self, result, parent: "ResourceBase", client=None): def get_next(self): """Return the next set of objects in an ObjectList.""" url = self._get_link("next") - resource = self.object_type.get_resource_class(self.client) - resp = resource.perform_api_call(resource.REST_READ, url) + if url is None: + return None + resp = self._parent.perform_api_call(self._parent.REST_READ, url) return PaginationList(resp, self._parent, self.client) def get_previous(self): """Return the previous set of objects in an ObjectList.""" url = self._get_link("previous") - resource = self.object_type.get_resource_class(self.client) - resp = resource.perform_api_call(resource.REST_READ, url) + if url is None: + return None + resp = self._parent.perform_api_call(self._parent.REST_READ, url) return PaginationList(resp, self._parent, self.client) - + @property def object_type(self): return self._parent.object_type - + def new(self, result): return PaginationList(result, self._parent, self.client) diff --git a/mollie/api/objects/mandate.py b/mollie/api/objects/mandate.py index 87405565..0f5f3d62 100644 --- a/mollie/api/objects/mandate.py +++ b/mollie/api/objects/mandate.py @@ -1,20 +1,7 @@ -from typing import TYPE_CHECKING, Any - from .base import ObjectBase -if TYPE_CHECKING: - from ..client import Client - from ..resources import CustomerMandates - class Mandate(ObjectBase): - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> "CustomerMandates": - from ..resources import CustomerMandates - - customer = kwargs["customer"] - return CustomerMandates(client, customer) - STATUS_PENDING = "pending" STATUS_VALID = "valid" STATUS_INVALID = "invalid" diff --git a/mollie/api/objects/method.py b/mollie/api/objects/method.py index 1ef9095b..c873c9a7 100644 --- a/mollie/api/objects/method.py +++ b/mollie/api/objects/method.py @@ -4,12 +4,6 @@ class Method(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Methods - - return Methods(client) - # Payment methods for Payments and Orders APPLEPAY = "applepay" BANCONTACT = "bancontact" diff --git a/mollie/api/objects/onboarding.py b/mollie/api/objects/onboarding.py index da9f5646..2db7febe 100644 --- a/mollie/api/objects/onboarding.py +++ b/mollie/api/objects/onboarding.py @@ -2,12 +2,6 @@ class Onboarding(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Onboarding as OnboardingResource - - return OnboardingResource(client) - STATUS_NEEDS_DATA = "needs-data" STATUS_IN_REVIEW = "in-review" # Waiting for a valid mandate. STATUS_COMPLETED = "completed" diff --git a/mollie/api/objects/order.py b/mollie/api/objects/order.py index 42497354..04cf9463 100644 --- a/mollie/api/objects/order.py +++ b/mollie/api/objects/order.py @@ -5,12 +5,6 @@ class Order(ObjectBase): def __init__(self, data, client): super().__init__(data, client) - @classmethod - def get_resource_class(cls, client): - from ..resources import Orders - - return Orders(client) - STATUS_CREATED = "created" STATUS_PAID = "paid" STATUS_AUTHORIZED = "authorized" diff --git a/mollie/api/objects/order_line.py b/mollie/api/objects/order_line.py index 086465a0..f7cf4cd9 100644 --- a/mollie/api/objects/order_line.py +++ b/mollie/api/objects/order_line.py @@ -1,20 +1,7 @@ -from typing import TYPE_CHECKING, Any - from .base import ObjectBase -if TYPE_CHECKING: - from ..client import Client - from ..resources import OrderLines - class OrderLine(ObjectBase): - @classmethod - def get_resource_class(cls, client: "Client", **kwargs: Any) -> "OrderLines": - from ..resources import OrderLines - - order = kwargs["order"] - return OrderLines(client, order) - STATUS_CREATED = "created" STATUS_AUTHORIZED = "authorized" STATUS_PAID = "paid" diff --git a/mollie/api/objects/organization.py b/mollie/api/objects/organization.py index 085e009e..4eea7d90 100644 --- a/mollie/api/objects/organization.py +++ b/mollie/api/objects/organization.py @@ -2,12 +2,6 @@ class Organization(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Organizations - - return Organizations(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/payment.py b/mollie/api/objects/payment.py index 23bf95e0..ed361d54 100644 --- a/mollie/api/objects/payment.py +++ b/mollie/api/objects/payment.py @@ -3,12 +3,6 @@ class Payment(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Payments - - return Payments(client) - STATUS_OPEN = "open" STATUS_PENDING = "pending" STATUS_CANCELED = "canceled" diff --git a/mollie/api/objects/payment_link.py b/mollie/api/objects/payment_link.py index 9c6327d1..94b0ca9c 100644 --- a/mollie/api/objects/payment_link.py +++ b/mollie/api/objects/payment_link.py @@ -2,12 +2,6 @@ class PaymentLink(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import PaymentLinks - - return PaymentLinks(client) - @classmethod def get_object_name(cls): return "payment_links" diff --git a/mollie/api/objects/permission.py b/mollie/api/objects/permission.py index 8015736c..a99e67ce 100644 --- a/mollie/api/objects/permission.py +++ b/mollie/api/objects/permission.py @@ -2,12 +2,6 @@ class Permission(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Permissions - - return Permissions(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/profile.py b/mollie/api/objects/profile.py index 86a2d6d4..fffc6d5c 100644 --- a/mollie/api/objects/profile.py +++ b/mollie/api/objects/profile.py @@ -9,12 +9,6 @@ class Profile(ObjectBase): STATUS_VERIFIED = "verified" STATUS_BLOCKED = "blocked" - @classmethod - def get_resource_class(cls, client): - from ..resources import Profiles - - return Profiles(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/refund.py b/mollie/api/objects/refund.py index 56ca1e30..420249cb 100644 --- a/mollie/api/objects/refund.py +++ b/mollie/api/objects/refund.py @@ -4,12 +4,6 @@ class Refund(ObjectBase): - @classmethod - def get_resource_class(cls, client): - from ..resources import Refunds - - return Refunds(client) - STATUS_QUEUED = "queued" STATUS_PENDING = "pending" STATUS_PROCESSING = "processing" diff --git a/mollie/api/objects/settlement.py b/mollie/api/objects/settlement.py index e82859c4..1fe3b176 100644 --- a/mollie/api/objects/settlement.py +++ b/mollie/api/objects/settlement.py @@ -10,12 +10,6 @@ class Settlement(ObjectBase): STATUS_PAIDOUT = "paidout" STATUS_FAILED = "failed" - @classmethod - def get_resource_class(cls, client): - from ..resources import Settlements - - return Settlements(client) - @property def id(self): return self._get_property("id") diff --git a/mollie/api/objects/subscription.py b/mollie/api/objects/subscription.py index 2d7c91c5..02572706 100644 --- a/mollie/api/objects/subscription.py +++ b/mollie/api/objects/subscription.py @@ -5,13 +5,6 @@ class Subscription(ObjectBase): - @classmethod - def get_resource_class(cls, client, **kwargs): - from ..resources import CustomerSubscriptions - - customer = kwargs["customer"] - return CustomerSubscriptions(client, customer) - STATUS_ACTIVE = "active" STATUS_PENDING = "pending" # Waiting for a valid mandate. STATUS_CANCELED = "canceled" From 4db46180a790938b2e0c7ff2cdf15a160dc652b8 Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Mon, 18 Sep 2023 10:55:20 +0200 Subject: [PATCH 07/11] Fix tests --- mollie/api/objects/balance.py | 4 ++-- mollie/api/objects/list.py | 13 +++++++------ mollie/api/resources/chargebacks.py | 4 ++-- mollie/api/resources/onboarding.py | 1 + mollie/api/resources/payments.py | 8 ++++---- mollie/api/resources/refunds.py | 4 ++-- 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/mollie/api/objects/balance.py b/mollie/api/objects/balance.py index fd3367a6..a2ea543a 100644 --- a/mollie/api/objects/balance.py +++ b/mollie/api/objects/balance.py @@ -2,7 +2,7 @@ from .balance_report import BalanceReport from .base import ObjectBase -from .list import ObjectList +from .list import PaginationList class Balance(ObjectBase): @@ -59,7 +59,7 @@ def get_report(self, **params: Any) -> BalanceReport: return BalanceReports(self.client, self).get_report(params=params) - def get_transactions(self, **params: Any) -> ObjectList: + def get_transactions(self, **params: Any) -> PaginationList: from ..resources import BalanceTransactions return BalanceTransactions(self.client, self).list(params=params) diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index 85f62c01..397403df 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -1,8 +1,10 @@ from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Type +from typing import TYPE_CHECKING, Any, Optional, Type + from .base import ObjectBase if TYPE_CHECKING: + from mollie.api.client import Client from mollie.api.resources.base import ResourceBase @@ -87,11 +89,10 @@ def new(self, result): ... - class PaginationList(ListBase): _parent: "ResourceBase" - def __init__(self, result, parent: "ResourceBase", client=None): + def __init__(self, result: Any, parent: "ResourceBase", client: "Client"): # If an empty dataset was injected, we mock the structure that the remainder of the clas expects. # TODO: it would be better if the ObjectList was initiated with a list of results, rather than with # the full datastructure as it is now, so we can remove all this mucking around with fake data, @@ -130,7 +131,7 @@ def new(self, result): class ObjectList(ListBase): _object_type: Type[ObjectBase] - def __init__(self, result, object_type: Type[ObjectBase], client=None): + def __init__(self, result: Any, object_type: Type[ObjectBase], client: Optional["Client"] = None): # If an empty dataset was injected, we mock the structure that the remainder of the clas expects. # TODO: it would be better if the ObjectList was initiated with a list of results, rather than with # the full datastructure as it is now, so we can remove all this mucking around with fake data, @@ -148,10 +149,10 @@ def get_next(self): def get_previous(self): return None - + @property def object_type(self): return self._object_type - + def new(self, result): return ObjectList(result, self._object_type, self.client) diff --git a/mollie/api/resources/chargebacks.py b/mollie/api/resources/chargebacks.py index cd8d5353..7d0a0ca3 100644 --- a/mollie/api/resources/chargebacks.py +++ b/mollie/api/resources/chargebacks.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Any from ..objects.chargeback import Chargeback -from ..objects.list import ObjectList +from ..objects.list import PaginationList from .base import ResourceBase, ResourceGetMixin, ResourceListMixin if TYPE_CHECKING: @@ -72,7 +72,7 @@ def __init__(self, client: "Client", profile: "Profile") -> None: self._profile = profile super().__init__(client) - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: # Set the profileId in the query params params.update({"profileId": self._profile.id}) return Chargebacks(self.client).list(**params) diff --git a/mollie/api/resources/onboarding.py b/mollie/api/resources/onboarding.py index d6c4b6b2..c60ad16f 100644 --- a/mollie/api/resources/onboarding.py +++ b/mollie/api/resources/onboarding.py @@ -12,6 +12,7 @@ class Onboarding(ResourceGetMixin): """Resource handler for the `/onboarding` endpoint.""" + object_type = OnboardingObject def get(self, resource_id: str, **params: Any) -> OnboardingObject: diff --git a/mollie/api/resources/payments.py b/mollie/api/resources/payments.py index 0878d819..11c0be2d 100644 --- a/mollie/api/resources/payments.py +++ b/mollie/api/resources/payments.py @@ -1,7 +1,7 @@ from typing import TYPE_CHECKING, Any, Dict, Optional from ..objects.customer import Customer -from ..objects.list import ObjectList +from ..objects.list import PaginationList from ..objects.order import Order from ..objects.payment import Payment from ..objects.profile import Profile @@ -72,7 +72,7 @@ def __init__(self, client: "Client", order: Order) -> None: def get_resource_path(self) -> str: return f"orders/{self._order.id}/payments" - def list(self) -> ObjectList: + def list(self) -> PaginationList: """ List the payments that might have been embedded in the related order. @@ -86,7 +86,7 @@ def list(self) -> ObjectList: }, "count": len(payments), } - return ObjectList(data, Payment, self.client) + return PaginationList(data, self, self.client) class CustomerPayments(PaymentsBase, ResourceCreateMixin, ResourceListMixin): @@ -143,7 +143,7 @@ def __init__(self, client: "Client", profile: Profile) -> None: self._profile = profile super().__init__(client) - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: # Set the profileId in the query params params.update({"profileId": self._profile.id}) return Payments(self.client).list(**params) diff --git a/mollie/api/resources/refunds.py b/mollie/api/resources/refunds.py index 3996bcc6..3b53c0dc 100644 --- a/mollie/api/resources/refunds.py +++ b/mollie/api/resources/refunds.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Any, Dict, Optional -from ..objects.list import ObjectList +from ..objects.list import PaginationList from ..objects.order import Order from ..objects.payment import Payment from ..objects.profile import Profile @@ -97,7 +97,7 @@ def __init__(self, client: "Client", profile: Profile) -> None: self._profile = profile super().__init__(client) - def list(self, **params: Any) -> ObjectList: + def list(self, **params: Any) -> PaginationList: # Set the profileId in the query params params.update({"profileId": self._profile.id}) return Refunds(self.client).list(**params) From 31e1ef07b2381dbb4c0d9659dc39db497091d37a Mon Sep 17 00:00:00 2001 From: Matthijs Wesseling Date: Mon, 18 Sep 2023 10:55:30 +0200 Subject: [PATCH 08/11] Add test for Subscription pagination results --- tests/responses/subscriptions_list.json | 2 +- tests/responses/subscriptions_list_more.json | 52 ++++++++++++++++++++ tests/test_subscriptions.py | 26 +++++++++- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/responses/subscriptions_list_more.json diff --git a/tests/responses/subscriptions_list.json b/tests/responses/subscriptions_list.json index 3c928e58..75c1edde 100644 --- a/tests/responses/subscriptions_list.json +++ b/tests/responses/subscriptions_list.json @@ -101,7 +101,7 @@ }, "previous": null, "next": { - "href": "https://api.mollie.com/v2/subscriptions?from=sub_mnfbwhMfvo", + "href": "https://api.mollie.com/v2/subscriptions?from=sub_rVKGtNd6s6", "type": "application/hal+json" }, "documentation": { diff --git a/tests/responses/subscriptions_list_more.json b/tests/responses/subscriptions_list_more.json new file mode 100644 index 00000000..a5f95d6c --- /dev/null +++ b/tests/responses/subscriptions_list_more.json @@ -0,0 +1,52 @@ +{ + "count": 1, + "_embedded": { + "subscriptions": [ + { + "resource": "subscription", + "id": "sub_rVKGtNd6s6", + "mode": "live", + "createdAt": "2018-06-01T12:23:34+00:00", + "status": "active", + "amount": { + "value": "35.00", + "currency": "EUR" + }, + "times": 4, + "interval": "3 months", + "description": "Quarterly payment", + "method": "ideal", + "webhookUrl": "https://webshop.example.org/subscriptions/webhook", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions/sub_rVKGtNd6s6", + "type": "application/hal+json" + }, + "profile": { + "href": "https://api.mollie.com/v2/profiles/pfl_URR55HPMGo", + "type": "application/hal+json" + }, + "customer": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U", + "type": "application/hal+json" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/subscriptions?from=sub_rVKGtNd6s6", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/subscriptions", + "type": "application/hal+json" + }, + "next": null, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/subscriptions-api/list-all-subscriptions", + "type": "text/html" + } + } +} diff --git a/tests/test_subscriptions.py b/tests/test_subscriptions.py index 0f9d3e5a..c7fdbf32 100644 --- a/tests/test_subscriptions.py +++ b/tests/test_subscriptions.py @@ -1,11 +1,35 @@ +from responses import matchers + from mollie.api.objects.subscription import Subscription from .utils import assert_list_object -def test_list_customers(client, response): +def test_list_subscriptions(client, response): """Retrieve a list of existing subscriptions.""" response.get("https://api.mollie.com/v2/subscriptions", "subscriptions_list") subscriptions = client.subscriptions.list() assert_list_object(subscriptions, Subscription) + + +def test_list_subscription_pagination(client, response): + """Retrieve a list of paginated subscriptions.""" + response.get( + "https://api.mollie.com/v2/subscriptions", "subscriptions_list", match=[matchers.query_string_matcher("")] + ) + response.get( + "https://api.mollie.com/v2/subscriptions", + "subscriptions_list_more", + match=[matchers.query_string_matcher("from=sub_rVKGtNd6s6")], + ) + + first_subscriptions_page = client.subscriptions.list() + assert first_subscriptions_page.has_previous() is False + assert first_subscriptions_page.has_next() is True + + second_subscriptions_page = first_subscriptions_page.get_next() + assert_list_object(second_subscriptions_page, Subscription) + + subscription = next(second_subscriptions_page) + assert subscription.id == "sub_rVKGtNd6s6" From a1af1a88a07470c269275a9fcb9d244be452a657 Mon Sep 17 00:00:00 2001 From: Tom Hendrikx Date: Mon, 11 Sep 2023 14:57:06 +0200 Subject: [PATCH 09/11] Add test for CustomerSubscription pagination results --- ....json => customer_subscriptions_list.json} | 2 +- .../customer_subscriptions_list_more.json | 48 +++++++++++++++++++ tests/test_customer_subscriptions.py | 29 ++++++++++- tests/test_customers.py | 2 +- 4 files changed, 78 insertions(+), 3 deletions(-) rename tests/responses/{subscriptions_customer_list.json => customer_subscriptions_list.json} (98%) create mode 100644 tests/responses/customer_subscriptions_list_more.json diff --git a/tests/responses/subscriptions_customer_list.json b/tests/responses/customer_subscriptions_list.json similarity index 98% rename from tests/responses/subscriptions_customer_list.json rename to tests/responses/customer_subscriptions_list.json index e8e8ff96..f4e52217 100644 --- a/tests/responses/subscriptions_customer_list.json +++ b/tests/responses/customer_subscriptions_list.json @@ -89,7 +89,7 @@ }, "previous": null, "next": { - "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions?from=sub_mnfbwhMfvo", + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions?from=sub_rVKGtNd6s6", "type": "application/hal+json" }, "documentation": { diff --git a/tests/responses/customer_subscriptions_list_more.json b/tests/responses/customer_subscriptions_list_more.json new file mode 100644 index 00000000..12dc0f3a --- /dev/null +++ b/tests/responses/customer_subscriptions_list_more.json @@ -0,0 +1,48 @@ +{ + "count": 1, + "_embedded": { + "subscriptions": [ + { + "resource": "subscription", + "id": "sub_rVKGtNd6s6", + "mode": "live", + "createdAt": "2018-06-01T12:23:34+00:00", + "status": "active", + "amount": { + "value": "35.00", + "currency": "EUR" + }, + "times": 4, + "interval": "3 months", + "description": "Quarterly payment", + "method": "ideal", + "webhookUrl": "https://webshop.example.org/subscriptions/webhook", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions/sub_rVKGtNd6s6", + "type": "application/hal+json" + }, + "customer": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U", + "type": "application/hal+json" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions?from=sub_rVKGtNd6s6", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/customers/cst_8wmqcHMN4U/subscriptions", + "type": "application/hal+json" + }, + "next": null, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/subscriptions-api/list-subscriptions", + "type": "text/html" + } + } +} diff --git a/tests/test_customer_subscriptions.py b/tests/test_customer_subscriptions.py index fa50cee7..01f42553 100644 --- a/tests/test_customer_subscriptions.py +++ b/tests/test_customer_subscriptions.py @@ -1,4 +1,5 @@ import pytest +from responses import matchers from mollie.api.error import IdentifierError from mollie.api.objects.customer import Customer @@ -19,13 +20,39 @@ def test_list_customer_subscriptions(client, response): """Retrieve a list of subscriptions.""" response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}", "customer_single") - response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", "subscriptions_customer_list") + response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", "customer_subscriptions_list") customer = client.customers.get(CUSTOMER_ID) subscriptions = customer.subscriptions.list() assert_list_object(subscriptions, Subscription) +def test_list_customer_subscription_pagination(client, response): + """Retrieve a list of paginated subscriptions.""" + response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}", "customer_single") + response.get( + f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", + "customer_subscriptions_list", + match=[matchers.query_string_matcher("")], + ) + response.get( + f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", + "customer_subscriptions_list_more", + match=[matchers.query_string_matcher("from=sub_rVKGtNd6s6")], + ) + + customer = client.customers.get(CUSTOMER_ID) + first_subscriptions_page = customer.subscriptions.list() + assert first_subscriptions_page.has_previous() is False + assert first_subscriptions_page.has_next() is True + + second_subscriptions_page = first_subscriptions_page.get_next() + assert_list_object(second_subscriptions_page, Subscription) + + subscription = next(second_subscriptions_page) + assert subscription.id == "sub_rVKGtNd6s6" + + def test_get_customer_subscription(client, response): response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}", "customer_single") response.get( diff --git a/tests/test_customers.py b/tests/test_customers.py index f52b8536..da502229 100644 --- a/tests/test_customers.py +++ b/tests/test_customers.py @@ -109,7 +109,7 @@ def test_customer_get_related_mandates(client, response): def test_customer_get_related_subscriptions(client, response): """Retrieve related subscriptions for a customer.""" response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}", "customer_single") - response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", "subscriptions_customer_list") + response.get(f"https://api.mollie.com/v2/customers/{CUSTOMER_ID}/subscriptions", "customer_subscriptions_list") customer = client.customers.get(CUSTOMER_ID) subscriptions = customer.subscriptions.list() From 92e68d96df3061d3e68326b7618389e5c55fb830 Mon Sep 17 00:00:00 2001 From: Tom Hendrikx Date: Thu, 12 Oct 2023 11:57:26 +0200 Subject: [PATCH 10/11] Add pagination tests for all Chargeback variants --- tests/responses/.coverage | Bin 0 -> 53248 bytes tests/responses/chargebacks_list.json | 8 ++- tests/responses/chargebacks_list_more.json | 50 ++++++++++++++++++ ...le.json => payment_chargeback_single.json} | 2 +- tests/responses/payment_chargebacks_list.json | 50 ++++++++++++++++++ .../payment_chargebacks_list_more.json | 50 ++++++++++++++++++ tests/responses/profile_chargebacks_list.json | 50 ++++++++++++++++++ .../profile_chargebacks_list_more.json | 50 ++++++++++++++++++ .../settlement_chargebacks_list.json | 50 ++++++++++++++++++ .../settlement_chargebacks_list_more.json | 50 ++++++++++++++++++ tests/test_chargebacks.py | 24 +++++++++ tests/test_payment_chargebacks.py | 41 ++++++++++++-- tests/test_profile_chargebacks.py | 34 +++++++++++- tests/test_settlement_chargebacks.py | 32 ++++++++++- 14 files changed, 481 insertions(+), 10 deletions(-) create mode 100644 tests/responses/.coverage create mode 100644 tests/responses/chargebacks_list_more.json rename tests/responses/{chargeback_single.json => payment_chargeback_single.json} (96%) create mode 100644 tests/responses/payment_chargebacks_list.json create mode 100644 tests/responses/payment_chargebacks_list_more.json create mode 100644 tests/responses/profile_chargebacks_list.json create mode 100644 tests/responses/profile_chargebacks_list_more.json create mode 100644 tests/responses/settlement_chargebacks_list.json create mode 100644 tests/responses/settlement_chargebacks_list_more.json diff --git a/tests/responses/.coverage b/tests/responses/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..6089ef8779f2ed61176f2368dab80af0b799b828 GIT binary patch literal 53248 zcmeI)O>Y}T7zgm(xb?+=g<|YZlyLo#>&V#kk41c<^3+MBM!e9`Ia=yCVK2?k zdjoewxngxpMNC82li{WKMO}8%1liqUbrI_mRETnqeNG|vv+QjVs<8@{@2E)EV&5IL z>+P4n)h&B_+q_a~n`G$F&&E<~=tR+!$73qU3BnQAei%yMIZ;tZ$axE$fa-Y>>(+*W z_b?8`#P!o=`jH#EfiKjBa*|k$Zf#(P(ejP(7F$DQJ?92J*EzF$E$9@PZ^@Y@&oYmx za(gh$b2B7$)`WH`6bokP*QIA$K^ z7&7F6CW0&>)%2}K8&{UZ=PVj&plT)lQSs@ct%Z7n)t=87nWpHzgA;)srJV z+__U0N<2SNH;U7%(U&q-vFjv%|HeAh~w2h?l1{;nJs_#W-QR1r9#cci_oQ_ux<~ zA=g8&2|009U<00Izz00bZa0SG{#!~%H!U*gV1(;xr=2tWV=5P$##AOHafKmY=n z0G|IN6d(Wr2tWV=5P$##AOHafKmY>e7r^uX^7k=X2muH{00Izz00bZa0SG_<0uaFS zf5ZR;AOHafKmY;|fB*y_009Ua$V yfB*y_009U<00Izz00bZa0SJ^|0MGx+-^XYn1Rwwb2tWV=5P$##AOHafK;VDc0~8Yg literal 0 HcmV?d00001 diff --git a/tests/responses/chargebacks_list.json b/tests/responses/chargebacks_list.json index 3290f82a..3840b1a1 100644 --- a/tests/responses/chargebacks_list.json +++ b/tests/responses/chargebacks_list.json @@ -26,7 +26,7 @@ "type": "application/hal+json" }, "documentation": { - "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-chargeback", + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", "type": "text/html" } } @@ -35,7 +35,11 @@ }, "_links": { "self": { - "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks", + "href": "https://api.mollie.com/v2/chargebacks", + "type": "application/hal+json" + }, + "next": { + "href": "https://api.mollie.com/v2/chargebacks?from=chb_n9z0tq", "type": "application/hal+json" }, "documentation": { diff --git a/tests/responses/chargebacks_list_more.json b/tests/responses/chargebacks_list_more.json new file mode 100644 index 00000000..db4a702f --- /dev/null +++ b/tests/responses/chargebacks_list_more.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tq", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXT/chargebacks/chb_n9z0tq", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXT", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/chargebacks?from=chb_n9z0tq", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/chargebacks", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/list-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/chargeback_single.json b/tests/responses/payment_chargeback_single.json similarity index 96% rename from tests/responses/chargeback_single.json rename to tests/responses/payment_chargeback_single.json index e44c935c..8bae229a 100644 --- a/tests/responses/chargeback_single.json +++ b/tests/responses/payment_chargeback_single.json @@ -26,7 +26,7 @@ "type": "application/hal+json" }, "documentation": { - "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-chargeback", + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", "type": "text/html" } } diff --git a/tests/responses/payment_chargebacks_list.json b/tests/responses/payment_chargebacks_list.json new file mode 100644 index 00000000..95f3abf8 --- /dev/null +++ b/tests/responses/payment_chargebacks_list.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tp", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks/chb_n9z0tp", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks", + "type": "application/hal+json" + }, + "next": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks?from=chb_n9z0tq", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/list-payment-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/payment_chargebacks_list_more.json b/tests/responses/payment_chargebacks_list_more.json new file mode 100644 index 00000000..8fc25b82 --- /dev/null +++ b/tests/responses/payment_chargebacks_list_more.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tq", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks/chb_n9z0tq", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks?from=chb_n9z0tq", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/list-payment-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/profile_chargebacks_list.json b/tests/responses/profile_chargebacks_list.json new file mode 100644 index 00000000..9ac6529a --- /dev/null +++ b/tests/responses/profile_chargebacks_list.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tp", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks/chb_n9z0tp?profileId=pfl_v9hTwCvYqw", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/chargebacks?profileId=pfl_v9hTwCvYqw", + "type": "application/hal+json" + }, + "next": { + "href": "https://api.mollie.com/v2/chargebacks?profileId=pfl_v9hTwCvYqw&from=chb_n9z0tq", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/list-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/profile_chargebacks_list_more.json b/tests/responses/profile_chargebacks_list_more.json new file mode 100644 index 00000000..b4b1bc09 --- /dev/null +++ b/tests/responses/profile_chargebacks_list_more.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tq", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXT/chargebacks/chb_n9z0tq?profileId=pfl_v9hTwCvYqw", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXT", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/chargebacks?profileId=pfl_v9hTwCvYqw&from=chb_n9z0tq", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/chargebacks?profileId=pfl_v9hTwCvYqw", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/list-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/settlement_chargebacks_list.json b/tests/responses/settlement_chargebacks_list.json new file mode 100644 index 00000000..5f8ddba3 --- /dev/null +++ b/tests/responses/settlement_chargebacks_list.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tp", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks/chb_n9z0tp", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/settlements/stl_jDk30akdN/chargebacks", + "type": "application/hal+json" + }, + "next": { + "href": "https://api.mollie.com/v2/settlements/stl_jDk30akdN/chargebacks?from=chb_n9z0tq", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/settlements-api/list-settlement-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/responses/settlement_chargebacks_list_more.json b/tests/responses/settlement_chargebacks_list_more.json new file mode 100644 index 00000000..c63e8719 --- /dev/null +++ b/tests/responses/settlement_chargebacks_list_more.json @@ -0,0 +1,50 @@ +{ + "count": 1, + "_embedded": { + "chargebacks": [ + { + "resource": "chargeback", + "id": "chb_n9z0tq", + "amount": { + "currency": "USD", + "value": "43.38" + }, + "settlementAmount": { + "currency": "EUR", + "value": "35.07" + }, + "createdAt": "2018-03-14T17:00:52.0Z", + "reversedAt": null, + "paymentId": "tr_7UhSN1zuXS", + "_links": { + "self": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS/chargebacks/chb_n9z0tq", + "type": "application/hal+json" + }, + "payment": { + "href": "https://api.mollie.com/v2/payments/tr_7UhSN1zuXS", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/chargebacks-api/get-payment-chargeback", + "type": "text/html" + } + } + } + ] + }, + "_links": { + "self": { + "href": "https://api.mollie.com/v2/settlements/stl_jDk30akdN/chargebacks?from=chb_n9z0tq", + "type": "application/hal+json" + }, + "previous": { + "href": "https://api.mollie.com/v2/settlements/stl_jDk30akdN/chargebacks", + "type": "application/hal+json" + }, + "documentation": { + "href": "https://docs.mollie.com/reference/v2/settlements-api/list-settlement-chargebacks", + "type": "text/html" + } + } +} diff --git a/tests/test_chargebacks.py b/tests/test_chargebacks.py index ca92963f..fe5e0575 100644 --- a/tests/test_chargebacks.py +++ b/tests/test_chargebacks.py @@ -1,3 +1,5 @@ +from responses import matchers + from mollie.api.objects.chargeback import Chargeback from .utils import assert_list_object @@ -9,3 +11,25 @@ def test_list_chargebacks(client, response): chargebacks = client.chargebacks.list() assert_list_object(chargebacks, Chargeback) + + +def test_list_chargeback_pagination(client, response): + """Retrieve a list of paginated chargebacks.""" + response.get( + "https://api.mollie.com/v2/chargebacks", "chargebacks_list", match=[matchers.query_string_matcher("")] + ) + response.get( + "https://api.mollie.com/v2/chargebacks", + "chargebacks_list_more", + match=[matchers.query_string_matcher("from=chb_n9z0tq")], + ) + + first_chargebacks_page = client.chargebacks.list() + assert first_chargebacks_page.has_previous() is False + assert first_chargebacks_page.has_next() is True + + second_chargebacks_page = first_chargebacks_page.get_next() + assert_list_object(second_chargebacks_page, Chargeback) + + subscription = next(second_chargebacks_page) + assert subscription.id == "chb_n9z0tq" diff --git a/tests/test_payment_chargebacks.py b/tests/test_payment_chargebacks.py index f738000c..a335d215 100644 --- a/tests/test_payment_chargebacks.py +++ b/tests/test_payment_chargebacks.py @@ -1,4 +1,5 @@ import pytest +from responses import matchers from mollie.api.error import IdentifierError from mollie.api.objects.chargeback import Chargeback @@ -15,17 +16,45 @@ def test_list_payment_chargebacks(client, response): """Get chargebacks relevant to a payment.""" response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}", "payment_single") - response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks", "chargebacks_list") + response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks", "payment_chargebacks_list") payment = client.payments.get(PAYMENT_ID) chargebacks = payment.chargebacks.list() assert_list_object(chargebacks, Chargeback) +def test_list_payment_chargebacks_pagination(client, response): + """Retrieve a list of paginated payment chargebacks.""" + response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}", "payment_single") + response.get( + f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks", + "payment_chargebacks_list", + match=[matchers.query_string_matcher("")], + ) + response.get( + f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks", + "payment_chargebacks_list_more", + match=[matchers.query_string_matcher("from=chb_n9z0tq")], + ) + + payment = client.payments.get(PAYMENT_ID) + first_chargebacks_page = payment.chargebacks.list() + assert first_chargebacks_page.has_previous() is False + assert first_chargebacks_page.has_next() is True + + second_chargebacks_page = first_chargebacks_page.get_next() + assert_list_object(second_chargebacks_page, Chargeback) + + subscription = next(second_chargebacks_page) + assert subscription.id == "chb_n9z0tq" + + def test_get_payment_chargeback(client, response): """Get a single chargeback relevant to a payment.""" response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}", "payment_single") - response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "chargeback_single") + response.get( + f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "payment_chargeback_single" + ) payment = client.payments.get(PAYMENT_ID) chargeback = payment.chargebacks.get(CHARGEBACK_ID) @@ -51,7 +80,9 @@ def test_get_payment_chargeback_invalid_id(client, response): def test_payment_chargeback_get_related_payment(client, response): response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}", "payment_single") - response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "chargeback_single") + response.get( + f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "payment_chargeback_single" + ) payment = client.payments.get(PAYMENT_ID) chargeback = payment.chargebacks.get(CHARGEBACK_ID) @@ -62,7 +93,9 @@ def test_payment_chargeback_get_related_payment(client, response): def test_payment_chargeback_get_related_settlement(client, response): response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}", "payment_single") - response.get(f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "chargeback_single") + response.get( + f"https://api.mollie.com/v2/payments/{PAYMENT_ID}/chargebacks/{CHARGEBACK_ID}", "payment_chargeback_single" + ) response.get(f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}", "settlement_single") payment = client.payments.get(PAYMENT_ID) diff --git a/tests/test_profile_chargebacks.py b/tests/test_profile_chargebacks.py index 98039370..185047a3 100644 --- a/tests/test_profile_chargebacks.py +++ b/tests/test_profile_chargebacks.py @@ -1,3 +1,5 @@ +from responses import matchers + from mollie.api.objects.chargeback import Chargeback from .utils import assert_list_object @@ -8,8 +10,38 @@ def test_get_profile_chargebacks(oauth_client, response): """Get chargebacks relevant to profile by profile id.""" response.get(f"https://api.mollie.com/v2/profiles/{PROFILE_ID}", "profile_single") - response.get(f"https://api.mollie.com/v2/chargebacks?profileId={PROFILE_ID}", "chargebacks_list") + response.get( + "https://api.mollie.com/v2/chargebacks", + "profile_chargebacks_list", + match=[matchers.query_string_matcher(f"profileId={PROFILE_ID}")], + ) profile = oauth_client.profiles.get(PROFILE_ID) chargebacks = profile.chargebacks.list() assert_list_object(chargebacks, Chargeback) + + +def test_list_profile_chargebacks_pagination(oauth_client, response): + """Retrieve a list of paginated profile chargebacks.""" + response.get(f"https://api.mollie.com/v2/profiles/{PROFILE_ID}", "profile_single") + response.get( + "https://api.mollie.com/v2/chargebacks", + "profile_chargebacks_list", + match=[matchers.query_string_matcher(f"profileId={PROFILE_ID}")], + ) + response.get( + "https://api.mollie.com/v2/chargebacks", + "profile_chargebacks_list_more", + match=[matchers.query_string_matcher(f"profileId={PROFILE_ID}&from=chb_n9z0tq")], + ) + + profile = oauth_client.profiles.get(PROFILE_ID) + first_chargebacks_page = profile.chargebacks.list() + assert first_chargebacks_page.has_previous() is False + assert first_chargebacks_page.has_next() is True + + second_chargebacks_page = first_chargebacks_page.get_next() + assert_list_object(second_chargebacks_page, Chargeback) + + subscription = next(second_chargebacks_page) + assert subscription.id == "chb_n9z0tq" diff --git a/tests/test_settlement_chargebacks.py b/tests/test_settlement_chargebacks.py index 71fc9bc8..6a1180a7 100644 --- a/tests/test_settlement_chargebacks.py +++ b/tests/test_settlement_chargebacks.py @@ -1,17 +1,45 @@ +from responses import matchers + from mollie.api.objects.chargeback import Chargeback from .utils import assert_list_object PAYMENT_ID = "tr_7UhSN1zuXS" SETTLEMENT_ID = "stl_jDk30akdN" -CHARGEBACK_ID = "chb_n9z0tp" def test_list_settlement_chargebacks(oauth_client, response): """Get a list of chargebacks related to a settlement.""" response.get(f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}", "settlement_single") - response.get(f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}/chargebacks", "chargebacks_list") + response.get(f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}/chargebacks", "settlement_chargebacks_list") settlement = oauth_client.settlements.get(SETTLEMENT_ID) chargebacks = settlement.chargebacks.list() assert_list_object(chargebacks, Chargeback) + + +def test_list_settlement_chargebacks_pagination(oauth_client, response): + """Retrieve a list of paginated settlement chargebacks.""" + response.get(f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}", "settlement_single") + + response.get( + f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}/chargebacks", + "settlement_chargebacks_list", + match=[matchers.query_string_matcher("")], + ) + response.get( + f"https://api.mollie.com/v2/settlements/{SETTLEMENT_ID}/chargebacks", + "settlement_chargebacks_list_more", + match=[matchers.query_string_matcher("from=chb_n9z0tq")], + ) + + settlement = oauth_client.settlements.get(SETTLEMENT_ID) + first_chargebacks_page = settlement.chargebacks.list() + assert first_chargebacks_page.has_previous() is False + assert first_chargebacks_page.has_next() is True + + second_chargebacks_page = first_chargebacks_page.get_next() + assert_list_object(second_chargebacks_page, Chargeback) + + subscription = next(second_chargebacks_page) + assert subscription.id == "chb_n9z0tq" From 547bffef339344716f7a75596cf462e8f6454574 Mon Sep 17 00:00:00 2001 From: Tom Hendrikx Date: Thu, 12 Oct 2023 13:34:45 +0200 Subject: [PATCH 11/11] Improve docstrings on list classes --- mollie/api/objects/list.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mollie/api/objects/list.py b/mollie/api/objects/list.py index 397403df..45598a16 100644 --- a/mollie/api/objects/list.py +++ b/mollie/api/objects/list.py @@ -90,6 +90,13 @@ def new(self, result): class PaginationList(ListBase): + """ + Pagination lists are used to return a paginated list of Objects. + + You can use the `has_next` and `get_next` methods to get the next page of result data from the API. + The `has_previous` and `get_previous` methods return the previous page. + """ + _parent: "ResourceBase" def __init__(self, result: Any, parent: "ResourceBase", client: "Client"): @@ -105,7 +112,7 @@ def __init__(self, result: Any, parent: "ResourceBase", client: "Client"): super().__init__(result, client) def get_next(self): - """Return the next set of objects in an ObjectList.""" + """Return the next set of objects in the paginated list.""" url = self._get_link("next") if url is None: return None @@ -113,7 +120,7 @@ def get_next(self): return PaginationList(resp, self._parent, self.client) def get_previous(self): - """Return the previous set of objects in an ObjectList.""" + """Return the previous set of objects in the paginated list.""" url = self._get_link("previous") if url is None: return None @@ -129,6 +136,12 @@ def new(self, result): class ObjectList(ListBase): + """ + Object lists are used to return an embedded list on an object. + + It works to similar to PaginationList, but has no pagination (as all data is already embedded). + """ + _object_type: Type[ObjectBase] def __init__(self, result: Any, object_type: Type[ObjectBase], client: Optional["Client"] = None):