Skip to content

Commit 4d3b7a6

Browse files
authored
Merge pull request #23 from softwareone-platform/MPT-10788-billing-add-new-products-parameters
MPT-10788 Billing add new product parameters
2 parents eb484fc + c48434d commit 4d3b7a6

File tree

10 files changed

+208
-0
lines changed

10 files changed

+208
-0
lines changed

.env.sample

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ EXT_FFC_SUB=FTKN-1111-1111
1010
EXT_FFC_OPERATIONS_API_BASE_URL=https://api.finops.s1.show/ops
1111
EXT_FFC_OPERATIONS_SECRET=supersecret
1212
MPT_NOTIFY_CATEGORIES={"ORDERS": "NTC-0000-0006"}
13+
DEFAULT_TRIAL_PERIOD_DURATION_DAYS=30
14+
DEFAULT_BILLED_PERCENTAGE=4

ffc/flows/fulfillment.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
ResetOrderErrors,
2727
SetupAgreementExternalId,
2828
SetupDueDate,
29+
SetupFulfillmentParameters,
2930
StartOrderProcessing,
3031
)
3132
from ffc.notifications import notify_unhandled_exception_in_teams
@@ -39,6 +40,7 @@
3940
CheckDueDate(),
4041
CheckOrderParameters(),
4142
QueryIfInvalid(),
43+
SetupFulfillmentParameters(),
4244
StartOrderProcessing(PURCHASE_TEMPLATE_NAME),
4345
CreateEmployee(),
4446
CreateOrganization(),

ffc/flows/steps/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
QueryIfInvalid,
1313
ResetOrderErrors,
1414
SetupAgreementExternalId,
15+
SetupFulfillmentParameters,
1516
StartOrderProcessing,
1617
)
1718
from ffc.flows.steps.subscription import CreateSubscription
@@ -30,6 +31,7 @@
3031
"CheckOrderParameters",
3132
"DeleteOrganization",
3233
"SetupAgreementExternalId",
34+
"SetupFulfillmentParameters",
3335
"StartOrderProcessing",
3436
"FailOrder",
3537
"OrderTypeIsNotSupported",

ffc/flows/steps/order.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import logging
2+
from datetime import UTC, datetime, timedelta
23

4+
from django.conf import settings
35
from mpt_extension_sdk.flows.pipeline import Step
46
from mpt_extension_sdk.mpt_http.mpt import (
57
complete_order,
@@ -25,13 +27,17 @@
2527
from ffc.notifications import send_mpt_notification
2628
from ffc.parameters import (
2729
PARAM_ADMIN_CONTACT,
30+
PARAM_BILLED_PERCENTAGE,
2831
PARAM_CURRENCY,
2932
PARAM_IS_NEW_USER,
3033
PARAM_ORGANIZATION_NAME,
34+
PARAM_TRIAL_END_DATE,
35+
PARAM_TRIAL_START_DATE,
3136
get_due_date,
3237
get_fulfillment_parameter,
3338
get_ordering_parameter,
3439
reset_ordering_parameters_error,
40+
set_fulfillment_parameter,
3541
set_ordering_parameter_error,
3642
)
3743

@@ -162,6 +168,54 @@ def __call__(self, client, context, next_step):
162168
next_step(client, context)
163169

164170

171+
class SetupFulfillmentParameters(Step):
172+
"""
173+
Set fulfillment parameters with default values if they are not provided
174+
"""
175+
176+
def __call__(self, client, context, next_step):
177+
order = context.order
178+
updates = self._get_parameter_updates(order)
179+
180+
if updates:
181+
for param_name, param_value in updates.items():
182+
order = set_fulfillment_parameter(
183+
order=order,
184+
parameter=param_name,
185+
value=param_value,
186+
)
187+
context.order = update_order(
188+
client, context.order["id"], parameters=order["parameters"]
189+
)
190+
logger.info(
191+
f"{context}: Updating fulfillment parameters",
192+
)
193+
194+
next_step(client, context)
195+
196+
@staticmethod
197+
def _get_parameter_updates(order):
198+
updates = {}
199+
200+
if not get_fulfillment_parameter(order, PARAM_BILLED_PERCENTAGE).get("value"):
201+
updates[PARAM_BILLED_PERCENTAGE] = int(
202+
settings.EXTENSION_CONFIG.get("DEFAULT_BILLED_PERCENTAGE")
203+
)
204+
205+
trial_start_date = get_fulfillment_parameter(order, PARAM_TRIAL_START_DATE).get("value")
206+
if not trial_start_date:
207+
trial_start_date = datetime.now(UTC).date().strftime("%Y-%m-%d")
208+
updates[PARAM_TRIAL_START_DATE] = trial_start_date
209+
210+
if not get_fulfillment_parameter(order, PARAM_TRIAL_END_DATE).get("value"):
211+
trail_end_date = datetime.strptime(trial_start_date, "%Y-%m-%d").date() + timedelta(
212+
days=int(settings.EXTENSION_CONFIG.get("DEFAULT_TRIAL_PERIOD_DURATION_DAYS"))
213+
)
214+
updates[PARAM_TRIAL_END_DATE] = trail_end_date.strftime("%Y-%m-%d")
215+
216+
return updates
217+
218+
165219
class ResetOrderErrors(Step):
166220
"""
167221
Reset order errors and parameter errors. Is used before processing

ffc/parameters.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
PARAM_CURRENCY = "currency"
1515
PARAM_ADMIN_CONTACT = "adminContact"
1616
PARAM_IS_NEW_USER = "isNewUser"
17+
PARAM_TRIAL_START_DATE = "trialStartDate"
18+
PARAM_TRIAL_END_DATE = "trialEndDate"
19+
PARAM_BILLED_PERCENTAGE = "billedPercentage"
1720

1821

1922
def get_parameter(parameter_phase, source, param_external_id):
@@ -116,6 +119,22 @@ def set_is_new_user(order, is_new):
116119
return updated_order
117120

118121

122+
def set_fulfillment_parameter(order, parameter, value):
123+
"""
124+
Set the provided fulfillment parameter with given value
125+
Args:
126+
order (dict): Order to be updated
127+
parameter (str): name of the parameter
128+
value (Any): value of the parameter
129+
"""
130+
updated_order = copy.deepcopy(order)
131+
132+
param = get_fulfillment_parameter(updated_order, parameter)
133+
param["value"] = value
134+
135+
return updated_order
136+
137+
119138
def reset_ordering_parameters_error(order):
120139
"""
121140
Reset errors for all ordering parameters

swo/mpt/extensions/runtime/djapp/conf/default.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,6 @@
213213

214214
EXTENSION_CONFIG = {
215215
"DUE_DATE_DAYS": "30",
216+
"DEFAULT_TRIAL_PERIOD_DURATION_DAYS": os.getenv("DEFAULT_TRIAL_PERIOD_DURATION_DAYS", "30"),
217+
"DEFAULT_BILLED_PERCENTAGE": os.getenv("DEFAULT_BILLED_PERCENTAGE", "4"),
216218
}

tests/conftest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,30 @@ def _fulfillment_parameters():
7676
"type": "Checkbox",
7777
"phase": "Fulfillment",
7878
},
79+
{
80+
"id": "PAR-7208-0459-0009",
81+
"externalId": "trialStartDate",
82+
"name": "Trial Start Date",
83+
"type": "Date",
84+
"phase": "Fulfillment",
85+
"value": "2025-01-01",
86+
},
87+
{
88+
"id": "PAR-7208-0459-0010",
89+
"externalId": "trialEndDate",
90+
"name": "Trial Start Date",
91+
"type": "Date",
92+
"phase": "Fulfillment",
93+
"value": "2025-01-31",
94+
},
95+
{
96+
"id": "PAR-7208-0459-0011",
97+
"externalId": "billedPercentage",
98+
"name": "Billed Percentage",
99+
"type": "SingleLineText",
100+
"phase": "Fulfillment",
101+
"value": "4",
102+
},
79103
]
80104

81105
return _fulfillment_parameters

tests/django/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,6 @@
179179
EXTENSION_CONFIG = {
180180
"WEBHOOKS_SECRETS": {"PRD-1111-1111": "that's my awesome test secret"},
181181
"DUE_DATE_DAYS": "30",
182+
"DEFAULT_TRIAL_PERIOD_DURATION_DAYS": os.getenv("DEFAULT_TRIAL_PERIOD_DURATION_DAYS", "30"),
183+
"DEFAULT_BILLED_PERCENTAGE": os.getenv("DEFAULT_BILLED_PERCENTAGE", "4"),
182184
}

tests/ffc/flows/steps/test_order.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from freezegun import freeze_time
2+
13
from ffc.flows.error import ERR_ORDER_TYPE_NOT_SUPPORTED
24
from ffc.flows.order import PURCHASE_EXISTING_TEMPLATE_NAME, OrderContext
35
from ffc.flows.steps.order import (
@@ -8,6 +10,7 @@
810
QueryIfInvalid,
911
ResetOrderErrors,
1012
SetupAgreementExternalId,
13+
SetupFulfillmentParameters,
1114
StartOrderProcessing,
1215
)
1316
from ffc.parameters import PARAM_PHASE_ORDERING, set_is_new_user
@@ -315,3 +318,53 @@ def test_fail_order(
315318
processing_purchase_order,
316319
ERR_ORDER_TYPE_NOT_SUPPORTED.to_dict(order_type=processing_purchase_order["type"]),
317320
)
321+
322+
323+
def test_setup_fulfillment_parameters(
324+
mocker,
325+
mocked_next_step,
326+
mpt_client,
327+
processing_purchase_order,
328+
):
329+
mocked_update_order = mocker.patch("ffc.flows.steps.order.update_order")
330+
ctx = OrderContext(order=processing_purchase_order)
331+
step = SetupFulfillmentParameters()
332+
333+
step(mpt_client, ctx, mocked_next_step)
334+
335+
mocked_next_step.assert_called_once()
336+
mocked_update_order.assert_not_called()
337+
338+
339+
@freeze_time("2025-01-01")
340+
def test_setup_fulfillment_parameters_empty_values(
341+
mocker,
342+
mocked_next_step,
343+
mpt_client,
344+
processing_purchase_order,
345+
):
346+
param_defaults = {
347+
'trialStartDate': '2025-01-01',
348+
'trialEndDate': '2025-01-31',
349+
'billedPercentage': 4,
350+
}
351+
for param in processing_purchase_order["parameters"]["fulfillment"]:
352+
if param["externalId"] in param_defaults:
353+
param["value"] = None
354+
355+
mocked_update_order = mocker.patch("ffc.flows.steps.order.update_order")
356+
ctx = OrderContext(order=processing_purchase_order)
357+
step = SetupFulfillmentParameters()
358+
359+
step(mpt_client, ctx, mocked_next_step)
360+
361+
for param in processing_purchase_order["parameters"]["fulfillment"]:
362+
if param["externalId"] in param_defaults:
363+
param["value"] = param_defaults[param["externalId"]]
364+
365+
mocked_next_step.assert_called_once()
366+
mocked_update_order.assert_called_once_with(
367+
mpt_client,
368+
processing_purchase_order["id"],
369+
parameters=processing_purchase_order["parameters"],
370+
)

tests/ffc/flows/test_fulfillment.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,30 @@ def test_purchase_order(
8888
"phase": "Fulfillment",
8989
"value": ["Yes"],
9090
},
91+
{
92+
"id": "PAR-7208-0459-0009",
93+
"externalId": "trialStartDate",
94+
"name": "Trial Start Date",
95+
"type": "Date",
96+
"phase": "Fulfillment",
97+
"value": "2025-01-01",
98+
},
99+
{
100+
"id": "PAR-7208-0459-0010",
101+
"externalId": "trialEndDate",
102+
"name": "Trial Start Date",
103+
"type": "Date",
104+
"phase": "Fulfillment",
105+
"value": "2025-01-31",
106+
},
107+
{
108+
"id": "PAR-7208-0459-0011",
109+
"externalId": "billedPercentage",
110+
"name": "Billed Percentage",
111+
"type": "SingleLineText",
112+
"phase": "Fulfillment",
113+
"value": "4",
114+
},
91115
],
92116
"ordering": [
93117
{
@@ -185,6 +209,30 @@ def test_terminate_order(
185209
"type": "Checkbox",
186210
"phase": "Fulfillment",
187211
},
212+
{
213+
"id": "PAR-7208-0459-0009",
214+
"externalId": "trialStartDate",
215+
"name": "Trial Start Date",
216+
"type": "Date",
217+
"phase": "Fulfillment",
218+
"value": "2025-01-01",
219+
},
220+
{
221+
"id": "PAR-7208-0459-0010",
222+
"externalId": "trialEndDate",
223+
"name": "Trial Start Date",
224+
"type": "Date",
225+
"phase": "Fulfillment",
226+
"value": "2025-01-31",
227+
},
228+
{
229+
"id": "PAR-7208-0459-0011",
230+
"externalId": "billedPercentage",
231+
"name": "Billed Percentage",
232+
"type": "SingleLineText",
233+
"phase": "Fulfillment",
234+
"value": "4",
235+
},
188236
],
189237
"ordering": [],
190238
},

0 commit comments

Comments
 (0)