В процессе разработки механизмов автоматизации в «1С:Предприятие 8» часто возникает задача автоматического создания документов, например, «Заказов клиентов», через фоновые задания. Одной из неочевидных проблем в этой ситуации становится заполнение служебных реквизитов, таких как Автор. Зачастую программисты сталкиваются с тем, что при интерактивном запуске обработки код работает корректно, а в фоновом режиме реквизит Автор остается либо пустым, либо заполняется системным пользователем. В этой статье мы подробно разберем, почему так происходит и как правильно реализовать установку автора.
Давайте проанализируем ситуацию. Когда мы запускаем код «от руки» (в интерактивном сеансе), система инициализирует все параметры сеанса, включая ТекущийПользователь. Однако фоновое задание выполняется в отдельном сеансе на сервере. Если регламентное задание не привязано к конкретному пользователю, оно может выполняться от имени системного пользователя, или параметры сеанса могут быть не заполнены в том объеме, который ожидает конфигурация.
Основная причина перезаписи или незаполнения автора кроется в логике модуля объекта. В типовых решениях (УТ 11, ERP, КА) в процедуре ПередЗаписью или в соответствующих подписках на события часто встречается следующий код:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если ЭтоНовый() И Не ЗначениеЗаполнено(Автор) Тогда
Автор = Пользователи.АвторизованныйПользователь();
КонецЕсли;
КонецПроцедуры
В контексте фонового задания функция Пользователи.АвторизованныйПользователь() может вернуть пустую ссылку или ссылку на служебного пользователя «Робот», что перетирает установленное вами значение, если вы не учли специфику работы платформы.
Самый быстрый и эффективный способ «заставить» платформу принять ваше значение автора — это использование свойства ОбменДанными.Загрузка. Этот флаг сообщает системе, что объект загружается из внешнего источника и большинство стандартных проверок и алгоритмов заполнения в модулях (включая ПередЗаписью) следует пропустить.
Рассмотрим пример кода, который позволит нам установить автора, идентичного менеджеру, в фоновом режиме:
// Создаем новый документ
ДокЗаказ = Документы.ЗаказКлиента.СоздатьДокумент();
// Устанавливаем основные реквизиты
ДокЗаказ.Дата = ТекущаяДата();
ДокЗаказ.Менеджер = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван");
// Включаем привилегированный режим для обхода ограничений прав
УстановитьПривилегированныйРежим(Истина);
// Устанавливаем флаг загрузки, чтобы игнорировать логику ПередЗаписью
ДокЗаказ.ОбменДанными.Загрузка = Истина;
// Присваиваем автора
ДокЗаказ.Автор = ДокЗаказ.Менеджер;
// Записываем документ
Попытка
ДокЗаказ.Записать(РежимЗаписиДокумента.Запись);
Исключение
ЗаписьЖурналаРегистрации("Ошибка создания заказа", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
ДокЗаказ.ОбменДанными.Загрузка = Ложь;
УстановитьПривилегированныйРежим(Ложь);
Важное примечание: Использование ОбменДанными.Загрузка = Истина отключает не только заполнение автора, но и проверку заполнения других обязательных полей, а также механизмы регистрации изменений для планов обмена. Будьте осторожны, если этот заказ должен сразу уйти в другую базу через синхронизацию.
Если по каким-то причинам использование ОбменДанными.Загрузка нежелательно (например, должны сработать другие важные алгоритмы в ПередЗаписью), можно прибегнуть к методу «двойной записи». Сначала мы создаем объект и записываем его, чтобы он перестал считаться новым, а затем получаем его снова и принудительно устанавливаем автора.
Разберем этот метод по шагам:
Автор.
// Первая запись для создания ссылки
ДокЗаказ.Записать();
// Получаем объект заново для чистоты эксперимента
СсылкаНаЗаказ = ДокЗаказ.Ссылка;
ДокОбъект = СсылкаНаЗаказ.ПолучитьОбъект();
// Теперь документ уже не новый, и системные подписки могут пропустить это поле
ДокОбъект.Автор = ДокОбъект.Менеджер;
ДокОбъект.Записать();
Этот способ менее производителен, так как требует двух обращений к базе данных, но он позволяет корректно обойти условие Если ЭтоНовый() в программном коде конфигурации.
Проанализируем еще один важный аспект — типы данных. В современных конфигурациях реквизит Автор часто имеет составной тип, например, СправочникСсылка.Пользователи и СправочникСсылка.ВнешниеПользователи. Если вы пытаетесь присвоить значение одного типа другому или используете поиск по наименованию, который в фоновом задании может вернуть пустую ссылку, запись не даст результата.
Проверьте следующие моменты:
Пользователи.НайтиПоНаименованию лучше использовать НайтиПоРеквизиту или поиск по уникальному идентификатору, так как наименования могут дублироваться или меняться.УстановитьПривилегированныйРежим(Истина), если работаете со служебными реквизитами, которые обычно закрыты для редактирования пользователями.Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), выясним, как правильно взаимодействовать с механизмами заполнения. В БСП существуют общие модули, такие как ЗаполнениеОбъектов. Иногда правильнее будет не переопределять автора вручную, а инициализировать параметры сеанса текущего пользователя в начале работы фонового задания. Это позволит всем документам, создаваемым в рамках этого сеанса, автоматически получать правильного автора без дополнительных манипуляций с кодом записи каждого документа.
Рассмотрим, как можно передать нужного пользователя в параметры сеанса (требуются права администратора):
// В начале выполнения фонового задания
ПараметрыСеанса.ТекущийПользователь = НужныйПользователь;
Подводя итог, отметим: для надежной установки автора в фоновом задании наиболее предпочтительным является использование Решения 1 с флагом ОбменДанными.Загрузка = Истина в сочетании с Привилегированным режимом. Это гарантирует, что никакие внутренние подписки на события или проверки модуля объекта не изменят установленное вами значение.