Skip to content

Commit ca8797c

Browse files
authored
MPT-17590 Add usage item by default in the purchase wizard (#227)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> Closes [MPT-17590](https://softwareone.atlassian.net/browse/MPT-17590) - Add AWS_ITEMS_SKUS constant containing "AWS Usage" - Add add_default_lines(client, order) to fetch product items by SKU and append default order lines (quantity=1) - Add validate_order(client, order) to orchestrate parameter visibility update and default line injection - Update extension.py to call validate_order(request.client, order) in order validation endpoint - Update tests and fixtures to mock and cover validate_order behavior <!-- end of auto-generated comment: release notes by coderabbit.ai --> [MPT-17590]: https://softwareone.atlassian.net/browse/MPT-17590?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
2 parents 598ca26 + a01296d commit ca8797c

File tree

6 files changed

+150
-15
lines changed

6 files changed

+150
-15
lines changed

swo_aws_extension/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,6 @@ class ExpirationPeriodEnum(IntEnum):
195195

196196
CURRENT_MONTH = 1
197197
NEXT_MONTH = 2
198+
199+
200+
AWS_ITEMS_SKUS = ("AWS Usage",)

swo_aws_extension/extension.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from ninja import Body
1313

1414
from swo_aws_extension.flows.fulfillment.base import fulfill_order
15-
from swo_aws_extension.flows.validation.base import update_parameters_visibility
15+
from swo_aws_extension.flows.validation.base import validate_order
1616

1717
logger = logging.getLogger(__name__)
1818

@@ -43,7 +43,7 @@ def process_order_fulfillment(client, event):
4343
def process_order_validation(request, order: Annotated[dict, Body()]):
4444
"""Start order process validation."""
4545
try:
46-
validated_order = update_parameters_visibility(order)
46+
validated_order = validate_order(request.client, order)
4747
except Exception:
4848
logger.exception("Unexpected error during validation")
4949
return 400, {

swo_aws_extension/flows/validation/base.py

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import copy
22
import logging
33

4+
from mpt_extension_sdk.mpt_http.base import MPTClient
5+
from mpt_extension_sdk.mpt_http.mpt import get_product_items_by_skus
46
from mpt_extension_sdk.mpt_http.wrap_http_error import ValidationError
57

6-
from swo_aws_extension.constants import AccountTypesEnum, OrderParametersEnum
8+
from swo_aws_extension.constants import AWS_ITEMS_SKUS, AccountTypesEnum, OrderParametersEnum
79
from swo_aws_extension.parameters import (
810
get_account_type,
911
reset_ordering_parameters,
@@ -55,7 +57,58 @@ def _apply_account_type_constraints(order: dict, account_type: str | None) -> di
5557

5658
def update_parameters_visibility(order: dict) -> dict:
5759
"""Updates the visibility of parameters in the given order object."""
58-
updated_order = copy.deepcopy(order)
59-
updated_order = reset_ordering_parameters_error(updated_order)
60-
60+
updated_order = reset_ordering_parameters_error(order)
6161
return _apply_account_type_constraints(updated_order, get_account_type(updated_order))
62+
63+
64+
def add_default_lines(client: MPTClient, order: dict) -> dict:
65+
"""
66+
Add default line items to the order based on product SKUs.
67+
68+
Retrieves product items by SKUs and adds them as lines to the order
69+
with quantity 1 each.
70+
71+
Args:
72+
client: MPT client for API calls.
73+
order: The order dictionary to add lines to.
74+
75+
Returns:
76+
The order with default lines added.
77+
"""
78+
product_id = order.get("product", {}).get("id", "")
79+
if not product_id:
80+
logger.warning("No product ID found in order, skipping default lines")
81+
return order
82+
83+
aws_items = get_product_items_by_skus(client, product_id, AWS_ITEMS_SKUS)
84+
if not aws_items:
85+
logger.error(
86+
"Failed to get product items with SKUs %s for product %s",
87+
AWS_ITEMS_SKUS,
88+
product_id,
89+
)
90+
return order
91+
92+
order["lines"] = [{"item": aws_item, "quantity": 1} for aws_item in aws_items]
93+
return order
94+
95+
96+
def validate_order(client: MPTClient, order: dict) -> dict:
97+
"""
98+
Main validation function that orchestrates all validation steps.
99+
100+
This function performs the following steps:
101+
1. Creates a deep copy of the order to avoid mutations
102+
2. Updates parameter visibility based on account type
103+
3. Adds default line items to the order
104+
105+
Args:
106+
client: MPT client for API calls.
107+
order: The order dictionary to validate.
108+
109+
Returns:
110+
The validated order with updated parameters and default lines.
111+
"""
112+
validated_order = copy.deepcopy(order)
113+
validated_order = update_parameters_visibility(validated_order)
114+
return add_default_lines(client, validated_order)

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -833,8 +833,8 @@ def ffc_client_settings(extension_settings):
833833

834834

835835
@pytest.fixture
836-
def mock_update_parameters_visibility(mocker):
837-
return mocker.patch("swo_aws_extension.extension.update_parameters_visibility", spec=True)
836+
def mock_validate_order(mocker):
837+
return mocker.patch("swo_aws_extension.extension.validate_order", spec=True)
838838

839839

840840
@pytest.fixture

tests/flows/validation/test_base.py

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
from unittest.mock import MagicMock
2+
13
from swo_aws_extension.constants import (
24
AccountTypesEnum,
35
OrderParametersEnum,
46
)
5-
from swo_aws_extension.flows.validation.base import update_parameters_visibility
7+
from swo_aws_extension.flows.validation.base import (
8+
add_default_lines,
9+
update_parameters_visibility,
10+
validate_order,
11+
)
612
from swo_aws_extension.parameters import get_ordering_parameter
713

814

@@ -55,7 +61,6 @@ def test_new_aws_environment(order_factory, order_parameters_factory):
5561

5662

5763
def test_existing_aws_environment(order_factory, order_parameters_factory):
58-
"""Test update params visibility for an existing AWS environment."""
5964
order = order_factory(
6065
order_parameters=order_parameters_factory(
6166
account_type=AccountTypesEnum.EXISTING_AWS_ENVIRONMENT.value,
@@ -104,7 +109,6 @@ def test_existing_aws_environment(order_factory, order_parameters_factory):
104109

105110

106111
def test_empty_values(order_factory, order_parameters_factory):
107-
"""Test the update_parameters_visibility function when parameter values are empty."""
108112
order = order_factory(order_parameters=order_parameters_factory(account_type=None))
109113

110114
result = update_parameters_visibility(order)
@@ -114,3 +118,78 @@ def test_empty_values(order_factory, order_parameters_factory):
114118
"id": "AWS001",
115119
"message": "Invalid account type: None",
116120
}
121+
122+
123+
def test_add_default_lines_success(order_factory, mocker):
124+
mock_client = MagicMock()
125+
order = order_factory(lines=[])
126+
mock_items = [
127+
{
128+
"id": "ITM-1234-1234-1234-0001",
129+
"name": "AWS Usage",
130+
"externalIds": {"vendor": "AWS Usage"},
131+
}
132+
]
133+
mocker.patch(
134+
"swo_aws_extension.flows.validation.base.get_product_items_by_skus",
135+
return_value=mock_items,
136+
)
137+
138+
result = add_default_lines(mock_client, order)
139+
140+
assert result["lines"] == [{"item": mock_items[0], "quantity": 1}]
141+
142+
143+
def test_add_default_lines_no_product_id(caplog):
144+
mock_client = MagicMock()
145+
order = {"product": {}, "lines": []}
146+
147+
with caplog.at_level("WARNING"):
148+
result = add_default_lines(mock_client, order)
149+
150+
assert result["lines"] == []
151+
assert "No product ID found in order, skipping default lines" in caplog.text
152+
153+
154+
def test_add_default_lines_no_items_found(order_factory, mocker):
155+
mock_client = MagicMock()
156+
order = order_factory(lines=[{"existing": "line"}])
157+
mocker.patch(
158+
"swo_aws_extension.flows.validation.base.get_product_items_by_skus",
159+
return_value=[],
160+
)
161+
162+
result = add_default_lines(mock_client, order)
163+
164+
assert result["lines"] == [{"existing": "line"}]
165+
166+
167+
def test_validate_order_orchestrates_all_steps(order_factory, order_parameters_factory, mocker):
168+
mock_client = MagicMock()
169+
order = order_factory(
170+
order_parameters=order_parameters_factory(
171+
account_type=AccountTypesEnum.NEW_AWS_ENVIRONMENT.value,
172+
constraints={"hidden": None, "required": None, "readonly": None},
173+
),
174+
lines=[],
175+
)
176+
mock_items = [
177+
{
178+
"id": "ITM-1234-1234-1234-0001",
179+
"name": "AWS Usage",
180+
"externalIds": {"vendor": "AWS Usage"},
181+
}
182+
]
183+
mocker.patch(
184+
"swo_aws_extension.flows.validation.base.get_product_items_by_skus",
185+
return_value=mock_items,
186+
)
187+
188+
result = validate_order(mock_client, order)
189+
190+
order_account_name_param = get_ordering_parameter(
191+
OrderParametersEnum.ORDER_ACCOUNT_NAME.value, result
192+
)
193+
assert order_account_name_param["constraints"]["hidden"] is False
194+
assert order_account_name_param["constraints"]["required"] is True
195+
assert result["lines"] == [{"item": mock_items[0], "quantity": 1}]

tests/test_extension.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ def test_validated_order(
5050
client,
5151
order_factory,
5252
jwt_token,
53-
mock_update_parameters_visibility,
53+
mock_validate_order,
5454
):
5555
order = order_factory()
56-
mock_update_parameters_visibility.return_value = order
56+
mock_validate_order.return_value = order
5757

5858
result = client.post(
5959
"/api/v1/orders/validate",
@@ -73,11 +73,11 @@ def test_handles_exception(
7373
client,
7474
order_factory,
7575
jwt_token,
76-
mock_update_parameters_visibility,
76+
mock_validate_order,
7777
):
7878
order = order_factory()
7979
error_message = "Test validation error"
80-
mock_update_parameters_visibility.side_effect = Exception(error_message)
80+
mock_validate_order.side_effect = Exception(error_message)
8181

8282
result = client.post(
8383
"/api/v1/orders/validate",

0 commit comments

Comments
 (0)