diff --git a/mpt_api_client/resources/commerce/__init__.py b/mpt_api_client/resources/commerce/__init__.py index d9922d60..ad22f2b4 100644 --- a/mpt_api_client/resources/commerce/__init__.py +++ b/mpt_api_client/resources/commerce/__init__.py @@ -1,4 +1,3 @@ from mpt_api_client.resources.commerce.commerce import AsyncCommerce, Commerce -from mpt_api_client.resources.commerce.orders import AsyncOrdersService, OrdersService -__all__ = ["AsyncCommerce", "AsyncOrdersService", "Commerce", "OrdersService"] # noqa: WPS410 +__all__ = ["AsyncCommerce", "Commerce"] # noqa: WPS410 diff --git a/mpt_api_client/resources/commerce/agreements.py b/mpt_api_client/resources/commerce/agreements.py new file mode 100644 index 00000000..3fbe8c3f --- /dev/null +++ b/mpt_api_client/resources/commerce/agreements.py @@ -0,0 +1,46 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.models import Model + + +class Agreement(Model): + """Agreement resource.""" + + +class AgreementsServiceConfig: + """Orders service config.""" + + _endpoint = "/public/v1/commerce/agreements" + _model_class = Agreement + _collection_key = "data" + + +class AgreementsService(Service[Agreement], AgreementsServiceConfig): + """Agreements service.""" + + def template(self, agreement_id: str) -> str: + """Renders the template for the given Agreement id. + + Args: + agreement_id: Agreement ID. + + Returns: + Agreement template. + """ + response = self._resource_do_request(agreement_id, action="template") + return response.text + + +class AsyncAgreementsService(AsyncService[Agreement], AgreementsServiceConfig): + """Agreements service.""" + + async def template(self, agreement_id: str) -> str: + """Renders the template for the given Agreement id. + + Args: + agreement_id: Agreement ID. + + Returns: + Agreement template. + """ + response = await self._resource_do_request(agreement_id, action="template") + return response.text diff --git a/mpt_api_client/resources/commerce/commerce.py b/mpt_api_client/resources/commerce/commerce.py index fc56c6e6..c089725f 100644 --- a/mpt_api_client/resources/commerce/commerce.py +++ b/mpt_api_client/resources/commerce/commerce.py @@ -1,4 +1,5 @@ from mpt_api_client.http import AsyncHTTPClient, HTTPClient +from mpt_api_client.resources.commerce.agreements import AgreementsService, AsyncAgreementsService from mpt_api_client.resources.commerce.orders import AsyncOrdersService, OrdersService @@ -8,6 +9,11 @@ class Commerce: def __init__(self, http_client: HTTPClient): self.http_client = http_client + @property + def agreements(self) -> AgreementsService: + """Agreement service.""" + return AgreementsService(http_client=self.http_client) + @property def orders(self) -> OrdersService: """Order service.""" @@ -20,6 +26,11 @@ class AsyncCommerce: def __init__(self, http_client: AsyncHTTPClient): self.http_client = http_client + @property + def agreements(self) -> AsyncAgreementsService: + """Agreement service.""" + return AsyncAgreementsService(http_client=self.http_client) + @property def orders(self) -> AsyncOrdersService: """Order service.""" diff --git a/tests/http/test_async_service.py b/tests/http/test_async_service.py index e71fcc96..43379d50 100644 --- a/tests/http/test_async_service.py +++ b/tests/http/test_async_service.py @@ -8,39 +8,6 @@ from tests.http.conftest import AsyncDummyService -async def test_async_create_mixin(async_dummy_service): # noqa: WPS210 - resource_data = {"name": "Test Resource", "status": "active"} - new_resource_data = {"id": "new-resource-id", "name": "Test Resource", "status": "active"} - create_response = httpx.Response(httpx.codes.OK, json=new_resource_data) - - with respx.mock: - mock_route = respx.post("https://api.example.com/api/v1/test").mock( - return_value=create_response - ) - - created_resource = await async_dummy_service.create(resource_data) - - assert created_resource.to_dict() == new_resource_data - assert mock_route.call_count == 1 - request = mock_route.calls[0].request - assert request.method == "POST" - assert request.url == "https://api.example.com/api/v1/test" - assert json.loads(request.content.decode()) == resource_data - - -async def test_async_delete_mixin(async_dummy_service): # noqa: WPS210 - delete_response = httpx.Response(httpx.codes.NO_CONTENT, json=None) - - with respx.mock: - mock_route = respx.delete("https://api.example.com/api/v1/test/RES-123").mock( - return_value=delete_response - ) - - await async_dummy_service.delete("RES-123") - - assert mock_route.call_count == 1 - - async def test_async_fetch_one_success(async_dummy_service, single_result_response): with respx.mock: mock_route = respx.get("https://api.example.com/api/v1/test").mock( diff --git a/tests/http/test_mixins.py b/tests/http/test_mixins.py new file mode 100644 index 00000000..e3fe705d --- /dev/null +++ b/tests/http/test_mixins.py @@ -0,0 +1,69 @@ +import json + +import httpx +import respx + + +async def test_async_create_mixin(async_dummy_service): # noqa: WPS210 + resource_data = {"name": "Test Resource", "status": "active"} + new_resource_data = {"id": "new-resource-id", "name": "Test Resource", "status": "active"} + create_response = httpx.Response(httpx.codes.OK, json=new_resource_data) + + with respx.mock: + mock_route = respx.post("https://api.example.com/api/v1/test").mock( + return_value=create_response + ) + + created_resource = await async_dummy_service.create(resource_data) + + assert created_resource.to_dict() == new_resource_data + assert mock_route.call_count == 1 + request = mock_route.calls[0].request + assert request.method == "POST" + assert request.url == "https://api.example.com/api/v1/test" + assert json.loads(request.content.decode()) == resource_data + + +async def test_async_delete_mixin(async_dummy_service): # noqa: WPS210 + delete_response = httpx.Response(httpx.codes.NO_CONTENT, json=None) + + with respx.mock: + mock_route = respx.delete("https://api.example.com/api/v1/test/RES-123").mock( + return_value=delete_response + ) + + await async_dummy_service.delete("RES-123") + + assert mock_route.call_count == 1 + + +def test_sync_create_mixin(dummy_service): # noqa: WPS210 + resource_data = {"name": "Test Resource", "status": "active"} + new_resource_data = {"id": "new-resource-id", "name": "Test Resource", "status": "active"} + create_response = httpx.Response(httpx.codes.OK, json=new_resource_data) + + with respx.mock: + mock_route = respx.post("https://api.example.com/api/v1/test").mock( + return_value=create_response + ) + + created_resource = dummy_service.create(resource_data) + + assert created_resource.to_dict() == new_resource_data + assert mock_route.call_count == 1 + request = mock_route.calls[0].request + assert request.method == "POST" + assert request.url == "https://api.example.com/api/v1/test" + assert json.loads(request.content.decode()) == resource_data + + +def test_sync_delete_mixin(dummy_service): + delete_response = httpx.Response(httpx.codes.NO_CONTENT, json=None) + with respx.mock: + mock_route = respx.delete("https://api.example.com/api/v1/test/RES-123").mock( + return_value=delete_response + ) + + dummy_service.delete("RES-123") + + assert mock_route.call_count == 1 diff --git a/tests/http/test_service.py b/tests/http/test_service.py index 7c45e22e..d93c2192 100644 --- a/tests/http/test_service.py +++ b/tests/http/test_service.py @@ -9,38 +9,6 @@ from tests.http.conftest import DummyService -def test_sync_create_mixin(dummy_service): # noqa: WPS210 - resource_data = {"name": "Test Resource", "status": "active"} - new_resource_data = {"id": "new-resource-id", "name": "Test Resource", "status": "active"} - create_response = httpx.Response(httpx.codes.OK, json=new_resource_data) - - with respx.mock: - mock_route = respx.post("https://api.example.com/api/v1/test").mock( - return_value=create_response - ) - - created_resource = dummy_service.create(resource_data) - - assert created_resource.to_dict() == new_resource_data - assert mock_route.call_count == 1 - request = mock_route.calls[0].request - assert request.method == "POST" - assert request.url == "https://api.example.com/api/v1/test" - assert json.loads(request.content.decode()) == resource_data - - -def test_sync_delete_mixin(dummy_service): - delete_response = httpx.Response(httpx.codes.NO_CONTENT, json=None) - with respx.mock: - mock_route = respx.delete("https://api.example.com/api/v1/test/RES-123").mock( - return_value=delete_response - ) - - dummy_service.delete("RES-123") - - assert mock_route.call_count == 1 - - def test_sync_fetch_one_success(dummy_service, single_result_response): with respx.mock: mock_route = respx.get("https://api.example.com/api/v1/test").mock( diff --git a/tests/resources/commerce/test_agreements.py b/tests/resources/commerce/test_agreements.py new file mode 100644 index 00000000..bd9e1db2 --- /dev/null +++ b/tests/resources/commerce/test_agreements.py @@ -0,0 +1,41 @@ +import httpx +import respx + +from mpt_api_client.resources.commerce.agreements import AgreementsService, AsyncAgreementsService + + +async def test_async_template(async_http_client): + async_agreements_service = AsyncAgreementsService(http_client=async_http_client) + template_content = "# Order Template\n\nThis is a markdown template." + with respx.mock: + respx.get("https://api.example.com/public/v1/commerce/agreements/AGR-123/template").mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": "text/markdown"}, + content=template_content, + ) + ) + + template = await async_agreements_service.template("AGR-123") + + assert template == template_content + + +def test_template(http_client): + agreements_service = AgreementsService(http_client=http_client) + with respx.mock: + mock_route = respx.get( + "https://api.example.com/public/v1/commerce/agreements/AGR-123/template" + ).mock( + return_value=httpx.Response( + status_code=200, + headers={"content-type": "text/markdown"}, + content="# Order Template\n\nThis is a markdown template.", + ) + ) + + markdown_template = agreements_service.template("AGR-123") + + assert mock_route.called + assert mock_route.call_count == 1 + assert markdown_template == "# Order Template\n\nThis is a markdown template." diff --git a/tests/resources/commerce/test_commerce.py b/tests/resources/commerce/test_commerce.py index 0823bc2c..61654ebb 100644 --- a/tests/resources/commerce/test_commerce.py +++ b/tests/resources/commerce/test_commerce.py @@ -1,5 +1,6 @@ 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.orders import AsyncOrdersService, OrdersService @@ -55,3 +56,21 @@ def test_async_commerce_orders_multiple_calls(async_http_client: AsyncHTTPClient assert orders_service is not orders_service_additional assert isinstance(orders_service, AsyncOrdersService) assert isinstance(orders_service_additional, AsyncOrdersService) + + +def test_async_agreements(async_http_client): + commerce = AsyncCommerce(http_client=async_http_client) + + agreements = commerce.agreements + + assert isinstance(agreements, AsyncAgreementsService) + assert agreements.http_client is async_http_client + + +def test_agreements(http_client): + commerce = Commerce(http_client=http_client) + + agreements = commerce.agreements + + assert isinstance(agreements, AgreementsService) + assert agreements.http_client is http_client