Skip to content

Commit 094ff1c

Browse files
author
Robert Segal
committed
Added seeding and e2e tests for commerce orders
1 parent d4ca602 commit 094ff1c

File tree

12 files changed

+497
-26
lines changed

12 files changed

+497
-26
lines changed

e2e_config.test.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"commerce.product.id": "PRD-1767-7355",
3333
"commerce.product.item.id": "ITM-1767-7355-0001",
3434
"commerce.product.listing.id": "LST-5489-0806",
35-
"commerce.product.template.id": "TPL-1767-7355-0003",
35+
"commerce.product.template.id": "TPL-1767-7355-0002",
36+
"commerce.user.id": "USR-4303-2348",
3637
"notifications.message.id": "MSG-0000-6215-1019-0139"
3738
}

mpt_api_client/resources/commerce/orders.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,30 @@ def template(self, resource_id: str) -> str:
105105
response = self._resource_do_request(resource_id, "GET", "template")
106106
return response.text
107107

108+
def render(self, resource_id: str) -> str:
109+
"""Render order template.
110+
111+
Args:
112+
resource_id: Order resource ID
113+
114+
Returns:
115+
Render template text in markdown format.
116+
"""
117+
response = self._resource_do_request(resource_id, "GET", "render")
118+
return response.text
119+
120+
def quote(self, resource_id: str, resource_data: ResourceData | None = None) -> Order:
121+
"""Quote the order.
122+
123+
Args:
124+
resource_id: Order resource ID
125+
resource_data: Order data will be updated
126+
127+
Returns:
128+
Quoted order resource.
129+
"""
130+
return self._resource_action(resource_id, "POST", "quote", json=resource_data)
131+
108132
def subscriptions(self, order_id: str) -> OrderSubscriptionsService:
109133
"""Get the subscription service for the given Order id.
110134
@@ -223,6 +247,30 @@ async def template(self, resource_id: str) -> str:
223247
response = await self._resource_do_request(resource_id, "GET", "template")
224248
return response.text
225249

250+
async def render(self, resource_id: str) -> str:
251+
"""Render order template.
252+
253+
Args:
254+
resource_id: Order resource ID
255+
256+
Returns:
257+
Render template text in markdown format.
258+
"""
259+
response = await self._resource_do_request(resource_id, "GET", "render")
260+
return response.text
261+
262+
async def quote(self, resource_id: str, resource_data: ResourceData | None = None) -> Order:
263+
"""Quote the order.
264+
265+
Args:
266+
resource_id: Order resource ID
267+
resource_data: Order data will be updated
268+
269+
Returns:
270+
Quoted order resource.
271+
"""
272+
return await self._resource_action(resource_id, "POST", "quote", json=resource_data)
273+
226274
def subscriptions(self, order_id: str) -> AsyncOrderSubscriptionsService:
227275
"""Get the subscription service for the given Order id.
228276

pyproject.toml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,31 +111,37 @@ select = ["AAA", "E999", "WPS"]
111111
show-source = true
112112
statistics = false
113113
per-file-ignores = [
114-
"mpt_api_client/mpt_client.py: WPS214 WPS235",
115114
"mpt_api_client/http/mixins.py: WPS202 WPS204 WPS235",
116-
"mpt_api_client/resources/*: WPS215",
117115
"mpt_api_client/models/model.py: WPS215 WPS110",
116+
"mpt_api_client/mpt_client.py: WPS214 WPS235",
117+
"mpt_api_client/resources/*: WPS215",
118118
"mpt_api_client/resources/accounts/*.py: WPS202 WPS215 WPS214 WPS235 WPS453",
119119
"mpt_api_client/resources/billing/*.py: WPS202 WPS204 WPS214 WPS215",
120120
"mpt_api_client/resources/catalog/*.py: WPS110 WPS214 WPS215 WPS235",
121121
"mpt_api_client/resources/catalog/mixins.py: WPS110 WPS202 WPS214 WPS215 WPS235",
122122
"mpt_api_client/resources/catalog/products.py: WPS204 WPS214 WPS215 WPS235",
123123
"mpt_api_client/rql/query_builder.py: WPS110 WPS115 WPS210 WPS214",
124+
"tests/e2e/accounts/*.py: WPS430 WPS202",
125+
"tests/e2e/catalog/*.py: WPS202 WPS421",
126+
"tests/e2e/catalog/items/*.py: WPS110 WPS202",
127+
"tests/e2e/commerce/*.py: WPS204 WPS453",
128+
"tests/e2e/commerce/agreement/*.py: WPS202",
129+
"tests/e2e/commerce/agreement/**/*.py: WPS202",
130+
"tests/e2e/commerce/order/*.py: WPS202 WPS204",
131+
"tests/e2e/commerce/order/**/*.py: WPS202 WPS204",
124132
"tests/unit/http/test_async_service.py: WPS204 WPS202",
125133
"tests/unit/http/test_service.py: WPS204 WPS202",
126134
"tests/unit/http/test_mixins.py: WPS204 WPS202 WPS210",
127-
"tests/unit/resources/catalog/test_products.py: WPS202 WPS210",
128135
"tests/unit/resources/accounts/*.py: WPS204 WPS202 WPS210",
136+
"tests/unit/resources/catalog/test_products.py: WPS202 WPS210",
137+
"tests/unit/resources/commerce/*.py: WPS202 WPS204",
129138
"tests/unit/resources/*/test_mixins.py: WPS118 WPS202 WPS204 WPS235",
130139
"tests/unit/test_mpt_client.py: WPS235",
131-
"tests/e2e/accounts/*.py: WPS430 WPS202",
132-
"tests/e2e/catalog/*.py: WPS202 WPS421",
133-
"tests/e2e/catalog/items/*.py: WPS110 WPS202",
134140
"tests/seed/catalog/test_product.py: WPS202 WPS204 WPS219",
135141
"tests/*: WPS432 WPS202",
136142
"seed/*: WPS404",
137143
"seed/accounts/*.py: WPS204 WPS404 WPS453",
138-
"seed/catalog/product.py: WPS202 WPS204 WPS217 WPS201 WPS213 WPS404"
144+
"seed/catalog/product.py: WPS202 WPS204 WPS217 WPS201 WPS213 WPS404",
139145
]
140146

141147
[tool.ruff]

tests/e2e/commerce/agreement/attachment/test_async_agreement_attachment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ async def test_filter_agreement_attachments(agreement_attachments, agreement_att
5252
assert len(result) == 1
5353

5454

55-
def test_create_agreement_attachment(created_agreement_attachment):
55+
def test_create_order_agreement_attachment(created_agreement_attachment):
5656
result = created_agreement_attachment
5757

5858
assert result is not None

tests/e2e/commerce/agreement/attachment/test_sync_agreement_attachment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def test_filter_agreement_attachments(agreement_attachments, agreement_attachmen
5454
assert len(result) == 1
5555

5656

57-
def test_create_agreement_attachment(created_agreement_attachment):
57+
def test_create_order_agreement_attachment(created_agreement_attachment):
5858
result = created_agreement_attachment
5959

6060
assert result is not None

tests/e2e/commerce/conftest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,23 @@ def agreement_id(e2e_config):
99
@pytest.fixture
1010
def commerce_product_id(e2e_config):
1111
return e2e_config["commerce.product.id"]
12+
13+
14+
@pytest.fixture
15+
def order_id(e2e_config):
16+
return e2e_config["commerce.order.id"]
17+
18+
19+
@pytest.fixture
20+
def commerce_item_id(e2e_config):
21+
return e2e_config["commerce.product.item.id"]
22+
23+
24+
@pytest.fixture
25+
def commerce_product_template_id(e2e_config):
26+
return e2e_config["commerce.product.template.id"]
27+
28+
29+
@pytest.fixture
30+
def commerce_user_id(e2e_config):
31+
return e2e_config["commerce.user.id"]
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import pytest
2+
from freezegun import freeze_time
3+
4+
5+
@pytest.fixture
6+
def invalid_order_id():
7+
return "ORD-0000-0000"
8+
9+
10+
@pytest.fixture
11+
@freeze_time("2025-12-01T10:00:00.000Z")
12+
def order_factory(licensee_id, commerce_product_id, commerce_item_id, authorization_id):
13+
def factory(
14+
notes: str = "E2E Created Order",
15+
line_item_period: str = "1y",
16+
line_item_commitment: str = "1y",
17+
line_quantity: int = 10,
18+
):
19+
return {
20+
"agreement": {
21+
"licensee": {"id": licensee_id},
22+
"product": {"id": commerce_product_id},
23+
},
24+
"authorization": {"id": authorization_id},
25+
"type": "Purchase",
26+
"status": "Draft",
27+
"parameters": {
28+
"ordering": [],
29+
"fulfillment": [],
30+
},
31+
"notes": notes,
32+
"lines": [
33+
{
34+
"item": {
35+
"id": commerce_item_id,
36+
"terms": {
37+
"model": "quantity",
38+
"period": line_item_period,
39+
"commitment": line_item_commitment,
40+
},
41+
},
42+
"price": {
43+
"currency": "USD",
44+
"unitSP": 15,
45+
"SPx1": None,
46+
"SPxM": 1.25,
47+
"SPxY": 15,
48+
},
49+
"quantity": line_quantity,
50+
}
51+
],
52+
}
53+
54+
return factory
55+
56+
57+
@pytest.fixture
58+
def order_subscription_factory():
59+
def factory(
60+
line_id: str,
61+
name: str = "E2E Created Order Subscription",
62+
):
63+
return {
64+
"name": name,
65+
"parameters": {"fulfillment": []},
66+
"lines": [{"id": line_id}],
67+
"terms": {"model": "quantity", "period": "1y", "commitment": "1y"},
68+
"autoRenew": True,
69+
"template": None,
70+
}
71+
72+
return factory
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import pytest
2+
3+
from mpt_api_client.exceptions import MPTAPIError
4+
from mpt_api_client.rql.query_builder import RQLQuery
5+
6+
pytestmark = [pytest.mark.flaky]
7+
8+
9+
@pytest.fixture
10+
async def created_order(async_mpt_client, order_factory):
11+
new_order_request_data = order_factory()
12+
13+
return await async_mpt_client.commerce.orders.create(new_order_request_data)
14+
15+
16+
@pytest.fixture
17+
async def processed_order(async_mpt_client, created_order):
18+
return await async_mpt_client.commerce.orders.process(created_order.id)
19+
20+
21+
async def test_get_order_by_id(async_mpt_client, order_id):
22+
result = await async_mpt_client.commerce.orders.get(order_id)
23+
24+
assert result is not None
25+
26+
27+
async def test_list_orders(async_mpt_client):
28+
limit = 10
29+
30+
result = await async_mpt_client.commerce.orders.fetch_page(limit=limit)
31+
32+
assert len(result) > 0
33+
34+
35+
async def test_get_order_by_id_not_found(async_mpt_client, invalid_order_id):
36+
with pytest.raises(MPTAPIError, match=r"404 Not Found"):
37+
await async_mpt_client.commerce.orders.get(invalid_order_id)
38+
39+
40+
async def test_filter_orders(async_mpt_client, order_id):
41+
select_fields = ["-authorization"]
42+
filtered_orders = (
43+
async_mpt_client.commerce.orders.filter(RQLQuery(id=order_id))
44+
.filter(RQLQuery(type="Purchase"))
45+
.select(*select_fields)
46+
)
47+
48+
result = [order async for order in filtered_orders.iterate()]
49+
50+
assert len(result) == 1
51+
52+
53+
def test_create_order(created_order):
54+
result = created_order
55+
56+
assert result is not None
57+
58+
59+
async def test_update_order(async_mpt_client, created_order, order_factory):
60+
update_data = order_factory(notes="E2E Updated Order Notes")
61+
62+
result = await async_mpt_client.commerce.orders.update(created_order.id, update_data)
63+
64+
assert result is not None
65+
66+
67+
async def test_process_order(async_mpt_client, created_order):
68+
result = await async_mpt_client.commerce.orders.process(created_order.id)
69+
70+
assert result is not None
71+
72+
73+
async def test_query_order(async_mpt_vendor, async_mpt_client, created_order):
74+
processed_order = await async_mpt_client.commerce.orders.process(created_order.id)
75+
76+
result = await async_mpt_vendor.commerce.orders.query(processed_order.id)
77+
78+
assert result is not None
79+
80+
81+
async def test_complete_order(async_mpt_vendor, order_subscription_factory, processed_order):
82+
processed_order_lines = processed_order.lines
83+
line_id = processed_order_lines[0].id
84+
order_subscription = order_subscription_factory(line_id)
85+
order_subscriptions = async_mpt_vendor.commerce.orders.subscriptions(processed_order.id)
86+
await order_subscriptions.create(order_subscription)
87+
88+
result = await async_mpt_vendor.commerce.orders.complete(processed_order.id)
89+
90+
assert result is not None
91+
92+
93+
async def test_fail_order(async_mpt_vendor, processed_order):
94+
fail_order_data = {
95+
"statusNotes": {
96+
"message": "Failing order for E2E test",
97+
"id": processed_order.id,
98+
}
99+
}
100+
101+
result = await async_mpt_vendor.commerce.orders.fail(processed_order.id, fail_order_data)
102+
103+
assert result is not None
104+
105+
106+
async def test_delete_draft_order(async_mpt_client, created_order):
107+
await async_mpt_client.commerce.orders.delete(created_order.id)
108+
109+
110+
async def test_quote_order(async_mpt_client, created_order):
111+
result = await async_mpt_client.commerce.orders.quote(created_order.id)
112+
113+
assert result is not None
114+
115+
116+
async def test_validate_order(async_mpt_client, created_order):
117+
result = await async_mpt_client.commerce.orders.validate(created_order.id)
118+
119+
assert result is not None
120+
121+
122+
async def test_order_template(async_mpt_client, created_order):
123+
result = await async_mpt_client.commerce.orders.template(created_order.id)
124+
125+
assert result is not None
126+
127+
128+
async def test_order_render(async_mpt_client, created_order):
129+
result = await async_mpt_client.commerce.orders.render(created_order.id)
130+
131+
assert result is not None
132+
133+
134+
async def test_notify_order(async_mpt_client, created_order, commerce_user_id):
135+
user_data = {
136+
"userId": commerce_user_id,
137+
"notifyMe": False,
138+
}
139+
await async_mpt_client.commerce.orders.quote(created_order.id)
140+
141+
await async_mpt_client.commerce.orders.notify(created_order.id, user_data)

0 commit comments

Comments
 (0)