Сводная ОСВ: сопоставление контрагента «Указать» → «Связать» по макету [32] (#14) #15

Merged
aep merged 1 commits from feat/14-osv-map-counterparty into test 2026-10-08 17:08:53 +03:00
Owner

Closes #14

Что сделано

  • «Указать» в сводной ОСВ [32-osv-no-inn]: у строк без сопоставленного ЮЛ ячейка ИНН подсвечена (цвета osv-table__inn-cell--required макета), рядом с ИНН из файла — красная ссылка «Указать».
  • Модалка «Выбор организации для связи с <имя из ОСВ>» [32-osv-map-counterparty]: поиск (пауза 300 мс), таблица ИНН / Организация / ГК / ГСК / ГСЗ / «Связать», блок «Рекомендуемые» с зелёной подсветкой и полосой слева, бейджи ГСК/ГСЗ как в макете. Галочка «Искать во всём справочнике» → scope=all; короче 3 символов запрос не уходит, показана подсказка.
  • «Связать» → POST …/osv/entries/{entry_ids.at(-1)}/counterparty. Ответы 409:
    • ALIAS_TAKEN → «Имя уже закреплено за <владельцы>. Перенести?» → повтор с move_alias: true;
    • LOCK_REQUIRED → «Взять версию в работу?» → POST …/lock → повтор;
    • LOCKED_BY_OTHER → «Версию держит <имя>» (имя из ответа lock или из карточки);
    • остальное — текстом сервера.
      После успеха: сообщение (с кем связано, сколько записей сопоставлено автоприменением, создан/перенесён алиас), модалка закрывается, перечитываются строки и …/osv/summary.
  • Логика — чистые функции counterpartyMapping.ts (14 тестов), API — getCounterpartyCandidates, mapCounterparty, lockVersion; типы CandidateOut, MapCounterpartyIn/Out.
  • Спека consolidated-osv-ui: требование «Ручное сопоставление контрагента».

Проверка

make check: biome — 0 ошибок (7 старых предупреждений, T2.3 из #6), tsc --noEmit чисто, vitest 20 файлов / 116 тестов, rsbuild build собирается.

В браузере (dev-сервер ветки :3001, Playwright 1600×1000, версия РБ 2025 К1, «Осталось: 1367»):

  • «Показать ЮЛ без ИНН» → у всех строк «Указать» в одну строку с ИНН; сверено с [32-osv-no-inn].
  • «Указать» у «АВТОГРУЗ» → модалка с кандидатами группы (реальный ответ arm-core); поиск «бисквит» → 1 кандидат; весь справочник + «аб» → подсказка, запроса нет; «пекар» → запрос scope=all. Блок «Рекомендуемые» сверен с [32-osv-map-counterparty] на подменённом флаге recommended (см. R-6).
  • Цепочка «Связать» → LOCK_REQUIRED → «Взять в работу» → POST …/lock → ALIAS_TAKEN → «Перенести» → move_alias: true → успех → перечитаны osv?unmapped=true и osv/summary; LOCKED_BY_OTHER → «Версию держит другой пользователь». POST сопоставления и lock в этом прогоне подменены (R-5).

Rulings I made

  • R-1: LOCK_REQUIRED → подтверждение «Взять версию в работу?» прямо в модалке. Кнопки «Взять в работу» в arm-web нет. Цена ошибки: н��зкая (подтверждение явное, блокировку можно снять DELETE …/lock).
  • R-2: LOCKED_BY_OTHER → только сообщение, перехвата нет (место перехвата — карточка [35]). Цена ошибки: низкая.
  • R-3: галочка «Искать во всём справочнике» (scope=all) — в макете её нет, там поиск только по группе. Без неё внешнего контрагента вне ГК не связать. Цена ошибки: низкая.
  • R-4: колонка ИНН 190 вместо 130, ИНН из файла показан рядом с «Указать». В макете у несопоставленной строки только «Указать», но несопоставленными считаются и строки с ИНН вне справочника (решение владельца 07.10.2026), и ИНН им нужен. Цена ошибки: низкая.
  • R-5: на стенде одна версия (РБ 2025 К1, демо 09.10). Настоящий POST записал бы сопоставление без отката через API и взял бы блокировку, поэтому в браузере POST сопоставления и lock подменены. Серверная часть покрыта тестами arm-core (Срез 4). Цена ошибки: средняя — первый настоящий прогон «Связать» стоит сделать после демо (D-5).
  • R-6: блок «Рекомендуемые» на реальных данных не появляется: строка с точным совпадением имени уже сопоставлена бы автоматически, кроме случая неоднозначности. Отрисовка проверена на подменённом флаге. Цена ошибки: низкая.

Deferred

  • D-1: пересопоставление уже связанных строк. В макете ИНН связанного ЮЛ — кнопка, которая снова открывает модалку, а у текущего кандидата стоит «Связано». Для этого нужен ИНН сопоставленного ЮЛ в ConsolidatedRowOut (arm-core).
  • D-2: «Взять в работу» / перехват блокировки на карточке версии [35].
  • D-3: модалка ухода с вкладки [31-00] «Остались неуказанные ИНН».
  • D-4: подсветка совпадений поиска в таблице кандидатов (в макете есть).
  • D-5: настоящий прогон «Связать» на стенде после демо.

🤖 Generated with Claude Code

https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2

Closes #14 ## Что сделано - **«Указать» в сводной ОСВ** [32-osv-no-inn]: у строк без сопоставленного ЮЛ ячейка ИНН подсвечена (цвета `osv-table__inn-cell--required` макета), рядом с ИНН из файла — красная ссылка «Указать». - **Модалка «Выбор организации для связи с <имя из ОСВ>»** [32-osv-map-counterparty]: поиск (пауза 300 мс), таблица ИНН / Организация / ГК / ГСК / ГСЗ / «Связать», блок «Рекомендуемые» с зелёной подсветкой и полосой слева, бейджи ГСК/ГСЗ как в макете. Галочка «Искать во всём справочнике» → `scope=all`; короче 3 символов запрос не уходит, показана подсказка. - **«Связать»** → `POST …/osv/entries/{entry_ids.at(-1)}/counterparty`. Ответы 409: - `ALIAS_TAKEN` → «Имя уже закреплено за <владельцы>. Перенести?» → повтор с `move_alias: true`; - `LOCK_REQUIRED` → «Взять версию в работу?» → `POST …/lock` → повтор; - `LOCKED_BY_OTHER` → «Версию держит <имя>» (имя из ответа lock или из карточки); - остальное — текстом сервера. После успеха: сообщение (с кем связано, сколько записей сопоставлено автоприменением, создан/перенесён алиас), модалка закрывается, перечитываются строки и `…/osv/summary`. - Логика — чистые функции `counterpartyMapping.ts` (14 тестов), API — `getCounterpartyCandidates`, `mapCounterparty`, `lockVersion`; типы `CandidateOut`, `MapCounterpartyIn/Out`. - Спека `consolidated-osv-ui`: требование «Ручное сопоставление контрагента». ## Проверка `make check`: biome — 0 ошибок (7 старых предупреждений, T2.3 из #6), `tsc --noEmit` чисто, vitest 20 файлов / 116 тестов, `rsbuild build` собирается. В браузере (dev-сервер ветки :3001, Playwright 1600×1000, версия РБ 2025 К1, «Осталось: 1367»): - «Показать ЮЛ без ИНН» → у всех строк «Указать» в одну строку с ИНН; сверено с [32-osv-no-inn]. - «Указать» у «АВТОГРУЗ» → модалка с кандидатами группы (реальный ответ arm-core); поиск «бисквит» → 1 кандидат; весь справочник + «аб» → подсказка, запроса нет; «пекар» → запрос `scope=all`. Блок «Рекомендуемые» сверен с [32-osv-map-counterparty] на подменённом флаге `recommended` (см. R-6). - Цепочка «Связать» → `LOCK_REQUIRED` → «Взять в работу» → `POST …/lock` → `ALIAS_TAKEN` → «Перенести» → `move_alias: true` → успех → перечитаны `osv?unmapped=true` и `osv/summary`; `LOCKED_BY_OTHER` → «Версию держит другой пользователь». POST сопоставления и lock в этом прогоне подменены (R-5). ## Rulings I made - R-1: `LOCK_REQUIRED` → подтверждение «Взять версию в работу?» прямо в модалке. Кнопки «Взять в работу» в arm-web нет. Цена ошибки: н��зкая (подтверждение явное, блокировку можно снять `DELETE …/lock`). - R-2: `LOCKED_BY_OTHER` → только сообщение, перехвата нет (место перехвата — карточка [35]). Цена ошибки: низкая. - R-3: галочка «Искать во всём справочнике» (`scope=all`) — в макете её нет, там поиск только по группе. Без неё внешнего контрагента вне ГК не связать. Цена ошибки: низкая. - R-4: колонка ИНН 190 вместо 130, ИНН из файла показан рядом с «Указать». В макете у несопоставленной строки только «Указать», но несопоставленными считаются и строки с ИНН вне справочника (решение владельца 07.10.2026), и ИНН им нужен. Цена ошибки: низкая. - R-5: на стенде одна версия (РБ 2025 К1, демо 09.10). Настоящий POST записал бы сопоставление без отката через API и взял бы блокировку, поэтому в браузере POST сопоставления и lock подменены. Серверная часть покрыта тестами arm-core (Срез 4). Цена ошибки: средняя — первый настоящий прогон «Связать» стоит сделать после демо (D-5). - R-6: блок «Рекомендуемые» на реальных данных не появляется: строка с точным совпадением имени уже сопоставлена бы автоматически, кроме случая неоднозначности. Отрисовка проверена на подменённом флаге. Цена ошибки: низкая. ## Deferred - D-1: пересопоставление уже связанных строк. В макете ИНН связанного ЮЛ — кнопка, которая снова открывает модалку, а у текущего кандидата стоит «Связано». Для этого нужен ИНН сопоставленного ЮЛ в `ConsolidatedRowOut` (arm-core). - D-2: «Взять в работу» / перехват блокировки на карточке версии [35]. - D-3: модалка ухода с вкладки [31-00] «Остались неуказанные ИНН». - D-4: подсветка совпадений поиска в таблице кандидатов (в макете есть). - D-5: настоящий прогон «Связать» на стенде после демо. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
aep added 1 commit 2026-10-08 16:40:04 +03:00
- ИНН-ячейка строк без сопоставления подсвечена, ссылка «Указать» рядом с ИНН из файла [32-osv-no-inn].
- Модалка «Выбор организации для связи с …» [32-osv-map-counterparty]: поиск с паузой 300 мс,
  scope group / весь справочник (от 3 символов), блок «Рекомендуемые», «Связать».
- POST …/osv/entries/{последняя entry_id}/counterparty; 409 ALIAS_TAKEN → перенос алиаса (move_alias),
  LOCK_REQUIRED → «Взять версию в работу?» → POST …/lock → повтор, LOCKED_BY_OTHER → имя держателя.
- После успеха перечитываются строки и сводка («Осталось N»).
- Чистые функции counterpartyMapping.ts + тесты; спека consolidated-osv-ui.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
aep merged commit 3bd8a22e33 into test 2026-10-08 17:08:53 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/arm-web#15
No description provided.