fix(ct): поставщик Шага 3 после черновика не задваивается при открытии СТ (#8)
«Сохранить черновик» оставляет поставщика, добавленного на Шаге 3, в списке шага, а в SP он уже лежит колонкой «поставщик_заглушка». Если других поставщиков в СТ нет, при открытии из реестра колонки собирались из SP — и поставщик приходил дважды: из SP без цен и из сессии с ценами (подписи колонок именем файла-заглушки .txt и «КП 2»). Теперь колонки из SP, которые уже есть поставщиком Шага 3, не добавляются, а их офферы идут к нему. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import { Step1PositionSelection } from './Step1PositionSelection/Step1PositionSe
|
||||
import { Step2CommercialOffers } from './Step2CommercialOffers/Step2CommercialOffers';
|
||||
import { Step3ComparisonTable } from './Step3ComparisonTable/Step3ComparisonTable';
|
||||
import { Step4Approval } from './Step4Approval/Step4Approval';
|
||||
import { buildColumnsFromSpOffers, buildSupplierColumnId, findColumnForRecord, findWinnerColumnId } from './utils/supplierColumns';
|
||||
import { buildColumnsFromSpOffers, buildSupplierColumnId, findColumnForRecord, findWinnerColumnId, withoutSessionExtras } from './utils/supplierColumns';
|
||||
import { buildOffersFromSpRecords } from './utils/spOffers';
|
||||
import { excludedItemsToFormData } from './utils/excludedColumns';
|
||||
import { isUserInApprovalChain } from './utils/approvalAccess';
|
||||
@@ -122,16 +122,22 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
|
||||
// КП в разных валютах. Используются, только когда в сессии колонок нет.
|
||||
const currencyCodeOf = (valutaSpId?: number): string =>
|
||||
valutaSpId ? (rateById.get(valutaSpId)?.code ?? 'KZT') : 'KZT';
|
||||
const spSuppliers = buildColumnsFromSpOffers(rawOffers.map(o => ({
|
||||
// Поставщики Шага 3 из сессии (после «Сохранить черновик») уже лежат в SP — их колонки из SP
|
||||
// не дублируем.
|
||||
const sessionExtras = formData.step3ExtraSuppliers ?? [];
|
||||
const spSuppliers = withoutSessionExtras(buildColumnsFromSpOffers(rawOffers.map(o => ({
|
||||
supplierSpId: o.supplierSpId,
|
||||
supplierName: o.supplierName,
|
||||
offerFileSpId: o.offerFileSpId,
|
||||
currencyCode: currencyCodeOf(o.valutaSpId),
|
||||
})));
|
||||
}))), sessionExtras);
|
||||
const supplierMap = new Map<number, string>();
|
||||
rawOffers.forEach(o => { if (!supplierMap.has(o.supplierSpId)) supplierMap.set(o.supplierSpId, o.supplierName); });
|
||||
// Колонка оффера: из сессии, если она есть (в т.ч. старая колонка без файла КП), иначе — из SP.
|
||||
const visibleColumns = formData.suppliers.length > 0 ? formData.suppliers : spSuppliers;
|
||||
// Поставщики Шага 3 — тоже колонки: их офферы из SP должны попасть к ним, а не в убранную колонку.
|
||||
const visibleColumns = formData.suppliers.length > 0
|
||||
? formData.suppliers
|
||||
: [...spSuppliers, ...sessionExtras.map(es => ({ id: es.id, spId: es.spId, name: es.name, hasOffer: true }))];
|
||||
const columnIdOf = (supplierSpId: number, offerFileSpId?: number): string =>
|
||||
findColumnForRecord(visibleColumns, supplierSpId, offerFileSpId)?.id
|
||||
?? buildSupplierColumnId(supplierSpId, offerFileSpId);
|
||||
|
||||
@@ -1,6 +1,31 @@
|
||||
import { buildColumnDisplayNames, buildColumnLabels, buildColumnsFromSpOffers, buildSupplierColumnId, findColumnForRecord, findSiblingColumnIds, findWinnerColumnId } from './supplierColumns';
|
||||
import { buildColumnDisplayNames, buildColumnLabels, buildColumnsFromSpOffers, buildSupplierColumnId, findColumnForRecord, findSiblingColumnIds, findWinnerColumnId, withoutSessionExtras } from './supplierColumns';
|
||||
import { Supplier } from '../types/domain';
|
||||
|
||||
describe('withoutSessionExtras (поставщик Шага 3 после «Сохранить черновик»)', () => {
|
||||
// СТ 375: единственный поставщик «fghfg» добавлен на Шаге 3, сохранён черновиком. При открытии из
|
||||
// реестра колонка собиралась из SP («285_322», без цен) и ещё раз приходила из сессии (с ценами).
|
||||
const fromSp: Supplier[] = [
|
||||
{ id: '285_322', spId: 285, kpFileSpId: 322, name: 'fghfg', hasOffer: true },
|
||||
{ id: '282_320', spId: 282, kpFileSpId: 320, name: 'Каспий Дорс', hasOffer: true },
|
||||
];
|
||||
|
||||
it('колонку поставщика Шага 3 из SP не добавляет — она уже есть в сессии', () => {
|
||||
const result = withoutSessionExtras(fromSp, [{ spId: 285, offerId: 322 }]);
|
||||
|
||||
expect(result.map(c => c.id)).toEqual(['282_320']);
|
||||
});
|
||||
|
||||
it('другой КП того же поставщика — отдельная колонка, остаётся', () => {
|
||||
const result = withoutSessionExtras(fromSp, [{ spId: 285, offerId: 999 }]);
|
||||
|
||||
expect(result.map(c => c.id)).toEqual(['285_322', '282_320']);
|
||||
});
|
||||
|
||||
it('поставщик Шага 3 ещё не сохранён в SP — ничего не убирает', () => {
|
||||
expect(withoutSessionExtras(fromSp, [{}])).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findWinnerColumnId (победитель из шапки СТ при открытии без сессии)', () => {
|
||||
const columns: Supplier[] = [
|
||||
{ id: '281_318', spId: 281, kpFileSpId: 318, name: 'SteelGate', hasOffer: true, exclusion: { reason: 'Дорого' } },
|
||||
|
||||
@@ -44,6 +44,22 @@ export function buildColumnsFromSpOffers(records: SpOfferColumnSource[]): Suppli
|
||||
return Array.from(columnsById.values());
|
||||
}
|
||||
|
||||
// Поставщик, добавленный на Шаге 3, в сессии: SP Id поставщика и его файла-заглушки КП.
|
||||
export interface SessionExtraColumn {
|
||||
spId?: number;
|
||||
offerId?: number;
|
||||
}
|
||||
|
||||
// Колонки из SP без тех, что в сессии уже есть поставщиком Шага 3. «Сохранить черновик» оставляет
|
||||
// такого поставщика в списке Шага 3 (см. buildSuppliersPatch), а в SP он уже лежит колонкой
|
||||
// «поставщик_заглушка». Без этого при открытии СТ, где других поставщиков нет, колонка задваивалась:
|
||||
// одна из SP без цен, вторая из сессии с ценами.
|
||||
export function withoutSessionExtras(spColumns: Supplier[], extras: SessionExtraColumn[]): Supplier[] {
|
||||
return spColumns.filter(column => !extras.some(extra =>
|
||||
extra.spId !== undefined && extra.spId === column.spId && extra.offerId === column.kpFileSpId,
|
||||
));
|
||||
}
|
||||
|
||||
// Колонка победителя по winSupplier из шапки СТ (СТ открыта без сессии). В SP хранится поставщик,
|
||||
// а не колонка: у поставщика с несколькими КП берём первую неисключённую колонку.
|
||||
export function findWinnerColumnId(columns: Supplier[], winSupplierSpId: number | undefined): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user