Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 7x 1x 1x 6x 6x 6x 6x 6x 6x 7x 1x 1x 5x 5x 7x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 7x 1x 1x 1x 1x 3x 3x 3x 3x 3x 7x 1x 1x 2x 2x 2x 2x 2x 7x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 7x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { isNil } from 'lodash-es';
import { isAccessorNode, isFunctionNode } from 'mathjs';
import { commonMathJs } from '@amalia/amalia-lang/amalia-mathjs';
import {
type AccessorNode,
type FunctionNode,
type MathNode,
type SymbolNode,
} from '@amalia/amalia-lang/formula/evaluate/shared';
import { type VariableDefinition, type VariableFormatOptionsTable } from '@amalia/amalia-lang/tokens/types';
import { type Statement } from '@amalia/core/types';
import { FormatsEnum } from '@amalia/data-capture/fields/types';
import {
isExtractedChartConfigurationSuccess,
type CommissionTableRow,
type ExtractedChartConfiguration,
type ExtractedChartConfigurationSuccess,
} from '@amalia/payout-calculation/statements/types';
import { type ComputedVariable } from '@amalia/payout-calculation/types';
import { type PlanRuleChart } from '@amalia/payout-definition/plans/types';
const getVariableMachineNameFromAccessorNode = (node: MathNode): string | null =>
isAccessorNode(node) && 'value' in node.index.dimensions[0] && typeof node.index.dimensions[0].value === 'string'
? node.index.dimensions[0].value
: null;
const traverseNodes = (nodes: MathNode): MathNode[] => {
const values: MathNode[] = [];
nodes.traverse((node) => {
if (!commonMathJs.isArrayNode(node)) {
values.push(node);
}
});
return values;
};
/**
* Extract chart configuration from chart and return all values
* @param statement
* @param chart
*/
export const extractChartConfiguration = (
statement: Pick<Statement, 'results'>,
chart: PlanRuleChart,
): ExtractedChartConfiguration => {
if (!chart.configuration.targetAchievementVariableId) {
return { error: `Target Achievement chart ${chart.name} has no target achievement variables set up!` };
}
// Get the target achievement variable from statement results
const targetAchievementVariable = Object.values(statement.results.definitions.variables).find(
(v) => v.id === chart.configuration.targetAchievementVariableId,
);
if (!targetAchievementVariable) {
return { error: `Unable to retrieve the variable for the target achievement chart ${chart.name}` };
}
// Try to get the FN node from its formula
let fnNodeAsMathNode: MathNode | undefined = commonMathJs.parse(targetAchievementVariable.formula ?? '');
if (!isFunctionNode(fnNodeAsMathNode) || !['LINEAR', 'TIER'].includes(fnNodeAsMathNode.fn.name)) {
// If we don't have it directly, it's maybe later in the formula
const nodesInFormula = traverseNodes(fnNodeAsMathNode);
fnNodeAsMathNode = nodesInFormula.find((f) => isFunctionNode(f) && ['LINEAR', 'TIER'].includes(f.fn.name));
// If we still can't find it, return an error
if (!fnNodeAsMathNode) {
return { error: `No tier or linear function detected in target achievement variable for chart ${chart.name}` };
}
}
const fnNode: FunctionNode = fnNodeAsMathNode as FunctionNode;
// If formula is not used correctly, return error
if (fnNode.args.length !== 2 || fnNode.args[0].type !== 'AccessorNode' || fnNode.args[1].type !== 'AccessorNode') {
return {
error: `Can't parse formula of target achievement variable for chart ${chart.name}: this formula doesn't use two accessors`,
};
}
// If formula is not using statement variables (if wrong scope OR if formula uses function in aggregation functions)
if (
((fnNode.args[0] as AccessorNode).object as SymbolNode).name !== 'statement' ||
((fnNode.args[1] as AccessorNode).object as SymbolNode).name !== 'statement'
) {
return { error: `You must use two statement variables in the target achievement variable for chart ${chart.name}` };
}
// Get the variable machineNames
const targetVariableMachineName = getVariableMachineNameFromAccessorNode(fnNode.args[0]);
const tableVariableMachineName = getVariableMachineNameFromAccessorNode(fnNode.args[1]);
if (!targetVariableMachineName || !tableVariableMachineName) {
return {
error: `Can't access statement variable names from target achievement variable formula on chart ${chart.name}`,
};
}
// Get the statement variables that correspond
const targetVariable: VariableDefinition | undefined =
statement.results.definitions.variables[targetVariableMachineName];
const tableVariable: VariableDefinition | undefined =
statement.results.definitions.variables[tableVariableMachineName];
// Get the computed objects that correspond to these variables
const computedTarget = statement.results.computedObjects.find(
(co) => (co as ComputedVariable).variableMachineName === targetVariableMachineName,
) as ComputedVariable<number> | undefined;
const computedTable = statement.results.computedObjects.find(
(co) => (co as ComputedVariable).variableMachineName === tableVariableMachineName,
) as ComputedVariable<CommissionTableRow[]> | undefined;
if (!computedTarget || isNil(computedTarget.value) || !computedTable) {
return { error: `Unable to retrieve both target and table variables values from formula for chart ${chart.name}` };
}
return {
values: {
mode: fnNode.fn.name as 'LINEAR' | 'TIER',
table: {
value: computedTable.value,
variable: tableVariable,
},
target: {
value: computedTarget.value,
variable: targetVariable,
},
},
};
};
export const getRuleChartYAxisFormat = (extractedChartConfiguration: ExtractedChartConfiguration | null) => {
const formatOptions =
extractedChartConfiguration && isExtractedChartConfigurationSuccess(extractedChartConfiguration)
? extractedChartConfiguration.values.table.variable?.formatOptions
: undefined;
const tableFormat =
formatOptions && 'columns' in formatOptions
? (formatOptions as VariableFormatOptionsTable).columns[2]?.format
: undefined;
return tableFormat === FormatsEnum.percent ? FormatsEnum.percent : FormatsEnum.number;
};
export const getRuleChartXAxisFormat = (extractedChartConfiguration: ExtractedChartConfigurationSuccess) =>
extractedChartConfiguration.values.target.variable?.format === FormatsEnum.percent
? FormatsEnum.percent
: FormatsEnum.number;
|