fix(ct): список загруженных КП пропадал при открытии СТ без сессии

Лукап offer в «Оценке поставщиков» смотрит на FileLeafRef библиотеки КП,
а SP не отдаёт такой лукап через REST (500), поэтому loadKpFilesForOffers
всегда возвращал пусто и «Загруженные КП» видел только автор в своей сессии.
Id файла теперь дублируется в числовое поле offerFileId и читается оттуда.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Тимур Городецкий
2026-09-23 15:30:36 +05:00
parent adf3efeb64
commit a45807f669
2 changed files with 18 additions and 8 deletions
@@ -65,7 +65,8 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
const rawOffers = await service.loadFullOffersForPositions(positionSpIds);
// Build supplierSpId → offerId map from session uploadedKpFiles.
// offerId cannot be read back via SP REST (500), so we restore it from session.
// Лукап offerId через REST не читается (500), поэтому сначала берём из сессии, а без сессии —
// из числового дубля offerFileId (см. CtService.loadKpFilesForOffers).
// formData here is the initial mount value (session state before this update).
const offerIdBySupplierSpId = new Map<number, number>();
for (const kpFile of (formData.uploadedKpFiles ?? [])) {
@@ -120,7 +121,7 @@ const CtCreateForm: React.FC<ICtCreateFormProps> = ({ context, userDisplayName,
// Build offers in domain format, restoring offerId from session
const offers = rawOffers.map(o => {
const offerIdNum = offerIdBySupplierSpId.get(o.supplierSpId);
const offerIdNum = offerIdBySupplierSpId.get(o.supplierSpId) ?? o.offerFileSpId;
const currencyCode = o.valutaSpId ? (rateById.get(o.valutaSpId)?.code ?? 'KZT') : 'KZT';
return {
id: '',
@@ -543,7 +543,11 @@ export class CtService {
if (!isNaN(valId)) body.valutaId = valId;
}
const resolvedOfferId = o.offerId ? parseInt(o.offerId, 10) : undefined;
if (resolvedOfferId && !isNaN(resolvedOfferId)) body.offerId = resolvedOfferId;
if (resolvedOfferId && !isNaN(resolvedOfferId)) {
body.offerId = resolvedOfferId;
// Дубль лукапа числом — только его можно прочитать обратно (см. loadKpFilesForOffers).
body.offerFileId = resolvedOfferId;
}
const res = await this.http.post(this._li(LISTS.OFFERS), SPHttpClient.configurations.v1, {
headers: { "Content-Type": "application/json;odata=nometadata" },
@@ -777,6 +781,7 @@ export class CtService {
currencyCode: string;
valutaSpId?: number;
deliveryDistanceKm?: number;
offerFileSpId?: number;
}>
> {
if (positionSpIds.length === 0) return [];
@@ -787,7 +792,7 @@ export class CtService {
// valutaId is selected directly; caller enriches currencyCode via loadCurrencyRatesByIds.
const url =
`${this._li(LISTS.OFFERS)}` +
`?$select=positionId,supplierId,price,quantity,unit,priceTenge,summaTenge,valutaId,deliveryDistanceKm,supplier/Id,supplier/Title` +
`?$select=positionId,supplierId,price,quantity,unit,priceTenge,summaTenge,valutaId,deliveryDistanceKm,offerFileId,supplier/Id,supplier/Title` +
`&$expand=supplier` +
`&$filter=${filter}` +
`&$top=2000`;
@@ -810,6 +815,7 @@ export class CtService {
currencyCode: "KZT", // enriched by caller via loadCurrencyRatesByIds
valutaSpId: valutaSpId && !isNaN(valutaSpId) ? valutaSpId : undefined,
deliveryDistanceKm: item["deliveryDistanceKm"] != null ? Number(item["deliveryDistanceKm"]) : undefined,
offerFileSpId: item["offerFileId"] ? Number(item["offerFileId"]) : undefined,
};
});
}
@@ -826,11 +832,13 @@ export class CtService {
const filter = positionSpIds
.map((id) => `positionId eq ${id}`)
.join(" or ");
// offerId — обычное числовое поле (SP-Id строки файла КП), НЕ лукап. Раньше в $select
// ошибочно был offerIdId (raw-ID суффикс лукапа) — такого поля нет, и SP валил запрос 400.
// Лукап offer (КП) смотрит на FileLeafRef библиотеки — SP не отдаёт такой лукап через REST
// ни $select=offerId, ни $expand (500 «типы полей установлены неправильно»), и список КП
// всегда был пустым для всех, кроме автора в его сессии. Поэтому id файла дублируется
// в числовое поле offerFileId при записи и читается отсюда.
const url =
`${this._li(LISTS.OFFERS)}` +
`?$select=supplierId,offerId` +
`?$select=supplierId,offerFileId` +
`&$filter=${filter}` +
`&$top=2000`;
const res = await this.http.get(url, SPHttpClient.configurations.v1);
@@ -841,7 +849,7 @@ export class CtService {
const pairs: Array<{ supplierSpId: number; offerSpId: number }> = [];
for (const item of data.value ?? []) {
const supplierSpId = Number(item["supplierId"]);
const offerSpId = Number(item["offerId"] ?? 0);
const offerSpId = Number(item["offerFileId"] ?? 0);
if (!offerSpId || !supplierSpId || seen.has(supplierSpId)) continue;
seen.add(supplierSpId);
pairs.push({ supplierSpId, offerSpId });
@@ -1566,6 +1574,7 @@ export class CtService {
positionId: params.positionSpId,
supplierId: params.supplierSpId,
offerId: params.offerSpId,
offerFileId: params.offerSpId,
supplierPosition: params.supplierPosition,
unit: params.unit,
quantity: Number(params.quantity) || 0,