Несколько условий шага, объединяемых через И/ИЛИ
Раньше шаг маршрута мог нести ровно одно условие (field_name/operation/ value). Теперь условий может быть сколько угодно, а их объединение задаётся явно — ConditionsLogic.And (все условия) или .Or (любое из условий). Бэкенд: - Новая сущность TemplateRouteStepCondition (дочерняя таблица template_route_step_conditions, FK на шаг, cascade delete) вместо трёх колонок на TemplateRouteStep. Миграция AddMultipleStepConditions переносит существующие условия шагов в новую таблицу перед удалением старых колонок, чтобы не потерять уже настроенные в деве/проде условия. - TemplateRouteService.MatchesConditions: несколько условий шага объединяются по ConditionsLogic (Any/All); HasUnevaluatableManagerCondition проверяет условие на IsManager в списке условий, а не единственное поле. - TemplateRouteStepService: дубликаты шагов теперь сравниваются по всему набору условий (без учёта порядка) и, если условий два и более, по логике их объединения — сравнение в памяти, а не в SQL, кандидатов на дубликат в пределах маршрута всегда мало. - Валидация условия: раньше «все три поля или ни одного», теперь — в каждом элементе списка все три поля обязательны. Фронтенд: - RouteStepFormModal: условие — динамический список строк (добавить/удалить), у каждой строки свой набор допустимых операторов по типу колонки; селектор И/ИЛИ появляется, когда условий два и больше. - describeStepCondition в таблице шагов склеивает все условия через « И »/« ИЛИ ». Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ComparisonOperator, Employee, HeadType, ProjectRole, RouteStepStatus, TemplateRouteStep } from '../models';
|
||||
import { ComparisonOperator, ConditionsLogic, Employee, HeadType, ProjectRole, RouteStepStatus, TemplateRouteStep } from '../models';
|
||||
import { describeStepCondition, describeStepExecutor, detectExecutorKind } from './stepExecutor';
|
||||
|
||||
function step(overrides: Partial<TemplateRouteStep>): TemplateRouteStep {
|
||||
@@ -12,9 +12,8 @@ function step(overrides: Partial<TemplateRouteStep>): TemplateRouteStep {
|
||||
status: RouteStepStatus.Approval,
|
||||
routeId: 1,
|
||||
allowReassignToOtherApprovers: false,
|
||||
fieldName: null,
|
||||
operation: null,
|
||||
value: null,
|
||||
conditions: [],
|
||||
conditionsLogic: ConditionsLogic.And,
|
||||
slaHours: null,
|
||||
askOverdueReason: null,
|
||||
...overrides
|
||||
@@ -95,16 +94,40 @@ describe('describeStepExecutor', () => {
|
||||
});
|
||||
|
||||
describe('describeStepCondition', () => {
|
||||
it('undefined, если условие не задано целиком', () => {
|
||||
it('undefined, если условий нет', () => {
|
||||
expect(describeStepCondition(step({}))).toBeUndefined();
|
||||
});
|
||||
|
||||
it('undefined, если operation === None', () => {
|
||||
expect(describeStepCondition(step({ fieldName: 'Amount', operation: ComparisonOperator.None, value: '100' }))).toBeUndefined();
|
||||
});
|
||||
|
||||
it('собирает "поле оператор значение", если условие задано полностью', () => {
|
||||
const result = describeStepCondition(step({ fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '100' }));
|
||||
it('собирает "поле оператор значение", если условие одно', () => {
|
||||
const result = describeStepCondition(
|
||||
step({ conditions: [{ fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '100' }] })
|
||||
);
|
||||
expect(result).toBe('Amount > 100');
|
||||
});
|
||||
|
||||
it('несколько условий склеиваются через "И"', () => {
|
||||
const result = describeStepCondition(
|
||||
step({
|
||||
conditions: [
|
||||
{ fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '1000' },
|
||||
{ fieldName: 'Priority', operation: ComparisonOperator.Equal, value: 'Urgent' }
|
||||
],
|
||||
conditionsLogic: ConditionsLogic.And
|
||||
})
|
||||
);
|
||||
expect(result).toBe('Amount > 1000 И Priority = Urgent');
|
||||
});
|
||||
|
||||
it('несколько условий склеиваются через "ИЛИ"', () => {
|
||||
const result = describeStepCondition(
|
||||
step({
|
||||
conditions: [
|
||||
{ fieldName: 'Amount', operation: ComparisonOperator.GreaterThan, value: '1000' },
|
||||
{ fieldName: 'Priority', operation: ComparisonOperator.Equal, value: 'Urgent' }
|
||||
],
|
||||
conditionsLogic: ConditionsLogic.Or
|
||||
})
|
||||
);
|
||||
expect(result).toBe('Amount > 1000 ИЛИ Priority = Urgent');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user