Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions src/webapp/reports/autogenerated-forms/hooks/useApplyRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ type UseApplyRulesProps = {
dataElementTotalRules?: DataElementTotalRule[];
};

type FormRuleOptions = Omit<UseApplyRulesProps, "dataElementTotalRules" | "dataElement"> & {
rules: Rule[];
dataElementTotalRule: Maybe<DataElementTotalRule | SectionTotalRule>;
};

type UseApplyRulesReturn = { isVisible: boolean; isDisabled: boolean };

export function useApplyRules(props: UseApplyRulesProps): UseApplyRulesReturn {
Expand Down Expand Up @@ -52,15 +57,29 @@ export function checkVisibleRule(options: UseApplyRulesProps): boolean {
const visibleRules = dataElement.rules.filter(rule => rule.type === "visible");
const visibleDataElementTotalRule = dataElementTotalRules?.find(rule => rule.type === "visible");

return getValueAndVerifyCondition(visibleRules, dataFormInfo, period, visibleDataElementTotalRule) ?? true;
return (
getValueAndVerifyCondition({
rules: visibleRules,
dataElementTotalRule: visibleDataElementTotalRule,
dataFormInfo,
period,
}) ?? true
);
}

function checkDisabledRule(options: UseApplyRulesProps): boolean {
const { dataElement, dataFormInfo, period, dataElementTotalRules: totalRules } = options;
const disabledRules = dataElement.rules.filter(rule => rule.type === "disabled");
const disabledDataElementTotalRule = totalRules?.find(rule => rule.type === "disabled");

return getValueAndVerifyCondition(disabledRules, dataFormInfo, period, disabledDataElementTotalRule) ?? false;
return (
getValueAndVerifyCondition({
rules: disabledRules,
dataElementTotalRule: disabledDataElementTotalRule,
dataFormInfo,
period,
}) ?? false
);
}

function checkEnabledRule(options: UseApplyRulesProps): Maybe<boolean> {
Expand All @@ -69,23 +88,25 @@ function checkEnabledRule(options: UseApplyRulesProps): Maybe<boolean> {
const enabledDataElementTotalRule = totalRules?.find(rule => rule.type === "enabled");

if (enabledRules.length === 0 && !enabledDataElementTotalRule) return undefined;
return getValueAndVerifyCondition(enabledRules, dataFormInfo, period, enabledDataElementTotalRule) ?? false;
return (
getValueAndVerifyCondition({
rules: enabledRules,
dataElementTotalRule: enabledDataElementTotalRule,
dataFormInfo,
period,
}) ?? false
);
}

function getValueAndVerifyCondition(
rules: Rule[],
dataFormInfo: DataFormInfo,
period: Maybe<string>,
dataElementTotalRule: Maybe<DataElementTotalRule>
): Maybe<boolean> {
function getValueAndVerifyCondition(options: FormRuleOptions): Maybe<boolean> {
const { rules, dataFormInfo, period, dataElementTotalRule } = options;

if (rules.length !== 0) {
return rules.some(rule => {
// Visibility/disabled/enabled rules evaluate against the form's base period,
// not the section's offset period. The related data element lives on the base
// period, so using the offset would look up the wrong value and break the rule.
const applicablePeriod = getApplicablePeriod(rule.relatedDataElement, dataFormInfo, period);
const dataValue = dataFormInfo.data.values.getOrEmpty(rule.relatedDataElement, {
orgUnitId: rule.relatedDataElement.orgUnit || dataFormInfo.orgUnitId,
period: dataFormInfo.period,
period: applicablePeriod,
categoryOptionComboId: dataFormInfo.categoryOptionComboId,
});

Expand All @@ -96,6 +117,20 @@ function getValueAndVerifyCondition(
}
}

// Use the row period when the trigger's section has data there, else the form base.
function getApplicablePeriod(
triggerDataElement: DataElement,
dataFormInfo: DataFormInfo,
rowPeriod: Maybe<string>
): string {
const { sections } = dataFormInfo.metadata.dataForm;
const triggerSection = sections.find(section => section.dataElements.some(de => de.id === triggerDataElement.id));
const triggerPeriods = triggerSection && "periods" in triggerSection ? triggerSection.periods : [];

if (rowPeriod && triggerPeriods.some(p => p.id === rowPeriod)) return rowPeriod;
return dataFormInfo.period;
}

type VerifyConditionRule = { condition: string; type?: RuleType | DeleteRule["type"] | SectionBase["toggle"]["type"] };
export function verifyConditionByDataValueType(dataValue: DataValue, rule: VerifyConditionRule): boolean {
const value = getValueAccordingType(dataValue);
Expand Down
Loading