Skip to content

Commit 22ecfc4

Browse files
committed
MPT-14889: Implement E2E Tests and Enhance Document Handling
- Added end-to-end tests for catalog/product document workflows - Refactored document service to improve usability and interface consistency - Introduced support for both URL-based and file-based document uploads - Updated download logic to include Accept header and retrieve it from the resource when required - Enabled follow_redirects on the http client
1 parent acee3bf commit 22ecfc4

30 files changed

+583
-90
lines changed

e2e_config.test.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"accounts.seller.id": "SEL-7310-3075",
44
"catalog.product.parameter_group.id": "PGR-7255-3950-0001",
55
"catalog.product.parameter.id": "PAR-7255-3950-0016",
6+
"catalog.product.document.id": "PDC-7255-3950-0001",
67
"accounts.account.id": "ACC-9042-0088",
78
"accounts.buyer.account.id": "ACC-1086-6867",
89
"accounts.buyer.id": "BUY-1591-2112",

mpt_api_client/http/async_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def __init__(
5353
headers=base_headers,
5454
timeout=timeout,
5555
transport=AsyncHTTPTransport(retries=retries),
56+
follow_redirects=True,
5657
)
5758

5859
async def request( # noqa: WPS211

mpt_api_client/http/async_service.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from urllib.parse import urljoin
22

3+
from mpt_api_client.constants import APPLICATION_JSON
34
from mpt_api_client.http.async_client import AsyncHTTPClient
45
from mpt_api_client.http.base_service import ServiceBase
56
from mpt_api_client.http.types import QueryParam, Response
@@ -69,6 +70,11 @@ async def _resource_action(
6970
query_params: Additional query parameters.
7071
"""
7172
response = await self._resource_do_request(
72-
resource_id, method, action, json=json, query_params=query_params
73+
resource_id,
74+
method,
75+
action,
76+
json=json,
77+
query_params=query_params,
78+
headers={"Accept": APPLICATION_JSON},
7379
)
7480
return self._model_class.from_response(response)

mpt_api_client/http/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ def __init__(
5555
headers=base_headers,
5656
timeout=timeout,
5757
transport=HTTPTransport(retries=retries),
58+
follow_redirects=True,
5859
)
5960

6061
def request( # noqa: WPS211

mpt_api_client/http/mixins.py

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from urllib.parse import urljoin
55

66
from mpt_api_client.constants import APPLICATION_JSON
7+
from mpt_api_client.exceptions import MPTError
78
from mpt_api_client.http.query_state import QueryState
89
from mpt_api_client.http.types import FileTypes, Response
910
from mpt_api_client.models import Collection, FileModel, ResourceData
@@ -60,7 +61,32 @@ def update(self, resource_id: str, resource_data: ResourceData) -> Model:
6061
return self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
6162

6263

63-
class FileOperationsMixin[Model]:
64+
class DownloadFileMixin[Model]:
65+
"""Download file mixin."""
66+
67+
def download(self, resource_id: str, accept: str | None = None) -> FileModel:
68+
"""Download the file for the given resource ID.
69+
70+
Args:
71+
resource_id: Resource ID.
72+
accept: The content type expected for the file.
73+
If not provided, the content type will be fetched from the resource.
74+
75+
Returns:
76+
File model containing the downloaded file.
77+
"""
78+
if not accept:
79+
resource: Model = self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
80+
accept = resource.content_type # type: ignore[attr-defined]
81+
if not accept:
82+
raise MPTError("Unable to download file. Content type not found in resource")
83+
response: Response = self._resource_do_request( # type: ignore[attr-defined]
84+
resource_id, method="GET", headers={"Accept": accept}
85+
)
86+
return FileModel(response)
87+
88+
89+
class FilesOperationsMixin[Model](DownloadFileMixin[Model]):
6490
"""Mixin that provides create and download methods for file-based resources."""
6591

6692
def create(
@@ -91,20 +117,6 @@ def create(
91117

92118
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
93119

94-
def download(self, resource_id: str) -> FileModel:
95-
"""Download the file for the given resource ID.
96-
97-
Args:
98-
resource_id: Resource ID.
99-
100-
Returns:
101-
File model containing the downloaded file.
102-
"""
103-
response: Response = self._resource_do_request( # type: ignore[attr-defined]
104-
resource_id, method="GET", headers={"Accept": "*"}
105-
)
106-
return FileModel(response)
107-
108120

109121
class CreateWithIconMixin[Model]:
110122
"""Create resource with icon mixin."""
@@ -221,7 +233,32 @@ async def update(self, resource_id: str, resource_data: ResourceData) -> Model:
221233
return await self._resource_action(resource_id, "PUT", json=resource_data) # type: ignore[attr-defined, no-any-return]
222234

223235

224-
class AsyncFileOperationsMixin[Model]:
236+
class AsyncDownloadFileMixin[Model]:
237+
"""Download file mixin."""
238+
239+
async def download(self, resource_id: str, accept: str | None = None) -> FileModel:
240+
"""Download the file for the given resource ID.
241+
242+
Args:
243+
resource_id: Resource ID.
244+
accept: The content type expected for the file.
245+
If not provided, the content type will be fetched from the resource.
246+
247+
Returns:
248+
File model containing the downloaded file.
249+
"""
250+
if not accept:
251+
resource: Model = await self._resource_action(resource_id, method="GET") # type: ignore[attr-defined]
252+
accept = resource.content_type # type: ignore[attr-defined]
253+
if not accept:
254+
raise MPTError("Unable to download file. Content type not found in resource")
255+
response = await self._resource_do_request( # type: ignore[attr-defined]
256+
resource_id, method="GET", headers={"Accept": accept}
257+
)
258+
return FileModel(response)
259+
260+
261+
class AsyncFilesOperationsMixin[Model](AsyncDownloadFileMixin[Model]):
225262
"""Async mixin that provides create and download methods for file-based resources."""
226263

227264
async def create(
@@ -253,20 +290,6 @@ async def create(
253290

254291
return self._model_class.from_response(response) # type: ignore[attr-defined, no-any-return]
255292

256-
async def download(self, resource_id: str) -> FileModel:
257-
"""Download the file for the given resource ID.
258-
259-
Args:
260-
resource_id: Resource ID.
261-
262-
Returns:
263-
File model containing the downloaded file.
264-
"""
265-
response = await self._resource_do_request( # type: ignore[attr-defined]
266-
resource_id, method="GET", headers={"Accept": "*"}
267-
)
268-
return FileModel(response)
269-
270293

271294
class AsyncCreateWithIconMixin[Model]:
272295
"""Create resource with icon mixin."""

mpt_api_client/http/service.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from urllib.parse import urljoin
22

3+
from mpt_api_client.constants import APPLICATION_JSON
34
from mpt_api_client.http.base_service import ServiceBase
45
from mpt_api_client.http.client import HTTPClient
56
from mpt_api_client.http.types import QueryParam, Response
@@ -74,6 +75,6 @@ def _resource_action(
7475
action,
7576
json=json,
7677
query_params=query_params,
77-
headers={"Accept": "application/json"},
78+
headers={"Accept": APPLICATION_JSON},
7879
)
7980
return self._model_class.from_response(response)

mpt_api_client/resources/billing/credit_memo_attachments.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFileOperationsMixin,
4+
AsyncFilesOperationsMixin,
55
AsyncModifiableResourceMixin,
66
CollectionMixin,
7-
FileOperationsMixin,
7+
FilesOperationsMixin,
88
ModifiableResourceMixin,
99
)
1010
from mpt_api_client.models import Model
@@ -23,7 +23,7 @@ class CreditMemoAttachmentsServiceConfig:
2323

2424

2525
class CreditMemoAttachmentsService(
26-
FileOperationsMixin[CreditMemoAttachment],
26+
FilesOperationsMixin[CreditMemoAttachment],
2727
ModifiableResourceMixin[CreditMemoAttachment],
2828
CollectionMixin[CreditMemoAttachment],
2929
Service[CreditMemoAttachment],
@@ -33,7 +33,7 @@ class CreditMemoAttachmentsService(
3333

3434

3535
class AsyncCreditMemoAttachmentsService(
36-
AsyncFileOperationsMixin[CreditMemoAttachment],
36+
AsyncFilesOperationsMixin[CreditMemoAttachment],
3737
AsyncModifiableResourceMixin[CreditMemoAttachment],
3838
AsyncCollectionMixin[CreditMemoAttachment],
3939
AsyncService[CreditMemoAttachment],

mpt_api_client/resources/billing/custom_ledger_attachments.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFileOperationsMixin,
4+
AsyncFilesOperationsMixin,
55
AsyncModifiableResourceMixin,
66
CollectionMixin,
7-
FileOperationsMixin,
7+
FilesOperationsMixin,
88
ModifiableResourceMixin,
99
)
1010
from mpt_api_client.models import Model
@@ -23,7 +23,7 @@ class CustomLedgerAttachmentsServiceConfig:
2323

2424

2525
class CustomLedgerAttachmentsService(
26-
FileOperationsMixin[CustomLedgerAttachment],
26+
FilesOperationsMixin[CustomLedgerAttachment],
2727
ModifiableResourceMixin[CustomLedgerAttachment],
2828
CollectionMixin[CustomLedgerAttachment],
2929
Service[CustomLedgerAttachment],
@@ -33,7 +33,7 @@ class CustomLedgerAttachmentsService(
3333

3434

3535
class AsyncCustomLedgerAttachmentsService(
36-
AsyncFileOperationsMixin[CustomLedgerAttachment],
36+
AsyncFilesOperationsMixin[CustomLedgerAttachment],
3737
AsyncModifiableResourceMixin[CustomLedgerAttachment],
3838
AsyncCollectionMixin[CustomLedgerAttachment],
3939
AsyncService[CustomLedgerAttachment],

mpt_api_client/resources/billing/custom_ledger_upload.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from mpt_api_client.http import AsyncService, Service
2-
from mpt_api_client.http.mixins import AsyncFileOperationsMixin, FileOperationsMixin
2+
from mpt_api_client.http.mixins import AsyncFilesOperationsMixin, FilesOperationsMixin
33
from mpt_api_client.models import Model
44

55

@@ -16,15 +16,15 @@ class CustomLedgerUploadServiceConfig:
1616

1717

1818
class CustomLedgerUploadService(
19-
FileOperationsMixin[CustomLedgerUpload],
19+
FilesOperationsMixin[CustomLedgerUpload],
2020
Service[CustomLedgerUpload],
2121
CustomLedgerUploadServiceConfig,
2222
):
2323
"""Custom Ledger Upload service."""
2424

2525

2626
class AsyncCustomLedgerUploadService(
27-
AsyncFileOperationsMixin[CustomLedgerUpload],
27+
AsyncFilesOperationsMixin[CustomLedgerUpload],
2828
AsyncService[CustomLedgerUpload],
2929
CustomLedgerUploadServiceConfig,
3030
):

mpt_api_client/resources/billing/invoice_attachments.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from mpt_api_client.http import AsyncService, Service
22
from mpt_api_client.http.mixins import (
33
AsyncCollectionMixin,
4-
AsyncFileOperationsMixin,
4+
AsyncFilesOperationsMixin,
55
AsyncModifiableResourceMixin,
66
CollectionMixin,
7-
FileOperationsMixin,
7+
FilesOperationsMixin,
88
ModifiableResourceMixin,
99
)
1010
from mpt_api_client.models import Model
@@ -23,7 +23,7 @@ class InvoiceAttachmentsServiceConfig:
2323

2424

2525
class InvoiceAttachmentsService(
26-
FileOperationsMixin[InvoiceAttachment],
26+
FilesOperationsMixin[InvoiceAttachment],
2727
ModifiableResourceMixin[InvoiceAttachment],
2828
CollectionMixin[InvoiceAttachment],
2929
Service[InvoiceAttachment],
@@ -33,7 +33,7 @@ class InvoiceAttachmentsService(
3333

3434

3535
class AsyncInvoiceAttachmentsService(
36-
AsyncFileOperationsMixin[InvoiceAttachment],
36+
AsyncFilesOperationsMixin[InvoiceAttachment],
3737
AsyncModifiableResourceMixin[InvoiceAttachment],
3838
AsyncCollectionMixin[InvoiceAttachment],
3939
AsyncService[InvoiceAttachment],

0 commit comments

Comments
 (0)