В процессе разработки конфигураций 1С часто возникает задача установить двустороннюю или перекрестную связь между документами. Например, когда сначала создается и сохраняется первый документ, а затем при проведении второго документа необходимо записать ссылку на второй документ в реквизит первого.
Рассмотрим подробно, как правильно реализовать эту логику программно, на какие технологические риски следует обратить внимание и какие существуют альтернативные архитектурные решения.
Когда документ проводится, у него уже сформирована ссылка в базе данных (доступная через ЭтотОбъект.Ссылка или просто Ссылка). Чтобы записать эту ссылку в другой документ, необходимо выполнить следующие шаги:
ОбработкаПроведения определить реквизит, ссылающийся на первый документ.ПолучитьОбъект().Записать() в режиме обычной записи без повторного проведения.Разберем пример кода, который помещается в модуль проводимого (второго) документа:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Проверяем, заполнен ли реквизит-ссылка на Первый Документ
Если ЗначениеЗаполнено(ПервыйДокумент) Тогда
Попытка
// Получаем объект Первого Документа для модификации
ОбъектПервогоДокумента = ПервыйДокумент.ПолучитьОбъект();
// Записываем ссылку текущего (Второго) документа в реквизит Первого Документа
ОбъектПервогоДокумента.РеквизитВторогоДокумента = ЭтотОбъект.Ссылка;
// Сохраняем Первый Документ в режиме обычной записи
ОбъектПервогоДокумента.Записать(РежимЗаписиДокумента.Запись);
Исключение
Отказ = Истина;
Сообщить("Ошибка при записи ссылки в первый документ: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Важно помнить: если пользователь отменит проведение второго документа, ссылка на него в первом документе останется. Чтобы избежать неактуальных или некорректных связей, необходимо очищать реквизит в обработчике ОбработкаОтменыПроведения.
Рассмотрим код для отмены проведения:
Процедура ОбработкаОтменыПроведения(Отказ)
Если ЗначениеЗаполнено(ПервыйДокумент) Тогда
Попытка
ОбъектПервогоДокумента = ПервыйДокумент.ПолучитьОбъект();
// Очищаем реквизит первого документа
ОбъектПервогоДокумента.РеквизитВторогоДокумента = Справочники.Неопределено; // или ПустаяСсылка
ОбъектПервогоДокумента.Записать(РежимЗаписиДокумента.Запись);
Исключение
Отказ = Истина;
Сообщить("Не удалось очистить связь в первом документе: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Проанализируем технические нюансы, с которыми можно столкнуться при перезаписи одного документа из модуля проведения другого:
УстановитьПривилегированныйРежим(Истина).Записать() вернет ошибку и отменит проведение текущего документа.Запись ссылки в уже записанный и проведенный документ считается не всегда оптимальной практикой, так как меняется исторический объект. Рассмотрим более надежные подходы:
1. Использование механизма «Ввод на основании»
Если Второй Документ создается на основании Первого, то во Втором Документе достаточно хранить реквизит ДокументОснование. Платформа 1С и стандартный отчет «Структура подчиненности» автоматически покажут связь документов без необходимости записывать встречные ссылки.
2. Использование регистра сведений для хранения связей
Вместо изменения реквизита первого документа создается независимый или подчиненный регистратору регистр сведений (например, СвязиДокументов):
Документ1 (тип: ссылка на первый документ).Документ2 (тип: ссылка на второй документ).При проведении Второго Документа запись автоматически добавляется в движения регистра сведений, а при отмене проведения — удаляется. При этом сам Первый Документ не редактируется и не блокируется.