diff --git a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.module.scss b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.module.scss index ec5459a..27a549b 100644 --- a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.module.scss +++ b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.module.scss @@ -109,6 +109,30 @@ } } +// Размеры совпадают с селектом валюты в очереди загрузки (FileUploadArea), чтобы строки выглядели одинаково. +.kpCurrencySelect { + font-size: 11px; + padding: 2px 6px; + border: 1px solid $border; + border-radius: 3px; + background: $surface; + color: $text; + font-family: inherit; + cursor: pointer; + outline: none; + flex-shrink: 0; + height: 26px; + + &:focus { border-color: $accent; } +} + +.kpCurrencyCode { + flex-shrink: 0; + font-size: 12px; + font-weight: 600; + color: $muted; +} + .noOfferBadge { background: $danger-bg; color: $danger; diff --git a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.tsx b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.tsx index aa706fd..8b849a2 100644 --- a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.tsx +++ b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/Step2CommercialOffers.tsx @@ -11,6 +11,7 @@ import { useKpProcessing } from './useKpProcessing'; import { persistStep2 } from './step2Persist'; import { SuppliersWithoutKp } from './SuppliersWithoutKp'; import { UploadedKpList } from './UploadedKpList'; +import { applySupplierCurrency, getSupplierCurrency } from './kpCurrency'; import styles from './Step2CommercialOffers.module.scss'; interface Props { @@ -72,6 +73,23 @@ export const Step2CommercialOffers: React.FC = ({ onSave({ suppliers: [...withOffer, ...withoutOffer] }); }; + // Смена валюты уже загруженного КП (список «Загруженные КП»). Если файл ещё в очереди этой сессии, + // синхронизируем и её: иначе persistStep2 пересоберёт поставщика из kpFiles со старой валютой. + const handleUploadedCurrencyChange = (fileSpId: number, currencyCode: string): void => { + const uploaded = formData.uploadedKpFiles.find(u => u.spId === fileSpId); + if (!uploaded?.supplierName) return; + onSave(applySupplierCurrency( + formData.suppliers ?? [], + formData.offers ?? [], + uploaded.supplierName, + currencyCode, + currencyRates, + )); + kp.kpFiles + .filter(f => f.supplierName === uploaded.supplierName) + .forEach(f => kp.handleCurrencyChange(f.localId, currencyCode)); + }; + const handleSave = async (): Promise => { setIsSaving(true); setSaveError(undefined); @@ -133,8 +151,11 @@ export const Step2CommercialOffers: React.FC = ({ getSupplierCurrency(formData.suppliers ?? [], supplierName)} + onCurrencyChange={handleUploadedCurrencyChange} onRemove={(spId) => onSave({ uploadedKpFiles: formData.uploadedKpFiles.filter(u => u.spId !== spId) })} - disabled={isReadOnly} + disabled={isNotificationLink || isReadOnly} /> )} diff --git a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/UploadedKpList.tsx b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/UploadedKpList.tsx index 88fac4c..e4de8ba 100644 --- a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/UploadedKpList.tsx +++ b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/UploadedKpList.tsx @@ -7,12 +7,24 @@ import styles from './Step2CommercialOffers.module.scss'; interface Props { files: CTFormData['uploadedKpFiles']; service: CtService; + currencyOptions: string[]; + getCurrency: (supplierName: string | undefined) => string; + onCurrencyChange: (spId: number, currencyCode: string) => void; onRemove: (spId: number) => void; disabled?: boolean; } -// Секция «Загруженные КП» (постоянный список из formData): ссылка на файл + удаление из списка. -export const UploadedKpList: React.FC = ({ files, service, onRemove, disabled }) => ( +// Секция «Загруженные КП» (постоянный список из formData): ссылка на файл, валюта КП и удаление. +// Валюту здесь можно поправить и после возврата с Шага 3 — очередь загрузки к этому моменту уже пуста. +export const UploadedKpList: React.FC = ({ + files, + service, + currencyOptions, + getCurrency, + onCurrencyChange, + onRemove, + disabled, +}) => (

Загруженные КП

    @@ -27,12 +39,27 @@ export const UploadedKpList: React.FC = ({ files, service, onRemove, disa > {f.name} - onRemove(f.spId)} - disabled={disabled} - /> + {disabled ? ( + {getCurrency(f.supplierName)} + ) : ( + <> + + onRemove(f.spId)} + /> + + )} ))}
diff --git a/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/kpCurrency.ts b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/kpCurrency.ts new file mode 100644 index 0000000..8ca42f6 --- /dev/null +++ b/src/webparts/ctFormsPortal/forms/ct/components/Step2CommercialOffers/kpCurrency.ts @@ -0,0 +1,38 @@ +import { CurrencyRate, Supplier, SupplierOffer } from '../types/domain'; + +const BASE_CURRENCY = 'KZT'; + +// Валюта хранится на поставщике (Шаг 3 читает supplier.currency), а офферы несут цену в валюте КП +// и её пересчёт в тенге. При смене валюты уже загруженного КП обновляем и то и другое, чтобы +// таблица сравнения и сохранение офферов в SP (valutaId) видели одну и ту же валюту. +export function applySupplierCurrency( + suppliers: Supplier[], + offers: SupplierOffer[], + supplierName: string, + currencyCode: string, + currencyRates: CurrencyRate[], +): { suppliers: Supplier[]; offers: SupplierOffer[] } { + const supplierIds = new Set( + suppliers.filter(s => s.hasOffer && s.name === supplierName).map(s => s.id), + ); + const rate = currencyCode === BASE_CURRENCY + ? 1 + : (currencyRates.find(r => r.code === currencyCode)?.rateToKzt ?? 1); + + const nextSuppliers = suppliers.map(s => + supplierIds.has(s.id) ? { ...s, currency: currencyCode } : s, + ); + const nextOffers = offers.map(o => { + if (!supplierIds.has(o.supplierId)) return o; + const pricePerUnitKzt = o.pricePerUnit * rate; + const totalPriceKzt = pricePerUnitKzt * o.quantity; + return { ...o, currencyCode, pricePerUnitKzt, totalPriceKzt, totalWithExtraKzt: totalPriceKzt }; + }); + + return { suppliers: nextSuppliers, offers: nextOffers }; +} + +export function getSupplierCurrency(suppliers: Supplier[], supplierName: string | undefined): string { + const supplier = suppliers.find(s => s.hasOffer && s.name === supplierName); + return supplier?.currency ?? BASE_CURRENCY; +}