From a45807f6691cb8b734fe1e7f11fd234fdc9c9317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=93=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=86=D0=BA=D0=B8=D0=B9?= Date: Wed, 23 Sep 2026 15:30:36 +0500 Subject: [PATCH] =?UTF-8?q?fix(ct):=20=D1=81=D0=BF=D0=B8=D1=81=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B6=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=9A=D0=9F=20=D0=BF=D1=80=D0=BE=D0=BF=D0=B0=D0=B4?= =?UTF-8?q?=D0=B0=D0=BB=20=D0=BF=D1=80=D0=B8=20=D0=BE=D1=82=D0=BA=D1=80?= =?UTF-8?q?=D1=8B=D1=82=D0=B8=D0=B8=20=D0=A1=D0=A2=20=D0=B1=D0=B5=D0=B7=20?= =?UTF-8?q?=D1=81=D0=B5=D1=81=D1=81=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Лукап offer в «Оценке поставщиков» смотрит на FileLeafRef библиотеки КП, а SP не отдаёт такой лукап через REST (500), поэтому loadKpFilesForOffers всегда возвращал пусто и «Загруженные КП» видел только автор в своей сессии. Id файла теперь дублируется в числовое поле offerFileId и читается оттуда. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../forms/ct/components/CtCreateForm.tsx | 5 +++-- .../forms/ct/services/CtService.ts | 21 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/webparts/ctFormsPortal/forms/ct/components/CtCreateForm.tsx b/src/webparts/ctFormsPortal/forms/ct/components/CtCreateForm.tsx index d6a01d3..e60e8c1 100644 --- a/src/webparts/ctFormsPortal/forms/ct/components/CtCreateForm.tsx +++ b/src/webparts/ctFormsPortal/forms/ct/components/CtCreateForm.tsx @@ -65,7 +65,8 @@ const CtCreateForm: React.FC = ({ 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(); for (const kpFile of (formData.uploadedKpFiles ?? [])) { @@ -120,7 +121,7 @@ const CtCreateForm: React.FC = ({ 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: '', diff --git a/src/webparts/ctFormsPortal/forms/ct/services/CtService.ts b/src/webparts/ctFormsPortal/forms/ct/services/CtService.ts index d18750e..31a46d6 100644 --- a/src/webparts/ctFormsPortal/forms/ct/services/CtService.ts +++ b/src/webparts/ctFormsPortal/forms/ct/services/CtService.ts @@ -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,