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