Skip to content

Commit

Permalink
#1137 - add question group specific fields when evaluating the rule
Browse files Browse the repository at this point in the history
  • Loading branch information
petmongrels committed Apr 2, 2024
1 parent b67151d commit c019502
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 45 deletions.
22 changes: 22 additions & 0 deletions src/common/model/WebFormElement.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FormElement } from "openchs-models";
import WebFormElementGroup from "./WebFormElementGroup";
import _ from 'lodash';

class WebFormElement extends FormElement {
get group() {
Expand All @@ -10,6 +11,14 @@ class WebFormElement extends FormElement {
this.that.group = this.fromObject(x);
}

get questionGroupIndex() {
return this.that.questionGroupIndex;
}

set questionGroupIndex(x) {
this.that.questionGroupIndex = x;
}

newFormElement() {
return new WebFormElement();
}
Expand All @@ -27,6 +36,19 @@ class WebFormElement extends FormElement {
set formElementGroup(x) {
this.that.formElementGroup = this.fromObject(x);
}

static logFormElement(fe) {
let feToString = `UUID:${fe.uuid} Name:${fe.name} Display:${fe.displayOrder}`;
if (!_.isNil(fe.group)) {
feToString += ` QGName:${fe.group.name} QGUuid:${fe.groupUuid} QGI:${fe.questionGroupIndex}`;
}
console.log(feToString);
}

static logFormElements(formElements) {
formElements.forEach((x) => WebFormElement.logFormElement(x));
console.log("------------------------------------------------------------");
}
}

export default WebFormElement;
29 changes: 17 additions & 12 deletions src/dataEntryApp/components/QuestionGroupFormElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ function getChildObservationValue(concept, questionGroupObservation) {
return childObs && childObs.getValueWrapper().getValue();
}

function getQuestionGroupLabel(formElement, isRepeatable, repeatableIndex) {
if (isRepeatable) return `${formElement.name} - ${repeatableIndex}`;
return formElement.name;
}

export default function QuestionGroupFormElement({
formElement,
obsHolder,
validationResults,
filteredFormElements,
updateObs
updateObs,
isRepeatable = false,
repeatableIndex
}) {
const allChildren = sortBy(
filter(filteredFormElements, ffe => get(ffe, "group.uuid") === formElement.uuid && !ffe.voided),
Expand All @@ -38,29 +45,27 @@ export default function QuestionGroupFormElement({
);
const childObservations = obsHolder.findObservation(formElement.concept);

console.log("QuestionGroupFormElement", formElement.name);

return (
<Fragment>
<div>{formElement.name}</div>
<div>{getQuestionGroupLabel(formElement, isRepeatable, repeatableIndex)}</div>
<div style={{ flexDirection: "row", alignItems: "center", marginTop: "10px" }}>
{map(textNumericAndNotes, cfe => (
{map(textNumericAndNotes, childFormElement => (
<FormElement
key={cfe.uuid}
concept={cfe.concept}
key={childFormElement.uuid}
concept={childFormElement.concept}
obsHolder={obsHolder}
value={getChildObservationValue(cfe.concept, childObservations)}
value={getChildObservationValue(childFormElement.concept, childObservations)}
validationResults={validationResults}
uuid={cfe.uuid}
uuid={childFormElement.uuid}
update={value => {
updateObs(formElement, value, cfe);
updateObs(formElement, value, childFormElement);
}}
feIndex={cfe.displayOrder}
feIndex={childFormElement.displayOrder}
filteredFormElements={filteredFormElements}
ignoreLineBreak={true}
isGrid={true}
>
{cfe}
{childFormElement}
</FormElement>
))}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ export function RepeatableQuestionGroupElement({
}) {
const childObservations = obsHolder.findObservation(formElement.concept);
const repeatableQuestionGroup = new RepeatableQuestionGroup(childObservations);
return repeatableQuestionGroup.getValue().map(x => {
return repeatableQuestionGroup.getValue().map((x, index) => {
return (
<QuestionGroupFormElement
formElement={formElement}
filteredFormElements={filteredFormElements}
obsHolder={obsHolder}
updateObs={updateObs}
validationResults={validationResults}
isRepeatable={true}
repeatableIndex={1}
key={index}
/>
);
});
Expand Down
44 changes: 25 additions & 19 deletions src/dataEntryApp/services/FormElementService.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import { Concept, FormElementGroup, ValidationResult, QuestionGroup } from "avni-models";
import { differenceWith, some, filter, flatMap, head, isEmpty, isNil, map, remove } from "lodash";
import { getFormElementsStatuses } from "./RuleEvaluationService";
import WebFormElement from "../../common/model/WebFormElement";

export default {
updateObservations(observationsHolder, formElement, value, childFormElement) {
if (!isNil(childFormElement) && !isNil(childFormElement.groupUuid)) {
observationsHolder.updateGroupQuestion(
formElement.concept,
childFormElement.concept,
value,
childFormElement
formElement,
childFormElement,
value
);
const childObservations = observationsHolder.findObservation(formElement.concept);
const childObservationsValue = childObservations
? childObservations.getValueWrapper()
: new QuestionGroup();
const childObs = childObservationsValue.findObservation(childFormElement.concept);
return childFormElement.concept.isPrimitive() && isNil(childFormElement.durationOptions)
? value
: childObs && childObs.getValueWrapper();

const questionGroupTypeObservation = observationsHolder.findObservation(formElement.concept);
let questionGroup;
if (questionGroupTypeObservation) {
questionGroup = questionGroupTypeObservation.getValueWrapper();
} else {
questionGroup = new QuestionGroup();
}
const childObs = questionGroup.findObservation(childFormElement.concept);
if (childFormElement.concept.isPrimitive() && isNil(childFormElement.durationOptions)) {
return value;
} else {
return childObs && childObs.getValueWrapper();
}
} else if (
formElement.isMultiSelect() &&
(formElement.concept.datatype === Concept.dataType.Coded ||
Expand Down Expand Up @@ -98,20 +104,20 @@ export default {
}
};

export const getFormElementStatuses = (entity, formElementGroup, observationsHolder) => {
export function getFormElementStatuses(entity, formElementGroup, observationsHolder) {
const formElementStatuses = getFormElementsStatuses(entity, formElementGroup);
const filteredFormElements = FormElementGroup._sortedFormElements(
formElementGroup.filterElements(formElementStatuses)
);
const filteredFormElements = formElementGroup.filterElements(formElementStatuses);
const sortedFilteredFormElements = FormElementGroup._sortedFormElements(filteredFormElements);
const allFormElements = formElementGroup.getFormElements();
const removedObs = observationsHolder.removeNonApplicableObs(
formElementGroup.getFormElements(),
filteredFormElements
allFormElements,
sortedFilteredFormElements
);
if (isEmpty(removedObs)) {
return formElementStatuses;
}
return getFormElementStatuses(entity, formElementGroup, observationsHolder);
};
}

const getRuleValidationErrors = formElementStatuses => {
return flatMap(
Expand Down
33 changes: 20 additions & 13 deletions src/dataEntryApp/services/RuleEvaluationService.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import _ from "lodash";
import lodash from "lodash";
import moment from "moment";
import * as models from "avni-models";
import { FormElementStatus } from "avni-models";
import {FormElementStatus} from "avni-models";
import * as rulesConfig from "rules-config";
import { common, motherCalculations, RuleRegistry } from "avni-health-modules";
import { store } from "common/store/createStore";
import {common, motherCalculations, RuleRegistry} from "avni-health-modules";
import {store} from "common/store/createStore";
import {
selectLegacyRules,
selectLegacyRulesAllRules
} from "dataEntryApp/reducers/metadataReducer";
import { individualService } from "./IndividualService";
import {individualService} from "./IndividualService";

const services = {
individualService
Expand All @@ -25,22 +25,23 @@ export const getFormElementsStatuses = (entity, formElementGroup) => {
.getFormElements()
.filter(formElement => !_.isNil(formElement.rule) && !_.isEmpty(_.trim(formElement.rule)));
const formElementStatusAfterGroupRule = runFormElementGroupRule(formElementGroup, entity);

const visibleFormElementsUUIDs = _.filter(
formElementStatusAfterGroupRule,
({ visibility }) => visibility === true
).map(({ uuid }) => uuid);
({visibility}) => visibility === true
).map(({uuid}) => uuid);
if (!_.isEmpty(formElementsWithRules) && !_.isEmpty(visibleFormElementsUUIDs)) {
let formElementStatuses = formElementsWithRules
.filter(({ uuid }) => _.includes(visibleFormElementsUUIDs, uuid))
.filter(({uuid}) => _.includes(visibleFormElementsUUIDs, uuid))
.map(formElement => {
try {
/* eslint-disable-next-line no-unused-vars */
const ruleServiceLibraryInterfaceForSharingModules = getRuleServiceLibraryInterfaceForSharingModules();
/* eslint-disable-next-line no-eval */
const ruleFunc = eval(formElement.rule);
return ruleFunc({
params: { formElement, entity, services },
imports: { rulesConfig, lodash, moment, common }
params: {formElement, entity, services},
imports: {rulesConfig, lodash, moment, common}
});
} catch (e) {
console.error(
Expand Down Expand Up @@ -69,18 +70,24 @@ export const getFormElementsStatuses = (entity, formElementGroup) => {

const runFormElementGroupRule = (formElementGroup, entity) => {
if (_.isNil(formElementGroup.rule) || _.isEmpty(_.trim(formElementGroup.rule))) {
console.log("RuleEvaluationService", "No FEGroup rule found");
return formElementGroup
.getFormElements()
.map(formElement => new FormElementStatus(formElement.uuid, true, undefined));
.map(formElement => {
const formElementStatus = new FormElementStatus(formElement.uuid, true, undefined);
if (!_.isNil(formElement.group))
formElementStatus.addQuestionGroupInformation(0);
return formElementStatus;
});
}
try {
/* eslint-disable-next-line no-unused-vars */
const ruleServiceLibraryInterfaceForSharingModules = getRuleServiceLibraryInterfaceForSharingModules();
/* eslint-disable-next-line no-eval */
const ruleFunc = eval(formElementGroup.rule);
return ruleFunc({
params: { formElementGroup, entity, services },
imports: { rulesConfig, lodash, moment, common }
params: {formElementGroup, entity, services},
imports: {rulesConfig, lodash, moment, common}
});
} catch (e) {
console.error(
Expand Down Expand Up @@ -125,7 +132,7 @@ const getRuleFunctions = (rules = []) => {
const allRules = selectLegacyRulesAllRules(store.getState());
return _.defaults(rules, [])
.filter(ar => _.isFunction(allRules[ar.fnName]) && _.isFunction(allRules[ar.fnName].exec))
.map(ar => ({ ...ar, fn: allRules[ar.fnName] }));
.map(ar => ({...ar, fn: allRules[ar.fnName]}));
};

const runRuleAndSaveFailure = (rule, entityName, entity, ruleTypeValue, config, context) => {
Expand Down

0 comments on commit c019502

Please sign in to comment.