Files
ct-forms-portal/docs/adr/0001-isklyuchenie-postavshchikov.md
T
2026-10-27 11:52:16 +05:00

9.3 KiB
Raw Blame History

0001. Исключение поставщика из сравнения вместо удаления

  • Статус: Принято
  • Дата: 2026-10-27
  • Задача: #1
  • Источник: Асиля Сарниязова, 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 (как и раньше для обычных поставщиков).

Ответы на открытые вопросы (2026-10-27, Тимур)

  1. Согласующий исключённых — заложить, но пока не показывать.
  2. Повторная загрузка КП не возвращает исключённого поставщика.
  3. Причина исключения — обязательная.
  4. Списки создаются через Provision-Lists.ps1 по манифестам (сначала тест, потом бой).