diff --git a/e2e_config.test.json b/e2e_config.test.json index d19b362c..4130e22f 100644 --- a/e2e_config.test.json +++ b/e2e_config.test.json @@ -10,7 +10,7 @@ "accounts.module.name": "Access Management", "accounts.seller.id": "SEL-7310-3075", "accounts.user_group.id": "UGR-6822-0561", - "catalog.item.id": "ITM-7255-3950-0001", + "catalog.product.item.id": "ITM-7255-3950-0751", "catalog.product.document.id": "PDC-7255-3950-0001", "catalog.product.id": "PRD-7255-3950", "catalog.product.item_group.id": "IGR-7255-3950-0001", diff --git a/mpt_api_client/resources/catalog/pricing_policies.py b/mpt_api_client/resources/catalog/pricing_policies.py index e8ee5502..23b66673 100644 --- a/mpt_api_client/resources/catalog/pricing_policies.py +++ b/mpt_api_client/resources/catalog/pricing_policies.py @@ -4,11 +4,9 @@ ) from mpt_api_client.http.mixins import ( AsyncCollectionMixin, - AsyncCreateMixin, - AsyncDeleteMixin, + AsyncManagedResourceMixin, CollectionMixin, - CreateMixin, - DeleteMixin, + ManagedResourceMixin, ) from mpt_api_client.models import Model, ResourceData from mpt_api_client.resources.catalog.pricing_policy_attachments import ( @@ -30,8 +28,7 @@ class PricingPoliciesServiceConfig: class PricingPoliciesService( # noqa: WPS215 - CreateMixin[PricingPolicy], - DeleteMixin, + ManagedResourceMixin[PricingPolicy], CollectionMixin[PricingPolicy], Service[PricingPolicy], PricingPoliciesServiceConfig, @@ -45,7 +42,9 @@ def attachments(self, pricing_policy_id: str) -> PricingPolicyAttachmentsService endpoint_params={"pricing_policy_id": pricing_policy_id}, ) - def activate(self, resource_id: str, resource_data: ResourceData) -> PricingPolicy: + def activate( + self, resource_id: str, resource_data: ResourceData | None = None + ) -> PricingPolicy: """Activate pricing policy. Args: @@ -57,7 +56,7 @@ def activate(self, resource_id: str, resource_data: ResourceData) -> PricingPoli """ return self._resource_action(resource_id, "POST", "activate", json=resource_data) - def disable(self, resource_id: str, resource_data: ResourceData) -> PricingPolicy: + def disable(self, resource_id: str, resource_data: ResourceData | None = None) -> PricingPolicy: """Disable pricing policy. Args: @@ -71,8 +70,7 @@ def disable(self, resource_id: str, resource_data: ResourceData) -> PricingPolic class AsyncPricingPoliciesService( - AsyncCreateMixin[PricingPolicy], - AsyncDeleteMixin, + AsyncManagedResourceMixin[PricingPolicy], AsyncCollectionMixin[PricingPolicy], AsyncService[PricingPolicy], PricingPoliciesServiceConfig, @@ -86,7 +84,9 @@ def attachments(self, pricing_policy_id: str) -> AsyncPricingPolicyAttachmentsSe endpoint_params={"pricing_policy_id": pricing_policy_id}, ) - async def activate(self, resource_id: str, resource_data: ResourceData) -> PricingPolicy: + async def activate( + self, resource_id: str, resource_data: ResourceData | None = None + ) -> PricingPolicy: """Activate pricing policy. Args: @@ -98,7 +98,9 @@ async def activate(self, resource_id: str, resource_data: ResourceData) -> Prici """ return await self._resource_action(resource_id, "POST", "activate", json=resource_data) - async def disable(self, resource_id: str, resource_data: ResourceData) -> PricingPolicy: + async def disable( + self, resource_id: str, resource_data: ResourceData | None = None + ) -> PricingPolicy: """Disable pricing policy. Args: diff --git a/tests/e2e/accounts/account/test_async_account.py b/tests/e2e/accounts/account/test_async_account.py index ca12d72a..7de87ac4 100644 --- a/tests/e2e/accounts/account/test_async_account.py +++ b/tests/e2e/accounts/account/test_async_account.py @@ -15,7 +15,7 @@ async def async_created_account(logger, async_mpt_ops, account_factory, account_ yield res_account try: - await async_mpt_ops.accounts.accounts.deactivate(res_account.id) + await async_mpt_ops.accounts.accounts.disable(res_account.id) except MPTAPIError as error: print("TEARDOWN - Unable to deactivate account: %s", error.title) # noqa: WPS421 diff --git a/tests/e2e/accounts/account/test_sync_account.py b/tests/e2e/accounts/account/test_sync_account.py index 57071088..9742dfe8 100644 --- a/tests/e2e/accounts/account/test_sync_account.py +++ b/tests/e2e/accounts/account/test_sync_account.py @@ -15,7 +15,7 @@ def created_account(logger, mpt_ops, account_factory, account_icon): yield res_account try: - mpt_ops.accounts.accounts.deactivate(res_account.id) + mpt_ops.accounts.accounts.disable(res_account.id) except MPTAPIError as error: print("TEARDOWN - Unable to deactivate account: %s", error.title) # noqa: WPS421 diff --git a/tests/e2e/accounts/sellers/test_async_sellers.py b/tests/e2e/accounts/sellers/test_async_sellers.py index 22de5417..3e90a82a 100644 --- a/tests/e2e/accounts/sellers/test_async_sellers.py +++ b/tests/e2e/accounts/sellers/test_async_sellers.py @@ -97,7 +97,7 @@ async def test_update_seller_mpt_error(async_mpt_ops, seller_factory, timestamp, async def test_activate_seller(async_mpt_ops, async_created_seller, timestamp): seller_data = await async_created_seller(external_id=f"Async Activate E2E Seller - {timestamp}") - await async_mpt_ops.accounts.sellers.deactivate(seller_data.id) + await async_mpt_ops.accounts.sellers.disable(seller_data.id) activated_seller = await async_mpt_ops.accounts.sellers.activate(seller_data.id) assert activated_seller is not None @@ -112,14 +112,14 @@ async def test_deactivate_seller(async_mpt_ops, async_created_seller, timestamp) seller_data = await async_created_seller( external_id=f"Async Deactivate E2E Seller - {timestamp}" ) - deactivated_seller = await async_mpt_ops.accounts.sellers.deactivate(seller_data.id) + deactivated_seller = await async_mpt_ops.accounts.sellers.disable(seller_data.id) assert deactivated_seller is not None async def test_deactivate_seller_mpt_error(async_mpt_ops, invalid_seller_id): with pytest.raises(MPTAPIError): - await async_mpt_ops.accounts.sellers.deactivate(invalid_seller_id) + await async_mpt_ops.accounts.sellers.disable(invalid_seller_id) async def test_disable_seller(async_mpt_ops, async_created_seller, timestamp): diff --git a/tests/e2e/accounts/sellers/test_sync_sellers.py b/tests/e2e/accounts/sellers/test_sync_sellers.py index f91b554d..14ff0e6d 100644 --- a/tests/e2e/accounts/sellers/test_sync_sellers.py +++ b/tests/e2e/accounts/sellers/test_sync_sellers.py @@ -96,7 +96,7 @@ def test_update_seller_mpt_error(mpt_ops, seller_factory, timestamp, invalid_sel def test_activate_seller(mpt_ops, created_seller, timestamp): seller_data = created_seller(external_id=f"Activate E2E Seller - {timestamp}") - mpt_ops.accounts.sellers.deactivate(seller_data.id) + mpt_ops.accounts.sellers.disable(seller_data.id) activated_seller = mpt_ops.accounts.sellers.activate(seller_data.id) assert activated_seller is not None @@ -109,14 +109,14 @@ def test_activate_seller_mpt_error(mpt_ops, invalid_seller_id): def test_deactivate_seller(mpt_ops, created_seller, timestamp): seller_data = created_seller(external_id=f"Deactivate E2E Seller - {timestamp}") - deactivated_seller = mpt_ops.accounts.sellers.deactivate(seller_data.id) + deactivated_seller = mpt_ops.accounts.sellers.disable(seller_data.id) assert deactivated_seller is not None def test_deactivate_seller_mpt_error(mpt_ops, invalid_seller_id): with pytest.raises(MPTAPIError): - mpt_ops.accounts.sellers.deactivate(invalid_seller_id) + mpt_ops.accounts.sellers.disable(invalid_seller_id) def test_disable_seller(mpt_ops, created_seller, timestamp): diff --git a/tests/e2e/catalog/conftest.py b/tests/e2e/catalog/conftest.py index 98f74b06..17facc11 100644 --- a/tests/e2e/catalog/conftest.py +++ b/tests/e2e/catalog/conftest.py @@ -3,7 +3,7 @@ @pytest.fixture def item_id(e2e_config): - return e2e_config.get("catalog.item.id") + return e2e_config.get("catalog.product.item.id") @pytest.fixture diff --git a/tests/e2e/catalog/pricing_policies/conftest.py b/tests/e2e/catalog/pricing_policies/conftest.py new file mode 100644 index 00000000..9cdcef9c --- /dev/null +++ b/tests/e2e/catalog/pricing_policies/conftest.py @@ -0,0 +1,23 @@ +import pytest + + +@pytest.fixture +def buyer_id(e2e_config): + return e2e_config["accounts.buyer.account.id"] + + +@pytest.fixture +def pricing_policy_data(buyer_id, product_id): + return { + "name": "e2e - pricing policy please delete", + "description": "Test pricing policy description", + "client": {"id": buyer_id}, + "product": {"id": product_id}, + "eligibility": {"client": True, "partner": False}, + "margin": "0.20", + } + + +@pytest.fixture +def pricing_policy_id(e2e_config): + return e2e_config.get("catalog.pricing_policy.id") diff --git a/tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py b/tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py new file mode 100644 index 00000000..07dc685c --- /dev/null +++ b/tests/e2e/catalog/pricing_policies/test_async_pricing_policies.py @@ -0,0 +1,83 @@ +import pytest + +from mpt_api_client.exceptions import MPTAPIError +from mpt_api_client.rql.query_builder import RQLQuery + +pytestmark = [pytest.mark.flaky] + + +@pytest.fixture +def async_pricing_policies_service(async_mpt_ops): + return async_mpt_ops.catalog.pricing_policies + + +@pytest.fixture +async def async_created_pricing_policy(async_pricing_policies_service, pricing_policy_data): + policy = await async_pricing_policies_service.create(pricing_policy_data) + + yield policy + + try: + await async_pricing_policies_service.delete(policy.id) + except MPTAPIError as error: + print(f"TEARDOWN - Unable to delete pricing policy {policy.id}: {error.title}") + + +def test_create_pricing_policy(async_created_pricing_policy, pricing_policy_data): + assert async_created_pricing_policy.name == pricing_policy_data["name"] + + +async def test_get_pricing_policy(async_pricing_policies_service, async_created_pricing_policy): + fetched = await async_pricing_policies_service.get(async_created_pricing_policy.id) + assert fetched.id == async_created_pricing_policy.id + + +async def test_get_pricing_policy_by_id( + async_pricing_policies_service, async_created_pricing_policy +): + fetched = await async_pricing_policies_service.get(async_created_pricing_policy.id) + assert fetched.id == async_created_pricing_policy.id + + +async def test_iterate_pricing_policies( + async_pricing_policies_service, async_created_pricing_policy +): + policies = [policy async for policy in async_pricing_policies_service.iterate()] + assert any(policy.id == async_created_pricing_policy.id for policy in policies) + + +async def test_filter_pricing_policies( + async_pricing_policies_service, async_created_pricing_policy +): + target_id = async_created_pricing_policy.id + select_fields = ["-description"] + filtered = async_pricing_policies_service.filter(RQLQuery(id=target_id)).select(*select_fields) + policies = [policy async for policy in filtered.iterate()] + assert len(policies) == 1 + assert policies[0].id == target_id + + +async def test_activate_deactivate_pricing_policy( + async_pricing_policies_service, async_created_pricing_policy +): + deactivate = await async_pricing_policies_service.disable(async_created_pricing_policy.id) + assert deactivate.id == async_created_pricing_policy.id + + activated = await async_pricing_policies_service.activate(async_created_pricing_policy.id) + assert activated.id == async_created_pricing_policy.id + + +async def test_delete_pricing_policy(async_pricing_policies_service, async_created_pricing_policy): + await async_pricing_policies_service.delete(async_created_pricing_policy.id) # act + + +async def test_get_pricing_policy_not_found(async_pricing_policies_service): + bogus_id = "PPY-0000-NOTFOUND" + with pytest.raises(MPTAPIError, match=r"404 Not Found"): + await async_pricing_policies_service.get(bogus_id) + + +async def test_create_pricing_policy_invalid_data(async_pricing_policies_service): + invalid_data = {"name": "e2e - delete me", "description": "invalid data"} + with pytest.raises(MPTAPIError, match=r"400 One or more validation errors occurred"): + await async_pricing_policies_service.create(invalid_data) diff --git a/tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py b/tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py new file mode 100644 index 00000000..ba479509 --- /dev/null +++ b/tests/e2e/catalog/pricing_policies/test_sync_pricing_policies.py @@ -0,0 +1,77 @@ +import pytest + +from mpt_api_client.exceptions import MPTAPIError +from mpt_api_client.rql.query_builder import RQLQuery + +pytestmark = [pytest.mark.flaky] + + +@pytest.fixture +def pricing_policies_service(mpt_ops): + return mpt_ops.catalog.pricing_policies + + +@pytest.fixture +def created_pricing_policy(pricing_policies_service, pricing_policy_data): + policy = pricing_policies_service.create(pricing_policy_data) + + yield policy + + try: + pricing_policies_service.delete(policy.id) + except MPTAPIError as error: + print(f"TEARDOWN - Unable to delete pricing policy {policy.id}: {error.title}") + + +def test_create_pricing_policy(created_pricing_policy, pricing_policy_data): + assert created_pricing_policy.name == pricing_policy_data["name"] + + +def test_get_pricing_policy(pricing_policies_service, created_pricing_policy): + fetched = pricing_policies_service.get(created_pricing_policy.id) + assert fetched.id == created_pricing_policy.id + + +def test_get_pricing_policy_by_id(pricing_policies_service, pricing_policy_id): + if not pricing_policy_id: + pytest.skip("No pricing_policy_id configured") + fetched = pricing_policies_service.get(pricing_policy_id) + assert fetched.id == pricing_policy_id + + +def test_iterate_pricing_policies(pricing_policies_service, created_pricing_policy): + policies = list(pricing_policies_service.iterate()) + assert any(policy.id == created_pricing_policy.id for policy in policies) + + +def test_filter_pricing_policies(pricing_policies_service, created_pricing_policy): + target_id = created_pricing_policy.id + select_fields = ["-description"] + filtered = pricing_policies_service.filter(RQLQuery(id=target_id)).select(*select_fields) + policies = list(filtered.iterate()) + assert len(policies) == 1 + assert policies[0].id == target_id + + +def test_activate_deactivate_pricing_policy(pricing_policies_service, created_pricing_policy): + deactivate = pricing_policies_service.disable(created_pricing_policy.id) + assert deactivate.id == created_pricing_policy.id + + activated = pricing_policies_service.activate(deactivate.id) + assert activated.id == created_pricing_policy.id + + +def test_delete_pricing_policy(pricing_policies_service, created_pricing_policy): + pricing_policies_service.delete(created_pricing_policy.id) # act + + +def test_get_pricing_policy_not_found(pricing_policies_service): + bogus_id = "PPY-0000-NOTFOUND" + with pytest.raises(MPTAPIError, match=r"404 Not Found"): + pricing_policies_service.get(bogus_id) + + +def test_create_pricing_policy_invalid_data(pricing_policies_service): + invalid_data = {"name": "e2e - delete me", "description": "invalid data"} + with pytest.raises(MPTAPIError, match=r"400 One or more validation errors occurred"): + pricing_policies_service.create(invalid_data) diff --git a/tests/unit/resources/catalog/test_pricing_policies.py b/tests/unit/resources/catalog/test_pricing_policies.py index c241f75c..69c2ae86 100644 --- a/tests/unit/resources/catalog/test_pricing_policies.py +++ b/tests/unit/resources/catalog/test_pricing_policies.py @@ -140,3 +140,19 @@ def test_async_property_services( assert isinstance(property_service, expected_service_class) assert property_service.endpoint_params == {"pricing_policy_id": "PRP-0000-0001"} + + +@pytest.mark.parametrize( + "method", + ["get", "create", "update", "delete", "activate", "disable"], +) +def test_mixins_present(pricing_policies_service, method): + assert hasattr(pricing_policies_service, method) + + +@pytest.mark.parametrize( + "method", + ["get", "create", "update", "delete", "activate", "disable"], +) +def test_async_mixins_present(async_pricing_policies_service, method): + assert hasattr(async_pricing_policies_service, method)