# 0001. Исключение поставщика из сравнения вместо удаления - Статус: Принято - Дата: 2026-10-27 - Задача: #1 (СТ ОМТС); ОИД — #3, КПС — #4 - Источник: Асиля Сарниязова, Teams, 2026-10-23, п.4: «Я случайно удалила из таблицы поставщика — и не смогла вернуть его назад, хоть и есть КП» ## Контекст На Шаге 3 (таблица сравнения) крестик на колонке поставщика удаляет его безвозвратно во всех трёх формах — СТ, ОИД, КПС: - колонка убирается из состояния формы, введённые цены стираются; - при сохранении все офферы по позициям СТ уходят в корзину и заново пишутся только оставшиеся поставщики (обычная правка записи на списках офферов заблокирована ресивером); - вернуть поставщика можно только повторной загрузкой КП на Шаге 2, цены, введённые руками, теряются. Офферы читает не только портал: - СТ — бэкенд `api.tnsu.kz/Report/CT` (PDF/Excel-отчёт, уходит в пакет INCORE); - ОИД — поток ИИ-комментария читает «Оценку поставщиков ОИД» сам; - потоки уведомлений — внешние, читают ли они офферы, по коду не определить. В закупочных системах (SAP Ariba, Coupa, Procore и др.) участника не удаляют, а отклоняют с причиной, и это остаётся в истории. ## Варианты **А. Флаг `isExcluded` на каждом оффере** в списках «Оценка поставщиков», «… ОИД», «… КПС». - Плюс: одна колонка, исключённые лежат рядом с обычными. - Минус: все сторонние читатели начнут видеть исключённых, пока каждый не добавит фильтр — бэкенд отчёта СТ (иначе исключённый попадёт в PDF и INCORE), поток ИИ ОИД, возможно потоки уведомлений. Выкатка строго по порядку: колонка → бэкенд и потоки → портал. **Б. JSON-снимок в шапке СТ** — колонка `excludedSuppliers` (Note) в «Сравнительной таблице» каждой формы. - Плюс: «Оценка поставщиков» не меняется, сторонние читатели ничего не замечают. - Минус: размер. Строка оффера — 200–300 символов; 3 поставщика × 100 позиций = 60–90 тыс. символов, с комплектами — вдвое больше. Предел многострочной колонки SP — около 64 тыс. Сохранение упадёт на обычных объёмах. **В. Отдельный список «Исключённые предложения»** под каждую форму («…», «… ОИД», «… КПС»): те же колонки, что в «Оценке поставщиков», плюс лукап на СТ. - Плюс: в «Оценке поставщиков» только активные поставщики — бэкенд, отчёт, INCORE и потоки не дорабатываются, порядок выкатки не важен. - Плюс: одна строка на оффер, объём не ограничен. - Минус: три новых списка, перенос строк между списками при исключении и возврате. ## Решение Вариант **В**. - Крестик исключает поставщика: колонка скрывается, итоги, минимумы, рекомендация и ИИ его не учитывают. Если исключили выбранного — выбор сбрасывается. - При исключении **причина обязательна**. Она хранится вместе с исключёнными строками. - Под таблицей у автора — плашка «Исключены из сравнения: поставщик — причина [Вернуть]». - **Согласующий исключённых пока не видит.** Данные для него грузятся так же, но показ выключен константой — включить можно без доработки хранения. - **Повторная загрузка КП** исключённого поставщика на Шаге 2 его не возвращает: он остаётся исключённым до «Вернуть». - При сохранении цены исключённых пишутся в «Исключённые предложения», в «Оценку поставщиков» не попадают. При открытии СТ исключённые читаются по id СТ. - «Вернуть» → при сохранении строки переезжают обратно в «Оценку поставщиков». - Поставщик без цен — одна строка-маркер без позиции, чтобы колонка не терялась. - Позицию сняли на Шаге 1 — её строки в «Исключённых» тоже уходят в корзину. - Запись офферов и исключённых — в общем модуле для трёх форм, чтобы позже перенести сохранение на бэкенд без переделки компонентов. ## Устройство списков Манифесты — `provisioning/manifests/{ct,oid,kps}.provisioning.json`. - Колонки — копия «Оценки поставщиков» своей формы (чтобы «Вернуть» восстановило оффер целиком) плюс `CT` (найти исключённых при открытии СТ) и `reason` (причина). - Ссылки на обычные списки — Lookup, файл КП — сразу `offerFileId: Number`: лукап на библиотеку документов не читается через REST. - Номер строки комплекта — в `Title`, как в «Оценке поставщиков» (`поставщик-позиция-N`): один формат во всех списках, разбор переиспользуется (`parseOfferItemIndex`). - Причина повторяется в каждой строке поставщика — осознанная денормализация. Отдельный список «Исключённые поставщики» дал бы 6 списков вместо 3 ради короткого текста. - Поставщик без цен — строка без `position`, чтобы колонка не терялась. ## Последствия - Три новых списка на `/sites/sed` — описать в `provisioning/manifests/{ct,oid,kps}`, создать через `Provision-Lists.ps1` (сначала тест, потом бой). - Доработка Шага 3 и загрузки СТ во всех трёх формах, Jest-тесты на исключение и возврат. - Попутно закрываются баги удаления: в ОИД выбор остаётся на удалённом поставщике, в КПС удалённый поставщик без КП возвращается после перезагрузки. ## Известные ограничения - **«Дополнительная информация» (условия оплаты, поставки, сроки) исключённого поставщика в SP не пишется** — «Критерии» читает отчёт СТ, и исключённый попал бы в него. В сессии автора условия сохраняются; если вернуть поставщика после открытия СТ в другом браузере, их придётся заполнить заново. Цены возвращаются всегда. - Если сессия автора уже есть, СТ берёт поставщиков из неё, а не из SP (как и раньше для обычных поставщиков). ## Объём Сейчас — только СТ ОМТС (#1). ОИД (#3) и КПС (#4) — позже: списки для них уже созданы, общий модуль `shared/offers/excludedOffers.ts` готов к переиспользованию. ## Ответы на открытые вопросы (2026-10-27, Тимур) 1. Согласующий исключённых — заложить, но пока не показывать. 2. Повторная загрузка КП не возвращает исключённого поставщика. 3. Причина исключения — обязательная. 4. Списки создаются через `Provision-Lists.ps1` по манифестам (сначала тест, потом бой).