В практике разработчика 1С часто возникает ситуация, когда ссылку на документ необходимо получить еще до того, как он будет физически записан в базу данных. Типичный пример: отправка электронного письма или уведомления в мессенджер в момент нажатия пользователем кнопки «Записать», где в тексте сообщения должна быть рабочая навигационная ссылка на этот самый документ.
Рассмотрим подробнее, почему стандартное обращение к свойству Ссылка нового объекта возвращает пустую ссылку, и разберем правильный алгоритм решения этой задачи.
Многие начинающие разработчики пытаются получить ссылку в обработчике ПередЗаписью, просто обращаясь к ЭтотОбъект.Ссылка. Однако для нового документа это значение будет пустым, так как уникальный идентификатор (GUID) присваивается объекту системой непосредственно в момент фиксации транзакции записи в таблицу базы данных.
В обсуждении на форуме мы видим типичную ошибку: попытку создать «левый» объект через менеджер документа:
// Ошибочный подход
СсылкаНового = Документы.МойДокумент.ПолучитьСсылку();
ДокументОбъект = Документы.МойДокумент.СоздатьДокумент();
ДокументОбъект.УстановитьСсылкуНового(СсылкаНового);
Проанализируем эту ситуацию. Здесь создается совершенно новый экземпляр документа в оперативной памяти (ДокументОбъект), который никак не связан с тем документом, который пользователь сейчас редактирует в форме. В итоге ссылка генерируется для временного объекта, а основной документ при записи получает свой собственный, другой идентификатор. Именно поэтому ссылки в письмах часто оказываются «битыми» (объект не найден).
Чтобы зарезервировать конкретную ссылку за текущим объектом, нам необходимо использовать метод УстановитьСсылкуНового(). Разберем по шагам, как это реализовать в модуле объекта документа.
Рассмотрим пример кода в процедуре ПередЗаписью:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// 1. Проверяем, что документ действительно новый
Если ЭтоНовый() Тогда
// 2. Генерируем новый уникальный идентификатор
НовыйУИД = Новый УникальныйИдентификатор();
// 3. Формируем ссылку через менеджер соответствующего типа документа
БудущаяСсылка = Документы.ПриходныйКассовыйОрдер.ПолучитьСсылку(НовыйУИД);
// 4. Фиксируем эту ссылку за текущим объектом
ЭтотОбъект.УстановитьСсылкуНового(БудущаяСсылка);
// Теперь мы можем использовать переменную БудущаяСсылка для формирования письма
ТекстПисьма = "Создан новый документ: " + ПолучитьНавигационнуюСсылку(БудущаяСсылка);
// Код отправки письма...
КонецЕсли;
КонецПроцедуры
Важный нюанс: метод УстановитьСсылкуНового() работает только в том случае, если объект еще не записан в базу. Если вы попытаетесь вызвать его для уже существующего документа, система выдаст ошибку.
Выясним причину, по которой метод ПолучитьНавигационнуюСсылку() может не работать так, как ожидается. Сама по себе функция возвращает внутренний адрес объекта в формате e1cib/data/Документ.ИмяДокумента?ref=....
Если вы планируете отправлять письмо внешнему пользователю, который должен открыть документ в веб-браузере или тонком клиенте, такой ссылки недостаточно. Вам необходимо добавить префикс информационной базы (адрес публикации на веб-сервере). Полная ссылка должна выглядеть примерно так: https://server.com/base_name/#e1cib/data/Документ.Имя....
Проанализируем ситуацию с транзакциями. Процедура ПередЗаписью выполняется внутри транзакции. Если после отправки письма выполнение кода прервется ошибкой или переменная Отказ примет значение Истина, запись документа в базу данных не произойдет.
В результате мы получим крайне неприятную ситуацию: пользователь получит письмо со ссылкой на документ, которого не существует в системе. Чтобы избежать этого, рекомендуется придерживаться следующей логики:
ПередЗаписью мы генерируем ссылку и сохраняем ее в ДополнительныеСвойства объекта.ПриЗаписи (которая все еще в транзакции) мы ничего не отправляем.ПослеЗаписи, когда транзакция успешно завершена и данные гарантированно сохранены, мы берем подготовленную ссылку из дополнительных свойств и инициируем отправку почты.Пример передачи ссылки через свойства объекта:
// В модуле объекта
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЭтоНовый() Тогда
НовыйУИД = Новый УникальныйИдентификатор();
СсылкаДляПисьма = Документы.СчетНаОплату.ПолучитьСсылку(НовыйУИД);
ЭтотОбъект.УстановитьСсылкуНового(СсылкаДляПисьма);
// Сохраняем для последующего использования
ДополнительныеСвойства.Вставить("СсылкаНаНовыйОбъект", СсылкаДляПисьма);
КонецЕсли;
КонецПроцедуры
Процедура ПослеЗаписи(ПараметрыЗаписи)
Если ДополнительныеСвойства.Свойство("СсылкаНаНовыйОбъект") Тогда
Ссылка = ДополнительныеСвойства.СсылкаНаНовыйОбъект;
// Здесь безопасно отправляем письмо
ОтправитьУведомление(Ссылка);
КонецЕсли;
КонецПроцедуры
Если нам нужно подготовить ссылку еще до того, как управление передано на сервер для записи (например, чтобы показать ее пользователю на экране), мы можем использовать аналогичный метод в модуле формы. Рассмотрим этот вариант:
В модуле формы (на клиенте) также доступен метод УстановитьСсылкуНового(), который можно вызвать перед вызовом Записать(). Это позволяет «забронировать» идентификатор объекта заранее, что бывает полезно при интеграции с внешними API или сложными веб-сервисами.
Подводя итог, отметим: получение ссылки на незаписанный документ в 1С — это абсолютно решаемая задача, требующая лишь понимания механизмов генерации УникальныйИдентификатор и правильного использования метода УстановитьСсылкуНового применительно к текущему экземпляру объекта.