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