Как проверить, принадлежат ли элементы табличной части одной группе, и программно управлять задачами бизнес-процесса

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С часто возникают задачи, связанные с контролем целостности данных при заполнении табличных частей. Типичный пример — необходимость убедиться, что пользователь выбрал в строках элементы, принадлежащие одному и тому же родителю (группе) в иерархическом справочнике. Кроме того, при работе с бизнес-процессами стандартная логика формирования задач не всегда отвечает требованиям бизнеса. Разберем по шагам, как реализовать проверку иерархии и как гибко управлять созданием задач на точках маршрута.

Часть 1: Проверка идентичности родителя для элементов в табличной части

Представим ситуацию: на форме бизнес-процесса есть табличная часть Причины, в которой заполняется реквизит Риск (ссылка на иерархический справочник Услуги). Нам нужно запретить проведение документа или старт процесса, если в таблицу добавлены элементы из разных групп. Проанализируем наиболее эффективный способ решения этой задачи через механизм запросов.

Шаг 1. Сбор данных для проверки

Для начала нам необходимо получить список всех выбранных элементов из табличной части. Вместо того чтобы перебирать строки в цикле и поочередно обращаться к базе данных, мы выгрузим все значения одной колонки в массив. Рассмотрим код, который выполняет эту операцию:


// Выгружаем колонку "Риск" из табличной части в массив
МассивЭлементов = Причины.ВыгрузитьКолонку("Риск");

Шаг 2. Использование запроса для проверки уникальности родителей

Наиболее производительный метод проверки — использование языка запросов 1С. Мы выберем количество различных родителей для переданного списка элементов. Если результат равен 1, значит, у всех элементов один и тот же родитель. Если больше — структура нарушена.


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Услуги.Родитель) КАК КоличествоРодителей
    |ИЗ
    |   Справочник.Услуги КАК Услуги
    |ГДЕ
    |   Услуги.Ссылка В (&Элементы)";

Запрос.УстановитьПараметр("Элементы", МассивЭлементов);

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    Если Выборка.КоличествоРодителей > 1 Тогда
        // Здесь мы обнаружили, что элементы из разных групп
        Сообщить("Ошибка: все выбранные риски должны принадлежать одной группе!");
    КонецЕсли;
КонецЕсли;

Важное дополнение: При использовании этого метода стоит учитывать пустые ссылки. Если в табличной части есть пустые строки, их следует исключить из массива перед передачей в запрос, чтобы избежать ложных срабатываний или ошибок выполнения.

Часть 2: Где разместить код проверки?

Выясним, в какой обработчик лучше всего поместить данную логику. Традиционно для проверки корректности заполнения данных в 1С используется событие ОбработкаПроверкиЗаполнения в модуле объекта. Это событие вызывается автоматически при записи объекта или при нажатии кнопки «Стартовать» в бизнес-процессе.

Рассмотрим пример реализации в модуле объекта:


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    МассивЭлементов = Причины.ВыгрузитьКолонку("Риск");
    
    // Удаляем пустые значения из массива, чтобы они не влияли на логику
    Пока МассивЭлементов.Найти(Справочники.Услуги.ПустаяСсылка()) <> Неопределено Цикл
        МассивЭлементов.Удалить(МассивЭлементов.Найти(Справочники.Услуги.ПустаяСсылка()));
    КонецЦикла;

    Если МассивЭлементов.Количество() = 0 Тогда
        Возврат; // Нет данных для проверки
    КонецЕсли;

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Услуги.Родитель) КАК КоличествоРодителей
        |ИЗ
        |   Справочник.Услуги КАК Услуги
        |ГДЕ
        |   Услуги.Ссылка В (&Элементы)";
    Запрос.УстановитьПараметр("Элементы", МассивЭлементов);

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() И Выборка.КоличествоРодителей > 1 Тогда
        ТекстСообщения = "Выбранные риски относятся к разным группам. Пожалуйста, выберите риски из одной группы.";
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , , , Отказ);
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры

Использование Отказ = Истина предотвратит дальнейшее выполнение операции (запись или старт процесса), пока пользователь не исправит ошибку.

Часть 3: Программное создание задач в бизнес-процессе

Вторая задача, которую мы разберем — это управление списком задач на точке маршрута. Стандартно 1С создает одну задачу для исполнителя, указанного в карте маршрута. Однако часто требуется создать несколько задач на основе данных табличной части (например, по одной задаче для каждого ответственного, указанного в строках).

Для этого используется событие ПриСозданииЗадач или ПередСозданиемЗадач. Основной секрет здесь заключается в использовании флага СтандартнаяОбработка.

Алгоритм действий:

  1. В обработчике точки маршрута анализируем, является ли эта точка той, где нам нужно «ручное» управление.
  2. Если да, устанавливаем СтандартнаяОбработка = Ложь. Это отключает автоматическое создание задачи платформой.
  3. В цикле создаем собственные объекты задач, заполняем их реквизиты и записываем.

Проанализируем пример кода в модуле бизнес-процесса:


Процедура ПриСозданииЗадач(ТочкаМаршрутаБизнесПроцесса, ФормируемыеЗадачи, Отказ)
    
    // Проверяем, что находимся на нужной точке маршрута
    Если ТочкаМаршрутаБизнесПроцесса = ТочкиМаршрута.Мероприятие Тогда
        
        // Перебираем строки табличной части для создания персональных задач
        Для Каждого СтрокаТЧ Из Причины Цикл
            
            // Создаем новую задачу программно
            НоваяЗадача = Задачи.УниверсальнаяЗадача.СоздатьЗадачу();
            НоваяЗадача.БизнесПроцесс = ЭтотОбъект.Ссылка;
            НоваяЗадача.ТочкаМаршрута = ТочкаМаршрутаБизнесПроцесса;
            НоваяЗадача.Дата = ТекущаяДата();
            
            // Заполняем индивидуальные параметры из строки ТЧ
            НоваяЗадача.Наименование = "Выполнить мероприятие: " + СтрокаТЧ.Риск;
            НоваяЗадача.Исполнитель = СтрокаТЧ.Ответственный;
            НоваяЗадача.СрокВыполненияЗадачи = СтрокаТЧ.Срок;
            
            // Обязательно записываем задачу
            НоваяЗадача.Записать();
            
        КонецЦикла;
        
        // Если задачи созданы вручную, мы можем очистить список ФормируемыеЗадачи,
        // чтобы платформа не создавала лишнюю стандартную задачу
        ФормируемыеЗадачи.Очистить();
        
    КонецЕсли;

КонецПроцедуры

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

Резюме

Мы рассмотрели два важных аспекта разработки сложных бизнес-логик. Во-первых, проверка иерархии элементов через запрос КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Услуги.Родитель) позволяет быстро и эффективно контролировать ввод данных пользователем. Во-вторых, гибкое управление задачами через программное создание объектов Задача дает возможность реализовывать сложные сценарии исполнения процессов, которые выходят за рамки стандартных возможностей карты маршрута 1С.

← На главную