Skip to content

Commit

Permalink
🐛 [#4579] Ensure triggerFromStep uses the correct current_step
Browse files Browse the repository at this point in the history
previously the current step was inferred by looking at the last completed step and considering the step after that the current step. This does not work however if you complete a step and go back to the previous step, so instead we explicitly pass the current form step via the serializer context

Backport-of: #4967
  • Loading branch information
stevenbal authored and sergei-maertens committed Dec 27, 2024
1 parent af8c1e2 commit 0ad3170
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 4 deletions.
6 changes: 5 additions & 1 deletion src/openforms/submissions/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ def create(self, validated_data):
return super().create(validated_data)

def to_representation(self, instance):
check_submission_logic(instance, unsaved_data=self.context.get("unsaved_data"))
check_submission_logic(
instance,
unsaved_data=self.context.get("unsaved_data"),
current_step=self.context.get("current_step"),
)
return super().to_representation(instance)


Expand Down
6 changes: 5 additions & 1 deletion src/openforms/submissions/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,10 @@ def logic_check(self, request, *args, **kwargs):

submission_state_logic_serializer = SubmissionStateLogicSerializer(
instance=SubmissionStateLogic(submission=submission, step=submission_step),
context={"request": request, "unsaved_data": data},
context={
"request": request,
"unsaved_data": data,
"current_step": submission_step,
},
)
return Response(submission_state_logic_serializer.data)
6 changes: 4 additions & 2 deletions src/openforms/submissions/form_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ def evaluate_form_logic(


def check_submission_logic(
submission: "Submission", unsaved_data: dict | None = None
submission: "Submission",
unsaved_data: dict | None = None,
current_step: "SubmissionStep | None" = None,
) -> None:
if getattr(submission, "_form_logic_evaluated", False):
return
Expand All @@ -198,7 +200,7 @@ def check_submission_logic(
if not submission_state.form_steps:
return

rules = get_rules_to_evaluate(submission)
rules = get_rules_to_evaluate(submission, current_step)

# load the data state and all variables
submission_variables_state = submission.load_submission_value_variables_state()
Expand Down
120 changes: 120 additions & 0 deletions src/openforms/submissions/tests/form_logic/test_submission_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,126 @@ def test_check_logic_on_whole_submission_with_variables(self):
self.assertTrue(data["steps"][1]["isApplicable"])
self.assertFalse(data["steps"][1]["canSubmit"])

@tag("gh-4579")
def test_properly_determine_current_step(self):
"""
Assert that the submission logic check properly determines the current step for
rules that define `triggerFromStep`
* We fill out step 1 and continue to step 2
* In step two the logic rule triggers that prevents us from continuing
* We go back to step 1 and it should be possible to continue to step 2 from there
"""
form = FormFactory.create()
step1 = FormStepFactory.create(
form=form,
form_definition__configuration={
"components": [
{
"type": "textfield",
"key": "text1",
}
]
},
)
step2 = FormStepFactory.create(
form=form,
form_definition__configuration={
"components": [
{
"type": "textfield",
"key": "text2",
}
]
},
)
FormVariableFactory.create(
form=form,
key="verdergaan",
user_defined=True,
data_type=FormVariableDataTypes.string,
)
# set up logic rules:
# 1. setting `text1` to `trigger-value` should set our user defined variable to `nee`
FormLogicFactory.create(
form=form,
json_logic_trigger={"==": [{"var": "text1"}, "trigger-rule"]},
actions=[
{
"component": "",
"variable": "verdergaan",
"formStepUuid": None,
"action": {"type": "variable", "value": "nee"},
}
],
)
# 2. if `verdergaan` is `nee`, block going to step3
FormLogicFactory.create(
form=form,
trigger_from_step=step2,
json_logic_trigger={"==": [{"var": "verdergaan"}, "nee"]},
actions=[
{
"component": "",
"formStepUuid": None,
"action": {"type": "disable-next"},
}
],
)
submission = SubmissionFactory.create(form=form)
self._add_submission_to_session(submission)

with self.subTest("fill in step1"):
endpoint = reverse(
"api:submission-steps-detail",
kwargs={
"submission_uuid": submission.uuid,
"step_uuid": step1.uuid,
},
)

response = self.client.put(
endpoint, data={"data": {"text1": "trigger-rule"}}
)

self.assertEqual(status.HTTP_201_CREATED, response.status_code)

data = response.json()

self.assertTrue(data["completed"])
self.assertTrue(data["canSubmit"])

with self.subTest("logic step for step 2 should not allow submitting"):
endpoint = reverse(
"api:submission-steps-logic-check",
kwargs={"submission_uuid": submission.uuid, "step_uuid": step2.uuid},
)
response = self.client.post(endpoint, data={"data": {"text2": "foo"}})

self.assertEqual(status.HTTP_200_OK, response.status_code)

data = response.json()

self.assertFalse(data["step"]["canSubmit"])

with self.subTest("logic check for step 1 should still allow submitting"):
endpoint = reverse(
"api:submission-steps-logic-check",
kwargs={"submission_uuid": submission.uuid, "step_uuid": step1.uuid},
)

response = self.client.post(
endpoint, data={"data": {"text1": "trigger-rule"}}
)

self.assertEqual(status.HTTP_200_OK, response.status_code)

data = response.json()

# It should be possible to go to the next step, because the logic rule
# to block going to the next step should only trigger from step2
self.assertTrue(data["step"]["canSubmit"])

def test_check_logic_with_full_datetime(self):
form = FormFactory.create()
step1 = FormStepFactory.create(
Expand Down

0 comments on commit 0ad3170

Please sign in to comment.