feat: история согласования — маршрут пересохраняется патчем
При доработке и повторной отправке writeRoute раньше удалял все строки маршрута и создавал заново — кто вернул или отклонил заявку и с каким комментарием, терялось. Теперь маршрут пересохраняется патчем (planRoutePatch + ApprovalListService.patchSteps): строки, что остаются в маршруте, обновляются на месте, и их прошлые решения лежат в истории версий; недостающие шаги создаются, выпавшие и строки делегатов уходят в корзину. Всё одним пакетом. Проверено пилотами на увольнении и рабочем месте (обе фазы, уход в корзину). Аварийный откат для всех форм — ROUTE_PATCH_ENABLED = false. Из версий строк маршрута и заявки собирается лента «История согласования» (shared/approval/history): отправки, решения с комментариями и временем на шаге, делегирование, замена исполнителя, у кого заявка сейчас. Свёрнутый раздел в карточке и в форме доработки всех форм, грузится только при раскрытии. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
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: [] });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user