fix(ct): поток уведомлений получает строку того, кто вернул на доработку или отклонил
Без активного согласующего форма отправляла потоку последнюю строку маршрута — при возврате на доработку это мог быть следующий согласующий в статусе «Ждёт очереди», и в письме инициатору нельзя было указать, кто вернул и с каким комментарием. Теперь (pickRowToNotify): активный согласующий → его строка; иначе строка «На доработке» или «Отклонено»; иначе последняя.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { findReworkRow, isUserInApprovalChain } from './approvalAccess';
|
import { findReworkRow, isUserInApprovalChain, pickRowToNotify } from './approvalAccess';
|
||||||
import { IMatrixRow } from '../../../../shared/approval';
|
import { IMatrixRow } from '../../../../shared/approval';
|
||||||
|
|
||||||
function makeRow(overrides: Partial<IMatrixRow>): IMatrixRow {
|
function makeRow(overrides: Partial<IMatrixRow>): IMatrixRow {
|
||||||
@@ -48,3 +48,29 @@ describe('findReworkRow (кто вернул СТ на доработку и ч
|
|||||||
expect(findReworkRow([makeRow({ status: 'Согласовано' })])).toBeUndefined();
|
expect(findReworkRow([makeRow({ status: 'Согласовано' })])).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('pickRowToNotify (какую строку маршрута передать потоку уведомлений)', () => {
|
||||||
|
const row = (id: number, status: string): { id: number; status: string } => ({ id, status });
|
||||||
|
|
||||||
|
it('есть активный согласующий — его строку («поступила на согласование»)', () => {
|
||||||
|
expect(pickRowToNotify([row(1, 'Согласовано'), row(2, 'На согласовании'), row(3, 'Ждёт очереди')])?.id).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Раньше при возврате уходила последняя строка (напр. «Ждёт очереди»), и поток не знал, кто вернул и с каким
|
||||||
|
// комментарием.
|
||||||
|
it('возврат на доработку — строку того, кто вернул', () => {
|
||||||
|
expect(pickRowToNotify([row(1, 'Согласовано'), row(2, 'На доработке'), row(3, 'Ждёт очереди')])?.id).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('отклонение — строку того, кто отклонил', () => {
|
||||||
|
expect(pickRowToNotify([row(1, 'Отклонено'), row(2, 'Ждёт очереди')])?.id).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('все согласовали — последнюю строку', () => {
|
||||||
|
expect(pickRowToNotify([row(1, 'Согласовано'), row(2, 'Согласовано')])?.id).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('пустой маршрут — нечего отправлять', () => {
|
||||||
|
expect(pickRowToNotify([])).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -22,3 +22,13 @@ export function isUserInApprovalChain(matrix: IMatrixRow[], user: CurrentUser):
|
|||||||
export function findReworkRow(matrix: IMatrixRow[]): IMatrixRow | undefined {
|
export function findReworkRow(matrix: IMatrixRow[]): IMatrixRow | undefined {
|
||||||
return matrix.find(row => row.status === REQUEST_STATUS.rework);
|
return matrix.find(row => row.status === REQUEST_STATUS.rework);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Строка маршрута для потока уведомлений (он по ней выходит на СТ, её автора и комментарий):
|
||||||
|
// активный согласующий — «поступила на согласование»; иначе строка того, кто вернул на доработку или
|
||||||
|
// отклонил, — чтобы в письме инициатору были его имя и комментарий; иначе (все согласовали) — последняя.
|
||||||
|
export function pickRowToNotify<T extends { status: string }>(rows: T[]): T | undefined {
|
||||||
|
return rows.find(r => r.status === REQUEST_STATUS.onApproval)
|
||||||
|
?? rows.find(r => r.status === REQUEST_STATUS.rework)
|
||||||
|
?? rows.find(r => r.status === REQUEST_STATUS.rejected)
|
||||||
|
?? rows[rows.length - 1];
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import {
|
|||||||
parseOfferItemIndex,
|
parseOfferItemIndex,
|
||||||
} from "../../../shared/offers/offerRecords";
|
} from "../../../shared/offers/offerRecords";
|
||||||
import { CriteriaRecord, plainTextFromSp } from "../components/utils/criteria";
|
import { CriteriaRecord, plainTextFromSp } from "../components/utils/criteria";
|
||||||
|
import { pickRowToNotify } from "../components/utils/approvalAccess";
|
||||||
import {
|
import {
|
||||||
NoOfferSupplierEntry,
|
NoOfferSupplierEntry,
|
||||||
NoOfferSupplierRecord,
|
NoOfferSupplierRecord,
|
||||||
@@ -746,14 +747,12 @@ export class CtService {
|
|||||||
async notifyActiveApprover(ctId: string): Promise<void> {
|
async notifyActiveApprover(ctId: string): Promise<void> {
|
||||||
const rows = await this.approval.getForRequest(parseInt(ctId, 10));
|
const rows = await this.approval.getForRequest(parseInt(ctId, 10));
|
||||||
if (rows.length === 0) return;
|
if (rows.length === 0) return;
|
||||||
// Есть активный согласующий → уведомляем его («поступила на согласование»).
|
// Есть активный согласующий → уведомляем его («поступила на согласование»). Иначе — строка того,
|
||||||
// Иначе финал (все согласовали / кто-то отклонил): активной строки уже нет, но поток
|
// кто вернул на доработку или отклонил (поток берёт из неё имя и комментарий для письма инициатору),
|
||||||
// сам выбирает получателя (инициатора) по статусу СТ — ему нужен лишь любой RowID этой СТ,
|
// а если все согласовали — последняя: поток по ней выходит на СТ и её автора. Раньше при возврате
|
||||||
// чтобы выйти на саму СТ и её автора. Берём последнюю строку маршрута. Без этого
|
// уходила последняя строка (напр. «Ждёт очереди»), и кто вернул и почему, поток не знал.
|
||||||
// «Согласовано»/«Отклонено» инициатору не уходили (поток вообще не вызывался).
|
const rowToNotify = pickRowToNotify(rows);
|
||||||
const active = rows.filter((r) => r.status === REQUEST_STATUS.onApproval)[0];
|
if (rowToNotify) await this.triggerApprovalNotification(rowToNotify.id);
|
||||||
const rowToNotify = active ?? rows[rows.length - 1];
|
|
||||||
await this.triggerApprovalNotification(rowToNotify.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async triggerApprovalNotification(spItemId: number): Promise<void> {
|
async triggerApprovalNotification(spItemId: number): Promise<void> {
|
||||||
|
|||||||
Reference in New Issue
Block a user