diff --git a/mpt_api_client/resources/commerce/assets.py b/mpt_api_client/resources/commerce/assets.py new file mode 100644 index 0000000..06d8731 --- /dev/null +++ b/mpt_api_client/resources/commerce/assets.py @@ -0,0 +1,100 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncCollectionMixin, + AsyncCreateMixin, + AsyncGetMixin, + AsyncUpdateMixin, + CollectionMixin, + CreateMixin, + GetMixin, + UpdateMixin, +) +from mpt_api_client.models import Model +from mpt_api_client.models.model import ResourceData + + +class Asset(Model): + """Asset resource.""" + + +class AssetTemplate(Model): + """Asset template resource.""" + + +class AssetsServiceConfig: + """Assets service config.""" + + _endpoint = "/public/v1/commerce/assets" + _model_class = Asset + _collection_key = "data" + + +class AssetsService( + CreateMixin[Asset], + UpdateMixin[Asset], + GetMixin[Asset], + CollectionMixin[Asset], + Service[Asset], + AssetsServiceConfig, +): + """Assets service.""" + + def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset: + """Terminate the given Asset id. + + Args: + asset_id: Asset ID. + resource_data: Resource data will be updated + """ + response = self._resource_do_request(asset_id, "POST", "terminate", json=resource_data) + return self._model_class.from_response(response) + + def render(self, asset_id: str) -> AssetTemplate: + """Renders the template for the given Asset id. + + Args: + asset_id: Asset ID. + + Returns: + Render asset template json. + """ + response = self._resource_do_request(asset_id, action="render") + + return AssetTemplate.from_response(response) + + +class AsyncAssetsService( + AsyncCreateMixin[Asset], + AsyncUpdateMixin[Asset], + AsyncGetMixin[Asset], + AsyncCollectionMixin[Asset], + AsyncService[Asset], + AssetsServiceConfig, +): + """Asynchronous Assets service.""" + + async def terminate(self, asset_id: str, resource_data: ResourceData | None = None) -> Asset: + """Terminate the given Asset id. + + Args: + asset_id: Asset ID. + resource_data: Resource data will be updated + """ + response = await self._resource_do_request( + asset_id, "POST", "terminate", json=resource_data + ) + + return self._model_class.from_response(response) + + async def render(self, asset_id: str) -> AssetTemplate: + """Renders the template for the given Asset id. + + Args: + asset_id: Asset ID. + + Returns: + Render asset template json. + """ + response = await self._resource_do_request(asset_id, action="render") + + return AssetTemplate.from_response(response) diff --git a/mpt_api_client/resources/commerce/commerce.py b/mpt_api_client/resources/commerce/commerce.py index 7ea9f7c..18bd3d1 100644 --- a/mpt_api_client/resources/commerce/commerce.py +++ b/mpt_api_client/resources/commerce/commerce.py @@ -1,5 +1,6 @@ from mpt_api_client.http import AsyncHTTPClient, HTTPClient from mpt_api_client.resources.commerce.agreements import AgreementsService, AsyncAgreementsService +from mpt_api_client.resources.commerce.assets import AssetsService, AsyncAssetsService from mpt_api_client.resources.commerce.orders import AsyncOrdersService, OrdersService from mpt_api_client.resources.commerce.subscriptions import ( AsyncSubscriptionsService, @@ -28,6 +29,11 @@ def subscriptions(self) -> SubscriptionsService: """Subscription service.""" return SubscriptionsService(http_client=self.http_client) + @property + def assets(self) -> AssetsService: + """Asset service.""" + return AssetsService(http_client=self.http_client) + class AsyncCommerce: """Commerce MPT API Module.""" @@ -49,3 +55,8 @@ def orders(self) -> AsyncOrdersService: def subscriptions(self) -> AsyncSubscriptionsService: """Subscription service.""" return AsyncSubscriptionsService(http_client=self.http_client) + + @property + def assets(self) -> AsyncAssetsService: + """Asset service.""" + return AsyncAssetsService(http_client=self.http_client) diff --git a/tests/unit/resources/commerce/test_assets.py b/tests/unit/resources/commerce/test_assets.py new file mode 100644 index 0000000..d5eb826 --- /dev/null +++ b/tests/unit/resources/commerce/test_assets.py @@ -0,0 +1,106 @@ +import httpx +import pytest +import respx + +from mpt_api_client.constants import APPLICATION_JSON +from mpt_api_client.resources.commerce.assets import AssetsService, AsyncAssetsService + + +@pytest.fixture +def assets_service(http_client): + return AssetsService(http_client=http_client) + + +@pytest.fixture +def async_assets_service(async_http_client): + return AsyncAssetsService(http_client=async_http_client) + + +async def test_async_render(async_assets_service): + render_response = {"id": "ASSET-123", "title": "Sample Asset"} + with respx.mock: + respx.get("https://api.example.com/public/v1/commerce/assets/ASSET-123/render").mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": APPLICATION_JSON}, + json=render_response, + ) + ) + + result = await async_assets_service.render("ASSET-123") + + assert result is not None + + +def test_render(assets_service): + render_response = {"id": "ASSET-123", "title": "Sample Asset"} + with respx.mock: + mock_route = respx.get( + "https://api.example.com/public/v1/commerce/assets/ASSET-123/render" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": APPLICATION_JSON}, + json=render_response, + ) + ) + + result = assets_service.render("ASSET-123") + + assert mock_route.called + assert mock_route.call_count == 1 + assert result is not None + + +def test_terminate(assets_service): + response_data = {"id": "ASSET-123", "status": "terminated"} + with respx.mock: + mock_route = respx.post( + "https://api.example.com/public/v1/commerce/assets/ASSET-123/terminate" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": APPLICATION_JSON}, + json=response_data, + ) + ) + + result = assets_service.terminate("ASSET-123") + + assert mock_route.called + assert mock_route.call_count == 1 + assert result is not None + + +async def test_async_terminate(async_assets_service): + response_data = {"id": "ASSET-123", "status": "terminated"} + with respx.mock: + mock_route = respx.post( + "https://api.example.com/public/v1/commerce/assets/ASSET-123/terminate" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": APPLICATION_JSON}, + json=response_data, + ) + ) + + result = await async_assets_service.terminate("ASSET-123") + + assert mock_route.called + assert mock_route.call_count == 1 + assert result is not None + + +@pytest.mark.parametrize("method", ["create", "update", "get", "render", "terminate"]) +def test_assets_service_methods(assets_service, method): + result = hasattr(assets_service, method) + + assert result is True + + +@pytest.mark.parametrize("method", ["create", "update", "get", "render", "terminate"]) +def test_async_assets_service_methods(async_assets_service, method): + result = hasattr(async_assets_service, method) + + assert result is True diff --git a/tests/unit/resources/commerce/test_commerce.py b/tests/unit/resources/commerce/test_commerce.py index efaadd5..26a6db1 100644 --- a/tests/unit/resources/commerce/test_commerce.py +++ b/tests/unit/resources/commerce/test_commerce.py @@ -3,6 +3,7 @@ from mpt_api_client.http import AsyncHTTPClient from mpt_api_client.resources.commerce import AsyncCommerce, Commerce from mpt_api_client.resources.commerce.agreements import AgreementsService, AsyncAgreementsService +from mpt_api_client.resources.commerce.assets import AssetsService, AsyncAssetsService from mpt_api_client.resources.commerce.orders import AsyncOrdersService, OrdersService from mpt_api_client.resources.commerce.subscriptions import ( AsyncSubscriptionsService, @@ -40,6 +41,7 @@ def test_async_commerce_init(async_http_client: AsyncHTTPClient): ("agreements", AgreementsService), ("orders", OrdersService), ("subscriptions", SubscriptionsService), + ("assets", AssetsService), ], ) def test_commerce_properties(http_client, attr_name, expected): @@ -56,6 +58,7 @@ def test_commerce_properties(http_client, attr_name, expected): ("agreements", AsyncAgreementsService), ("orders", AsyncOrdersService), ("subscriptions", AsyncSubscriptionsService), + ("assets", AsyncAssetsService), ], ) def test_async_commerce_properties(http_client, attr_name, expected):