При разработке сложных систем на платформе 1С:Предприятие 8.3 часто возникает задача создания связанных объектов. Одной из типовых задач является генерация документа на основании бизнес-процесса. Особенную сложность у начинающих разработчиков вызывает перенос данных из табличных частей и корректное управление жизненным циклом нового объекта (нужно ли его записывать сразу или дать возможность пользователю проверить данные в форме).
В этой статье мы подробно разберем, как правильно реализовать механизм создания документа на основании бизнес-процесса, проанализируем типичные ошибки и рассмотрим профессиональные приемы работы с данными заполнения.
Когда мы используем стандартный конструктор «Ввод на основании», платформа 1С помогает связать простые реквизиты. Однако, если данные находятся внутри табличной части бизнес-процесса, конструктор может их «не видеть» или требовать ручного написания кода. Рассмотрим ситуацию: у нас есть бизнес-процесс СнижениеРисков с табличной частью Причины, и нам нужно создать документ ОценкаЗначимостиРиска, заполнив его реквизиты данными из этой таблицы.
Основная ошибка часто заключается в неправильной передаче контекста или попытке обратиться к переменной ДанныеЗаполнения там, где она не определена. Выясним, как это исправить.
Логика заполнения нового документа всегда должна располагаться в Модуле объекта создаваемого документа в предопределенной процедуре ОбработкаЗаполнения. Рассмотрим, как правильно обратиться к данным бизнес-процесса-основания.
Проанализируем пример кода, который позволяет достать данные из первой строки табличной части бизнес-процесса:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
// Проверяем, что основанием является именно наш бизнес-процесс
Если ТипЗнч(ДанныеЗаполнения) = Тип("БизнесПроцессСсылка.СнижениеРисков") Тогда
// Важно: проверяем, есть ли вообще строки в табличной части
Если ДанныеЗаполнения.Причины.Количество() > 0 Тогда
// Получаем доступ к первой строке (индекс 0)
СтрокаИсточника = ДанныеЗаполнения.Причины[0];
// Заполняем реквизиты документа из строки ТЧ бизнес-процесса
Ответственный = СтрокаИсточника.Ответственный;
ВероятностьРиска = СтрокаИсточника.планируемаяВероятностьриска;
ЗначимостьРиска = СтрокаИсточника.ПланируемаяЗначимостьРиска;
ПоследствияРиска = СтрокаИсточника.ПланируемыеПоследствияРиска;
Риск = СтрокаИсточника.Риск;
КонецЕсли;
// Можно также заполнить реквизиты из шапки бизнес-процесса, если нужно
// Например: ДокументОснование = ДанныеЗаполнения;
КонецЕсли;
КонецПроцедуры
Важный момент: обращение по индексу [0] допустимо только в том случае, если вы на 100% уверены, что в бизнес-процессе всегда ровно одна строка. Если строк может быть несколько, правильнее использовать цикл или метод Загрузить(), о которых мы поговорим ниже.
Теперь рассмотрим, как инициировать создание документа. Часто разработчики создают собственную команду на форме. Основная трудность здесь — передать ссылку на текущий бизнес-процесс в метод Заполнить(). Ошибка «Переменная не определена (ДанныеЗаполнения)» возникает именно тогда, когда программист пытается использовать имя параметра из модуля объекта внутри модуля формы.
Правильный способ программного создания и записи документа на сервере выглядит так:
&НаСервере
Процедура СоздатьДокументНаОснованииНаСервере()
// Создаем новый объект документа в памяти
НовыйДокумент = Документы.ОценкаЗначимостиРиска.СоздатьДокумент();
// Инициализируем заполнение, передавая ССЫЛКУ на текущий бизнес-процесс
// Именно эта ссылка попадет в параметр "ДанныеЗаполнения" в модуле объекта
НовыйДокумент.Заполнить(Объект.Ссылка);
// Устанавливаем дополнительные реквизиты, если нужно
НовыйДокумент.Дата = ТекущаяДата();
// Записываем документ в базу данных
Попытка
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
Сообщить("Документ успешно создан: " + НовыйДокумент.Ссылка);
Исключение
Сообщить("Не удалось записать документ: " + КраткоеОписаниеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Рассмотрим ситуацию, когда в бизнес-процессе много строк, и все они должны попасть в табличную часть документа. Проанализируем два способа решения этой задачи.
Способ А: Перебор строк в цикле
Этот метод хорош, если имена колонок в бизнес-процессе и документе различаются.
// В модуле объекта документа
Для Каждого СтрокаБП Из ДанныеЗаполнения.Причины Цикл
НоваяСтрока = ТабличнаяЧастьДокумента.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаБП);
// Если имена не совпадают, заполняем вручную:
// НоваяСтрока.Сотрудник = СтрокаБП.Ответственный;
КонецЦикла;
Способ Б: Метод Загрузить
Если структуры таблиц идентичны, мы можем воспользоваться методом Выгрузить() у источника и Загрузить() у приемника. Это работает значительно быстрее.
ТаблицаДанных = ДанныеЗаполнения.Причины.Выгрузить();
ТабличнаяЧастьДокумента.Загрузить(ТаблицаДанных);
Как справедливо заметили участники обсуждения, автоматическая запись документа в базу не всегда удобна. Пользователь может захотеть дозаполнить данные или передумать создавать документ. В управляемом приложении для открытия заполненной формы используется метод ОткрытьФорму.
Рассмотрим, как вызвать создание документа так, чтобы открылась форма, а процедура ОбработкаЗаполнения отработала автоматически:
&НаКлиенте
Процедура СоздатьБезЗаписи(Команда)
// Формируем параметры для открытия формы
// Ключ "Основание" автоматически инициирует механизм заполнения
ПараметрыФормы = Новый Структура("Основание", Объект.Ссылка);
// Открываем форму нового документа
ОткрытьФорму("Документ.ОценкаЗначимостиРиска.ФормаОбъекта", ПараметрыФормы);
КонецПроцедуры
В этом случае документ не будет записан в базу данных до тех пор, пока пользователь не нажмет кнопку «Провести и закрыть». Это избавляет систему от появления «пустых» или ошибочных документов, если пользователь просто закрыл форму.
При реализации механизма «Ввод на основании» всегда придерживайтесь следующих правил:
ТипЗнч(ДанныеЗаполнения) в начале процедуры. Один и тот же документ может создаваться на основании разных объектов (например, из другого документа или из задачи).ДанныеЗаполнения — это не пустая ссылка, иначе обращение к реквизитам через точку вызовет ошибку.А = Б, используйте функцию ЗаполнитьЗначенияСвойств(Приемник, Источник). Она автоматически копирует значения реквизитов с одинаковыми именами.ОбработкаЗаполнения выполняется внутри транзакции записи. Ошибки в ней приведут к откату всей операции.Таким образом, мы рассмотрели полный цикл создания документа на основании бизнес-процесса. Правильное разделение логики между модулем формы (где мы инициируем процесс) и модулем объекта (где мы описываем правила переноса данных) делает ваш код чистым, понятным и соответствующим стандартам разработки 1С.