В платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с задачей автоматического перемещения элемента справочника в другую папку (группу) при изменении каких-либо реквизитов прямо в форме списка. Однако при попытке присвоить новое значение реквизиту Родитель в предопределенной процедуре ПриЗаписи() модуль формы выдает критическую ошибку: «Объект не может быть перепозиционирован!».
Рассмотрим подробно причины возникновения данной проблемы и проанализируем проверенные способы ее решения.
Проанализируем механику работы формы списка справочника в 1С 7.7. Когда пользователь редактирует строку непосредственно в форме списка, элемент справочника находится в строгом контексте текущей выборки и иерархического дерева отображения.
Существуют две ключевые причины, из-за которых платформа блокирует прямую смену родителя:
Родитель в 1С 7.7 принимает исключительно ссылку на существующую группу справочника (объект типа Справочник.ИмяСправочника), а не текстовое наименование или код папки. Попытка присвоить строку вроде Родитель = "Оплаченные"; вызывает ошибку типа данных.ПриЗаписи() запись строки списка еще не завершена полностью. Изменение атрибута Родитель влечет за собой смену положения элемента в иерархическом дереве (перемещение в другую группу). Платформа 1С 7.7 запрещает изменять иерархическую позицию объекта, пока открыт контекст его интерактивного редактирования в форме списка.Разберем наиболее распространенный и безопасный метод решения задачи средствами встроенного языка 1С 7.7. Суть метода заключается в том, чтобы отложить фактическую смену родителя до момента, когда интерактивная запись строки полностью завершится и платформа освободит контекст объекта.
Рассмотрим алгоритм реализации по шагам:
ПриЗаписи() определяем необходимость смены родителя, запоминаем ссылки и запускаем таймер с помощью функции ОбработкаОжидания.СоздатьОбъект(), находим наш элемент и меняем у него родителя.Посмотрим на пример кода в модуле формы списка справочника:
Перем ЭлементДляПереноса;
Перем НовыйРодитель;
Процедура ПеренестиЭлемент()
// Отключаем обработку ожидания, чтобы она не циклилась
ОбработкаОжидания("ПеренестиЭлемент", 0);
Если ПустоеЗначение(ЭлементДляПереноса) = 0 Тогда
Спр = СоздатьОбъект("Справочник.ДолгиПередКонтрагентами");
Если Спр.НайтиЭлемент(ЭлементДляПереноса) = 1 Тогда
Спр.Родитель = НовыйРодитель;
Спр.Записать();
КонецЕсли;
КонецЕсли;
// Обновляем отображение формы списка
Форма.Обновить();
КонецПроцедуры
Процедура ПриЗаписи()
// Проверяем условие для переноса (например, признак оплаты)
Если Оплачено = 1 Тогда
СпрГруппа = СоздатьОбъект("Справочник.ДолгиПередКонтрагентами");
Если СпрГруппа.НайтиПоНаименованию("Оплаченные", 0, 1) = 1 Тогда
ЭлементДляПереноса = ТекущийЭлемент();
НовыйРодитель = СпрГруппа.ТекущийЭлемент();
// Запускаем отложенный перенос через 1 секунду после завершения записи
ОбработкаОжидания("ПеренестиЭлемент", 1);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для конфигураций, работающих на базе SQL-версии 1С 7.7 с использованием внешних компонент (например, 1С++ / DirectSQL), доступен вариант изменения поля родителя прямым запросом к базе данных. Этот метод обходит ограничение платформы на перепозиционирование, так как изменение происходит непосредственно на уровне СУБД.
Выясним, как формируется данный запрос:
// Пример SQL-запроса для изменения ParentID элемента
UPDATE
$Справочник.ДолгиПередКонтрагентами AS Спр
SET
Спр.ParentID = :ВыбРодитель
WHERE
Спр.id = :ИскомыйЭлементСправочника
Важное примечание: при использовании прямого SQL-запроса следует учитывать, что структура иерархического дерева в самой открытой форме списка обновится только после вызова метода Форма.Обновить() или переоткрытия формы списка.
Если специфика бизнес-процесса позволяет, рекомендуется вынести изменение реквизитов, влияющих на положение элемента в иерархии, из формы списка в форму элемента (диалог). При редактировании в форме элемента после нажатия кнопки «Записать» изменение родителя через отдельный объект СоздатьОбъект("Справочник...") проходит штатно и не вызывает конфликтов с текущей выборкой списка.
При программировании задач, связанных с изменением структуры иерархии, придерживайтесь следующих правил:
Родитель значения строкового типа. Всегда предварительно находите объект группы через НайтиПоКоду() или НайтиПоНаименованию().Пока Спр.ПолучитьЭлемент() = 1 Цикл при включенной иерархии. Изменение родителя сбивает внутренний индекс выборки 1С 7.7. Для массового переноса сначала собирайте ссылки на элементы в СписокЗначений или ТаблицуЗначений, после чего обрабатывайте их отдельным циклом.Форма.Обновить().