Skip to content

Commit 9d77bd1

Browse files
authored
[MPT-16678] Added missing billing statement attachments endpoints (#176)
Added missing billing statement attachments endpoints Even though mixins will be re-organized, I added an attachment mixin because there's almost half a dozen of attachment resources. https://softwareone.atlassian.net/browse/MPT-16678 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added statement attachments support with upload/download and create/list/get/delete operations (sync and async). * Added attachments accessors on statements to obtain per-statement attachment services. * **Refactor** * Replaced multiple per-operation attachment mixins with unified attachment mixins for consistent behavior across attachment services. * **Tests** * Expanded unit tests for statement attachments and added iterate/download checks across attachment services. <sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents 91901a2 + 74e3a58 commit 9d77bd1

14 files changed

+204
-62
lines changed

mpt_api_client/resources/billing/credit_memo_attachments.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFilesOperationsMixin,
5-
AsyncModifiableResourceMixin,
64
CollectionMixin,
7-
FilesOperationsMixin,
8-
ModifiableResourceMixin,
95
)
106
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
118

129

1310
class CreditMemoAttachment(Model):
@@ -20,11 +17,12 @@ class CreditMemoAttachmentsServiceConfig:
2017
_endpoint = "/public/v1/billing/credit-memos/{credit_memo_id}/attachments"
2118
_model_class = CreditMemoAttachment
2219
_collection_key = "data"
20+
_upload_file_key = "file"
21+
_upload_data_key = "attachment"
2322

2423

2524
class CreditMemoAttachmentsService(
26-
FilesOperationsMixin[CreditMemoAttachment],
27-
ModifiableResourceMixin[CreditMemoAttachment],
25+
AttachmentMixin[CreditMemoAttachment],
2826
CollectionMixin[CreditMemoAttachment],
2927
Service[CreditMemoAttachment],
3028
CreditMemoAttachmentsServiceConfig,
@@ -33,8 +31,7 @@ class CreditMemoAttachmentsService(
3331

3432

3533
class AsyncCreditMemoAttachmentsService(
36-
AsyncFilesOperationsMixin[CreditMemoAttachment],
37-
AsyncModifiableResourceMixin[CreditMemoAttachment],
34+
AsyncAttachmentMixin[CreditMemoAttachment],
3835
AsyncCollectionMixin[CreditMemoAttachment],
3936
AsyncService[CreditMemoAttachment],
4037
CreditMemoAttachmentsServiceConfig,

mpt_api_client/resources/billing/custom_ledger_attachments.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFilesOperationsMixin,
5-
AsyncModifiableResourceMixin,
64
CollectionMixin,
7-
FilesOperationsMixin,
8-
ModifiableResourceMixin,
95
)
106
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
118

129

1310
class CustomLedgerAttachment(Model):
@@ -20,11 +17,12 @@ class CustomLedgerAttachmentsServiceConfig:
2017
_endpoint = "/public/v1/billing/custom-ledgers/{custom_ledger_id}/attachments"
2118
_model_class = CustomLedgerAttachment
2219
_collection_key = "data"
20+
_upload_file_key = "file"
21+
_upload_data_key = "attachment"
2322

2423

2524
class CustomLedgerAttachmentsService(
26-
FilesOperationsMixin[CustomLedgerAttachment],
27-
ModifiableResourceMixin[CustomLedgerAttachment],
25+
AttachmentMixin[CustomLedgerAttachment],
2826
CollectionMixin[CustomLedgerAttachment],
2927
Service[CustomLedgerAttachment],
3028
CustomLedgerAttachmentsServiceConfig,
@@ -33,8 +31,7 @@ class CustomLedgerAttachmentsService(
3331

3432

3533
class AsyncCustomLedgerAttachmentsService(
36-
AsyncFilesOperationsMixin[CustomLedgerAttachment],
37-
AsyncModifiableResourceMixin[CustomLedgerAttachment],
34+
AsyncAttachmentMixin[CustomLedgerAttachment],
3835
AsyncCollectionMixin[CustomLedgerAttachment],
3936
AsyncService[CustomLedgerAttachment],
4037
CustomLedgerAttachmentsServiceConfig,

mpt_api_client/resources/billing/invoice_attachments.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFilesOperationsMixin,
5-
AsyncModifiableResourceMixin,
64
CollectionMixin,
7-
FilesOperationsMixin,
8-
ModifiableResourceMixin,
95
)
106
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
118

129

1310
class InvoiceAttachment(Model):
@@ -20,11 +17,12 @@ class InvoiceAttachmentsServiceConfig:
2017
_endpoint = "/public/v1/billing/invoices/{invoice_id}/attachments"
2118
_model_class = InvoiceAttachment
2219
_collection_key = "data"
20+
_upload_file_key = "file"
21+
_upload_data_key = "attachment"
2322

2423

2524
class InvoiceAttachmentsService(
26-
FilesOperationsMixin[InvoiceAttachment],
27-
ModifiableResourceMixin[InvoiceAttachment],
25+
AttachmentMixin[InvoiceAttachment],
2826
CollectionMixin[InvoiceAttachment],
2927
Service[InvoiceAttachment],
3028
InvoiceAttachmentsServiceConfig,
@@ -33,8 +31,7 @@ class InvoiceAttachmentsService(
3331

3432

3533
class AsyncInvoiceAttachmentsService(
36-
AsyncFilesOperationsMixin[InvoiceAttachment],
37-
AsyncModifiableResourceMixin[InvoiceAttachment],
34+
AsyncAttachmentMixin[InvoiceAttachment],
3835
AsyncCollectionMixin[InvoiceAttachment],
3936
AsyncService[InvoiceAttachment],
4037
InvoiceAttachmentsServiceConfig,

mpt_api_client/resources/billing/journal_attachments.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncCreateFileMixin,
5-
AsyncDeleteMixin,
6-
AsyncDownloadFileMixin,
7-
AsyncGetMixin,
8-
AsyncUpdateMixin,
94
CollectionMixin,
10-
CreateFileMixin,
11-
DeleteMixin,
12-
DownloadFileMixin,
13-
GetMixin,
14-
UpdateMixin,
155
)
166
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
178

189

1910
class JournalAttachment(Model):
@@ -31,11 +22,7 @@ class JournalAttachmentsServiceConfig:
3122

3223

3324
class JournalAttachmentsService(
34-
CreateFileMixin[JournalAttachment],
35-
UpdateMixin[JournalAttachment],
36-
DownloadFileMixin[JournalAttachment],
37-
DeleteMixin,
38-
GetMixin[JournalAttachment],
25+
AttachmentMixin[JournalAttachment],
3926
CollectionMixin[JournalAttachment],
4027
Service[JournalAttachment],
4128
JournalAttachmentsServiceConfig,
@@ -44,11 +31,7 @@ class JournalAttachmentsService(
4431

4532

4633
class AsyncJournalAttachmentsService(
47-
AsyncCreateFileMixin[JournalAttachment],
48-
AsyncUpdateMixin[JournalAttachment],
49-
AsyncDownloadFileMixin[JournalAttachment],
50-
AsyncDeleteMixin,
51-
AsyncGetMixin[JournalAttachment],
34+
AsyncAttachmentMixin[JournalAttachment],
5235
AsyncCollectionMixin[JournalAttachment],
5336
AsyncService[JournalAttachment],
5437
JournalAttachmentsServiceConfig,

mpt_api_client/resources/billing/ledger_attachments.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFilesOperationsMixin,
5-
AsyncModifiableResourceMixin,
64
CollectionMixin,
7-
FilesOperationsMixin,
8-
ModifiableResourceMixin,
95
)
106
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
118

129

1310
class LedgerAttachment(Model):
@@ -20,11 +17,12 @@ class LedgerAttachmentsServiceConfig:
2017
_endpoint = "/public/v1/billing/ledgers/{ledger_id}/attachments"
2118
_model_class = LedgerAttachment
2219
_collection_key = "data"
20+
_upload_file_key = "file"
21+
_upload_data_key = "attachment"
2322

2423

2524
class LedgerAttachmentsService(
26-
FilesOperationsMixin[LedgerAttachment],
27-
ModifiableResourceMixin[LedgerAttachment],
25+
AttachmentMixin[LedgerAttachment],
2826
CollectionMixin[LedgerAttachment],
2927
Service[LedgerAttachment],
3028
LedgerAttachmentsServiceConfig,
@@ -33,8 +31,7 @@ class LedgerAttachmentsService(
3331

3432

3533
class AsyncLedgerAttachmentsService(
36-
AsyncFilesOperationsMixin[LedgerAttachment],
37-
AsyncModifiableResourceMixin[LedgerAttachment],
34+
AsyncAttachmentMixin[LedgerAttachment],
3835
AsyncCollectionMixin[LedgerAttachment],
3936
AsyncService[LedgerAttachment],
4037
LedgerAttachmentsServiceConfig,

mpt_api_client/resources/billing/mixins.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
from mpt_api_client.http.mixins import (
2+
AsyncCreateFileMixin,
3+
AsyncDeleteMixin,
4+
AsyncDownloadFileMixin,
5+
AsyncGetMixin,
6+
AsyncUpdateMixin,
7+
CreateFileMixin,
8+
DeleteMixin,
9+
DownloadFileMixin,
10+
GetMixin,
11+
UpdateMixin,
12+
)
113
from mpt_api_client.models import ResourceData
214

315

@@ -392,3 +404,23 @@ async def queue(self, resource_id: str, resource_data: ResourceData | None = Non
392404
return await self._resource_action( # type: ignore[attr-defined, no-any-return]
393405
resource_id, "POST", "queue", json=resource_data
394406
)
407+
408+
409+
class AttachmentMixin[Model](
410+
CreateFileMixin[Model],
411+
UpdateMixin[Model],
412+
DeleteMixin,
413+
DownloadFileMixin[Model],
414+
GetMixin[Model],
415+
):
416+
"""Attachment mixin."""
417+
418+
419+
class AsyncAttachmentMixin[Model](
420+
AsyncCreateFileMixin[Model],
421+
AsyncUpdateMixin[Model],
422+
AsyncDeleteMixin,
423+
AsyncDownloadFileMixin[Model],
424+
AsyncGetMixin[Model],
425+
):
426+
"""Async Attachment mixin."""
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from mpt_api_client.http import AsyncService, Service
2+
from mpt_api_client.http.mixins import (
3+
AsyncCollectionMixin,
4+
CollectionMixin,
5+
)
6+
from mpt_api_client.models import Model
7+
from mpt_api_client.resources.billing.mixins import AsyncAttachmentMixin, AttachmentMixin
8+
9+
10+
class StatementAttachment(Model):
11+
"""Statement Attachment resource."""
12+
13+
14+
class StatementAttachmentsServiceConfig:
15+
"""Statement Attachments service configuration."""
16+
17+
_endpoint = "/public/v1/billing/statements/{statement_id}/attachments"
18+
_model_class = StatementAttachment
19+
_collection_key = "data"
20+
_upload_file_key = "file"
21+
_upload_data_key = "attachment"
22+
23+
24+
class StatementAttachmentsService(
25+
AttachmentMixin[StatementAttachment],
26+
CollectionMixin[StatementAttachment],
27+
Service[StatementAttachment],
28+
StatementAttachmentsServiceConfig,
29+
):
30+
"""Statement Attachments service."""
31+
32+
33+
class AsyncStatementAttachmentsService(
34+
AsyncAttachmentMixin[StatementAttachment],
35+
AsyncCollectionMixin[StatementAttachment],
36+
AsyncService[StatementAttachment],
37+
StatementAttachmentsServiceConfig,
38+
):
39+
"""Statement Attachments service."""

mpt_api_client/resources/billing/statements.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
)
1010
from mpt_api_client.models import Model
1111
from mpt_api_client.resources.billing.mixins import AsyncIssuableMixin, IssuableMixin
12+
from mpt_api_client.resources.billing.statement_attachments import (
13+
AsyncStatementAttachmentsService,
14+
StatementAttachmentsService,
15+
)
1216
from mpt_api_client.resources.billing.statement_charges import (
1317
AsyncStatementChargesService,
1418
StatementChargesService,
@@ -44,6 +48,13 @@ def charges(self, statement_id: str) -> StatementChargesService:
4448
endpoint_params={"statement_id": statement_id},
4549
)
4650

51+
def attachments(self, statement_id: str) -> StatementAttachmentsService:
52+
"""Return statement attachments service."""
53+
return StatementAttachmentsService(
54+
http_client=self.http_client,
55+
endpoint_params={"statement_id": statement_id},
56+
)
57+
4758

4859
class AsyncStatementsService(
4960
AsyncUpdateMixin[Statement],
@@ -61,3 +72,10 @@ def charges(self, statement_id: str) -> AsyncStatementChargesService:
6172
http_client=self.http_client,
6273
endpoint_params={"statement_id": statement_id},
6374
)
75+
76+
def attachments(self, statement_id: str) -> AsyncStatementAttachmentsService:
77+
"""Return statement attachments service."""
78+
return AsyncStatementAttachmentsService(
79+
http_client=self.http_client,
80+
endpoint_params={"statement_id": statement_id},
81+
)

tests/unit/resources/billing/test_credit_memo_attachments.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ def test_async_endpoint(async_credit_memo_attachments_service):
3838
assert result is True
3939

4040

41-
@pytest.mark.parametrize("method", ["get", "create", "update", "delete"])
41+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate", "download"])
4242
def test_methods_present(credit_memo_attachments_service, method: str):
4343
result = hasattr(credit_memo_attachments_service, method)
4444

4545
assert result is True
4646

4747

48-
@pytest.mark.parametrize("method", ["get", "create", "update", "delete"])
48+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate", "download"])
4949
def test_async_methods_present(async_credit_memo_attachments_service, method: str):
5050
result = hasattr(async_credit_memo_attachments_service, method)
5151

tests/unit/resources/billing/test_custom_ledger_attachments.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ def test_async_endpoint(async_custom_ledger_attachments_service):
3636
assert result is True
3737

3838

39-
@pytest.mark.parametrize("method", ["get", "create", "update", "delete"])
39+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate", "download"])
4040
def test_methods_present(custom_ledger_attachments_service, method: str):
4141
result = hasattr(custom_ledger_attachments_service, method)
4242

4343
assert result is True
4444

4545

46-
@pytest.mark.parametrize("method", ["get", "create", "update", "delete"])
46+
@pytest.mark.parametrize("method", ["get", "create", "update", "delete", "iterate", "download"])
4747
def test_async_methods_present(async_custom_ledger_attachments_service, method: str):
4848
result = hasattr(async_custom_ledger_attachments_service, method)
4949

0 commit comments

Comments
 (0)