При работе в конфигурации «1С:ERP Управление предприятием» (в частности, на релизах линейки 2.5.8) пользователи могут столкнуться с критической ошибкой при создании документа распределения расходов будущих периодов (РБП). Ошибка возникает при переходе в меню «Финансовый результат и контроллинг» — «Распределение РБП» — «Распределить расходы».
Система прерывает работу со следующим сообщением:
Ошибка при выполнении обработчика - 'ОбработкаЗаполнения'
по причине:
{Документ.РаспределениеРасходовБудущихПериодов.МодульМенеджера(290)}: Преобразование значения к типу Дата не может быть выполнено
Разберем детально, почему возникает эта проблема, как диагностировать ее причину и какие шаги предпринять для устранения сбоя.
Давайте посмотрим на исходный код типовой конфигурации, в котором происходит падение. Отладчик приводит нас в функцию ПолучитьДатуВозникновенияРБП. Внутри этой функции выполняется объемный запрос к регистрам накопления ПрочиеРасходы и СебестоимостьТоваров.
Суть запроса сводится к поиску максимальной даты возникновения расхода по определенной статье:
ВЫБРАТЬ
МАКСИМУМ(ДатыРасходов.Период) КАК Период
ИЗ
(ВЫБРАТЬ ПрочиеРасходы.Период ... ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ СебестоимостьТоваров.Период ...) КАК ДатыРасходов
После выполнения запроса код пытается получить результат и вернуть начало дня найденной даты:
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
Возврат НачалоДня(Выборка.Период); // ВОТ ЗДЕСЬ ПРОИСХОДИТ ПАДЕНИЕ
КонецЕсли;
Возврат КонецМесяца(ДанныеЗаполнения.Период);
В чем же здесь подвох? Выясним механику работы агрегатной функции языка запросов 1С. Когда внутренний подзапрос не находит ни одной подходящей записи (база данных пуста по заданным фильтрам), внешняя агрегатная функция МАКСИМУМ() не возвращает пустой результат запроса. Согласно стандартам SQL, она вернет ровно одну строку, в которой значением колонки Период будет NULL.
В результате условие Выборка.Следующий() отрабатывает как истина (ведь строка есть!), и система пытается выполнить встроенную функцию НачалоДня(NULL). Платформа 1С не умеет преобразовывать значение NULL в тип Дата, что и вызывает немедленный вылет с ошибкой.
Часто разработчики и аналитики недоумевают: по одной статье РБП документ создается без проблем, а по другой вылетает ошибка, хотя в регистрах визуально присутствуют движения по обеим статьям. Рассмотрим подробнее условия отбора в запросе (секция ГДЕ):
ГДЕ
ПрочиеРасходы.Организация = &Организация
И ПрочиеРасходы.Подразделение = &Подразделение
И ПрочиеРасходы.АналитикаРасходов = &АналитикаРасходов
И ПрочиеРасходы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
И ПрочиеРасходы.Активность
И ПрочиеРасходы.Период МЕЖДУ НАЧАЛОПЕРИОДА(&Период, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Период, МЕСЯЦ)
Обратите пристальное внимание на последнюю строку отбора. Это скрытый фильтр по месяцу! Запрос ищет дату возникновения расходов будущих периодов строго в том месяце, за который сейчас создается документ распределения.
Если первичные расходы были проведены в системе месяцем или годом ранее, этот запрос физически их не увидит. Подзапрос вернет 0 строк, агрегатная функция вернет NULL, и программа упадет.
Кроме того, запрос требует полного и идеального совпадения всех аналитик. Иногда визуально пустая колонка в регистре содержит значение типа Неопределено, а в параметры передается пустая ссылка типа СправочникСсылка. Для запроса это разные значения, и он отсеет такие записи.
Разберем по шагам полезный прием, который значительно ускорит поиск недостающих данных. Вместо того чтобы вручную переносить параметры запроса в консоль, воспользуемся скрытой возможностью платформы.
Результат = Запрос.Выполнить()).ОбщегоНазначения.ЗапросВСтрокуXML(Запрос) и нажмите Enter.Теперь вы можете запускать запрос и удалять условия из блока ГДЕ по одному, пока не поймете, какой именно фильтр отсекает ваши данные.
Проанализируем ситуацию и рассмотрим несколько путей решения, в зависимости от ваших прав на изменение базы и релизной политики компании.
Если вы не можете быстро обновить базу, самым надежным способом будет перехват проблемной функции и добавление проверки на пустые значения. Для этого создайте Расширение конфигурации и добавьте туда общий модуль менеджера документа.
Используйте аннотацию &Вместо, чтобы модифицировать блок с получением результата:
&Вместо("ПолучитьДатуВозникновенияРБП")
Функция Расш1_ПолучитьДатуВозникновенияРБП(ДанныеЗаполнения) Экспорт
// ... здесь идет оригинальный текст запроса и установка параметров ...
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
// ВАЖНО: Добавляем проверку ЗначениеЗаполнено()
Если Выборка.Следующий() И ЗначениеЗаполнено(Выборка.Период) Тогда
Возврат НачалоДня(Выборка.Период);
КонецЕсли;
Возврат КонецМесяца(ДанныеЗаполнения.Период);
КонецФункции
Благодаря функции ЗначениеЗаполнено(), если в выборку попадет NULL, условие не выполнится. Алгоритм спокойно перейдет к следующей строке и вернет дату по умолчанию (конец месяца периода заполнения). Документ будет создан без ошибок.
Если программиста под рукой нет, проверьте исходные данные в пользовательском режиме. Вам необходимо убедиться, что:
Если расход возник в прошлом периоде, возможно, нужно изменить логику закрытия прошлого месяца или скорректировать дату начала распределения в параметрах статьи.
Стоит отметить, что разработчики фирмы 1С признали эту особенность кода в релизах ветки 2.5.8. В последующих обновлениях и накопительных патчах (начиная с релизов 2.5.9 и выше) алгоритм обработки РБП был доработан. В типовой код была штатно внедрена проверка на пустые значения при обработке агрегатных функций. Поэтому, если у вас есть возможность планово обновить 1С:ERP, это решит проблему автоматически.