Смарт-действия — Известные проблемы¶
Документ — реестр известных проблем и ограничений смарт-действий (Smart Actions) 1Формы: активные ограничения (локализация ФИО в CreateUser/UpdateUser, EventID 64 в WhenOpenTask, Lua-ориентированная справка редактора при любом языке скрипта) и ранее исправленные проблемы. Для инженеров поддержки и разработчиков, работающих с пакетами смарт-действий.
1. CreateUser / UpdateUser не поддерживают локализованные ФИО¶
Статус: исправлено
Симптом: при создании пользователя через смарт-действие «Создать пользователя» нельзя указать ФИО на дополнительном языке (например, английском). ФИО записывается как локализация только для языка, указанного в параметре «Язык».
Причина: действие записывает локализованное ФИО только для основного языка пользователя; параметров для второго языка нет.
Решение: в действиях «Создать пользователя» и «Обновить пользователя» добавлены параметры «Фамилия (локализованная)», «Имя (локализованное)», «Отчество (локализованное)» и «Язык локализации» — ФИО на дополнительном языке задаётся штатно. См. actions-reference-people.md. Ограничение касается только одного действия: при обычном сохранении карточки пользователя локализованные ФИО распространяются на языки-автокопии — см. Локализация — бизнес-правила.
2. WhenOpenTask (EventID 64) срабатывает в SPA только в представлении «Чаты»¶
Статус: ограничение подтверждено, поведение намеренное
Симптом: смарт-правило на событие «Во время открытия задачи» не срабатывает, когда пользователь открывает задачу в стандартной карточке (полное представление). Срабатывает только при открытии в представлении «Чаты».
Обходной путь: событие можно вызвать напрямую через API (POST /api/v2/tasks/{taskId}/when-open-task) — без ограничений по представлению. Актуально для интеграций и мобильного клиента.
Дополнительно: контекст открытия передаётся в @eventParam1 (не @eventParam0). @eventParam0 у данного события не используется — нетипичное поведение по сравнению с другими событиями.
3–6. Исправленные ранее проблемы (сборки 2.268.63 – 2.268 «Скульптор»)¶
Четыре исправленные ранее проблемы с указанием сборок исправления; в текущих сборках не воспроизводятся.
Mustache-шаблоны возвращали пустые строки (исправлено в 2.268.77): смарт-действие «Сгенерировать файл по шаблону» с mustache-шаблоном возвращало пустое содержимое.
Смарт-отмена (Cancel) в Lua не работала (исправлено в 2.268.63): действие «Отменить» (Cancel) не отрабатывало корректно при вызове из Lua-скрипта.
Ошибка 500 на смарт-кнопках действий (исправлено в 2.268.74): ошибка при нажатии на смарт-кнопки действий (в частности, при генерации файла по шаблону).
HTML-таблица с числовыми отступами обрывала формирование файла по шаблону (исправлено в 2.268 «Скульптор»): значение с <table cellspacing="0"> или <table cellpadding="0"> приводило к ошибке The input string '"0"' was not in a correct format и отказу действия «Сгенерировать по шаблону». Теперь такие значения формируются так же, как записанные с обычными кавычками.
6. ESQL: FROM {0} без алиаса — 500 на reserved keyword¶
Статус: исправлено
Симптом: запросы вида SELECT VALUE COUNT(1) FROM {0} WHERE ... возвращают 500. Проявлялось при вычислении видимости блоков смарт-фильтра в МТФ.
Причина: в бесконтекстной ветке генератора ESQL конструкция FROM {0} подставлялась без алиаса коллекции. Парсер ESQL принимал стоящий сразу за FROM reserved keyword (WHERE, ORDER, GROUP) за имя коллекции. В контекстной ветке (FROM Tasks as t) алиас присутствовал, поэтому ошибка не воспроизводилась.
Инвариант: алиас as t подставляется во всех ветках генератора ESQL.
7. Потеря значения параметра действия через admin-MCP (JsonElement)¶
Статус: исправлено
Симптом: при сохранении действия пакета через admin-MCP (/mcp-admin-api-actions-pack-editor → actions_pack_editor_save_pack_action) значение параметра не записывалось в БД. Проявлялось двумя способами:
- ArgumentException: unknown value type: System.Text.Json.JsonElement — значение не распознавалось контролом параметра.
- SqlException 547 — нарушение CHECK-ограничения CK_PacksActionsParameters_Value_XOR_Expression при вставке параметра с пустым значением.
Причина: admin-MCP десериализует тело запроса через System.Text.Json, помещая в object-поле FixedValue тип JsonElement. Базовый класс контролов ParameterControlBase обрабатывал только JObject (Newtonsoft) и нативные типы — JsonElement попадал в else-ветку с исключением. Отдельно — отсутствие фильтрации пустых параметров в MergeParameters позволяло довести до БД строку с пустыми значениями всех источников.
Инвариант: ParameterControlBase.SerializeValue обрабатывает JsonElement наравне с JObject; PacksActionsEntityService.MergeParameters фильтрует параметры без значения через HasParameterValue перед записью.
8. CreateUser / UpdateUser: поле «Пароль» в редакторе всегда пустое, отдельной очистки нет¶
Симптом: в редакторе пакета действий поле «Пароль» действий «Создать пользователя» и «Изменить пользователя» всегда отображается пустым, даже если пароль был задан ранее. Отдельного способа очистить ранее сохранённый пароль в интерфейсе нет.
Причина: значение пароля хранится в зашифрованном виде и намеренно не возвращается в редактор, в описание действия и в экспорт модуля — поле работает только на запись. Пустое поле при сохранении трактуется как «не менять сохранённое значение».
Обходной путь: чтобы заменить пароль, введите новое значение. Чтобы убрать ранее сохранённый пароль, смените источник значения параметра (выражение, скрипт или предопределённый параметр) либо пересоздайте действие.
9. Невалидный JSON в значении параметра действия пакета — 500 вместо ошибки ввода¶
Статус: исправлено
Симптом: сохранение действия пакета со значением параметра, структура которого не соответствует контролу — например, у элемента выбора пользователей идентификатор пустой, — отвечало HTTP 500, а в журнал исключений писалась ошибка десериализации Error converting value {null} to type 'System.Int32'. Path 'users[0].id'.
Причина: в ParameterControlBase.TryParseNaive десериализация входного значения — JsonElement.Deserialize<TV> для запросов от admin-MCP и JObject.ToObject<TV>() для запросов от SPA — выполнялась без перехвата: исключение уходило наверх мимо фильтра, который переводит логические ошибки в 400.
Решение: блок десериализации обёрнут в try/catch, перехватывающий System.Text.Json.JsonException, Newtonsoft.Json.JsonException, InvalidCastException и ArgumentException, и вместо них бросается TCLogicException с сообщением «некорректное значение параметра действия» — фильтр API транслирует её в HTTP 400. Поведение наследуют все контролы на базе ParameterControlBase<TV>; разбор корректных значений не изменился.
10. Справка в редакторе смарт-скриптов всегда Lua-ориентированная¶
Симптом: в скрипте на языке, отличном от Lua (Python, JavaScript, OneScript, C#), кнопка «i» («Библиотека подсказок») открывает окно с заголовком «Помощь по lua-скриптам» и содержимым про Lua: RESULT, CONTEXT как объект задачи/пользователя/письма, var_dump, is_empty, вкладка «Смарт-действия». В Python и остальных языках эти имена и конструкции не работают.
Причина: справка — единый текст из ресурсов интерфейса (ключи luaDoc.* словаря common). Язык скрипта в компонент справки не передаётся, переключение её содержания по языку не реализовано; кнопка выводится в тулбаре независимо от языка, а заголовок берётся из ресурса common.helpWithLuaScripts.
Обходной путь: штатного переключателя справки нет. Для Python ориентир — python-scripting.md: ключи ctx, возврат результата, ограничения песочницы; для остальных языков — документы домена по соответствующему языку.
11. Правило «После смены ДП» из другого правила читало значение параметра до изменения¶
Статус: исправлено
Симптом: правило на событие «После смены ДП», запущенное смарт-действием другого правила, в смарт-выражении получало прежнее значение изменённого параметра — и при чтении из денормализованной таблицы категории, и из значений параметров. Тот же результат давало сохранение пачки параметров одной операцией.
Причина: смарт-выражение выполнялось под отдельной строкой подключения, в собственной сессии базы, и не видело записи, сделанной смарт-действием внутри текущей операции: запись оставалась незафиксированной до её конца.
Решение: признак «читать основной строкой подключения внутри текущей транзакции» удерживается на самой транзакции — при сохранении значения параметра и при сохранении пачки транзакция помечается, и смарт-выражение внутри неё читает записанное значение. Вне таких операций поведение не изменилось. Вошло в сборку 2.268 «Скульптор».
12. «Время ожидания выполнения истекло» по смарт-выражению при сохранении факта¶
Статус: исправлено в 2.268 «Скульптор»
Симптом: при сохранении трудозатрат с каскадом на проект в журнале ошибок появляются записи о таймауте смарт-выражения, а значение параметра проекта считается по старым данным; пользователь повторяет сохранение.
Причина: выражение в режиме XML-формулы при заданной отдельной строке подключения для смарт-выражений считалось вне транзакции запроса и в другой сессии базы. При уровне изоляции соединения из пула выше «повторяемого чтения» оно ожидало блокировку, которую держала транзакция самого запроса, — отсюда таймаут; при более слабом уровне виден был устаревший результат.
Исправлено. На MS SQL выражение в режиме XML-формулы считается в транзакции вызвавшего запроса и в его сессии, поэтому видит записанное в этой же транзакции. Выражения с собственным T-SQL под отдельной строкой подключения и поведение на PostgreSQL не менялись.
Обходной путь (на сборках до исправления): нет; записи о таймауте по сохранению факта на исправленной сборке не воспроизводятся. Если симптом остался — проверить, что у выражения нет собственного T-SQL, и уточнить сборку площадки.
13. Подсказка типа результата действия «Распаковать» расходилась с рантайм-типом при пропущенных записях¶
Статус: исправлено (сборка 2.268 «Скульптор»)
Симптом: в редакторе смарт-скриптов у действия «Распаковать» подсказка результата показывала int[]; если в архиве были повреждённые записи или записи, пропущенные по лимитам, скрипт получал объект с полями fileIds и skippedEntries, и штатные приёмы работы с массивом (#, ipairs, table.insert) на нём не работали. Смарт-выражение последующего действия, ссылавшееся на результат разархивации, падало с ошибкой Entity SQL.
Причина: действие объявляет ResultType = int[], а при пропущенных записях возвращает UnzipArchiveResult; в параметр смарт-выражения значение попадало без приведения к массиву.
Исправлено. Подсказка в редакторе показывает обе формы — int[] | { fileIds (int[], 1..n), skippedEntries (string[], 1..n) }, значение UnzipArchiveResult на границе Lua отдаётся таблицей, а в параметр смарт-выражения передаётся массив идентификаторов распакованных файлов. Подробности о форме результата — в справочнике действий, раздел «Файлы (расширение)».
Обходной путь: нет. Признак старого поведения — подсказка результата у действия «Распаковать» показывает только int[], а при пропущенных записях скрипт получает объект.
Связанные документы:
- Файлы — справочник действий, раздел «Файлы (расширение)»
14. «Экспортировать данные в Excel»: выгрузка падает на вычисляемых текстовых колонках¶
Статус: в работе
Симптом: действие отказывает с текстом Column '<имя колонки>' is read only, файл не создаётся. На PostgreSQL так ведёт себя любая функция с текстовой колонкой; на MS SQL — процедура, у которой строковая колонка получена выражением: склейкой строк, CASE, ISNULL, литералом, параметром процедуры или CAST/CONVERT.
Причина: после перевода вызова на общий доступ к базе результат читается в таблицу данных, и драйвер помечает колонки-выражения как нередактируемые. Генератор файла переписывает текстовые ячейки (срезает HTML-разметку, обрезает краевые пробелы), а запись в такую колонку запрещена. До перевода результат читался способом, который этот признак не выставлял, и те же процедуры выгружались.
Обходной путь: выбирать в процедуре колонки из таблиц и табличных переменных — они остаются редактируемыми. Текст, собираемый выражением, формировать на стороне пакета либо отдельными действиями.
Когда обращаться в поддержку 1Ф: если процедура отдаёт только колонки из таблиц и отказ всё равно воспроизводится — приложить версию площадки, текст ошибки из журнала ошибок платформы и текст процедуры.
15. «Экспортировать данные в Excel»: ошибка после второго набора не останавливает действие¶
Статус: в работе
Симптом: процедура на MS SQL вернула два и более набора и упала после второго (RAISERROR уровня 11 и выше, THROW, ошибка выполнения) — действие завершается успешно, в задачу вкладывается файл с данными первого набора, в журнале ошибок записи нет, пакет идёт дальше. При откате транзакции внутри процедуры изменения откатываются, а файл с данными отменённого расчёта остаётся в задаче.
Причина: чтение останавливается на первом наборе с колонками; остаток ответа дочитывается при закрытии соединения, а ошибка этой части при закрытии не поднимается. На PostgreSQL проблема не проявляется: функция, завершившаяся ошибкой, строк не отдаёт и вызов падает целиком.
Обходной путь: не держать в одной процедуре с выгрузкой инструкции, способные упасть после выборки, — вынести их отдельным действием пакета либо перестроить процедуру так, чтобы она падала до возврата данных.
Когда обращаться в поддержку 1Ф: при подозрении на частичные данные в приложенном файле — приложить версию площадки и текст процедуры: по журналу пакета такой отказ не виден.
16. Пользовательские смарт-действия не загрузились — редактор пакета отдаёт ошибку или пустой список¶
Статус: исправлено в 2.268 «Скульптор»
Симптом: после сбоя загрузки пользовательских действий обращение к смарт-действию по идентификатору пользовательского действия отдавало NullReferenceException — в интерфейсе и в фоновых заданиях; каталог доступных типов действий в редакторе пакета отдавал ошибку с пустым списком вместо стандартных групп; предварительная загрузка пользовательских действий не сообщала о сбое.
Причина: реестр пользовательских (кастомных) действий загружается лениво и один раз на процесс — сканером подключённых сборок. При сбое загрузки геттер реестра перехватывал исключение, писал его в лог и возвращал «пустое значение», а потребители разыменовывали его без проверки: строгие — падали, списочный — терял уже собранный список стандартных действий.
Исправлено. Сбой загрузки больше не маскируется: он записывается в журнал ошибок платформы и возвращается как управляемая ошибка «Загрузка пользовательских действий не удалась» с исходной причиной внутри. Обращение по идентификатору пользовательского действия даёт эту управляемую ошибку; каталог имён в редакторе пакета возвращает стандартные действия и не ломается; предварительная загрузка возвращает признак «пользовательские действия не загружены». Стандартные действия и безопасное разрешение имени действия работают как раньше.
Обходной путь: нет. Признак старого поведения — в редакторе пакета не видно ни одного пользовательского действия (либо открывается ошибка), а в журнале ошибок платформы лежит запись о сбое загрузки пользовательских действий. На исправленной сборке в редакторе остаются стандартные группы действий.
Когда обращаться в поддержку 1Ф: если на исправленной сборке пропадают и стандартные действия либо сбой повторяется после перезапуска пула приложения — приложить версию площадки и текст записи из журнала ошибок платформы.
17. «Отправить системный email» без почтового ящика падал разыменованием вместо ошибки конфигурации¶
Статус: исправлено в 2.268 «Скульптор»
Симптом: пакет с действием «Отправить системный email» (SendMailBoxEmail, ID 44) при незаполненном параметре «Email отправителя» завершался технической ошибкой — NullReferenceException, а при ящике без идентификатора — InvalidOperationException — вместо сообщения о незаполненном параметре. Проявлялось в раздельной рассылке (параметр «Каждому адресату отдельное письмо»).
Причина: в ветке раздельной отправки ящик читался без проверки — mailBox.MailBoxId.Value в TCClassLib/Smart/Actions/ActionsInfoProvider.Methods.cs, при том что отсутствие ящика выше допускалось.
Исправлено. Проверка ящика и его идентификатора выполняется один раз до ветвления — if (mailBox?.MailBoxId == null) в SendMailBoxEmail; при пустом ящике действие отдаёт ошибку конфигурации с указанием «Email отправителя». Отправка с заданным ящиком — и раздельная, и общая — не изменилась; общая отправка без ящика тоже стала возвращать ошибку конфигурации — это принятое расширение поведения, а не прежний сценарий.
Обходной путь: нет. На сборках до исправления раздельная отправка без ящика отвечает технической ошибкой.
Когда обращаться в поддержку 1Ф: если на исправленной сборке отправка с корректно заданным ящиком завершается ошибкой конфигурации — приложить версию площадки, имя пакета и текст ошибки из журнала пакета.
18. Тип контекста смарт-скрипта затирался сохранением¶
Статус: исправлено в 2.268 «Скульптор»
Симптом: после переименования, публикации или сохранения кода скрипт терял контекст — CONTEXT оказывался пустым, хотя раньше скрипт с задачей работал. Тип мог «прыгать»: один и тот же скрипт в тесте редактора выполнялся то с контекстом, то без.
Причина: тип контекста нигде не задавался явно и доезжал из адреса редактора. При открытии скрипта из действия пакета в адресе стоял тип «задача», и бэкенд подменял им значение из базы — любое сохранение записывало «задача» независимо от того, что было в скрипте, а обновление по API без поля типа записывало «без контекста».
Решение: у существующего скрипта тип всегда берётся из базы и меняется только отдельным вызовом смены типа; адрес редактора и обычное сохранение тип не трогают. См. Редактор смарт-скриптов.
Обходной путь на сборках до исправления: не пересохранять скрипт из действия пакета; тип деплоить по API вместе с полем типа в DTO.
19. Пакет по событию откатывал все итерации списочного действия вместе со сбойной¶
Статус: исправлено в 2.268 «Скульптор»
Симптом: правило «После изменения значения параметра» проставляло значения по списку, но при сбое одного элемента не сохранялось ни одного: список откатывался целиком, запись о выполнении действия в журнале автоматизации тоже исчезала, а в журнале ошибок оставалась только ошибка итерации. Тот же пакет, запущенный переходом по маршруту, сохранял остальные элементы.
Причина: пакет, запущенный событием внутри транзакции, подтверждал свою область только при полном успехе. Одна отклонённая или сбойная итерация делала пакет неуспешным, и объемлющая операция завершалась без фиксации.
Решение: событийный запуск пакета со списочным действием изолирует сбойную итерацию — её записи откатываются, а записи успешных итераций и запись в журнале автоматизации сохраняются после фиксации объемлющей операции. Поведение прямого запуска пакета, запуск вне транзакции и пакеты без сбоев не изменились; сбой вне итераций списка по-прежнему откатывает пакет целиком. См. Типичные проблемы действий пакета, раздел 4.2.
Обходной путь на сборках до исправления: вынести правило из «После изменения значения параметра» на событие, выполняемое вне операции (например, «После перехода»), либо разбить список на короткие пакеты.