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