diff --git a/fintoc/managers/v2/__init__.py b/fintoc/managers/v2/__init__.py index 5234f5f..32b8d43 100644 --- a/fintoc/managers/v2/__init__.py +++ b/fintoc/managers/v2/__init__.py @@ -8,11 +8,13 @@ from .customers_manager import CustomersManager from .entities_manager import EntitiesManager from .invoices_manager import InvoicesManager +from .lines_manager import LinesManager from .movements_manager import MovementsManager from .onboardings_manager import OnboardingsManager from .payment_intents_manager import PaymentIntentsManager from .payment_methods_manager import PaymentMethodsManager from .products_manager import ProductsManager from .simulate_manager import SimulateManager +from .subscription_items_manager import SubscriptionItemsManager from .subscriptions_manager import SubscriptionsManager from .transfers_manager import TransfersManager diff --git a/fintoc/managers/v2/invoices_manager.py b/fintoc/managers/v2/invoices_manager.py index 9392c1d..3b90d98 100644 --- a/fintoc/managers/v2/invoices_manager.py +++ b/fintoc/managers/v2/invoices_manager.py @@ -1,5 +1,6 @@ """Module to hold the invoices manager.""" +from fintoc.managers.v2.lines_manager import LinesManager from fintoc.mixins import ManagerMixin @@ -7,4 +8,32 @@ class InvoicesManager(ManagerMixin): """Represents an invoices manager.""" resource = "invoice" - methods = ["list", "get"] + methods = ["list", "get", "add_lines", "remove_lines"] + + def __init__(self, path, client): + super().__init__(path, client) + self.__lines_manager = None + + @property + def lines(self): + """Proxies the invoice lines manager.""" + if self.__lines_manager is None: + self.__lines_manager = LinesManager( + "/v2/invoices/{invoice_id}/lines", + self._client, + ) + return self.__lines_manager + + @lines.setter + def lines(self, new_value): # pylint: disable=no-self-use + raise NameError("Attribute name corresponds to a manager") + + def _add_lines(self, identifier, **kwargs): + """Add line items to an invoice.""" + path = f"{self._build_path(**kwargs)}/{identifier}/add_lines" + return self._create(path_=path, **kwargs) + + def _remove_lines(self, identifier, **kwargs): + """Remove line items from an invoice.""" + path = f"{self._build_path(**kwargs)}/{identifier}/remove_lines" + return self._create(path_=path, **kwargs) diff --git a/fintoc/managers/v2/lines_manager.py b/fintoc/managers/v2/lines_manager.py new file mode 100644 index 0000000..c7fa181 --- /dev/null +++ b/fintoc/managers/v2/lines_manager.py @@ -0,0 +1,10 @@ +"""Module to hold the invoice lines manager.""" + +from fintoc.mixins import ManagerMixin + + +class LinesManager(ManagerMixin): + """Represents an invoice lines manager.""" + + resource = "line" + methods = ["update"] diff --git a/fintoc/managers/v2/subscription_items_manager.py b/fintoc/managers/v2/subscription_items_manager.py new file mode 100644 index 0000000..2f43a76 --- /dev/null +++ b/fintoc/managers/v2/subscription_items_manager.py @@ -0,0 +1,10 @@ +"""Module to hold the subscription items manager.""" + +from fintoc.mixins import ManagerMixin + + +class SubscriptionItemsManager(ManagerMixin): + """Represents a subscription items manager.""" + + resource = "subscription_item" + methods = ["create", "update", "delete"] diff --git a/fintoc/managers/v2/subscriptions_manager.py b/fintoc/managers/v2/subscriptions_manager.py index 5b12d32..1ae27b6 100644 --- a/fintoc/managers/v2/subscriptions_manager.py +++ b/fintoc/managers/v2/subscriptions_manager.py @@ -1,5 +1,6 @@ """Module to hold the subscriptions manager.""" +from fintoc.managers.v2.subscription_items_manager import SubscriptionItemsManager from fintoc.mixins import ManagerMixin @@ -7,7 +8,25 @@ class SubscriptionsManager(ManagerMixin): """Represents a subscriptions manager.""" resource = "subscription" - methods = ["list", "get", "cancel"] + methods = ["list", "get", "create", "update", "cancel"] + + def __init__(self, path, client): + super().__init__(path, client) + self.__items_manager = None + + @property + def items(self): + """Proxies the subscription items manager.""" + if self.__items_manager is None: + self.__items_manager = SubscriptionItemsManager( + "/v2/subscriptions/{subscription_id}/items", + self._client, + ) + return self.__items_manager + + @items.setter + def items(self, new_value): # pylint: disable=no-self-use + raise NameError("Attribute name corresponds to a manager") def _cancel(self, identifier, **kwargs): """Cancel a subscription.""" diff --git a/fintoc/resources/__init__.py b/fintoc/resources/__init__.py index ea9e9ef..bb8cac4 100644 --- a/fintoc/resources/__init__.py +++ b/fintoc/resources/__init__.py @@ -31,10 +31,12 @@ from .v2.customer import Customer from .v2.entity import Entity from .v2.invoice import Invoice as InvoiceV2 +from .v2.line import Line from .v2.onboarding import Onboarding from .v2.onboarding_document import OnboardingDocument from .v2.onboarding_shareholder import OnboardingShareholder from .v2.payment_method import PaymentMethod from .v2.subscription import Subscription as SubscriptionV2 +from .v2.subscription_item import SubscriptionItem from .v2.transfer import Transfer from .webhook_endpoint import WebhookEndpoint diff --git a/fintoc/resources/v2/__init__.py b/fintoc/resources/v2/__init__.py index b0e9e7e..12d2306 100644 --- a/fintoc/resources/v2/__init__.py +++ b/fintoc/resources/v2/__init__.py @@ -6,6 +6,7 @@ from .account_verification import AccountVerification from .entity import Entity from .invoice import Invoice +from .line import Line from .movement import Movement from .onboarding import Onboarding from .onboarding_document import OnboardingDocument @@ -13,4 +14,5 @@ from .payment_method import PaymentMethod from .product import Product from .subscription import Subscription +from .subscription_item import SubscriptionItem from .transfer import Transfer diff --git a/fintoc/resources/v2/line.py b/fintoc/resources/v2/line.py new file mode 100644 index 0000000..6f708c5 --- /dev/null +++ b/fintoc/resources/v2/line.py @@ -0,0 +1,7 @@ +"""Module to hold the Line resource.""" + +from fintoc.mixins import ResourceMixin + + +class Line(ResourceMixin): + """Represents a Fintoc Invoice Line.""" diff --git a/fintoc/resources/v2/subscription_item.py b/fintoc/resources/v2/subscription_item.py new file mode 100644 index 0000000..f20bf22 --- /dev/null +++ b/fintoc/resources/v2/subscription_item.py @@ -0,0 +1,7 @@ +"""Module to hold the SubscriptionItem resource.""" + +from fintoc.mixins import ResourceMixin + + +class SubscriptionItem(ResourceMixin): + """Represents a Fintoc Subscription Item.""" diff --git a/tests/test_integration.py b/tests/test_integration.py index cedd439..c200322 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1103,6 +1103,66 @@ def test_v2_subscription_cancel(self): assert result.method == "post" assert result.url == f"v2/subscriptions/{subscription_id}/cancel" + def test_v2_subscription_create(self): + """Test creating a subscription using v2 API.""" + subscription_data = { + "customer": "cus_test_id", + "items": [{"price": "price_test_id", "quantity": 1}], + } + + subscription = self.fintoc.v2.subscriptions.create(**subscription_data) + + assert subscription.method == "post" + assert subscription.url == "v2/subscriptions" + assert subscription.json.customer == subscription_data["customer"] + + def test_v2_subscription_update(self): + """Test updating a subscription using v2 API.""" + subscription_id = "test_subscription_id" + + subscription = self.fintoc.v2.subscriptions.update( + subscription_id, trial_end="2024-12-31T00:00:00Z" + ) + + assert subscription.method == "patch" + assert subscription.url == f"v2/subscriptions/{subscription_id}" + + def test_v2_subscription_item_create(self): + """Test creating a subscription item using v2 API.""" + subscription_id = "test_subscription_id" + + item = self.fintoc.v2.subscriptions.items.create( + subscription_id=subscription_id, + price_data={"product": "prod_test_id", "amount": 10000, "currency": "CLP"}, + quantity=1, + ) + + assert item.method == "post" + assert item.url == f"v2/subscriptions/{subscription_id}/items" + + def test_v2_subscription_item_update(self): + """Test updating a subscription item using v2 API.""" + subscription_id = "test_subscription_id" + item_id = "si_test_item_id" + + item = self.fintoc.v2.subscriptions.items.update( + item_id, subscription_id=subscription_id, quantity=3 + ) + + assert item.method == "patch" + assert item.url == f"v2/subscriptions/{subscription_id}/items/{item_id}" + + def test_v2_subscription_item_delete(self): + """Test deleting a subscription item using v2 API.""" + subscription_id = "test_subscription_id" + item_id = "si_test_item_id" + + result = self.fintoc.v2.subscriptions.items.delete( + item_id, subscription_id=subscription_id + ) + + assert result == item_id + def test_v2_products_list(self): """Test getting all products using v2 API.""" products = list(self.fintoc.v2.products.list()) @@ -1155,6 +1215,46 @@ def test_v2_invoice_get(self): assert invoice.method == "get" assert invoice.url == f"v2/invoices/{invoice_id}" + def test_v2_invoice_add_lines(self): + """Test adding line items to an invoice using v2 API.""" + invoice_id = "test_invoice_id" + lines = [ + { + "amount": 10000, + "currency": "CLP", + "period_end": "2024-02-01", + "period_start": "2024-01-01", + "quantity": 1, + } + ] + + invoice = self.fintoc.v2.invoices.add_lines(invoice_id, lines=lines) + + assert invoice.method == "post" + assert invoice.url == f"v2/invoices/{invoice_id}/add_lines" + + def test_v2_invoice_remove_lines(self): + """Test removing line items from an invoice using v2 API.""" + invoice_id = "test_invoice_id" + lines = ["il_test_line_id"] + + invoice = self.fintoc.v2.invoices.remove_lines(invoice_id, lines=lines) + + assert invoice.method == "post" + assert invoice.url == f"v2/invoices/{invoice_id}/remove_lines" + + def test_v2_invoice_line_update(self): + """Test updating an invoice line item using v2 API.""" + invoice_id = "test_invoice_id" + line_id = "il_test_line_id" + + line = self.fintoc.v2.invoices.lines.update( + line_id, invoice_id=invoice_id, quantity=2 + ) + + assert line.method == "patch" + assert line.url == f"v2/invoices/{invoice_id}/lines/{line_id}" + def test_v2_account_statements_list(self): """Test getting account statements from an account using v2 API.""" account_id = "acc_12345"