From d76cfd9cec53286ba2c043653fa66aae60b44cb2 Mon Sep 17 00:00:00 2001 From: mamunozcar Date: Fri, 7 Nov 2025 10:44:16 -0300 Subject: [PATCH 1/5] feat: add payment links --- fintoc/core.py | 2 ++ fintoc/managers/__init__.py | 1 + fintoc/managers/payment_links_manager.py | 16 +++++++++ fintoc/resources/__init__.py | 1 + fintoc/resources/payment_link.py | 7 ++++ tests/test_integration.py | 43 ++++++++++++++++++++++++ 6 files changed, 70 insertions(+) create mode 100644 fintoc/managers/payment_links_manager.py create mode 100644 fintoc/resources/payment_link.py diff --git a/fintoc/core.py b/fintoc/core.py index f16a5bf..92c443f 100644 --- a/fintoc/core.py +++ b/fintoc/core.py @@ -11,6 +11,7 @@ InvoicesManager, LinksManager, PaymentIntentsManager, + PaymentLinksManager, RefreshIntentsManager, RefundsManager, SubscriptionIntentsManager, @@ -50,6 +51,7 @@ def __init__(self, api_key, api_version=None, jws_private_key=None): self.payment_intents = PaymentIntentsManager( "/v1/payment_intents", self._client ) + self.payment_links = PaymentLinksManager("/v1/payment_links", self._client) self.refunds = RefundsManager("/v1/refunds", self._client) self.subscriptions = SubscriptionsManager("/v1/subscriptions", self._client) self.subscription_intents = SubscriptionIntentsManager( diff --git a/fintoc/managers/__init__.py b/fintoc/managers/__init__.py index 94357d8..6d5d663 100644 --- a/fintoc/managers/__init__.py +++ b/fintoc/managers/__init__.py @@ -7,6 +7,7 @@ from .links_manager import LinksManager from .movements_manager import MovementsManager from .payment_intents_manager import PaymentIntentsManager +from .payment_links_manager import PaymentLinksManager from .refresh_intents_manager import RefreshIntentsManager from .refunds_manager import RefundsManager from .subscription_intents_manager import SubscriptionIntentsManager diff --git a/fintoc/managers/payment_links_manager.py b/fintoc/managers/payment_links_manager.py new file mode 100644 index 0000000..4c84b5a --- /dev/null +++ b/fintoc/managers/payment_links_manager.py @@ -0,0 +1,16 @@ +"""Module to hold the payment_links manager.""" + +from fintoc.mixins import ManagerMixin + + +class PaymentLinksManager(ManagerMixin): + + """Represents a payment_links manager.""" + + resource = "payment_link" + methods = ["list", "get", "create", "cancel"] + + def _cancel(self, identifier, **kwargs): + """Cancel a payment link.""" + path = f"{self._build_path(**kwargs)}/{identifier}/cancel" + return self._update(path_=path, **kwargs) diff --git a/fintoc/resources/__init__.py b/fintoc/resources/__init__.py index 1074e61..a5e7cad 100644 --- a/fintoc/resources/__init__.py +++ b/fintoc/resources/__init__.py @@ -14,6 +14,7 @@ from .movement import Movement from .other_taxes import OtherTaxes from .payment_intent import PaymentIntent +from .payment_link import PaymentLink from .refresh_intent import RefreshIntent from .services_invoice import ServicesInvoice from .subscription import Subscription diff --git a/fintoc/resources/payment_link.py b/fintoc/resources/payment_link.py new file mode 100644 index 0000000..f44de40 --- /dev/null +++ b/fintoc/resources/payment_link.py @@ -0,0 +1,7 @@ +"""Module to hold the PaymentLink resource.""" + +from fintoc.mixins import ResourceMixin + + +class PaymentLink(ResourceMixin): + """Represents a Fintoc PaymentLink.""" diff --git a/tests/test_integration.py b/tests/test_integration.py index a4805a1..0ba0306 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -392,6 +392,49 @@ def test_payment_intent_expire(self): assert result.method == "post" assert result.url == f"v1/payment_intents/{payment_intent_id}/expire" + def test_payment_links_list(self): + """Test getting all payment links.""" + payment_links = list(self.fintoc.payment_links.list()) + + assert len(payment_links) > 0 + for payment_link in payment_links: + assert payment_link.method == "get" + assert payment_link.url == "v1/payment_links" + + def test_payment_link_get(self): + """Test getting a specific payment link.""" + payment_link_id = "test_payment_link_id" + + payment_link = self.fintoc.payment_links.get(payment_link_id) + + assert payment_link.method == "get" + assert payment_link.url == f"v1/payment_links/{payment_link_id}" + + def test_payment_link_create(self): + """Test creating a payment link.""" + payment_link_data = { + "amount": 1000, + "currency": "CLP", + "description": "Test payment link", + } + + payment_link = self.fintoc.payment_links.create(**payment_link_data) + + assert payment_link.method == "post" + assert payment_link.url == "v1/payment_links" + assert payment_link.json.amount == payment_link_data["amount"] + assert payment_link.json.currency == payment_link_data["currency"] + assert payment_link.json.description == payment_link_data["description"] + + def test_payment_link_cancel(self): + """Test canceling a payment link.""" + payment_link_id = "test_payment_link_id" + + result = self.fintoc.payment_links.cancel(payment_link_id) + + assert result.method == "patch" + assert result.url == f"v1/payment_links/{payment_link_id}/cancel" + def test_refund_list(self): """Test getting all refunds.""" refunds = list(self.fintoc.refunds.list()) From fb7523f12811fb3aff402a5a259e28462c5fd303 Mon Sep 17 00:00:00 2001 From: mamunozcar Date: Fri, 7 Nov 2025 10:46:16 -0300 Subject: [PATCH 2/5] feat(payment_intents): add check eligibility method --- fintoc/managers/payment_intents_manager.py | 7 ++++++- tests/test_integration.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/fintoc/managers/payment_intents_manager.py b/fintoc/managers/payment_intents_manager.py index 797c42d..7980246 100644 --- a/fintoc/managers/payment_intents_manager.py +++ b/fintoc/managers/payment_intents_manager.py @@ -8,9 +8,14 @@ class PaymentIntentsManager(ManagerMixin): """Represents a payment_intents manager.""" resource = "payment_intent" - methods = ["list", "get", "create", "expire"] + methods = ["list", "get", "create", "expire", "check_eligibility"] def _expire(self, identifier, **kwargs): """Expire a payment intent.""" path = f"{self._build_path(**kwargs)}/{identifier}/expire" return self._create(path_=path, **kwargs) + + def _check_eligibility(self, **kwargs): + """Check eligibility for a payment intent.""" + path = f"{self._build_path(**kwargs)}/check_eligibility" + return self._create(path_=path, **kwargs) diff --git a/tests/test_integration.py b/tests/test_integration.py index 0ba0306..0ea03cc 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -392,6 +392,18 @@ def test_payment_intent_expire(self): assert result.method == "post" assert result.url == f"v1/payment_intents/{payment_intent_id}/expire" + def test_payment_intent_check_eligibility(self): + """Test checking eligibility for a payment intent.""" + eligibility_data = { + "amount": 1000, + "currency": "CLP", + } + + result = self.fintoc.payment_intents.check_eligibility(**eligibility_data) + + assert result.method == "post" + assert result.url == "v1/payment_intents/check_eligibility" + def test_payment_links_list(self): """Test getting all payment links.""" payment_links = list(self.fintoc.payment_links.list()) From d35b7e8cb8cef0675172347937df5462e7d089b2 Mon Sep 17 00:00:00 2001 From: mamunozcar Date: Fri, 7 Nov 2025 15:53:28 -0300 Subject: [PATCH 3/5] feat: enhance resource update functionality with custom path support --- fintoc/mixins/manager_mixin.py | 4 +++- fintoc/mixins/resource_mixin.py | 5 ++++- fintoc/resource_handlers.py | 7 +++++-- tests/mixins/test_manager_mixin.py | 6 ++++++ tests/mixins/test_resource_mixin.py | 17 +++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/fintoc/mixins/manager_mixin.py b/fintoc/mixins/manager_mixin.py index 55a4215..1d7b076 100644 --- a/fintoc/mixins/manager_mixin.py +++ b/fintoc/mixins/manager_mixin.py @@ -118,13 +118,14 @@ def _create(self, idempotency_key=None, path_=None, **kwargs): return self.post_create_handler(object_, **kwargs) @can_raise_fintoc_error - def _update(self, identifier, **kwargs): + def _update(self, identifier, path_=None, **kwargs): """ Update an instance of the resource being handled by the manager, identified by :identifier:. Data is passed using :kwargs:, as specified by the API. """ klass = get_resource_class(self.__class__.resource) + custom_path = path_ if path_ else None object_ = resource_update( client=self._client, path=self._build_path(**kwargs), @@ -133,6 +134,7 @@ def _update(self, identifier, **kwargs): handlers=self._handlers, methods=self.__class__.methods, params=kwargs, + custom_path=custom_path, ) return self.post_update_handler(object_, identifier, **kwargs) diff --git a/fintoc/mixins/resource_mixin.py b/fintoc/mixins/resource_mixin.py index 58e600f..08d6ad3 100644 --- a/fintoc/mixins/resource_mixin.py +++ b/fintoc/mixins/resource_mixin.py @@ -61,8 +61,10 @@ def serialize(self): return serialized @can_raise_fintoc_error - def _update(self, **kwargs): + def _update(self, path_=None, **kwargs): + """Update the resource.""" id_ = getattr(self, self.__class__.resource_identifier) + custom_path = path_ if path_ else None object_ = resource_update( client=self._client, path=self._path, @@ -71,6 +73,7 @@ def _update(self, **kwargs): handlers=self._handlers, methods=self._methods, params=kwargs, + custom_path=custom_path, ) object_ = self._handlers.get("update")(object_, id_, **kwargs) self.__dict__.update(object_.__dict__) diff --git a/fintoc/resource_handlers.py b/fintoc/resource_handlers.py index 1a892ed..1fa92df 100644 --- a/fintoc/resource_handlers.py +++ b/fintoc/resource_handlers.py @@ -59,9 +59,12 @@ def resource_create( ) -def resource_update(client, path, id_, klass, handlers, methods, params): +def resource_update( + client, path, id_, klass, handlers, methods, params, custom_path=None +): """Update a specific instance of a resource.""" - data = client.request(f"{path}/{id_}", method="patch", json=params) + update_path = custom_path if custom_path else f"{path}/{id_}" + data = client.request(update_path, method="patch", json=params) return objetize( klass, client, diff --git a/tests/mixins/test_manager_mixin.py b/tests/mixins/test_manager_mixin.py index f09b2c9..e55b320 100644 --- a/tests/mixins/test_manager_mixin.py +++ b/tests/mixins/test_manager_mixin.py @@ -154,6 +154,12 @@ def test_update_method(self): assert isinstance(object_, ResourceMixin) assert object_.method == "patch" + def test_update_update_method_with_custom_path(self): + object_ = self.manager.update("my_id", path_="/resources/my_id/cancel") + assert isinstance(object_, ResourceMixin) + assert object_.method == "patch" + assert object_.url == "resources/my_id/cancel" + def test_delete_method(self): id_ = self.manager.delete("my_id") isinstance(id_, str) diff --git a/tests/mixins/test_resource_mixin.py b/tests/mixins/test_resource_mixin.py index d0bd99d..dc8f1f4 100644 --- a/tests/mixins/test_resource_mixin.py +++ b/tests/mixins/test_resource_mixin.py @@ -267,3 +267,20 @@ def test_empty_mock_resource_update_method(self, capsys): assert data["id"] not in resource.url assert data["identifier"] in resource.url + + def test_resource_update_with_custom_path(self, capsys): + methods = ["update"] + data = { + "id": "id0", + "identifier": "identifier0", + } + resource = EmptyMockResource( + self.client, self.handlers, methods, self.path, **data + ) + + custom_path = f"{self.path}/id0/cancel" + resource.update(path_=custom_path) + + captured = capsys.readouterr().out + assert "update" in captured + assert resource.url == custom_path.lstrip("/") From 64187c63cbeea1d5b3e1ced40c3654e632c3ddba Mon Sep 17 00:00:00 2001 From: mamunozcar Date: Fri, 7 Nov 2025 15:53:44 -0300 Subject: [PATCH 4/5] fixup! feat: add payment links --- fintoc/managers/payment_links_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fintoc/managers/payment_links_manager.py b/fintoc/managers/payment_links_manager.py index 4c84b5a..0399984 100644 --- a/fintoc/managers/payment_links_manager.py +++ b/fintoc/managers/payment_links_manager.py @@ -13,4 +13,4 @@ class PaymentLinksManager(ManagerMixin): def _cancel(self, identifier, **kwargs): """Cancel a payment link.""" path = f"{self._build_path(**kwargs)}/{identifier}/cancel" - return self._update(path_=path, **kwargs) + return self._update(identifier, path_=path, **kwargs) From 9c9cc967b718675a64d45bd9268e14438f5124ab Mon Sep 17 00:00:00 2001 From: mamunozcar Date: Mon, 10 Nov 2025 11:14:38 -0300 Subject: [PATCH 5/5] pre-release: prepare 2.14.0 release --- fintoc/version.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fintoc/version.py b/fintoc/version.py index c61a2b5..28e764b 100644 --- a/fintoc/version.py +++ b/fintoc/version.py @@ -1,4 +1,4 @@ """Module to hold the version utilities.""" -version_info = (2, 13, 0) +version_info = (2, 14, 0) __version__ = ".".join([str(x) for x in version_info]) diff --git a/pyproject.toml b/pyproject.toml index ad29e8c..671be82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "fintoc" -version = "2.13.0" +version = "2.14.0" description = "The official Python client for the Fintoc API." authors = ["Daniel Leal ", "Nebil Kawas "] maintainers = ["Daniel Leal "]