Перейти к содержанию

Паттерны Smart-автоматизации

Smart-выражения — основы

Два режима редактора

  • SMART (по умолчанию) — графический конструктор с деревом сущностей
  • T-SQL — прямой ввод SQL-запросов

Переключение в T-SQL необратимо — вернуться в режим SMART после конвертации невозможно.

Дерево сущностей

Содержит все доступные объекты для smart-выражения:

Узел Что содержит
Системные параметры № задачи, ID заказчика, текст, дата создания, срок
ДП категории Все ДП, настроенные в текущей категории
Свойства контекста Зависят от точки вызова (событие, фильтр, подпись)
Результаты предыдущих действий Доступны внутри пакета
Прочее Все объекты системы вне контекста: категории, пользователи, группы

Единичные объекты (например, заказчик) раскрываются стрелкой > для доступа к вложенным параметрам. Множественные объекты (ДП «Выбор пользователей», «Таблица») представлены как коллекции со специальными конструкциями.

Правила составления

  • Строковые выражения заключаются в одинарные кавычки
  • Для преобразования числа в строку — функция ВСтроку
  • Вместо ручного ввода ID — кнопка «ID объекта» (вставляет типизированную ссылку)
  • Не копировать выражения из других задач/уроков — выбирать элементы вручную из дерева
  • Тестировать через поле «Протестировать на задаче №» + кнопка «Тест»

Smart-фильтры

Базовый принцип

Smart-фильтр — это smart-выражение, возвращающее: - boolean (true/false, 1/0) — для фильтрации отдельных задач - массив элементов — для отбора списка задач (в расписаниях на T-SQL)

Фильтрация в табличных представлениях (smart-поиск)

Путь: Настройки категории > Смарты > Доступен в смарт-поиске > + Создать.

Пример — отбор задач в статусе «Новая заявка»:

ID статуса = <ID нужного статуса>

Галка «Доступен в smart-поиске» управляет видимостью отбора в UI.

Фильтрация в БИ (Блок Используется)

БИ > Добавить таблицу > Источник: smart-фильтр. Фильтр возвращает true для задач, которые должны отображаться.

Пример — задачи не в статусе «Отклонено», где ДП совпадает с текущей задачей:

ID категории = 33 И ID статуса != 16 И Задача.ДП[90] = Текущая задача.ДП[90]

Ограничение: если отбор задач в БИ ограничивается smart-фильтром, связи по ДП Lookup не учитываются.

Фильтрация видимости кнопки перехода

Переход > Ограничить доступ > smart-фильтр видимости кнопки. Фильтр возвращает true — кнопка видна, false — скрыта.

Пример — кнопка видна, если задача в ДП Lookup находится в определенном статусе:

Задача.ДП[«Заявка на приём»].ID статуса = <ID статуса «Организация рабочего места»>

Фильтрация значений в ДП Lookup

Настройки ДП > smart-фильтр (блок «Табличный вид»). Фильтрует задачи, доступные для выбора.

Важно: smart-фильтр в ДП Lookup распространяется на этот ДП во всех категориях, где он добавлен. Для ограничения по категории — добавить дополнительное условие в фильтр.


Smart-события и триггеры

Основные события

Событие Параметры Применение
После постановки Инициатор Заполнить ДП, назначить исполнителей
После перехода Переход (опционально) Автоматические действия при смене статуса
После смены ДП ДП, инициатор, новое/старое значение Пересчет зависимых полей
Перед сменой ДП ДП, инициатор, новое/старое значение, причина Валидация, блокировка

Если для события «После перехода» не выбран конкретный переход — пакет выполняется после любого перехода.

Паттерн: расчет даты по условию

Событие: после смены ДП «Дата выхода на работу».

Кейс 1 — вычисление: если значение не пустое, рассчитать дату окончания испытательного срока:

Дата выхода + Период испытательного срока (месяцев)
Smart-фильтр: ДП[«Дата выхода на работу»] есть значение

Кейс 2 — очистка: если значение пустое, очистить зависимое поле. Smart-фильтр: ДП[«Дата выхода на работу»] нет значения

Паттерн: автоматический переход по условию

Событие: после перехода «Выполняется - Ожидание выдачи». Smart-фильтр (два условия через И):

ДП[«Заявка на приём сотрудника»] есть значение
  И
Текущая дата >= ДП[«Дата выхода на работу»]
Действие: выполнить переход «Ожидание выдачи - Завершена».


Smart-действия — типы

Действие: изменить срок

Параметры: - Инициатор — по умолчанию системный пользователь - Срок — значение или smart-выражение (рекомендуется Smart/TSQL) - Причина — обязательна - Задача — по умолчанию текущая - Не писать комментарий — опционально

Пример выражения для срока:

ДобавитьРабочихДней(ТекущиеДатаИВремя, 3)

Действие: изменить значение ДП

Указывается целевой ДП и новое значение (фиксированное или через smart-выражение). Для очистки значения — передать пустое значение.

Действие: назначить исполнителей

Два действия часто используются вместе: 1. «Удалить текущих исполнителей» 2. «Добавить группу исполнителей» (параметр «Кого (группа)»)

Порядок важен: сначала удаление, потом добавление.

Действие: создать задачу

Параметры: категория, заказчик, ДП при создании, связь с текущей задачей (подзадача или связанная).

Действие: запрос подписи

Условие запроса через smart-фильтр. Акцептанты — по smart-выражению.

Для проверки неуволенных пользователей в ДП «Выбор пользователей»:

в Согласующие есть элемент, такой что Уволен есть ложь

Коллекция ExtParamSelectUsersValues содержит значения ДП типа «Выбор пользователей».


Smart-пакеты

Последовательность

Действия внутри пакета выполняются строго по порядку (сверху вниз). Пакеты внутри события — тоже по порядку.

Можно менять очередность перетаскиванием строк.

Циклические пакеты

Для повторения действий над несколькими объектами. Настройка: 1. Переключить пакет в режим «Циклический» 2. Задать список итерируемых объектов — smart-выражение, возвращающее массив ID 3. Опционально — условие прерывания цикла 4. В действиях использовать переменные цикла из контекста SMART

Индекс итерации начинается с 0. Доступен в smart-выражениях внутри пакета.

Важно: если при создании действий в циклическом пакете переменные цикла не появляются в дереве — сохранить пакет, закрыть и открыть заново.


Smart-кнопки

Создание

Путь: Настройки категории > Кнопки > Создать. Указать имя, видимость, настройки доступа.

Отличие от кнопки перехода: smart-кнопка не связана с маршрутом. Примеры: рассчитать ДП, создать задачу, отправить email.

Видимость

Регулируется по: - Статусу задачи - Группам пользователя - Smart-фильтру

Привязка действий

К кнопке привязывается пакет действий (+ рядом с полем «Пакеты действий»). Несколько пакетов выполняются последовательно.

Пример: кнопка «Отменить приём сотрудника» — пакет 1 меняет статус текущей задачи на «Отклонено», событие смены статуса запускает циклический пакет 2, который переводит все связанные задачи.


Smart-расписания

Настройка

Путь: Настройки категории > Смарты > Smart-расписания > + Создать.

Параметры: - Периодичность — от минут до месяцев - Дата и время начала — должны быть в будущем - Продолжительность — по умолчанию «10 повторений» (обычно менять на «Без ограничений») - Попытки выполнения — при ошибках, по умолчанию 5, минимум 1 - Флажок «Активно» — вкл/выкл

Режимы выполнения

Режим Описание
Вне контекста задачи Пакет выполняется для всех задач категории
Для каждой задачи, отфильтрованной Smart-фильтр отбирает задачи

Пример фильтра — задачи с датой выхода на работу = сегодня:

УсечьВремя(ДП[«Дата выхода на работу»]) = УсечьВремя(ТекущиеДатаИВремя)

Функция УсечьВремя необходима для сравнения дат без учета времени.

Ограничения

  • Расписание работает только при наличии хотя бы одной задачи в категории
  • Пакеты с действием «Отменить» недоступны в расписаниях
  • Для действий без привязки к категории — глобальные smart-расписания (Общие SMART)

Проверка

  • Тестирование фильтра через кнопку «Тест»
  • Принудительный запуск: ПКМ на расписании > «Выполнить» (или кнопка «Запустить сейчас»)

T-SQL в Smart

Когда использовать

  • Стандартных возможностей SMART недостаточно
  • Нужны JOIN-ы между категориями
  • Сложные условия с подзапросами
  • Фильтрация расписаний (T-SQL фильтр возвращает список задач, не boolean)

Правило: в первую очередь используйте язык SMART. T-SQL — когда SMART не справляется.

Ключевые таблицы и переменные

Объект Описание
TasksInSubcat{N}Denormalized Денормализованная таблица категории N
ExtParam{N}NativeValue Значение ДП N (нативный тип)
ExtParam{N}Value Значение ДП N (строка)
@ContextID ID текущей задачи
@eventParam0 ID задачи в контексте подписи
ExtParamSelectUsersValues Таблица значений ДП «Выбор пользователей»
Users Таблица пользователей (IsFired_2 = признак увольнения)
TaskHelpers Исполнители задачи (IsResponsible = ответственный)
dbo.tc_AddWorkingDays(date, days) Стандартная функция: добавить рабочие дни
IsWaitingSign Признак «на подписи» (1/0)

Паттерн: условный расчет срока

SELECT
   CASE
       WHEN Extparam84NativeValue IS NOT NULL
            AND Extparam71NativeValue > GETDATE()
       THEN dbo.tc_AddWorkingDays(Extparam71NativeValue, 1)
       ELSE dbo.tc_AddWorkingDays(GETDATE(), 1)
   END
FROM TasksInSubcat21Denormalized
WHERE Taskid = @ContextID

Паттерн: фильтр расписания — отбор задач

SELECT t29.Taskid
FROM TasksInSubcat29Denormalized t29
JOIN TasksInSubcat18Denormalized t18
    ON t18.taskid = t29.Extparam114NativeValue
WHERE t29.Stateid = 28
    AND t18.Extparam277Value <> ''
    AND FORMAT(t29.Extparam74NativeValue,'dd.MM.yyyy')
        <= FORMAT(GETDATE(),'dd.MM.yyyy')
    AND t29.IsWaitingSign = 0

Паттерн: проверка акцептантов подписи через SQL

if exists (
    select u.UserID
    from TasksInSubcat22Denormalized t22 (nolock)
    join TasksInSubcat19Denormalized t19 (nolock)
        on t19.TaskID = t22.ExtParam88NativeValue
    join ExtParamSelectUsersValues epvu (nolock)
        on t19.TaskID = epvu.TaskID
        and epvu.ExtParamID = 76
    join Users u (nolock)
        on u.UserID = epvu.UserID
    where t22.TaskID = @ContextId
        and u.IsFired_2 = 0
    )
  select 1
else
  select 0

Для акцептантов: параметр задачи = @eventParam0 (не @ContextId).


Изменение настроек с учетом автоматизации

Чек-лист при изменениях

  1. Добавление ДП в категорию: проверить, есть ли автоматизация, создающая задачи в эту категорию (Маршрут > Постановка задач в категорию). Если ДП обязательный — добавить его в действие «Создать задачу»
  2. Удаление ДП: проверить все связанные выражения и пакеты. Лучше скрыть, чем удалить
  3. Удаление перехода: если на переходе настроена автоматизация — она удалится вместе с переходом. Лучше скрыть
  4. Проверка зависимостей: вкладка «Smart выражения» показывает, в каких пакетах используется выражение

LUA-автоматизация

Преимущества Lua перед SMART

  • Снижение нагрузки на БД (скрипты выполняются вне СУБД)
  • Быстрее SMART-выражений
  • Обработка контекстных данных, которых еще нет в БД
  • Полноценный язык: циклы, таблицы, строки
  • Защита от SQL-инъекций

Для простых задач — SMART предпочтительнее (проще поддержка).

Основные библиотеки 1Формы

Объект Метод Назначение
CONTEXT .Id, .OwnerId, .ExtParamValues Контекст текущей задачи
SQL :query(sql, params) Выполнить SQL-запрос, вернуть таблицу результатов
SMART :execute_action(action, contextId, 'task', params) Вызвать смарт-действие
UTILS :json_encode(table) Сериализовать таблицу в JSON
EVENTPARAMS ["HasChangedUser"], ["NewValue"] Параметры события
SESSION_USER .Id Текущий пользователь сессии
RESULT (зарезервировано) Выходной параметр скрипта

Паттерн: получение значения ДП из контекста

local function getExtParamValue(ep_id)
    for _, value in pairs(CONTEXT.ExtParamValues) do
        if value.ExtParamId == ep_id then
            return value.DateTimeValue, value.ExtParamValue
        end
    end
    return nil, nil
end

Возвращает два значения: timestamp и строковое представление.

Паттерн: SQL-запрос с параметрами

local query = [[
    SELECT t.TaskID, t.ExtParam55Value as Name
    FROM TasksInSubcat34Denormalized as t WITH (nolock)
    WHERE t.StateID = 7
    AND t.ExtParam114NativeValue = 1186
]]
local params = {}
local res = SQL:query(query, params)

for _, data in pairs(res) do
    print(data.TaskID, data.Name)
end

Параметры передаются как таблица {ParamName = value}, в SQL используются как @ParamName. Ключи результата регистрозависимые (как в SQL-запросе).

Паттерн: создание задачи с заполнением ДП

local function createTask(owner, helpers, due_time, newtaskextparams_json)
    SMART:execute_action('CreateTask', CONTEXT.Id, 'task', {
        Owner = owner,
        Subcat = 31,               -- ID категории
        TaskText = nil,
        CreateLink = false,
        CreateSubtask = true,       -- подзадача текущей
        Performers = helpers,       -- таблица ID пользователей
        DueTime = due_time,         -- timestamp
        ExtParams = newtaskextparams_json,  -- JSON
        NewTaskCopySubscribers = true,
        Priority = 1
    })
end

-- Подготовка ДП для новой задачи
local newtaskextparams = {
    {ExtParamID = 99,  FixedValue = project_id},
    {ExtParamID = 55,  FixedValue = name},
    {ExtParamID = 102, FixedValue = description},
}
local json = UTILS:json_encode(newtaskextparams)
createTask(owner, helpers, due_time, json)

Паттерн: обновление срока задачи

local function updateTaskOrderedTime(task_id, due_time)
    SMART:execute_action('UpdateTaskOrderedTime', task_id, 'task', {
        InitUser = EVENTPARAMS["HasChangedUser"].Id,
        DueTime = due_time,
        Reason = 'Изменение даты планового открытия проекта',
        Task = task_id,
        DoNotWriteComment = false
    })
end

Важно: при событии «После смены ДП» новое значение уже в БД. При «Перед сменой ДП» — новое значение в EVENTPARAMS["NewValue"], в БД еще старое.

Паттерн: расчет срока от плановой даты

local project_open_date = getExtParamValue(93)  -- timestamp

if project_open_date then
    due_time = project_open_date - work_days * 24 * 3600
end
if not due_time or due_time <= os.time() then
    due_time = os.time() + 18 * 3600  -- fallback: сегодня + 18ч
end

Стиль кода Lua (рекомендации)

Правило Пример
Всегда local local function f(), local x = 1
snake_case для переменных helpers_table, due_time
camelCase для функций getExtParamValue(), createTask()
UPPER_CASE для констант PI = 3.14, MAX_RETRY = 5
_ для неиспользуемых переменных for _, v in pairs(t) do
Проверка на nil без явного сравнения if var then вместо if var ~= nil then
Объявлять функции до вызова Порядок: вспомогательные, затем основной код
Комментарии к end end -- if string, end -- for each t

Значение по умолчанию:

x = x or 'default'

Тернарный оператор:

answer = (2*2 == 4) and 'Истина' or 'Ложь'


JS в карточках задач

Назначение

JS-вставки управляют представлением карточки задачи: скрытие/отображение ДП, подсветка полей, динамическое поведение в зависимости от условий.

Путь: Настройки категории > Формы > Настройки JS и CSS вставок (NTF).

Доступные API

Переменная/объект Описание
taskId Номер текущей задачи
StateID ID текущего статуса
SessionUserId ID текущего пользователя
getSessionUserInfo() {userId, isAdmin, groups[]}
new ExtParam(id) Объект ДП для чтения/управления

Паттерн: скрытие ДП по значению другого ДП

Скрыть поле «Телефон» если «Вид связи» = «E-mail личный»:

// Обработчик NTF — обернуть в событие открытия задачи
var epVidSvyazi = new ExtParam(1234);  // ID ДП «Вид связи»
var epPhone = new ExtParam(1235);      // ID ДП «Телефон»
var epEmail = new ExtParam(1236);      // ID ДП «E-mail»

var val = epVidSvyazi.getValue();
if (val === 'E-mail личный') {
    epPhone.hide();
    epEmail.show();
} else if (val === 'Телефон личный') {
    epEmail.hide();
    epPhone.show();
} else {
    epPhone.hide();
    epEmail.hide();
}

Паттерн: подсветка незаполненных полей

var epList = [1234, 1235, 1236, 1237]; // ID обязательных ДП
epList.forEach(function(id) {
    var ep = new ExtParam(id);
    if (!ep.getValue()) {
        ep.setLabelColor('red');
    }
});

Активация вставки

  • Создать вставку (тип: js)
  • Добавить в категорию
  • Поставить галку «Форма задачи» для активности
  • Для NTF — обернуть код в обработчик события открытия задачи
  • Для MTF — создать отдельную функцию-обработчик (для корректного удаления)

Рецепты смарт-кнопок с динамическим URL

Смарт-кнопка может открывать URL, сформированный динамически на основе данных текущей задачи. Механизм — поле URL в настройках кнопки (тип «Произвольная ссылка»), которое принимает смарт-выражение, возвращающее строку.

Справочник переменных: docs/domains/smart-actions/variables-reference.md


1. Открыть внешний URL с ID задачи

Сценарий: кнопка «Открыть в CRM» — переходит на внешний сервис, передавая taskId как параметр запроса.

Как настраивается (UI):

  1. Настройки категории → вкладка Кнопки → Создать
  2. Заполнить Имя кнопки
  3. В поле URL выбрать тип «Произвольная ссылка»
  4. Привязать смарт-выражение, возвращающее URL со встроенным ID задачи
  5. Открывать ссылку в → «В новом окне» (для внешних ресурсов рекомендуется)

Смарт-выражение (T-SQL):

SELECT 'https://external.service/form?taskId=' + CAST(@ContextID AS nvarchar(20))

@ContextID — ID текущей задачи (TaskID). Подставляется автоматически в контексте смарт-выражения.

Смарт-выражение (SMART-режим, без T-SQL):

В режиме SMART конкатенация строк: 'https://external.service/form?taskId=' + ВСтроку(№ задачи).

Важно: внешние ресурсы с заголовком X-Frame-Options: sameorigin нельзя открывать в модальном окне — браузер заблокирует. Используйте режим «В новом окне».


2. mailto с динамической темой и телом

Сценарий: кнопка «Написать письмо» — открывает почтовый клиент пользователя с заполненными получателем, темой и телом письма.

Вариант A — через поле URL кнопки (смарт-выражение):

SELECT 'mailto:support@example.com?subject=Задача%20' + CAST(@ContextID AS nvarchar(20))
    + '&body=Добрый%20день%2C%20прошу%20помочь%20с%20задачей%20' + CAST(@ContextID AS nvarchar(20))

Вариант B — через JS-выражение кнопки:

window.open('mailto:support@example.com?subject=Задача ' + taskId + '&body=Текст письма');

Переменная taskId доступна в JS-вставках карточки задачи. JS-выражение указывается в поле JavaScript выражение настроек кнопки. Если указаны и JS, и URL — сначала выполняется JS, затем открывается URL.

Кириллица в параметрах: браузеры обычно кодируют её автоматически, но для надёжности — кодируйте вручную: пробел = %20, запятая = %2C.


3. Открыть связанную задачу в новой вкладке

Сценарий: кнопка «Перейти к проекту» — открывает карточку связанной задачи (ID берётся из ДП текущей задачи).

Рекомендованный способ (тип URL = «Форма задачи»):

В поле URL выбрать тип «Форма задачи» (RedirectActionType.OpenTask = 3). Привязать смарт-выражение, возвращающее ID нужной задачи:

-- Вернуть ID связанной задачи из ДП (ДП №77 — ID проекта)
SELECT ExtParam77NativeValue
FROM TasksInSubcat{N}Denormalized
WHERE TaskID = @ContextID

Система сама сформирует корректный внутренний URL /tasks/{taskId}.

Альтернатива через OpenUrl (явный URL):

SELECT '/tasks/' + CAST(ExtParam77NativeValue AS nvarchar(20))
FROM TasksInSubcat{N}Denormalized
WHERE TaskID = @ContextID

Режим открытия: «В новом окне» или «В модальном окне» — на выбор администратора.


4. Вызов внешнего HTTP API без открытия браузера

Сценарий: кнопка «Отправить в 1С» — при нажатии выполняет HTTP-запрос к внешнему API серверной стороной, не открывая URL в браузере.

Механизм: пакет действий со стандартным действием «Отправить HTTP запрос» (StandardAction.SendHttpRequest). Кнопка запускает пакет через поле Пакет действий — не через поле URL.

Конфигурация пакета действий:

Параметр Значение
Метод GET / POST / PUT / DELETE / PATCH
URL Смарт-выражение → строка с адресом
Параметры запроса Список Имя=Значение (для GET — query string, для POST — body)
Заголовки Список Имя=Значение (например, Authorization)
Raw Body Строка (для POST с JSON — вместо параметров)
Таймаут, мс Необязательный, по умолчанию стандартный

Пример URL в пакете (смарт-выражение):

SELECT 'https://api.external.service/tasks/' + CAST(@ContextID AS nvarchar(20)) + '/sync'

Отличие от поля URL кнопки: поле URL кнопки открывает адрес в браузере (клиентская сторона). Действие «Отправить HTTP запрос» выполняется сервером — пользователь не видит переход, ответ можно использовать в следующих действиях пакета.


Ловушки

Проблема Решение
Внешний URL в модальном окне — ошибка X-Frame-Options: sameorigin Переключить «Открывать в» на «В новом окне»
Кириллица в URL отображается как %D0%... Норма для HTTP; если нужна читаемость — использовать только ASCII в параметрах
Смарт-выражение возвращает NULL Переход по ссылке не выполняется без сообщения. Добавьте проверку в SQL: ISNULL(result, 'https://fallback.url')
Длинный URL обрезается Ограничений на стороне платформы не задокументировано; браузерный лимит — ~2000 символов. Длинные данные передавайте через POST-запрос в пакете
JS-выражение с ошибкой блокирует переход по URL Если указаны и JS, и URL — при ошибке JS переход по URL не выполняется (проверить через консоль браузера)
Переменная @ContextID не работает в JS-выражении кнопки @ContextID — только для смарт-выражений T-SQL. В JS используйте переменную taskId