Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion e2e_config.test.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"catalog.product.id": "PRD-7255-3950",
"accounts.seller.id": "SEL-7310-3075"
"accounts.seller.id": "SEL-7310-3075",
"accounts.account.id": "ACC-9042-0088"
}
136 changes: 127 additions & 9 deletions mpt_api_client/resources/accounts/account.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
from typing import override

from mpt_api_client.http import AsyncService, Service
from mpt_api_client.http.mixins import (
AsyncCollectionMixin,
AsyncCreateMixin,
AsyncCreateWithIconMixin,
AsyncGetMixin,
AsyncUpdateMixin,
AsyncUpdateWithIconMixin,
CollectionMixin,
CreateMixin,
CreateWithIconMixin,
GetMixin,
UpdateMixin,
UpdateWithIconMixin,
)
from mpt_api_client.http.types import FileTypes
from mpt_api_client.models import Model
from mpt_api_client.models.model import ResourceData
from mpt_api_client.resources.accounts.accounts_users import (
AccountsUsersService,
AsyncAccountsUsersService,
Expand All @@ -31,14 +35,14 @@ class Account(Model):
class AccountsServiceConfig:
"""Accounts service configuration."""

_endpoint = "/public/v1/accounts"
_endpoint = "/public/v1/accounts/accounts"
_model_class = Account
_collection_key = "data"


class AccountsService(
CreateMixin[Account],
UpdateMixin[Account],
CreateWithIconMixin[Account],
UpdateWithIconMixin[Account],
ActivatableMixin[Account],
EnablableMixin[Account],
ValidateMixin[Account],
Expand All @@ -49,6 +53,63 @@ class AccountsService(
):
"""Accounts service."""

@override
def create(
self,
resource_data: ResourceData,
logo: FileTypes,
data_key: str = "account",
icon_key: str = "logo",
) -> Account:
"""
Create a new account with logo.

Args:
resource_data (ResourceData): Account data.
logo: Logo image in jpg, png, GIF, etc.
data_key: Key for the account data.
icon_key: Key for the logo.

Returns:
Account: The created account.
"""
return super().create(
resource_data=resource_data,
icon=logo,
data_key=data_key,
icon_key=icon_key,
)

@override
def update(
self,
resource_id: str,
resource_data: ResourceData,
logo: FileTypes,
data_key: str = "account",
icon_key: str = "logo",
) -> Account:
"""
Update an existing account with logo.

Args:
resource_id (str): The ID of the account to update.
resource_data (ResourceData): Account data.
logo: Logo image in jpg, png, GIF, etc.
data_key: Key for the account data.
icon_key: Key for the logo.

Returns:
Account: The updated account.
"""
return super().update(
resource_id=resource_id,
resource_data=resource_data,
icon=logo,
data_key=data_key,
icon_key=icon_key,
)

def users(self, account_id: str) -> AccountsUsersService:
"""Return account users service."""
return AccountsUsersService(
Expand All @@ -57,8 +118,8 @@ def users(self, account_id: str) -> AccountsUsersService:


class AsyncAccountsService(
AsyncCreateMixin[Account],
AsyncUpdateMixin[Account],
AsyncCreateWithIconMixin[Account],
AsyncUpdateWithIconMixin[Account],
AsyncActivatableMixin[Account],
AsyncEnablableMixin[Account],
AsyncValidateMixin[Account],
Expand All @@ -69,6 +130,63 @@ class AsyncAccountsService(
):
"""Async Accounts service."""

@override
async def create(
self,
resource_data: ResourceData,
logo: FileTypes,
data_key: str = "account",
icon_key: str = "logo",
) -> Account:
"""
Create a new account with logo.

Args:
resource_data (ResourceData): Account data.
logo: Logo image in jpg, png, GIF, etc.
data_key: Key for the account data.
icon_key: Key for the logo.

Returns:
Account: The created account.
"""
return await super().create(
resource_data=resource_data,
icon=logo,
data_key=data_key,
icon_key=icon_key,
)

@override
async def update(
self,
resource_id: str,
resource_data: ResourceData,
logo: FileTypes,
data_key: str = "account",
icon_key: str = "logo",
) -> Account:
"""
Update an existing account with logo.

Args:
resource_id (str): The ID of the account to update.
resource_data (ResourceData): Account data.
logo: Logo image in jpg, png, GIF, etc.
data_key: Key for the account data.
icon_key: Key for the logo.

Returns:
Account: The updated account.
"""
return await super().update(
resource_id=resource_id,
resource_data=resource_data,
icon=logo,
data_key=data_key,
icon_key=icon_key,
)

def users(self, account_id: str) -> AsyncAccountsUsersService:
"""Return account users service."""
return AsyncAccountsUsersService(
Expand Down
48 changes: 27 additions & 21 deletions tests/e2e/accounts/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,6 @@ def timestamp():
return int(dt.datetime.now(tz=dt.UTC).strftime("%Y%m%d%H%M%S"))


@pytest.fixture
def account_data():
return {
"name": "Test Api Client Vendor",
"address": {
"addressLine1": "123 Test St",
"city": "San Francisco",
"state": "CA",
"postCode": "12345",
"country": "US",
},
"type": "Vendor",
"status": "Active",
}


@pytest.fixture
def account_icon():
return pathlib.Path(__file__).parent / "logo.png"


@pytest.fixture
def currencies():
return ["USD", "EUR"]
Expand All @@ -56,3 +35,30 @@ def _seller(
}

return _seller


@pytest.fixture
def account():
def _account(
name: str = "Test Api Client Vendor",
external_id: str = "",
):
return {
"name": name,
"address": {
"addressLine1": "123 Test St",
"city": "San Francisco",
"state": "CA",
"postCode": "12345",
"country": "US",
},
"type": "Vendor",
"status": "Active",
}

return _account


@pytest.fixture
def account_icon():
return pathlib.Path.open(pathlib.Path(__file__).parents[1] / "logo.png", "rb")
109 changes: 109 additions & 0 deletions tests/e2e/accounts/test_async_account.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import pytest

from mpt_api_client import AsyncMPTClient
from mpt_api_client.exceptions import MPTAPIError
from mpt_api_client.rql.query_builder import RQLQuery

pytestmark = [pytest.mark.flaky]


@pytest.fixture
async def async_created_account(logger, async_mpt_ops, account, account_icon):
account_data = account()

res_account = await async_mpt_ops.accounts.accounts.create(account_data, logo=account_icon)

yield res_account

try:
await async_mpt_ops.accounts.accounts.deactivate(res_account.id)
except MPTAPIError as error:
print("TEARDOWN - Unable to deactivate account: %s", error.title) # noqa: WPS421


async def test_get_account_by_id_not_found(async_mpt_ops):
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
await async_mpt_ops.accounts.accounts.get("INVALID-ID")


async def test_get_account_by_id(async_mpt_ops, account_id):
account = await async_mpt_ops.accounts.accounts.get(account_id)
assert account is not None


async def test_list_accounts(async_mpt_ops):
limit = 10
accounts_page = await async_mpt_ops.accounts.accounts.fetch_page(limit=limit)
assert len(accounts_page) > 0


def test_create_account(async_created_account):
account = async_created_account
assert account is not None


async def test_update_account(async_mpt_ops, async_created_account, account, account_icon):
updated_data = account(name="Updated Account Name")

updated_account = await async_mpt_ops.accounts.accounts.update(
async_created_account.id, updated_data, logo=account_icon
)

assert updated_account is not None


async def test_update_account_invalid_data(
async_mpt_ops, account, async_created_account, account_icon
):
updated_data = account(name="")

with pytest.raises(MPTAPIError, match=r"400 Bad Request"):
await async_mpt_ops.accounts.accounts.update(
async_created_account.id, updated_data, logo=account_icon
)


async def test_update_account_not_found(async_mpt_ops, account, invalid_account_id, account_icon):
non_existent_account = account(name="Non Existent Account")

with pytest.raises(MPTAPIError, match=r"404 Not Found"):
await async_mpt_ops.accounts.accounts.update(
invalid_account_id, non_existent_account, logo=account_icon
)


async def test_account_enable(async_mpt_ops, account, async_created_account):
await async_mpt_ops.accounts.accounts.disable(async_created_account.id)

account = await async_mpt_ops.accounts.accounts.enable(async_created_account.id)

assert account is not None


async def test_account_enable_not_found(async_mpt_ops, invalid_account_id):
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
await async_mpt_ops.accounts.accounts.enable(invalid_account_id)


async def test_account_disable(async_mpt_ops, async_created_account):
account = await async_mpt_ops.accounts.accounts.disable(async_created_account.id)

assert account is not None


async def test_account_disable_not_found(async_mpt_ops, invalid_account_id):
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
await async_mpt_ops.accounts.accounts.disable(invalid_account_id)


async def test_account_rql_filter(async_mpt_ops, account_id):
selected_fields = ["-address"]
filtered_accounts = (
async_mpt_ops.accounts.accounts.filter(RQLQuery(id=account_id))
.filter(RQLQuery(name="Test Api Client Vendor"))
.select(*selected_fields)
)

accounts = [account async for account in filtered_accounts.iterate()]

assert len(accounts) > 0
2 changes: 1 addition & 1 deletion tests/e2e/accounts/test_async_sellers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ async def _async_created_seller(
try:
await async_mpt_ops.accounts.sellers.delete(ret_seller.id)
except MPTAPIError:
logger.exception("TEARDOWN - Unable to delete seller %s", ret_seller.id)
print("TEARDOWN - Unable to delete seller %s", ret_seller.id) # noqa: WPS421


async def test_get_seller_by_id(async_mpt_ops, seller_id):
Expand Down
Loading