From e3584ef78d7b319ac0ce0fa9bf9c0e1d953dec95 Mon Sep 17 00:00:00 2001 From: Robert Segal Date: Mon, 29 Sep 2025 09:08:13 -0600 Subject: [PATCH] Added billing invoice attachments endpoints --- .../resources/billing/invoice_attachments.py | 42 ++++++++++++++++++ mpt_api_client/resources/billing/invoices.py | 18 ++++++++ .../billing/test_invoice_attachments.py | 44 +++++++++++++++++++ tests/resources/billing/test_invoices.py | 30 +++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 mpt_api_client/resources/billing/invoice_attachments.py create mode 100644 tests/resources/billing/test_invoice_attachments.py diff --git a/mpt_api_client/resources/billing/invoice_attachments.py b/mpt_api_client/resources/billing/invoice_attachments.py new file mode 100644 index 00000000..7d9c2ee6 --- /dev/null +++ b/mpt_api_client/resources/billing/invoice_attachments.py @@ -0,0 +1,42 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncDeleteMixin, + AsyncFileOperationsMixin, + AsyncUpdateMixin, + DeleteMixin, + FileOperationsMixin, + UpdateMixin, +) +from mpt_api_client.models import Model + + +class InvoiceAttachment(Model): + """Invoice Attachment resource.""" + + +class InvoiceAttachmentsServiceConfig: + """Invoice Attachments service configuration.""" + + _endpoint = "/public/v1/billing/invoices/{invoice_id}/attachments" + _model_class = InvoiceAttachment + _collection_key = "data" + + +class InvoiceAttachmentsService( + FileOperationsMixin[InvoiceAttachment], + DeleteMixin, + UpdateMixin[InvoiceAttachment], + Service[InvoiceAttachment], + InvoiceAttachmentsServiceConfig, +): + """Invoice Attachments service.""" + + +class AsyncInvoiceAttachmentsService( + AsyncFileOperationsMixin[InvoiceAttachment], + AsyncDeleteMixin, + AsyncUpdateMixin[InvoiceAttachment], + AsyncService[InvoiceAttachment], + InvoiceAttachmentsServiceConfig, +): + """Invoice Attachments service.""" diff --git a/mpt_api_client/resources/billing/invoices.py b/mpt_api_client/resources/billing/invoices.py index a1b06927..b4b20ac7 100644 --- a/mpt_api_client/resources/billing/invoices.py +++ b/mpt_api_client/resources/billing/invoices.py @@ -1,6 +1,10 @@ from mpt_api_client.http import AsyncService, Service from mpt_api_client.http.mixins import AsyncCreateMixin, AsyncUpdateMixin, CreateMixin, UpdateMixin from mpt_api_client.models import Model +from mpt_api_client.resources.billing.invoice_attachments import ( + AsyncInvoiceAttachmentsService, + InvoiceAttachmentsService, +) class Invoice(Model): @@ -23,6 +27,13 @@ class InvoicesService( ): """Invoices service.""" + def attachments(self, invoice_id: str) -> InvoiceAttachmentsService: + """Return invoice attachments service.""" + return InvoiceAttachmentsService( + http_client=self.http_client, + endpoint_params={"invoice_id": invoice_id}, + ) + class AsyncInvoicesService( AsyncCreateMixin[Invoice], @@ -31,3 +42,10 @@ class AsyncInvoicesService( InvoicesServiceConfig, ): """Async Invoices service.""" + + def attachments(self, invoice_id: str) -> AsyncInvoiceAttachmentsService: + """Return invoice attachments service.""" + return AsyncInvoiceAttachmentsService( + http_client=self.http_client, + endpoint_params={"invoice_id": invoice_id}, + ) diff --git a/tests/resources/billing/test_invoice_attachments.py b/tests/resources/billing/test_invoice_attachments.py new file mode 100644 index 00000000..e6942970 --- /dev/null +++ b/tests/resources/billing/test_invoice_attachments.py @@ -0,0 +1,44 @@ +import pytest + +from mpt_api_client.resources.billing.invoice_attachments import ( + AsyncInvoiceAttachmentsService, + InvoiceAttachmentsService, +) + + +@pytest.fixture +def invoice_attachments_service(http_client): + return InvoiceAttachmentsService( + http_client=http_client, endpoint_params={"invoice_id": "INV-0000-0001"} + ) + + +@pytest.fixture +def async_invoice_attachments_service(async_http_client): + return AsyncInvoiceAttachmentsService( + http_client=async_http_client, endpoint_params={"invoice_id": "INV-0000-0001"} + ) + + +def test_endpoint(invoice_attachments_service): + assert ( + invoice_attachments_service.endpoint + == "/public/v1/billing/invoices/INV-0000-0001/attachments" + ) + + +def test_async_endpoint(async_invoice_attachments_service): + assert ( + async_invoice_attachments_service.endpoint + == "/public/v1/billing/invoices/INV-0000-0001/attachments" + ) + + +@pytest.mark.parametrize("method", ["get", "create", "update", "delete"]) +def test_methods_present(invoice_attachments_service, method: str): + assert hasattr(invoice_attachments_service, method) + + +@pytest.mark.parametrize("method", ["get", "create", "update", "delete"]) +def test_async_methods_present(async_invoice_attachments_service, method: str): + assert hasattr(async_invoice_attachments_service, method) diff --git a/tests/resources/billing/test_invoices.py b/tests/resources/billing/test_invoices.py index 2bfb2175..600b4d7f 100644 --- a/tests/resources/billing/test_invoices.py +++ b/tests/resources/billing/test_invoices.py @@ -1,5 +1,9 @@ import pytest +from mpt_api_client.resources.billing.invoice_attachments import ( + AsyncInvoiceAttachmentsService, + InvoiceAttachmentsService, +) from mpt_api_client.resources.billing.invoices import ( AsyncInvoicesService, InvoicesService, @@ -30,3 +34,29 @@ def test_mixins_present(invoices_service, method): ) def test_async_mixins_present(async_invoices_service, method): assert hasattr(async_invoices_service, method) + + +@pytest.mark.parametrize( + ("service_method", "expected_service_class"), + [ + ("attachments", InvoiceAttachmentsService), + ], +) +def test_property_services(invoices_service, service_method, expected_service_class): + service = getattr(invoices_service, service_method)("INV-0000-0001") + + assert isinstance(service, expected_service_class) + assert service.endpoint_params == {"invoice_id": "INV-0000-0001"} + + +@pytest.mark.parametrize( + ("service_method", "expected_service_class"), + [ + ("attachments", AsyncInvoiceAttachmentsService), + ], +) +def test_async_property_services(async_invoices_service, service_method, expected_service_class): + service = getattr(async_invoices_service, service_method)("INV-0000-0001") + + assert isinstance(service, expected_service_class) + assert service.endpoint_params == {"invoice_id": "INV-0000-0001"}