fix(ct): null из потока КП не превращается в строку «null»

Когда в КП нет поля (например, сертификатов), поток отдаёт null, а
String(null) давал «null» — он показывался в «Сертификатах» шага 3 и
сохранялся в «Критерии». Разбор ответа вынесен в mapFlowResult: null —
«не распознано», как уже сделано в КПС и ОИД.
This commit is contained in:
Тимур Городецкий
2026-10-22 10:15:37 +05:00
parent 48c7999fa0
commit a0d9179d9d
3 changed files with 79 additions and 29 deletions
@@ -0,0 +1,48 @@
import { mapFlowResult } from './flowResult';
describe('mapFlowResult (ответ потока разбора КП)', () => {
// СТ 367: в КП нет сертификатов, поток вернул sertificates: null → String(null) = «null»,
// и в шаге 3 у всех поставщиков в «Сертификатах» стоял текст «null».
it('null в текстовых полях — пусто, а не строка «null»', () => {
const result = mapFlowResult({
position: null, unit: null, conditions: null, deliveryType: null,
deadline: null, sertificates: null, supplier: null, supplierBIN: null,
});
expect(result).toEqual({});
});
it('null в числах — не распознано (undefined), а не 0', () => {
const result = mapFlowResult({ price: null, cost: null, quantity: null });
expect(result).toEqual({});
});
it('заполненные поля переносятся как есть', () => {
const result = mapFlowResult({
position: 'Дюбель-гвоздь 6 x 40',
unit: 'шт.',
conditions: '40% предоплата, 60% перед отгрузкой',
deadline: '25-30 рабочих дней',
supplier: 'BuildCore Supply Ltd.',
price: '0.10',
cost: 1527.5,
quantity: 15275,
});
expect(result).toEqual({
position: 'Дюбель-гвоздь 6 x 40',
unit: 'шт.',
conditions: '40% предоплата, 60% перед отгрузкой',
deadline: '25-30 рабочих дней',
supplier: 'BuildCore Supply Ltd.',
price: 0.1,
cost: 1527.5,
quantity: 15275,
});
});
it('нечисловая цена — 0, как раньше', () => {
expect(mapFlowResult({ price: 'по запросу' }).price).toBe(0);
});
});
@@ -0,0 +1,29 @@
import { FlowResult } from '../types/domain';
// Поток отдаёт null, когда в КП поля нет (например, сертификатов). String(null) давал строку «null»,
// и она показывалась в шаге 3 и уходила в SP. null и undefined — «не распознано».
function optionalText(value: unknown): string | undefined {
return value !== undefined && value !== null ? String(value) : undefined;
}
// Нечисловое значение (например, «по запросу») — 0, как и раньше.
function optionalNumber(value: unknown): number | undefined {
return value !== undefined && value !== null ? Number(value) || 0 : undefined;
}
// Разбор ответа потока КП (JSON из responsev2.predictionOutput.text) — как в КПС (_mapFlowResult).
export function mapFlowResult(parsed: Record<string, unknown>): FlowResult {
return {
position: optionalText(parsed.position),
unit: optionalText(parsed.unit),
conditions: optionalText(parsed.conditions),
deliveryType: optionalText(parsed.deliveryType),
deadline: optionalText(parsed.deadline),
sertificates: optionalText(parsed.sertificates),
cost: optionalNumber(parsed.cost),
price: optionalNumber(parsed.price),
quantity: optionalNumber(parsed.quantity),
supplier: optionalText(parsed.supplier),
supplierBIN: optionalText(parsed.supplierBIN),
};
}
@@ -33,6 +33,7 @@ import {
import { CriteriaRecord, plainTextFromSp } from "../components/utils/criteria";
import { pickRowToNotify } from "../components/utils/approvalAccess";
import { buildPositionKeys } from "../components/utils/positionKey";
import { mapFlowResult } from "../components/utils/flowResult";
import {
NoOfferSupplierEntry,
NoOfferSupplierRecord,
@@ -1612,35 +1613,7 @@ export class CtService {
} catch {
return {};
}
return {
position:
parsed.position !== undefined ? String(parsed.position) : undefined,
unit: parsed.unit !== undefined ? String(parsed.unit) : undefined,
conditions:
parsed.conditions !== undefined ? String(parsed.conditions) : undefined,
deliveryType:
parsed.deliveryType !== undefined
? String(parsed.deliveryType)
: undefined,
deadline:
parsed.deadline !== undefined ? String(parsed.deadline) : undefined,
sertificates:
parsed.sertificates !== undefined
? String(parsed.sertificates)
: undefined,
cost: parsed.cost !== undefined ? Number(parsed.cost) || 0 : undefined,
price: parsed.price !== undefined ? Number(parsed.price) || 0 : undefined,
quantity:
parsed.quantity !== undefined
? Number(parsed.quantity) || 0
: undefined,
supplier:
parsed.supplier !== undefined ? String(parsed.supplier) : undefined,
supplierBIN:
parsed.supplierBIN !== undefined
? String(parsed.supplierBIN)
: undefined,
};
return mapFlowResult(parsed);
}
async loadOffersForPositions(positionSpIds: number[]): Promise<