Skip to content

Commit

Permalink
fix: updateQuestionnaire after assign rules applied to allow for casc…
Browse files Browse the repository at this point in the history
…ading updates
  • Loading branch information
MatiasArriola committed Feb 13, 2025
1 parent 0592d5b commit 9ade210
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 15 deletions.
64 changes: 50 additions & 14 deletions src/domain/entities/Questionnaire/Questionnaire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ export class Questionnaire {
return this.data.subLevelDetails;
}

/** Returns all questions, including entity questions and stage questions */
getAllQuestions(): Question[] {
const stageQuestions = this.stages.flatMap((stage: QuestionnaireStage) => {
return stage.sections.flatMap(section => {
return section.questions.map(question => question);
});
});
const entityQuestions = this.entity?.questions || [];
return [...stageQuestions, ...entityQuestions];
}

public static create(data: QuestionnaireData): Questionnaire {
//TO DO : Add validations if any
return new Questionnaire({
Expand Down Expand Up @@ -257,21 +268,11 @@ export class Questionnaire {
questionnaire: Questionnaire,
updatedQuestion: Question,
stageId?: string,
initialLoad = false
initialLoad = false,
alreadyUpdatedQuestions?: undefined | Question[]
): Questionnaire {
//For the updated question, get all rules that are applicable
const allQsInQuestionnaireStages = questionnaire.stages.flatMap(
(stage: QuestionnaireStage) => {
return stage.sections.flatMap(section => {
return section.questions.map(question => question);
});
}
);

const allQsInQuestionnaire = [
...(questionnaire.entity?.questions || []),
...allQsInQuestionnaireStages,
];
const allQsInQuestionnaire = questionnaire.getAllQuestions();

const allQsInQuestionnaireWithUpdatedQ = allQsInQuestionnaire.map(question =>
question.id === updatedQuestion.id ? updatedQuestion : question
Expand All @@ -289,7 +290,19 @@ export class Questionnaire {
question => question.id === updatedQuestion.id
);

return Questionnaire.create({
// "assign" actions may cause cascading updates
const assignRuleTargets: Question[] =
QuestionnaireQuestion.filterQuestionsTargettedByAssign(
allQsInQuestionnaireWithUpdatedQ,
applicableRules
)
// we don't want to update questions already updated to prevent infinite recursion
.filter(
question =>
question && !alreadyUpdatedQuestions?.some(uq => uq.id === question.id)
);

const updatedQuestionnaire = Questionnaire.create({
...questionnaire.data,
stages: questionnaire.stages.map(stage => {
if (stageId && stage.id !== stageId) return stage;
Expand All @@ -313,6 +326,29 @@ export class Questionnaire {
)
: questionnaire.entity,
});

if (assignRuleTargets.length > 0) {
// We need to update the questionnaire again based on updates from "assign" actions
const updatedQuestionnaireWithAssigns = assignRuleTargets.reduce(
(accQuestionnaire, question) => {
const updatedAssignQuestion = QuestionnaireQuestion.updateQuestion(
question,
applicableRules
);
return this.updateQuestionnaire(
accQuestionnaire,
updatedAssignQuestion,
stageId,
initialLoad,
[...(alreadyUpdatedQuestions ?? []), updatedAssignQuestion]
);
},
updatedQuestionnaire
);

return updatedQuestionnaireWithAssigns;
}
return updatedQuestionnaire;
}

static doesQuestionnaireHaveErrors(questionnaire: Questionnaire): boolean {
Expand Down
22 changes: 21 additions & 1 deletion src/domain/entities/Questionnaire/QuestionnaireQuestion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,27 @@ export class QuestionnaireQuestion {
return finalUpdatesWithSideEffects;
}

private static updateQuestion<T extends Question>(question: T, rules: QuestionnaireRule[]): T {
public static filterQuestionsTargettedByAssign(
questions: Question[],
applicableRules: QuestionnaireRule[]
): Question[] {
return applicableRules
.flatMap(rule =>
rule.parsedResult
? rule.actions.filter(action => action.programRuleActionType === "ASSIGN")
: []
)
.map(action =>
questions.find(
q =>
q.id === action.dataElement?.id ||
q.id === action.trackedEntityAttribute?.id
)
)
.filter(x => x !== undefined) as Question[];
}

public static updateQuestion<T extends Question>(question: T, rules: QuestionnaireRule[]): T {
const updatedIsVisible = this.isQuestionVisible(question, rules);
const updatedErrors = this.getQuestionWarningsAndErrors(question, rules);
const updatedIsDisabled = this.isQuestionDisabled(question, rules);
Expand Down

0 comments on commit 9ade210

Please sign in to comment.