From d8c1117c434732b1e673b773522f730e7468d6b9 Mon Sep 17 00:00:00 2001 From: Albert Sola Date: Thu, 11 Sep 2025 13:44:59 +0100 Subject: [PATCH 1/2] MPT-13422 Add catalog product update settings --- mpt_api_client/resources/catalog/products.py | 10 +++- setup.cfg | 3 +- tests/resources/catalog/test_products.py | 48 +++++++++++++++++++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/mpt_api_client/resources/catalog/products.py b/mpt_api_client/resources/catalog/products.py index 6dd7f82e..082c9a18 100644 --- a/mpt_api_client/resources/catalog/products.py +++ b/mpt_api_client/resources/catalog/products.py @@ -6,7 +6,7 @@ DeleteMixin, UpdateMixin, ) -from mpt_api_client.models import Model +from mpt_api_client.models import Model, ResourceData from mpt_api_client.resources.catalog.mixins import ( AsyncPublishableMixin, PublishableMixin, @@ -103,6 +103,10 @@ def terms(self, product_id: str) -> TermService: """Return terms service.""" return TermService(http_client=self.http_client, endpoint_params={"product_id": product_id}) + def update_settings(self, product_id: str, settings: ResourceData) -> Product: + """Update product settings.""" + return self._resource_action(product_id, "PUT", "settings", settings) + class AsyncProductsService( AsyncCreateMixin[Product], @@ -155,3 +159,7 @@ def terms(self, product_id: str) -> AsyncTermService: return AsyncTermService( http_client=self.http_client, endpoint_params={"product_id": product_id} ) + + async def update_settings(self, product_id: str, settings: ResourceData) -> Product: + """Update product settings.""" + return await self._resource_action(product_id, "PUT", "settings", settings) diff --git a/setup.cfg b/setup.cfg index 1a3de1ba..e24ef4af 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ extend-ignore = per-file-ignores = mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214 - mpt_api_client/resources/catalog/products.py: WPS204 WPS215 + mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 mpt_api_client/resources/catalog/items.py: WPS215 mpt_api_client/resources/catalog/products_item_groups.py: WPS215 mpt_api_client/resources/catalog/products_parameter_groups.py: WPS215 @@ -48,6 +48,7 @@ per-file-ignores = tests/http/test_async_service.py: WPS204 WPS202 tests/http/test_service.py: WPS204 WPS202 tests/http/test_mixins.py: WPS204 WPS202 + tests/resources/catalog/test_products.py: WPS202 WPS210 tests/*: # Allow magic strings. diff --git a/tests/resources/catalog/test_products.py b/tests/resources/catalog/test_products.py index 787f5283..4c87a38a 100644 --- a/tests/resources/catalog/test_products.py +++ b/tests/resources/catalog/test_products.py @@ -1,4 +1,6 @@ +import httpx import pytest +import respx from mpt_api_client.resources.catalog.product_terms import ( AsyncTermService, @@ -42,14 +44,16 @@ def async_products_service(async_http_client): @pytest.mark.parametrize( - "method", ["get", "create", "update", "delete", "review", "publish", "unpublish"] + "method", + ["get", "create", "update", "delete", "review", "publish", "unpublish", "update_settings"], ) def test_mixins_present(products_service, method): assert hasattr(products_service, method) @pytest.mark.parametrize( - "method", ["get", "create", "update", "delete", "review", "publish", "unpublish"] + "method", + ["get", "create", "update", "delete", "review", "publish", "unpublish", "update_settings"], ) def test_async_mixins_present(async_products_service, method): assert hasattr(async_products_service, method) @@ -91,3 +95,43 @@ def test_async_property_services(async_products_service, service_method, expecte assert isinstance(property_service, expected_service_class) assert property_service.endpoint_params == {"product_id": "PRD-001"} + + +def test_update_settings(products_service): + """Test updating product settings.""" + product_id = "PRD-001" + settings_data = {"visibility": "public", "searchable": True, "featured": False} + expected_response = {"id": product_id, "name": "Test Product", "settings": settings_data} + + with respx.mock: + mock_route = respx.put( + f"https://api.example.com/public/v1/catalog/products/{product_id}/settings" + ).mock(return_value=httpx.Response(httpx.codes.OK, json=expected_response)) + + product = products_service.update_settings(product_id, settings_data) + + assert mock_route.call_count == 1 + request = mock_route.calls[0].request + assert request.method == "PUT" + assert request.url.path == f"/public/v1/catalog/products/{product_id}/settings" + assert product.to_dict() == expected_response + + +async def test_async_update_settings(async_products_service): + """Test updating product settings asynchronously.""" + product_id = "PRD-002" + settings_data = {"visibility": "private", "searchable": False, "featured": True} + expected_response = {"id": product_id, "name": "Test Product Async", "settings": settings_data} + + with respx.mock: + mock_route = respx.put( + f"https://api.example.com/public/v1/catalog/products/{product_id}/settings" + ).mock(return_value=httpx.Response(httpx.codes.OK, json=expected_response)) + + product = await async_products_service.update_settings(product_id, settings_data) + + assert mock_route.call_count == 1 + request = mock_route.calls[0].request + assert request.method == "PUT" + assert request.url.path == f"/public/v1/catalog/products/{product_id}/settings" + assert product.to_dict() == expected_response From 2f2997494c3e39bab69dac592a87a3d13abf06cb Mon Sep 17 00:00:00 2001 From: Albert Sola Date: Thu, 11 Sep 2025 16:38:55 +0100 Subject: [PATCH 2/2] MPT-13327 Add catalog authorizations --- .../resources/catalog/authorizations.py | 42 +++++++++++++++++++ mpt_api_client/resources/catalog/catalog.py | 14 +++++++ setup.cfg | 1 + .../resources/catalog/test_authorizations.py | 26 ++++++++++++ tests/resources/catalog/test_catalog.py | 6 +++ 5 files changed, 89 insertions(+) create mode 100644 mpt_api_client/resources/catalog/authorizations.py create mode 100644 tests/resources/catalog/test_authorizations.py diff --git a/mpt_api_client/resources/catalog/authorizations.py b/mpt_api_client/resources/catalog/authorizations.py new file mode 100644 index 00000000..dbc1cbda --- /dev/null +++ b/mpt_api_client/resources/catalog/authorizations.py @@ -0,0 +1,42 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncCreateMixin, + AsyncDeleteMixin, + AsyncUpdateMixin, + CreateMixin, + DeleteMixin, + UpdateMixin, +) +from mpt_api_client.models import Model + + +class Authorization(Model): + """Authorization resource.""" + + +class AuthorizationsServiceConfig: + """Authorizations service configuration.""" + + _endpoint = "/public/v1/catalog/authorizations" + _model_class = Authorization + _collection_key = "data" + + +class AuthorizationsService( + CreateMixin[Authorization], + DeleteMixin, + UpdateMixin[Authorization], + Service[Authorization], + AuthorizationsServiceConfig, +): + """Authorizations service.""" + + +class AsyncAuthorizationsService( + AsyncCreateMixin[Authorization], + AsyncDeleteMixin, + AsyncUpdateMixin[Authorization], + AsyncService[Authorization], + AuthorizationsServiceConfig, +): + """Authorizations service.""" diff --git a/mpt_api_client/resources/catalog/catalog.py b/mpt_api_client/resources/catalog/catalog.py index 53b61766..999d169c 100644 --- a/mpt_api_client/resources/catalog/catalog.py +++ b/mpt_api_client/resources/catalog/catalog.py @@ -1,4 +1,8 @@ from mpt_api_client.http import AsyncHTTPClient, HTTPClient +from mpt_api_client.resources.catalog.authorizations import ( + AsyncAuthorizationsService, + AuthorizationsService, +) from mpt_api_client.resources.catalog.items import AsyncItemsService, ItemsService from mpt_api_client.resources.catalog.products import AsyncProductsService, ProductsService @@ -9,6 +13,11 @@ class Catalog: def __init__(self, *, http_client: HTTPClient): self.http_client = http_client + @property + def authorizations(self) -> AuthorizationsService: + """Authorizations service.""" + return AuthorizationsService(http_client=self.http_client) + @property def products(self) -> ProductsService: """Products service.""" @@ -26,6 +35,11 @@ class AsyncCatalog: def __init__(self, *, http_client: AsyncHTTPClient): self.http_client = http_client + @property + def authorizations(self) -> AsyncAuthorizationsService: + """Authorizations service.""" + return AsyncAuthorizationsService(http_client=self.http_client) + @property def products(self) -> AsyncProductsService: """Products service.""" diff --git a/setup.cfg b/setup.cfg index e24ef4af..24f1b99a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,6 +33,7 @@ extend-ignore = per-file-ignores = mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214 + mpt_api_client/resources/catalog/authorizations.py: WPS215 mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 mpt_api_client/resources/catalog/items.py: WPS215 mpt_api_client/resources/catalog/products_item_groups.py: WPS215 diff --git a/tests/resources/catalog/test_authorizations.py b/tests/resources/catalog/test_authorizations.py new file mode 100644 index 00000000..e8fa0008 --- /dev/null +++ b/tests/resources/catalog/test_authorizations.py @@ -0,0 +1,26 @@ +import pytest + +from mpt_api_client.resources.catalog.authorizations import ( + AsyncAuthorizationsService, + AuthorizationsService, +) + + +@pytest.fixture +def authorizations_service(http_client): + return AuthorizationsService(http_client=http_client) + + +@pytest.fixture +def async_authorizations_service(async_http_client): + return AsyncAuthorizationsService(http_client=async_http_client) + + +@pytest.mark.parametrize("method", ["get", "create", "update", "delete"]) +def test_mixins_present(authorizations_service, method): + assert hasattr(authorizations_service, method) + + +@pytest.mark.parametrize("method", ["get", "create", "update", "delete"]) +def test_async_mixins_present(async_authorizations_service, method): + assert hasattr(async_authorizations_service, method) diff --git a/tests/resources/catalog/test_catalog.py b/tests/resources/catalog/test_catalog.py index 06212d41..4afcfa5e 100644 --- a/tests/resources/catalog/test_catalog.py +++ b/tests/resources/catalog/test_catalog.py @@ -1,5 +1,9 @@ import pytest +from mpt_api_client.resources.catalog.authorizations import ( + AsyncAuthorizationsService, + AuthorizationsService, +) from mpt_api_client.resources.catalog.catalog import AsyncCatalog, Catalog from mpt_api_client.resources.catalog.items import AsyncItemsService, ItemsService from mpt_api_client.resources.catalog.products import AsyncProductsService, ProductsService @@ -18,6 +22,7 @@ def async_catalog(async_http_client): @pytest.mark.parametrize( ("property_name", "expected_service_class"), [ + ("authorizations", AuthorizationsService), ("products", ProductsService), ("items", ItemsService), ], @@ -33,6 +38,7 @@ def test_catalog_properties(catalog, property_name, expected_service_class): @pytest.mark.parametrize( ("property_name", "expected_service_class"), [ + ("authorizations", AsyncAuthorizationsService), ("products", AsyncProductsService), ("items", AsyncItemsService), ],