153c966f0b
При доработке и повторной отправке writeRoute раньше удалял все строки маршрута и создавал заново — кто вернул или отклонил заявку и с каким комментарием, терялось. Теперь маршрут пересохраняется патчем (planRoutePatch + ApprovalListService.patchSteps): строки, что остаются в маршруте, обновляются на месте, и их прошлые решения лежат в истории версий; недостающие шаги создаются, выпавшие и строки делегатов уходят в корзину. Всё одним пакетом. Проверено пилотами на увольнении и рабочем месте (обе фазы, уход в корзину). Аварийный откат для всех форм — ROUTE_PATCH_ENABLED = false. Из версий строк маршрута и заявки собирается лента «История согласования» (shared/approval/history): отправки, решения с комментариями и временем на шаге, делегирование, замена исполнителя, у кого заявка сейчас. Свёрнутый раздел в карточке и в форме доработки всех форм, грузится только при раскрытии. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import { IExistingRouteRow, planRoutePatch } from './routePatchPlan';
|
|
|
|
const APPROVAL = 'Согласование';
|
|
const EXECUTION = 'Исполнение';
|
|
|
|
function row(id: number, approverId: number, phase = APPROVAL, delegatedById = 0): IExistingRouteRow {
|
|
return { id, approverId, phase, delegatedById };
|
|
}
|
|
|
|
describe('planRoutePatch', () => {
|
|
it('маршрут не изменился — все строки обновляются на месте, ничего не создаётся и не удаляется', () => {
|
|
const plan = planRoutePatch(
|
|
[row(10, 1), row(11, 2), row(12, 3)],
|
|
[
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
{ phase: APPROVAL, approverId: 2 },
|
|
{ phase: APPROVAL, approverId: 3 },
|
|
]
|
|
);
|
|
expect(plan.update).toEqual([
|
|
{ rowId: 10, stepIndex: 0 },
|
|
{ rowId: 11, stepIndex: 1 },
|
|
{ rowId: 12, stepIndex: 2 },
|
|
]);
|
|
expect(plan.create).toEqual([]);
|
|
expect(plan.remove).toEqual([]);
|
|
});
|
|
|
|
it('согласующий сменился — старая строка убирается, новая создаётся', () => {
|
|
const plan = planRoutePatch(
|
|
[row(10, 1), row(11, 2)],
|
|
[
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
{ phase: APPROVAL, approverId: 9 },
|
|
]
|
|
);
|
|
expect(plan.update).toEqual([{ rowId: 10, stepIndex: 0 }]);
|
|
expect(plan.create).toEqual([1]);
|
|
expect(plan.remove).toEqual([11]);
|
|
});
|
|
|
|
it('порядок шагов поменялся — строки сопоставляются по человеку, а не по позиции', () => {
|
|
const plan = planRoutePatch(
|
|
[row(10, 1), row(11, 2)],
|
|
[
|
|
{ phase: APPROVAL, approverId: 2 },
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
]
|
|
);
|
|
expect(plan.update).toEqual([
|
|
{ rowId: 11, stepIndex: 0 },
|
|
{ rowId: 10, stepIndex: 1 },
|
|
]);
|
|
expect(plan.create).toEqual([]);
|
|
expect(plan.remove).toEqual([]);
|
|
});
|
|
|
|
it('один человек дважды в фазе — пары по порядку, лишняя строка убирается', () => {
|
|
const plan = planRoutePatch([row(10, 1), row(11, 1), row(12, 1)], [
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
]);
|
|
expect(plan.update).toEqual([
|
|
{ rowId: 10, stepIndex: 0 },
|
|
{ rowId: 11, stepIndex: 1 },
|
|
]);
|
|
expect(plan.remove).toEqual([12]);
|
|
});
|
|
|
|
it('фаза важна — тот же человек в другой фазе считается другим шагом', () => {
|
|
const plan = planRoutePatch([row(10, 1, APPROVAL)], [{ phase: EXECUTION, approverId: 1 }]);
|
|
expect(plan.update).toEqual([]);
|
|
expect(plan.create).toEqual([0]);
|
|
expect(plan.remove).toEqual([10]);
|
|
});
|
|
|
|
it('строка делегата не сопоставляется и убирается, даже если человек есть в новом маршруте', () => {
|
|
const plan = planRoutePatch([row(10, 1), row(11, 5, APPROVAL, 1)], [
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
{ phase: APPROVAL, approverId: 5 },
|
|
]);
|
|
expect(plan.update).toEqual([{ rowId: 10, stepIndex: 0 }]);
|
|
expect(plan.create).toEqual([1]);
|
|
expect(plan.remove).toEqual([11]);
|
|
});
|
|
|
|
it('первая отправка (строк ещё нет) — всё создаётся', () => {
|
|
const plan = planRoutePatch([], [
|
|
{ phase: APPROVAL, approverId: 1 },
|
|
{ phase: EXECUTION, approverId: 2 },
|
|
]);
|
|
expect(plan).toEqual({ update: [], create: [0, 1], remove: [] });
|
|
});
|
|
});
|