# Подписи

Подпись — фиксация согласия пользователя с решением: утверждён документ, принята заявка и т.д. Пользователь, ставящий подпись, называется **акцептантом** (конкретный сотрудник или группа). Подписи запрашиваются при переходе задачи между статусами; в момент подписания система делает цифровой снимок объекта — после этого изменить подписанные данные нельзя. Виды подписей: статическая (на переходе маршрута), динамическая (ручной запрос из карточки), должностная (акцептант по должности/оргструктуре), личная (конкретный пользователь). Документ описывает настройку шаблонов подписей, типов резолюций, привязку к шагам маршрута, подключение ЭЦП (КриптоПро, PayControl, DSS, Контур.Облако) и диагностику типичных ошибок.

## Где настраиваются подписи

## Настройки подписей категории (страница «Подписи»)

В настройках категории подписи вынесены на отдельную страницу «Подписи»: она открывается из списка настроек категории и заменяет прежнюю плоскую форму с флагами. Страница собрана на вкладках.

**Основные настройки** — правила работы с уже поставленными подписями: разрешить отзывать подписи; разрешить отзыв акцепторам; разрешить отзыв заказчику; остальные флаги того же блока.

**Дополнительные настройки** — параметры блока подписей на карточке: заголовок блока, порядок и видимость, а также настройки, зависящие от категории.

Сохранение общее для страницы: уход с несохранёнными изменениями требует подтверждения, а правки применяются после сохранения целиком.

Настройки подписей разнесены по нескольким местам администрирования:

| Что настроить | Где |
|---------------|-----|
| Шаблоны подписей (имя, акцептанты, срок, резолюции) | Администрирование → раздел **«Подписи»** (форма `signatures`) |
| Типы резолюций (Согласовать, Отклонить, Делегировать…) | На странице «Подписи» → кнопка **«Типы резолюций»** |
| Запрос подписи на переходе | Настройки категории → **Маршрут** → переход → вкладка **«Подписи на переходе»** |
| Право запрашивать и создавать динамическую подпись | Группа → вкладка **«Специальные права»** |
| Подключение ЭЦП (КриптоПро, DSS) | Администрирование → Подключения → **Сервисы** + форма сервиса |
| Выбор плагина ЭЦП | Администрирование → **КриптоПро: Выбор плагина** (`/spa/administration/eds-plugin-settings`) |

## Механизмы администрирования

Настройки подписей доступны через несколько механизмов: формы автоадминки, отдельную форму AdminSPA (выбор плагина ЭЦП) и Admin API.

### Автоадминка (dbadmin)

Часть настроек задаётся через формы автоадминки по их alias:

| Alias формы | Название | Таблица БД | Полей | Секций | Папка |
|-------------|----------|-----------|-------|--------|-------|
| `signatures` | Подписи | dbo.Signatures | 3 | 1 | Категории и процессы |
| `signature-resolution-types` | Типы резолюций | dbo.SignatureResolutionTypes | 13 | 1 | Служебное |
| `equal-users-for-signature` | Подписи группы | dbo.EqualUsersForSignature | 6 | 1 | Служебное |
| `cryptopro-verification-centers` | КриптоПро | dbo.CryptoProCertificationCenters | 7 | 1 | Подключения |
| `dsscryptopro-service-settings` | Сервис DSSCryptoPro | dbo.DSSCryptoProCredentials | 14 | 1 | Подключения |

### Отдельная форма AdminSPA и Admin API

Выбор плагина ЭЦП и журнал транзакций DSS вынесены в отдельные страницы AdminSPA:

| Страница | Адрес | Назначение |
|----------|------|------------|
| КриптоПро: Выбор плагина | `/spa/administration/eds-plugin-settings` | Выбор плагина ЭЦП: CryptoPro / RuToken / DefineOnClient (v2.268+) |
| Лог транзакций DSS | `/admin/DSSTransactionLog.aspx` (устаревший интерфейс; пункт меню AdminSPA в группе «Логи и статистика») | Журнал транзакций электронной подписи через DSS КриптоПро — диагностика проблем с ЭЦП, проверка статуса транзакции, аудит |

**Несохранённые изменения на странице выбора плагина.** Страница сравнивает текущий набор настроек с тем, что был загружен или сохранён последним: плагин по умолчанию и пары «категория — плагин», «группа — плагин». Если уйти со страницы с отличиями, открывается окно «Сохранить изменения»: «Сохранить» записывает настройки и продолжает переход, «Не сохранять» уходит без записи, крестик оставляет на странице. Имена категорий и групп в сравнении не участвуют — они приходят с сервера и отдельно не редактируются.

Программно подписи настраиваются через Admin API:

| Маршрут | Методы | Назначение |
|---------|--------|------------|
| `/api/admin/signatures` | GET, POST, DELETE | Управление подписями, привязка резолюций |
| `/api/admin/signature-resolution-types` | GET, POST, PUT, DELETE | Справочник типов резолюций: список и запись по id, создание, изменение, удаление |
| `/api/admin/subcat/step/signatures` | GET, POST, DELETE | Подписи на шагах маршрута, SQL-маршруты |
| `/api/admin/eds/plugin` | GET, PUT | Настройки плагина ЭЦП (глобально, по категории, по группе) |

**Контракт справочника типов резолюций.** Путь `/api/admin/signature-resolution-types`: `GET` — список всех типов, `GET {id}` — один тип, `POST` — создание, `PUT {id}` — изменение, `DELETE {id}` — удаление. Изменяющие методы доступны только под правами администратора. Поля записи: `id`, `name`, `nameSmartExpressionId`, `signatureActionId`, `memo`, `dialogHeader`, `colorHex`, `isDefault`, `reasonRequired`, `needConfirm`; в ответе дополнительно приходит `nameSmartExpression { id, name }` — найденное смарт-выражение названия. Проверка пары «Название / Название по смарт-выражению» выполняется на сервере до записи.

## Ключевые настройки

### Подписи (Signatures)

**Где настраивается:** Администрирование → раздел **«Подписи»** → карточка подписи (или Admin API `/api/admin/signatures`)
**Таблица БД:** `dbo.Signatures`

Все подписи системы перечислены на странице «Подписи» (рядом с названием — значок мультиязычности).

![Страница «Подписи»: список всех настроенных в системе подписей](https://help.1forma.ru/help-images/signatures/signature_list-01.png)

Новая подпись создаётся кнопкой «Создать»: задаётся название и при необходимости флаг «Может быть динамической».

![Форма создания подписи: название и флаг «Может быть динамической»](https://help.1forma.ru/help-images/signatures/signature_list_create.png)

Подпись — базовая сущность согласования. В карточке подписи настройки сгруппированы по вкладкам:

| Вкладка | Что настраивается |
|---------|-------------------|
| **Основное** | Название, «Не запрашивать повторно», добавление акцептанта в подписчики, запрос комментария при подписании, «Можно эскалировать» |
| **Подпись начальника** | Запрос подписи руководителя акцептанта |
| **Срок** | Минимальное и стандартное время на подписание, обязательность и возможность менять срок |
| **Динамическая подпись** | Может ли подпись запрашиваться вручную, обязательность причины, поведение при отклонении |
| **Резолюции** | Какие варианты решения доступны акцептанту |
| **Акцептанты** | Кто подписывает — алгоритм определения акцептанта (см. ниже) |
| **Используется** | В каких категориях задействована подпись |

![Карточка настройки подписи: вкладки «Основное», «Срок», «Динамическая подпись», «Резолюции», «Акцептанты»](https://help.1forma.ru/help-images/signatures/signature_settings.png)

**Несохранённые изменения в карточке подписи.** Настройки карточки записываются кнопкой «Сохранить». Если закрыть карточку кнопкой «Отмена» или уйти из неё по хлебным крошкам или ссылке с несохранёнными правками, открывается окно «Сохранить изменения» с тремя действиями: «Сохранить» записывает настройки и выполняет выход только после успешной записи — при ошибке пользователь остаётся в карточке и введённые значения не теряются; «Не сохранять» выходит без записи; крестик и «Отмена» оставляют в карточке. На карточке без изменений выход происходит без окна. Мгновенное применение состава акцептантов в таблицах «По группам» и «По параметру» и подтверждение удаления подписи этим окном не затронуты.

**Единица «день» в полях срока — рабочий день (с 2.268.341).** При сохранении значения в формах настройки подписи и подписи на переходе маршрута поле «дни» конвертируется в минуты по числу рабочих минут в дне из системной настройки `workTimeSettings.workMinutesInDay` (при стандартной конфигурации 8 рабочих часов → 480 минут). На обоих формах работает один общий хелпер `signature-time.helpers.ts`, поэтому единица измерения интерпретируется одинаково и при сохранении, и при загрузке существующей подписи. До 2.268.341 форма подписи на переходе сохраняла «1 день» как 1440 минут (календарные сутки), а рантайм складывал их через `AddWorkingMinutesToDate` (480 минут/день) — итог получался ≈3 рабочих дня вместо одного.

**Основное** — помимо названия, модуля и базовых флагов, есть **«Запретить акцептовать, если в документах есть правки от текущего пользователя»** (защита от конфликта интересов; файлы в скрытых ДП из проверки исключены).

**Подпись начальника** — выбор подписи руководителя (для эскалации) и флаг **«Добавлять акцептантов подписи начальника»**: акцептанты выбранной подписи начальника автоматически добавляются в акцептанты объекта.

![Вкладка «Подпись начальника»: выбор подписи руководителя и добавление её акцептантов](https://help.1forma.ru/help-images/signatures/signature_edit-0002.png)

**Срок** — минимальное и стандартное время на подписание (часы/минуты/дни), «Срок обязателен», «Срок можно менять»; срок на переходе не может быть меньше минимального для подписи.

![Вкладка «Срок»: минимальное и стандартное время на подписание](https://help.1forma.ru/help-images/signatures/signature_edit-003-001.png)

**Динамическая подпись** — «Может быть динамической», «Акцептант определяется по» (заказчик/исполнитель/ответственный/запросивший/смарт-выражение), «Причина запроса обязательна» и **«При отклонении»** с тремя вариантами: *Прервать согласование*, *Ожидать решения всех участников*, *Продолжить согласование*.

![Вкладка «Динамическая подпись»: режим, определение акцептанта, действие при отклонении](https://help.1forma.ru/help-images/signatures/signature_edit-0004.png)

**Резолюции** — доступные типы резолюций (по умолчанию: Подписать, Отклонить, Удалить, Делегировать); порядок кнопок при запросе подписи = порядок в блоке. «Эскалировать» доступна только при включённом «Можно эскалировать».

![Вкладка «Резолюции»: список доступных типов резолюций подписи](https://help.1forma.ru/help-images/signatures/signature_edit-0005.png)

**Используется** — категории и переходы, где подпись задействована: исходный и целевой статусы, обязательность, кнопка перехода.

![Вкладка «Используется»: категории и переходы, на которых запрашивается подпись](https://help.1forma.ru/help-images/signatures/signature_edit-0007.png)

**Активная подпись.** Запрошенная подпись считается активной, если `TaskSignatures.IsActive = 1` и `TaskSignatures.SignatureStateID = 3` (ожидание резолюции) — по этим полям диагностируют статус подписи в БД.

**Служебные подписи.** Часть подписей на странице «Подписи» служебные (например, «Подпись пользователя» для личной подписи) — удалить их нельзя. Подпись также нельзя удалить, если она используется хотя бы в одной категории.

В карточке задачи должностные и личные подписи запрашиваются на разных вкладках (см. [бизнес-логику подписей](https://help.1forma.ru/domains/signatures/business.md), раздел «Должностные и личные»). Вкладку, на которой открывается окно запроса, задаёт общая настройка «Вид динамической подписи по умолчанию» (`Settings.DynSignatureRequestDefaultType`: 1 — должностные, 2 — личные; без значения — должностные). Категории, в которых окно показывает только личные подписи, перечисляются в ключе `personalDynSignaturesOnly`.

![Запрос подписи в карточке задачи: вкладки «Должностные подписи» и «Личные подписи»](https://help.1forma.ru/help-images/signatures/signature_request_tabs.png)

| Маршрут | Назначение |
|----------|------------|
| `POST /api/admin/signatures` | Создание подписи |
| `GET /api/admin/signatures/{id}` | Карточка подписи |
| `GET /api/admin/signatures/{id}/resolutions` | Список привязанных резолюций |
| `POST .../resolutions/add` | Привязать резолюцию |
| `POST .../resolutions/remove` | Отвязать резолюцию |
| `GET .../subcategories` | Где используется подпись |

**История изменений шаблона.** Создание, изменение и удаление подписи фиксируются в общем журнале действий одной записью на операцию: при изменении в ней видны значения полей до и после, при изменении состава акцептантов — какие связи добавлены и какие удалены. Записи по самим шаблонам и записи по подписям на шагах маршрута различаются типом. В комментарии к записям по акцептантам указываются идентификаторы пользователя, группы и подписи, а не их названия.

#### Алгоритмы определения акцептанта

Кто должен подписать, задаётся в блоке «Акцептанты» настроек подписи. Параметр **«Акцептант определяется по»** задаёт базового пользователя, от которого считается алгоритм: заказчик, исполнитель, ответственный исполнитель или запросивший подпись. Если алгоритм определит нескольких акцептантов, подпись может обработать любой из них — резолюция любого считается их общей.

**По группам** — таблица соответствий «группа → акцептант»: если базовый пользователь входит в группу, подпись запрашивается у указанных для неё акцептантов. Если пользователь не входит ни в одну группу таблицы — подпись без акцептантов. Чтобы подпись всегда запрашивалась у одних и тех же акцептантов, добавьте единственную системную группу Users (в неё входят все).

![Определение акцептанта «По группам»: таблица «группа → акцептант»](https://help.1forma.ru/help-images/signatures/signature_edit-007.png)

**По параметру (ДП)** — акцептант зависит от значения ДП (таблица «значение → акцептант»; детали и валидация — в подразделе «Акцептанты «По параметру»» ниже). Таблица соответствий задаётся вручную или выбирается из таблицы БД (указываются колонка значений ДП и колонка ID пользователей-акцептантов). Если ДП имеет тип Lookup — в поле значения указывается ID задачи, а в таблицу добавляется третья колонка с текстом задачи. Если совпадений нет — берётся «Акцептант по умолчанию» (поле «Кому»); если и он не задан — подпись без акцептантов.

![Определение акцептанта «По параметру»: таблица «значение ДП → акцептант»](https://help.1forma.ru/help-images/signatures/signature_edit-011.png)

**По руководителю** — подпись запрашивается у руководителя базового пользователя. Параметр **«Ступень руководителя»** задаёт смещение от непосредственного руководителя: `0` (по умолчанию) — непосредственный (линейный) руководитель; `1` — руководитель непосредственного руководителя; `2` — на два уровня выше, и т. д. (ступень `N` соответствует уровню `N + 1` оргструктуры). Подпись запрашивается ровно у руководителей указанного уровня — одного яруса, а не у всей цепочки руководителей до него. Если руководителя нужного уровня в оргструктуре нет (заданная ступень выше её глубины), подпись запрашивается у руководителей верхнего доступного яруса: например, при ступени `2` в оргструктуре с двумя ярусами руководства акцептантом станет руководитель второго яруса. Если у пользователя нет ни одного руководителя, подпись создаётся без акцептантов. Если руководителей несколько — формируется одна подпись с несколькими акцептантами; опция **«Каждому акцептанту отдельную копию»** делает отдельную подпись каждому руководителю.

![Определение акцептанта «По руководителю»: ступень руководителя](https://help.1forma.ru/help-images/signatures/signature_edit-010.png)

**По смарт-выражению** — акцептанты возвращаются вычислением смарт-выражения. ⚠️ Выражение должно возвращать **список** пользователей, а не число/ID одного пользователя.

![Определение акцептанта «По смарт-выражению»](https://help.1forma.ru/help-images/signatures/signature_edit-013.png)

**По уровню оргструктуры** — акцептант = руководитель орг. единицы заданного уровня (уровень — по справочнику типов оргструктур) в той ветке иерархии, где находится базовый пользователь. Если руководителя нужного уровня нет (орг. единица в ветке пропущена) — берётся ближайший вышестоящий руководитель.

![Определение акцептанта «По уровню оргструктуры»](https://help.1forma.ru/help-images/signatures/signature_edit-009.png)

**По типу оргструктуры** — акцептант = руководитель орг. единицы более высокого уровня (тип — по справочнику оргструктур) относительно базового пользователя.

![Определение акцептанта «По типу оргструктуры»](https://help.1forma.ru/help-images/signatures/signature_edit-008.png)

```mermaid
flowchart TD
    A["Акцептант определяется по…"] --> B["По группам"]
    A --> C["По параметру (ДП)"]
    A --> D["По руководителю"]
    A --> E["По смарт-выражению"]
    A --> F["По уровню / типу оргструктуры"]
    B --> B1{"базовый юзер в группе таблицы?"}
    B1 -->|да| OK["Акцептанты определены"]
    B1 -->|нет| NONE["Без акцептантов"]
    C --> C1{"значение ДП в таблице?"}
    C1 -->|да| OK
    C1 -->|"нет, есть «по умолчанию»"| OK
    C1 -->|"нет и нет default"| NONE
    D --> D1{"есть руководитель выше пользователя?"}
    D1 -->|"да → нужный ярус или верхний доступный"| OK
    D1 -->|нет| NONE
    E --> OK
    F --> F1{"руководитель нужного уровня есть?"}
    F1 -->|да| OK
    F1 -->|"нет → ближайший вышестоящий"| OK
```

### Типы резолюций (SignatureResolutionTypes)

**Где настраивается:** на странице «Подписи» → кнопка **«Типы резолюций»** (форма `signature-resolution-types`)
**Таблица БД:** `dbo.SignatureResolutionTypes`
**Страница:** `/administration/signature-resolution-types` — отдельный экран админки; пункт «Типы резолюций» в дереве ведёт на него. Прежняя универсальная форма автоадминки `signature-resolution-types` оставлена только для просмотра: флаги добавления, изменения и удаления у неё сняты, поэтому править типы резолюций через неё в интерфейсе нельзя.

Тип резолюции — это вариант решения, который акцептант выбирает при обработке подписи (кнопки «Согласовать», «Отклонить», «На доработку» и т.д.). Каждый тип привязан к одному из действий над подписью.

Чтобы создать тип, на странице «Типы резолюций» нажмите **«+ Создать»**, заполните параметры и сохраните:

| Параметр | Описание |
|----------|----------|
| Название | Текст на кнопке резолюции (поддерживает мультиязычность) |
| Описание | Всплывающая подсказка при наведении на кнопку |
| Заголовок диалога | Заголовок окна ввода причины. Если пусто — стандартный текст «Введите причину…» |
| **Действие** | Что происходит при выборе резолюции: **Подписать** (задача переходит дальше по маршруту), **Отклонить** (остаётся в текущем статусе), **Удалить** (подпись удаляется, задача переходит дальше), **Эскалировать** (акцептантом становится руководитель), **Делегировать** (акцептантом становится другой пользователь), **Отозвать согласование** (подпись удаляется, задача остаётся) |
| Причина обязательна | Акцептант обязан ввести комментарий к резолюции; при пустом поле резолюция не выносится, сервер отвечает «Пожалуйста, заполните комментарий к резолюции» |
| Необходимо подтверждение резолюции | Защита от случайного нажатия: появляется окно «Вы уверены…» (особенно актуально в мобильном приложении) |
| Цвет | Цвет кнопки: `red`, `yellow`, `orange`, `green`, `cyan`, `blue`, `purple`, `pink`, `brown`, `grey` или в формате HEX (`#42AAFF`) |
| По умолчанию | Резолюция автоматически добавляется к новым подписям |
| Название по смарт-выражению | Текст кнопки рассчитывается смарт-выражением. В списке доступны только глобальные выражения; вычисление идёт при построении списка резолюций задачи |

**Правило обязательности названия.** В паре полей «**Название**» и «**Название по смарт-выражению**» должно быть заполнено **не менее одного**. Значения проверяются после обрезки пробелов по краям: строка из одних пробелов считается пустой. Оба поля можно заполнить одновременно — тогда текст кнопки рассчитывается по смарт-выражению. Если смарт-выражение не вернуло значения или его вычисление завершилось ошибкой, резолюция показывается со статичным «Название». Если оба поля пусты, тип не сохраняется: запрос отклоняется с ошибкой.

**Удаление типа.** Тип резолюции нельзя удалить, пока он выбран хотя бы на одной подписи задачи, — удаление отклоняется. Если тип нигде не выбран, вместе с ним удаляются его привязки к подписям.

![Окно создания типа резолюции: название, действие, причина, цвет, подтверждение](https://help.1forma.ru/help-images/signatures/resolution_type_editor.png)

### Подписи на шагах маршрута (StatesRoutesSignatures)

**Где настраивается:** Admin API
**Маршрут:** `/api/admin/subcat/step/signatures`

Привязка подписей к переходам между статусами (шагам маршрута). Ключевые возможности:

| Маршрут | Назначение |
|----------|------------|
| `GET .../step/{stepId}/id/{stepSignatureId}` | Детальная настройка подписи на переходе |
| `POST /api/admin/subcat/step/signatures` | Добавление подписи на переход |
| `GET .../route-from-sql` | SQL-маршрут (динамическое определение акцептантов) |
| `POST .../route-from-sql` | Обновление SQL-маршрута |
| `POST .../step/{stepId}/add-owner-signature` | Быстрое добавление подписи заказчика |

#### Окно «Редактирование подписи при переходе»

Подпись на переходе настраивается карточкой: на вкладке «Подписи на переходе» в настройках перехода выберите или добавьте подпись и откройте «Редактирование подписи при переходе». Окно хранит настройку по вкладкам, и набор дополнительных параметров каждой вкладки записывается отдельным полем.

| Вкладка | Что задаёт | Поле в Admin API |
|---------|-----------|-----------------|
| Общее окно | Свойства подписи: акцептанты, срок, флаги активности и обязательности, поведение при неподписании. Полный состав — [Ключевые параметры подписи на переходе](https://help.1forma.ru/domains/signatures/business.md) | — |
| Обязательные ДП | Параметры, которые должны быть заполнены перед вынесением резолюции, и признаки «Обязателен перед подписью» и «Блокировать ДП при запросе подписи» | `stepExtParamRestrictions: [{ extParamId, isRequiredForSign, isReadOnlyOnSign }]` (с 2.267; ранее — `stepSignExtParamsIdForRestriction`) |
| Информационные ДП | Параметры, которые согласующий видит при обработке подписи, — только для чтения, заполнять их не нужно | `StepSignExtParamsIdForInfo` и признак `IsSignInfo` |
| Условия запроса | Условие, при котором подпись запрашивается: по значениям параметров или по смарт-фильтру | `StepSignatureConditions` |
| Настройки ЭП (ЭЦП) | Файлы параметров, которые подписываются, и настройки криптопровайдера | `EdsSignSettings` |

Вкладки «Обязательные ДП», «Информационные ДП» и «Условия запроса» устроены одинаково: сверху выпадающий список доступных параметров, рядом — поле значения (на вкладке «Обязательные ДП» — два флажка у каждой строки), ниже таблица уже добавленных параметров. Чтобы добавить параметр, выберите его в выпадающем списке и нажмите «Добавить»: строка появляется в таблице и уходит на сервер только после «Сохранить» в окне. Уже добавленный параметр повторно не добавляется — строка в выпадающем списке убирается, а по кнопке удаления она снимается из настройки.

**Быстрое добавление подписи заказчика (UI).** В окне настройки перехода, на вкладке «Подписи на переходе», есть кнопка **«Добавить подпись заказчика»** — она одним нажатием добавляет в список подпись заказчика (через `.../add-owner-signature`), после чего становится неактивной. Если подпись заказчика на переходе уже есть, кнопка неактивна сразу. При ошибке кнопка остаётся активной — можно повторить. Обычное добавление подписи через «+ Добавить» работает как прежде.

**Связь с категориями:** привязка подписей к маршрутам — часть настройки категории, но управляется через отдельный раздел Admin API.

Подписи элементов настройки подписей — названия вкладок, пункты выпадающих списков, подписи полей и тексты диалогов — зависят от языка администратора и правятся ресурсными ключами SPA; см. [localization/admin.md](https://help.1forma.ru/domains/localization/admin.md).

#### Справочник форматов запросов

**Создание шаблона подписи** (`POST /api/admin/signatures`):

Тело запроса — 2 поля:

```json
{ "name": "TM_Signature", "canBeDynamic": true }
```

Ответ: `{ "data": 2460 }` — ID созданной подписи.

**Обновление шаблона** (`POST /api/admin/signatures/{id}`):

Тело запроса (как в ответе GET). Ключевые поля:

```json
{
  "id": 2460,
  "description": "TM_Signature",
  "canBeDynamic": true,
  "acceptorsEvalutionBaseUser": "Owner",
  "acceptorsEvalutionMethod": "ByGroup",
  "actionIfNotSigned": 0,
  "signatureAcceptorsByGroups": [
    { "groupId": 2085, "aceptorUsers": [], "aceptorGroups": [] }
  ]
}
```

Ответ: 204 No Content.

**Привязка подписи к шагу маршрута** (`POST /api/admin/subcat/step/signatures`):

Тело запроса — 30+ полей. Минимальный рабочий пример:

```json
{
  "StepId": 216570,
  "SignatureId": 2460,
  "IsNecessary": true,
  "SignatureOrder": 1,
  "Enabled": true,
  "AcceptorsEvalutionBaseUser": 0,
  "Description": "",
  "IsSignRestriction": false,
  "IsSignInfo": false,
  "IsOwnerSignature": false,
  "IsEds": false,
  "StepsIfNotSigned": [],
  "StepSignExtParamsIdForRestriction": [],
  "StepSignExtParamsIdForInfo": [],
  "StepSignatureConditions": [],
  "EdsSignSettings": []
}
```

Ответ: 200 OK с полной настройкой подписи (поле `id` — это stepSignatureId).

**Важные нюансы:**

- `StepId` — это PK из таблицы `StatesRoutesInSubcat` (не StateID!). Поиск: `SELECT StepID, StateID, StateNextID, StepDescr FROM StatesRoutesInSubcat WHERE SubcatID = X`
- `AcceptorsEvalutionBaseUser` — число (0=Owner, 1=Performer, 2=ResponsiblePerformer, 3=Requester, 4=SmartExpression), не строка
- `SignatureOrder` — этап согласования (нумерация с 1). Несколько подписей на одном шаге с разными order = последовательное согласование
- `IsNecessary: true` — подпись обязательна (блокирует переход до получения)
- Массивы `StepsIfNotSigned`, `StepSignExtParamsIdForRestriction` и т.д. можно передавать пустыми `[]`
- **С 2.267:** вместо плоского массива `StepSignExtParamsIdForRestriction` используется `stepExtParamRestrictions: [{ extParamId, isRequiredForSign, isReadOnlyOnSign }]`. Два независимых флага:
  - `IsRequiredForSign` (по умолчанию = 1) — ДП обязателен к заполнению перед акцептом подписи (старое поведение, сохранено для всех существующих записей).
  - `IsReadOnlyOnSign` (по умолчанию = 0) — ДП блокируется (становится только для чтения) на время, пока на шаге активна подпись.
  - Флаги независимы: один ДП может быть одновременно обязательным к заполнению и блокируемым при подписи (сценарий «заполнить → отправить на подпись → заморозить»). Хранение: колонки `IsRequiredForSign` и `IsReadOnlyOnSign` в таблице `dbo.StepSignExtParamRestrictions`.
- Идемпотентность: API не проверяет дубли — при повторном POST создаст дублирующую привязку. Проверяйте через `GET ?stepId=X`

#### Маршрут из SQL-запроса: пустой Source при сохранении (с 2.268.373, задача #2095907)

При сохранении настройки «Маршрут из sql запроса» (`POST .../route-from-sql`) с пустым полем `Source` запись sql-настроек и сам сервис c `ServiceType=SqlRouteSignatures` теперь полностью удаляются. Раньше сервис оставался без источника, и при попытке перехода по маршруту падала ошибка `CommandText property has not been initialized`. Поведение: чтобы выключить динамический SQL-маршрут — достаточно очистить Source и сохранить.

#### Параллельные подписи (флаг IsWaitingSign, v2.268.104)

Флаг `IsWaitingSign` на задаче определяет, ожидает ли задача подписи. Логика сброса при выполнении шага:

- **До 2.268.104:** `IsWaitingSign = false` при завершении любого шага подписи — даже если на других шагах оставались активные подписи. Это приводило к некорректному состоянию задачи.
- **С 2.268.104:** `IsWaitingSign` сбрасывается только если **нет активных подписей на других шагах**.

**Сценарий:** задача на маршруте с параллельными подписями (несколько StepSignature с разными `SignatureOrder` или на разных шагах). При завершении одной подписи остальные продолжают удерживать задачу в состоянии «ожидание подписи».

### Подписи группы и КриптоПро-сервисы

**Подписи группы (EqualUsersForSignature):**

Где настраивается: автоадминка → форма `equal-users-for-signature`. Таблица БД: `dbo.EqualUsersForSignature`.

Определяет, какие пользователи из группы могут подписывать за друг друга (взаимозаменяемость подписантов). 6 полей: `SignatureId`, `GroupId`, `UserId`, настройки доступа.

**КриптоПро (CryptoProCertificationCenters):**

Где настраивается: автоадминка → форма `cryptopro-verification-centers`. Таблица БД: `dbo.CryptoProCertificationCenters`.

Подключение к удостоверяющим центрам КриптоПро для электронной подписи. 7 полей: URL, сертификат, настройки подключения и список доверенных отпечатков серверного сертификата УЦ.

Поле «Доверенные отпечатки SHA-256 серверного сертификата» задаёт, каким серверным сертификатам УЦ доверяет сервер 1Формы при вызове его REST API. Значения — отпечатки SHA-256 через запятую; после удаления двоеточий и пробелов отпечаток содержит ровно 64 шестнадцатеричных символа, регистр не важен. Пустое поле оставляет прежнее поведение: соединение принимается с любым сертификатом, а в лог один раз пишется предупреждение. Заполненное — запрос проходит только при совпадении отпечатка сертификата сервера или элемента его цепочки; при этом отклоняются сертификат с чужим именем хоста, сертификат вне срока действия, отсутствующий сертификат и запись, из которой не разобралось ни одного отпечатка, — даже если рядом стоит корректная. Ошибки цепочки доверия допускаются: это нужно для приватных и самоподписанных УЦ. Проверка распространяется только на REST-вызовы к УЦ (`CRYPTO:send_request`) — резервные операции через SOAP поле не читают. Отказ проверки возвращается вызывающему коду как ошибка HTTP-запроса и записывается в лог автоматизаций. Полное описание — [cryptopro-ca.md](https://help.1forma.ru/domains/signatures/cryptopro-ca.md), раздел «Проверка серверного сертификата УЦ (по отпечаткам)».

**DSS КриптоПро (DSSCryptoProCredentials):**

> Недоступно в Certificate Edition (ФСТЭК-сборка `UniForm.Barebone`, с 2.268.353): модуль `UniForm.Module.Eds` исключён из сборки, формы и журнал транзакций DSS не публикуются. То же — для Контур.Cloud.

**Где настраивается:** автоадминка → форма `dsscryptopro-service-settings`
**Таблица БД:** `dbo.DSSCryptoProCredentials`

Подключение к сервису облачной ЭЦП КриптоПро DSS. 14 полей:

| Параметр | Описание |
|----------|---------|
| Сервис | Предварительно созданный сервис с типом DSSCryptoPro (страница Сервисы) |
| SignServer | Сервер подписания |
| StsAppName | Сервер регистрации |
| Host | Стенд |
| Auth with password | Тип аутентификации: **One-factor authentication with password** (логин + пароль) или **Two-factor authentication with MyDSS** (логин + код на привязанный телефон). При 2FA при смене устройства требуется перевыпуск. |
| ClientId | ID клиента |
| ClientSecret | Секретный код клиента |
| Waiting sign time | Максимальное время ожидания подтверждения подписи с телефона при двухфакторной аутентификации, секунды. При превышении транзакция прерывается. |

![Форма «Сервис DSSCryptoPro»: сервер подписания, метод аутентификации, время ожидания подписи](https://help.1forma.ru/help-images/signatures/dss_service_settings.png)

**Порядок подключения (4 шага):** установить и настроить DSSCryptoPro по документации производителя → создать сервис в 1Форме → заполнить параметры подключения → указать сервис в настройках подписи на переходе.

### PayControl

Подключение и параметры сервиса (system_id, Server Signer API, ДП пользователя) описаны в [integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md).

Здесь — только то, что не покрыто интеграциями: **перерегистрация при утере телефона**. Перевыпуск сертификата по истечении срока, утеря смартфона или переустановка приложения 1F Mobile — через API PayControl (обновление ключа `server_signer: true` на сервере PayControl вручную).

Подробнее — раздел [PayControl в integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md#paycontrol-мобильная-эп).

### PayControl, Контур.Облако и настройка рабочего места для ЭЦП

Подключение и параметры сервиса PayControl (system_id, Server Signer API, ДП пользователя) описаны в [integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md).

Здесь — только то, что не покрыто интеграциями: **перерегистрация при утере телефона**. Перевыпуск сертификата по истечении срока, утеря смартфона или переустановка приложения 1F Mobile — через API PayControl (обновление ключа `server_signer: true` на сервере PayControl вручную).

Подробнее — раздел [PayControl в integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md#paycontrol-мобильная-эп).

**Контур.Облако (УКЭП без локального токена):**

Подключение и параметры описаны в [integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md).

Позволяет подписывать документы УКЭП или НЭП без локального носителя; подтверждение — SMS-кодом.

Подробнее — раздел [Контур.Облако в integrations/admin.md](https://help.1forma.ru/domains/integrations/admin.md#контуроблако-облачная-укэп).

**Настройка рабочего места пользователя для ЭЦП:**

**КриптоПро (токен КриптоПро):**

- [Плагин КриптоПро](https://www.cryptopro.ru/products/cades/plugin) — установить и включить в браузере
- [КриптоПро CSP](https://www.cryptopro.ru/downloads) — криптопровайдер
- Корневой сертификат УЦ, выдавшего ЭП — установить в доверенные корневые центры сертификации

**РуТокен:**

- [Плагин РуТокен](https://www.rutoken.ru/support/download/rutoken-plugin/) — установить и включить в браузере
- Корневой сертификат УЦ, выдавшего ЭП

**Выбор на клиенте:** если выбран плагин «Определять на клиенте» — в момент подписания у пользователя запрашивается, какой плагин использовать. Требуется установка обоих плагинов.


### JS API КриптоПро и смарт-автоматизация для сертификатов

УЦ КриптоПро управляет сертификатами (выдача, проверка, отзыв, приостановка, возобновление). Серверные действия автоматизируются смарт-действиями, клиентские (считывание токена) — JS API.

#### Смарт-действия (CryptoPro CA)

Серверные действия с сертификатами автоматизируются смарт-действиями:

| Смарт-действие | Назначение | Ключевые параметры |
|----------------|-----------|-------------------|
| Issue certificate | Выпуск сертификата | ID CA, ID ДП с GUID пользователя в УЦ, ID ДП со строкой запроса, ID ДП с Request ID, ID ДП для записи сертификата |
| New or update user | Привязка сертификата к пользователю 1Формы | ID CA, ID ДП с XML данными пользователя, Task number |
| Pause certificate | Приостановка сертификата | ID CA, ID ДП с сертификатом (base64), дата начала/конца, причина |
| Resume certificate | Возобновление сертификата | ID CA, ID ДП с сертификатом |
| Revoke certificate | Отзыв сертификата | ID CA, ID ДП с сертификатом, дата отзыва, причина |
| Get Thumbprint | Получение отпечатка подписи | ID ДП с сертификатом, ID ДП для записи отпечатка |

#### JS API (выполняется на клиенте)

Клиентские методы для работы с токеном:

| Метод | Что делает | Параметры |
|-------|-----------|-----------|
| `tcCryptoLogic.newRequest(taskId, RequestString_EP_ID, Request_EP_ID, {extParamsId:{ContainerName: 'Container_EP_ID'}})` | Создать запрос на сертификат | ID ДП со строкой запроса, ID ДП для записи Request, ID ДП с названием носителя |
| `tcCryptoLogic.installCertificate(taskId, Certificate_EP_ID)` | Записать сертификат на носитель | ID ДП с сертификатом |
| `tcCryptoLogic.changePin(thumbprint_EP_ID)` | Сменить PIN-код (CryptoPro) | ID ДП с отпечатком. Для RuToken — без параметров |

Формат XML данных о пользователе (для Issue certificate / New or update user):

```xml
<ProfileAttributesChange>
  <From>
    <Attribute Oid="2.5.4.3" Value="Иванов Иван Иванович"/>
    <Attribute Oid="2.5.4.4" Value="Иванов"/>
    <Attribute Oid="2.5.4.42" Value="Иван Иванович"/>
    <Attribute Oid="1.2.840.113549.1.9.2" Value="29U6MCO"/>
    <Attribute Oid="2.5.4.10" Value="ООО Ромашка"/>
    <Attribute Oid="2.5.4.12" Value="Заместитель директора"/>
  </From>
  <To>
    <!-- аналогично для целевых значений -->
  </To>
</ProfileAttributesChange>
```

Формат атрибутов сертификата:

```json
[
  {"rdn": "commonName", "cpn": "CN", "value": "ИвановИИ"},
  {"rdn": "surname", "cpn": "SN", "value": "Иванов"},
  {"rdn": "givenName", "cpn": "G", "value": "Иван Иванович"},
  {"rdn": "organizationName", "cpn": "O", "value": "ООО Ромашка"},
  {"rdn": "title", "cpn": "T", "value": "Директор"},
  {"rdn": "emailAddress", "cpn": "E", "value": "ivanov@romashka.ru"}
]
```


### Выбор плагина ЭЦП

**Где настраивается:** AdminSPA → `/spa/administration/eds-plugin-settings` (v2.268+)

Три уровня настройки:

1. **Глобальный** — плагин по умолчанию для всей системы
2. **По категории** — переопределение для конкретных категорий
3. **По группе** — переопределение для групп пользователей

Варианты плагинов: CryptoPro, RuToken, DefineOnClient (определить на клиенте).

![Страница «КриптоПро: Выбор плагина»: плагин по умолчанию, переопределение по категориям и группам](https://help.1forma.ru/help-images/signatures/eds_plugin_settings.png)

Удаление записей (категории или группы из списка) выполняется мгновенно, отдельным запросом — без нажатия «Сохранить».

**Admin API:**

| Маршрут | Назначение |
|----------|------------|
| `GET /api/admin/eds/plugin` | Получить текущие настройки плагина: плагин по умолчанию, настройки для категорий и групп |
| `PUT /api/admin/eds/plugin` | Полностью заменить настройки категорий и групп (полная замена) |

До v2.268 настройка выполнялась через EntityEditor (`/spa/administration/entity/cryptoProPlugin`); этот механизм упразднён.

### SignaturesGridSettings — настройка колонок списка подписей

**Версии:** v2.256 Феникс — v2.265 Цефей. С v2.266 — нативная настройка колонок.
**Где настраивается:** пользовательский ключ `SignaturesGridSettings` (`SettingsCustom`)

Формат ключа:

```json
{"columns":[{"key": "...", "type": "...", "isHidden": true/false}]}
```

Флаг `isHidden` управляет видимостью колонки: `false` — отображается, `true` — скрыта даже из меню «доступных колонок».

Для вывода значений ДП в список подписей: в качестве `type` указать `"extparam"`, в `key` — ID нужного ДП. Работает для обычных ДП; информационные ДП (отображаются серыми блоками под строкой) этим не управляются.

#### Системные колонки

Доступные системные колонки списка подписей:

| key | Колонка | type |
|-----|---------|------|
| `taskText` | Текст задачи | `general` |
| `signatureReason` | Причина запроса подписи | `general` |
| `signatureOrderedTime` | Срок | `general` |
| `description` | Описание | `general` |
| `signatureAndText` | Подпись и текст задачи | `general` |
| `signatureAcceptants` | Согласующие | `general` |
| `signatureInitializeDate` | Дата запроса | `general` |
| `subcatName` | Категория | `general` |
| `ownerName` | Заказчик | `general` |
| `responsiblePerformer` | Исполнитель | `general` |
| `requestorName` | Запросивший подпись | `general` |
| `timeToSign` | Время на подпись | `general` |
| `actions` | Действия | `general` |
| `commentsFromMeCount` | Вопросы от меня | `general` |
| `commentsToMeCount` | Вопросы мне | `general` |
| `isAnyUnAnswered` | Мои вопросы | `general` |
| `taskId` | Номер задачи | `general` |
| `taskState` | Статус | `general` |
| `activeSubtasks` | Активных подзадач | `general` |
| `totalSubtasks` | Всего подзадач | `general` |
| `subtasksRes` | Подзадачи | `general` |
| `taskPriority` | Приоритет | `general` |
| `{ExtParamId}` | Любой ДП (ID задаётся в key) | `extparam` |


### Совмещение статической и динамической подписи

Одна и та же подпись может быть **одновременно** статической и динамической: на переходе она запрашивается как статическая (привязана к шагу), но в рамках того же перехода допускается запросить её динамически.

При отклонении динамической подписи параметр **«Прерывать согласование на переходе, если подпись отклонена»** (блок «Динамическая подпись» в настройках подписи) определяет поведение:

- **Прервать** — всё согласование на переходе останавливается
- **Продолжить** — остальные подписи на переходе продолжают выполняться

Оба типа маршрутов (статический и динамический) детально описаны в [бизнес-логике подписей](https://help.1forma.ru/domains/signatures/business.md), секции «Статическая подпись» и «Динамическая подпись».

### Сводная матрица настроек подписей — акцептанты, срок, резолюции

Таблица группирует все параметры подписей по функциональным задачам, а не по форме настройки. Колонки: **Где настраивается**, **Область действия** (подпись/переход/группа/категория), **Смарт-события и смарт-действия**.

| Тема | Где настраивается | Область | Смарт-события / смарт-действия |
|------|-------------------|---------|-------------------------------|
| **Акцептанты** | Подпись → блок «Акцептанты» | Подпись | — |
| Акцептанты на переходе | Настройки подписи на переходе, колонка «Акцептанты» | Переход | — |
| Акцептанты динамической подписи | Подпись → блок «Динамическая подпись», параметр «Акцептант определяется по» | Подпись | — |
| Акцептанты от имени группы | Группа → вкладка «Подписи» | Подпись\\Группа | — |
| Изменение списка акцептантов | Группа → вкладка «Права на категорию» / Категория → вкладка «Доступ» | Категория\\Группа | — |
| Предупреждение при пустом акцептанте | Подпись → параметр «Не слать ошибку, если акцептант не указан» | Подпись | — |
| Добавление в подписчики | Подпись → параметр «Добавлять в подписчики акцептанта» | Подпись | Смарт-действие: «Добавить акцептанта динамической подписи» |
| **Срок подписи** | Подпись → блок «Срок», параметры «Минимальное время» и «Время по умолчанию» | Подпись | — |
| Срок на конкретном переходе | Настройки подписи на переходе, колонка «На подписание» | Переход | — |
| Обязательность срока | Подпись → блок «Срок», параметр «Срок обязателен» | Подпись | — |
| Изменение срока | Подпись → блок «Срок», параметр «Срок можно менять» | Подпись | Смарт-событие: «После истечения срока подписи» |
| **Доступные резолюции** | Подпись → блок «Резолюции» | Подпись | — |
| Запрос подписи на переходе | Настройки маршрута категории, колонка «Подписи» | Категория | Смарт-событие: «Перед запросом подписи на переходе» |
| Обязательность подписи на переходе | Настройки подписи на переходе, колонка «Обязательна» | Переход | — |

### Сводная матрица настроек подписей — причина, комментарий, резолюции

Продолжение матрицы настроек подписей.

| Тема | Где настраивается | Область | Смарт-события / смарт-действия |
|------|-------------------|---------|-------------------------------|
| **Причина запроса подписи** | Настройки подписи на переходе, колонка «Причина» | Переход | — |
| Причина для динамической подписи | Подпись → блок «Динамическая подпись», параметр «Причина запроса для динамической подписи обязательна» | Подпись | — |
| Изменение причины | Настройки подписи на переходе, колонка «Причину запроса подписи можно менять» | Переход | Смарт-действие: «Изменить причину динамической подписи» |
| **Комментарий при акцепте** | Подпись → параметр «Запрашивать комментарий при подписании» | Подпись | — |
| Комментарий на переходе | Настройки подписи на переходе, колонка «Запрашивать комментарий при подписании» | Переход | — |
| Обязательность причины у резолюции | Резолюция → параметр «Обязательна причина» | Резолюция | События: «Перед акцептом/делегированием/отклонением/удалением подписи» |

> При действии «Отклонить» диалог ввода причины открывается всегда (чтобы можно было оставить необязательный комментарий), но обязательным поле становится только при включённом флаге «Причина обязательна» у данного типа резолюции.


### Сводная матрица настроек подписей — эскалирование, отзыв, динамика, условия

Продолжение матрицы настроек подписей.

| Тема | Где настраивается | Область | Смарт-события / смарт-действия |
|------|-------------------|---------|-------------------------------|
| **Эскалирование** | Подпись → параметр «Можно эскалировать» | Подпись | События: «Перед эскалированием», «После эскалирования динамической подписи» |
| Эскалирование на переходе | Настройки подписи на переходе, колонки «Можно эскалировать», «Эскалировать, когда просрочена» | Переход | — |
| Подпись начальника | Подпись → блок «Подпись начальника» | Подпись | — |
| **Отзыв подписи** | Категория → параметры «Разрешить исполнителям отзывать...» | Категория | Смарт-действие: «Отозвать запрошенную подпись». События: «Перед/После отзыва подписи» |
| Показ кнопки «Отозвать согласование» в карточке | Категория → настройки панели инструментов (пункт «Отозвать согласование» в дереве элементов) | Категория | — |

**Показ кнопки «Отозвать согласование» в карточке задачи.** Кнопка с иконкой корзины в шапке блока «Подписи» и пункт «Отозвать согласование» панели инструментов — один и тот же переключатель: право задают настройки отзыва в категории, а показывает их только тогда, когда пункт «Отозвать согласование» включён в настройках панели инструментов категории (по умолчанию он включён). Если пункт выключен, кнопки в шапке блока не будет ни при каких правах — это ожидаемое поведение, а не ошибка. Настройки панели меняются в категории: правый клик по панели инструментов карточки → «Настройки» → «Тулбар», см. [Конфигурация панели инструментов карточки задачи](https://help.1forma.ru/domains/task-forms/admin.md).
| **Динамическая подпись** | Подпись → блок «Динамическая подпись», параметр «Может быть динамической» | Подпись | Смарт-действия: «Запросить динамическую подпись», «Запросить подпись пользователя». События: «Перед/После запроса динамической подписи» |
| Право запрашивать динамическую подпись | Группа → вкладка «Специальные права», параметр «Запрашивать динамическую подпись» | Группа | — |
| Право создавать динамическую подпись | Группа → вкладка «Специальные права», параметр «Создавать динамическую подпись» | Группа | — |
| Повторный запрос подписи | Подпись → параметр «Не запрашивать повторно» | Подпись | — |
| Повторный запрос на переходе | Настройки подписи на переходе, колонка «Не запрашивать повторно» | Переход | — |
| Отдельная копия каждому акцептанту | Настройки подписи на переходе, колонка «Каждому акцептанту отдельную копию» | Переход | — |
| **Условия запроса** | Настройки подписи на переходе, колонки «Обязательные ДП», «Условия запроса» | Переход | — |
| Последовательность подписей | Настройки подписи на переходе, колонка «Этап согласования» | Переход | — |
| Действие при отклонении | Настройки подписи на переходе, колонки «При отклонении», «В статус если отклонена», «При отклонении выполнить переход» | Переход | — |
| Действие при отклонении динамической | Подпись → блок «Динамическая подпись», параметр «Прерывать согласование...» | Подпись | — |
| SQL-процедура на переходе | Настройки подписи на переходе, колонка «Процедура» | Переход | — |
| Активность подписи | Настройки подписи на переходе, колонка «Активна» | Переход | — |


### Акцептанты «По параметру» — валидация и несколько акцептантов

При выборе алгоритма [«По параметру»](https://help.1forma.ru/domains/signatures/business.md#алгоритмы-определения-акцептантов) обязателен **Дополнительный параметр** — выбор ДП, по которому строится таблица соответствий «значение → акцептант» (красная звёздочка `*`). Поле **«Акцептант по умолчанию»** (fallback-пользователь, поле «Кому») — **необязательно** (звёздочки нет): если оно не задано и подходящего значения в таблице соответствий нет, подпись формируется без акцептантов.

При попытке «Сохранить» с незаполненным **Дополнительным параметром** запрос на сервер **не отправляется**; под полем выводится сообщение «**Для алгоритма «По параметру» необходимо выбрать дополнительный параметр (ДП)**». Поля рамкой не подсвечиваются — индикация только звёздочкой и сообщением под полем.

**Источник таблицы соответствий — «Задать вручную» или «Из таблицы».** Таблицу «значение ДП → акцептант» заполняют вручную (грид, см. ниже) либо берут из таблицы БД. В режиме **«Из таблицы»** обязательны три поля (все со звёздочкой `*`): **Имя таблицы**, **Колонка значения параметров** и **Акцептант** (колонка с пользователем-акцептантом). Пока все три не заполнены, кнопка «Сохранить» неактивна. При смене таблицы значения колонок сбрасываются; при переключении на «Задать вручную» табличные поля очищаются.

**Несколько акцептантов на одно значение параметра (с 2.268.336 — бэк, с 2.268.346 — фронт).** В таблице соответствий «значение ДП → акцептант» на одно значение можно назначить несколько пользователей. В Admin API и в форме настройки подписи каждый акцептант отображается **отдельной строкой** — со своим `Id`, `ExtParamValue` и `UserId`. До 2.268.336 имена нескольких акцептантов одного значения склеивались в одну запись через `; `, а `Id`/`UserId` брались от последнего пользователя группы — отсюда поломанные сохранение и удаление.

#### UI-фикс грида и разрыв между бэк-/фронт-фиксами

В форме настройки подписи AdminSPA (`signature-acceptors-by-ext-params-grid.component`) после фикса работают три ранее сломанных сценария:

- **Редактирование существующей строки** — сохраняются все выбранные в мульти-выборе пользователи, не только последний.
- **Добавление новой пары значение–акцептанты с мульти-выбором** — в результирующую запись попадают все выбранные пользователи, не только первый.
- **Добавление к существующему значению параметра** — новая строка с тем же значением сохраняется отдельно, без склейки с существующими; каждая строка редактируется и удаляется независимо.

Способов добавить нескольких акцептантов на одно значение два: (1) сразу при создании строки выбрать нескольких пользователей в поле «Акцептанты», (2) добавить новую строку с тем же значением параметра и другим набором акцептантов.

Между релизами 2.268.336 (бэк) и 2.268.346 (фронт) — 10 версий, на которых API уже отдавал данные корректно, но UI грида в AdminSPA всё ещё склеивал пользователей и терял строки. На версиях 2.268.336 — 2.268.345 включительно использовать алгоритм «По параметру» с несколькими акцептантами на одно значение **не следует** — данные в БД могут быть корректными, а в интерфейсе отображаться неправильно. Полностью функционал работает с **2.268.346**.

Под капотом сохранение приведено к паттерну, уже принятому для алгоритма «По группам» (`UpdateSignatureAcceptorsByGroups`): диффинг акцептантов идёт по естественному ключу `(ExtParamValue, UserId)`, удаление выполняется точечно по PK строки — не пакетно по значению параметра, как раньше через старый `DeleteAcceptorByExtParam(signatureId, extParamValue)`. Поэтому добавление, изменение или удаление одного акцептанта на конкретное значение параметра не затрагивает остальных, назначенных на то же значение.

Хранится в `dbo.SignatureAcceptorsByExtParamValues`. Сценарий с одним акцептантом на значение и остальные режимы определения акцептантов (по группам, по руководителю/оргструктуре, `SetDefaultAcceptorsForExtParamSignature`) фиксом не затронуты.

### Делегирование и лист согласования

**Делегирование подписи** (смена акцептантов) доступно, если выполнено одно из условий: на переходе включён флаг **«Можно делегировать»** (`CanBeDelegated` у StepSignature) и пользователь является акцептантом подписи; либо у пользователя есть право категории **«Добавлять и менять акцептантов»**.

**Лист согласования.** По умолчанию сведения о том, у кого изначально была запрошена подпись, после её обработки из БД удаляются — остаётся только фактически вынесший резолюцию. Чтобы сохранять исходных акцептантов (например, для контроля заместителей, подписывающих за других), в «Общих настройках приложения» отключите параметр **«Удалять историю акцептантов подписи после обработки»** (по умолчанию включён).

![Лист согласования: история запрошенных подписей и вынесенных резолюций](https://help.1forma.ru/help-images/signatures/signatures_info.png)

## Обработка резолюции (пошагово)

Внутренний порядок выполнения при вынесении резолюции акцептантом:

1. Загрузка данных подписи и резолюции из БД.
2. Выполнение смарт-пакетов «Перед» (акцептом / делегированием / отклонением / удалением / эскалированием).
3. Проверка прав акцептанта.
4. Создание снимка задачи.
5. Запись нового состояния подписи и резолюции в БД.
6. Публикация комментария и отправка уведомления.
7. Проверка завершения текущего этапа; инициация следующего этапа при необходимости.
8. Обновление статуса задачи (снятие «На подписи»).
9. Отправка файлов в SharePoint.
10. Выполнение действий, подтверждённых подписью (смена срока, заказчика, трудозатраты).
11. Выполнение действий при отклонении (если подпись отклонена).
12. Переход задачи по маршруту.
13. Выполнение смарт-пакетов «После» (подписания / отклонения / удаления / эскалирования — статических и динамических).

## Связи с другими доменами

Подписи связаны с другими доменами системы:

| Домен | Связь |
|-------|-------|
| **Задачи** | Подписи — часть жизненного цикла задачи; запрашиваются на переходах; создают промежуточный статус «На подписи» |
| **Категории** | Маршрут согласования настраивается для каждой категории; настройки отзыва и подписей-для-действий — на уровне категории |
| **Статусы и переходы** | Подписи привязаны к конкретным переходам; этапы согласования определяют порядок |
| **ДП (ext-params)** | Условия запроса по значениям ДП; определение акцептантов по ДП; обязательные и информационные ДП; файлы для ЭЦП из ДП «Файл» |
| **Пользователи и группы** | Акцептанты определяются по группам, оргструктуре, руководителям; специальные права группы на подписи |
| **Смарт-автоматизация** | Обширный набор событий и действий; определение акцептантов по смарт-выражениям; условия запроса через смарт-фильтры |
| **Уведомления** | Персональные настройки уведомлений для события «Подписи»; почтовые уведомления акцептантам |
| **Файлы** | Подписание файлов через ЭЦП; создание системных копий при акцепте; снимки |
| **Заместители** | Заместители получают подписи замещаемого; настройка запрета подписания заместителем; отображение в листе согласования |

## CustomSettings и серверная криптография подписей

Дополнительное поведение подписей задаётся ключами `CustomSettings`:

| Ключ | Тип | Назначение |
|------|-----|------------|
| `IsOldSignTicker` | bool | Если `true` — клик на индикатор подписей в SPA открывает **старый** список подписей. Используется при переходе на новый интерфейс для совместимости |
| `AddUserLoginToSignedFiles` | bool | Если `true` — логин акцептанта добавляется к имени SIG-файла при ЭЦП-подписании |

Серверные ключи криптографии в `appsettings.json`:

| Ключ | Default | Назначение |
|------|---------|------------|
| `DecodeEdsSignatures` | `true` | Серверная криптографическая верификация подписей ЭЦП при акцепте. **Только для КриптоПро / РуТокен** (`EbdsTypes.CryptoProRuToken`). Для DSS КриптоПро и Контур.Облако серверная проверка не выполняется (верификация на стороне облачного провайдера). При ошибке возвращается `Eds_CryptographicException`. ⚠️ Отключать (`false`), если на сервере не установлен КриптоПро CSP или недоступны корневые сертификаты УЦ — иначе акцепт упадёт |

### Типичные ошибки настройки подписей

В таблице собраны наиболее частые проблемы при конфигурировании подписей, их вероятные причины и SQL-запросы для диагностики.

| Симптом | Причина | Где проверить | SQL-диагностика |
|---------|---------|---------------|-----------------|
| «Подпись недоступна» на переходе | Подпись не привязана к шагу маршрута | Подписи на шаге маршрута | `select ss.*, s.Name from dbo.StatesRoutesSignatures ss inner join dbo.Signatures s on ss.SignatureID = s.SignatureID where ss.StepID = {stepId}` |
| «Нет доступных резолюций» | К подписи не привязаны типы резолюций | Подпись → резолюции | `select s.Name, srt.* from dbo.SignatureResolutionTypesSignatures srts inner join dbo.Signatures s on srts.SignatureID = s.SignatureID inner join dbo.SignatureResolutionTypes srt on srts.SignatureResolutionTypeID = srt.ID where s.SignatureID = {id}` |
| ЭЦП не работает | Неверные настройки КриптоПро / DSS | Формы `cryptopro-verification-centers`, `dsscryptopro-service-settings` | `select * from dbo.CryptoProCertificationCenters; select * from dbo.DSSCryptoProCredentials` |
| Подпись требует комментарий, но нет поля | Тип резолюции требует комментарий | Форма `signature-resolution-types` | `select * from dbo.SignatureResolutionTypes where Id = {resTypeId}` |
| Динамическая подпись не появляется | Неверный SQL-маршрут или не настроена видимость | SQL-маршрут подписи на шаге | `select ID, StepID, SignatureID, SPName, SmartFilterID, Enabled from dbo.StatesRoutesSignatures where StepID = {stepId} and SPName is not null` (динамический маршрут акцептантов задаётся полем `SPName`) |
| На вкладке «Информационные ДП» добавленный параметр не появляется в таблице, после «Сохранить» настройка прежняя | До 2.268.706 (SPA 2.268.706) выпадающий список показывал первый доступный параметр вместо выбранного, а таблица вкладки имела нулевую высоту и не рисовалась — параметр сохранялся «вслепую» и выглядел как потерянный | Настройки категории → Маршрут → переход → вкладка «Подписи на переходе» → «Редактирование подписи при переходе» → вкладка «Информационные ДП». Сверить версию SPA на стенде | `GET /api/admin/subcat/step/signatures`: у подписи должен быть непустой `stepSignExtParamsIdForInfo`. Пустой массив — настройка не дошла до сервера, это дефект фронта; непустой массив при пустом списке — проблема только в отрисовке |

## Связи таблиц подписей (модель данных)

Центральная таблица — `TaskSignatures` (запрошенные подписи): каждая строка связывает задачу (`TaskID`), пользователя-обработчика (`SignatureUserID`), подпись из справочника (`SignatureID`), её статус (`SignatureStateID`), тип резолюции (`SignatureResolutionTypeID`) и переход маршрута, на котором подпись запрошена (`SignatureStepID`). Дополнительные акцептанты хранятся в `TaskSignatureUsers`. Какие подписи запрашиваются на переходах, задаёт `StatesRoutesSignatures`; какие резолюции доступны для подписи — `SignatureResolutionTypesSignatures`.

```mermaid
graph LR
    TS["TaskSignatures — запрошенные подписи"]
    TSU["TaskSignatureUsers — акцептанты"]
    U["Users — пользователи"]
    T["Tasks — задачи"]
    SIG["Signatures — справочник подписей"]
    SRS["StatesRoutesSignatures — подписи на переходах"]
    SS["SignaturesStates — статусы подписей"]
    SRT["SignatureResolutionTypes — типы резолюций"]
    SRTS["SignatureResolutionTypesSignatures — доступные резолюции"]
    SRIS["StatesRoutesInSubcat — переходы маршрута"]

    TS -- "TaskID" --> T
    TS -- "SignatureUserID" --> U
    TS -- "SignatureID" --> SIG
    TS -- "SignatureStateID" --> SS
    TS -- "SignatureResolutionTypeID" --> SRT
    TS -- "SignatureStepID" --> SRIS
    TSU -- "TaskSignatureID" --> TS
    TSU -- "UserID" --> U
    SRS -- "SignatureID" --> SIG
    SRS -- "StepID" --> SRIS
    SRTS -- "SignatureID" --> SIG
    SRTS -- "SignatureResolutionTypeID" --> SRT
    T -- "StepID" --> SRIS
```

### Электронная подпись (ЭЦП)

Подписание через криптопровайдеры хранится в отдельной группе таблиц `Eds*`. `EdsExternalUsers` — пользователи, зарегистрированные для внешней ЭП (тип в `EdsType`: CryptoPro RuToken, PayControl, CryptoPro DSS). Облачное подписание (PayControl, CryptoPro DSS) идёт транзакцией `EdsExternalRequests`; результат подписания фиксирует `EdsFileInfo` (файл с подписью, сертификат, дата), для DSS промежуточную проверку файла ведёт `EdsDSSFileInfo`. Пунктир — логические связи, не закреплённые внешним ключом БД.

```mermaid
graph LR
    EEU["EdsExternalUsers — пользователи внешней ЭП"]
    EER["EdsExternalRequests — транзакции подписания"]
    EFI["EdsFileInfo — файлы с подписью"]
    EDSS["EdsDSSFileInfo — проверка файла (DSS)"]
    U["Users — пользователи"]
    TS["TaskSignatures — запрошенные подписи"]
    FSF["FileStorageFiles — файлы"]

    EEU -- "UserId" --> U
    EER -- "EdsExternalUserId" --> EEU
    EER -- "TaskSignatureId" --> TS
    EER -- "FileId" --> FSF
    EFI -. "TaskSignatureId" .-> TS
    EFI -. "SignedFileId" .-> FSF
    EDSS -. "EdsId" .-> EFI
```

Полная схема ЭЦП с атрибутами всех полей — в [system/db-er-diagrams.md](https://help.1forma.ru/domains/system/db-er-diagrams.md#электронная-подпись-эцп); там же — схемы связей других подсистем БД.

См. также:

- [Подписи — бизнес-логика](https://help.1forma.ru/domains/signatures/business.md) — типы подписей, статическая и динамическая, акцептанты
- [Настройка категорий](https://help.1forma.ru/domains/categories/admin.md) — маршруты, к шагам которых привязываются подписи
- [Интеграции](https://help.1forma.ru/domains/integrations/admin.md) — PayControl, Контур.Облако
