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