Возникла задача прикреплять файл счета, уже загруженный в один документ, в другой, создаваемый на основании этого. Причем в этом втором документе файл нужен даже больше и выбрать надо только один из файлов, прикрепленных к первому документу, поэтому вариант показывать файлы основания отпадает. Дробить процесс создания на основании также не хотелось, хотя сейчас понимаю, что это тоже вариант, поскольку можно перед записью заполнить состояние мЭтоНовый и после записи предлагать выбрать файл для прикрепления. Поскольку был знаком с механизмом установки ссылки нового, решил действовать по этому сценарию, однако оказалось, что стандартные процедуры ЗначениеВРеквизитФормы и РеквизитФормыВЗначение не дают инструментов для работы с ссылкой нового! Но путем чтения форумов и экспериментов решение таки нашлось и очень простое!
Что такое вообще за тема ссылка нового? Ведь известно, что у нового объекта ссылка пустая. Однако 1С позволяет для случаев, когда ссылка нужна до момента записи объекта, получить и установить для объекта некоторую ссылку, которая и после его записи будет использована в том же виде, сохраняя таким образом целостность данных. Делается это достаточно просто - у менеджера справочников и документов есть метод ПолучитьСсылку, в который передается новый уникальный идентификатор. Эта ссылка и устанавливается методом УстановитьСсылкуНового у расширения объекта (имеется ввиду ДокументОбъект, например). Поскольку до записи Ссылка все равно будет пустая, есть также отдельный метод объекта ПолучитьСсылкуНового, который установленную ссылку и возвращает, но на управляемых формах бесполезен.
Таким образом, в серверных сценариях и на обычных формах можно без проблем работать с этим механизмом, ведь там не происходит преобразования в реквизит формы. А в клиентском коде на управляемых формах (как и на обычных, в общем) - да, это может показаться немного неуместным, ведь пользователь может в любой момент передумать, а о транзакции не может быть и речи... Но это возможно, и иногда хочется прибегнуть к данному методу.
Итак, РеквизитФормыВЗначение и ЗначениеВРеквизитФормы не передают ссылку нового, в том числе проверял сценарий с установкой ссылки нового в Обработке Заполнения, также не подхватывается при сохранении. Значит, нужно добавить реквизиты формы и использовать уже его:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ТипыОбъекта = Новый Массив;
ТипыОбъекта.Добавить(ТипЗнч(Объект.Ссылка));
ОписаниеТипаОбъекта = Новый ОписаниеТипов(ТипыОбъекта);
НовыеРеквизиты = Новый Массив;
НовыеРеквизиты.Добавить(Новый РеквизитФормы("СсылкаНового", ОписаниеТипаОбъекта));
ИзменитьРеквизиты(НовыеРеквизиты);
КонецПроцедуры
Таким образом, реквизит будет того же типа, что и рассматриваемый документ.
Далее, в случае необходимости, то есть когда нужно прикреплять файл, мы присваиваем этому реквизиту значение в соответствии с типом документа / справочника:
&НаСервере
Функция УстановитьСсылкуНового()
Если ЭтаФорма["СсылкаНового"].Пустая() Тогда
ЭтаФорма["СсылкаНового"] = Документы.СчетНаОплату.ПолучитьСсылку(Новый УникальныйИдентификатор);
КонецЕсли;
КонецФункции
При записи присоединенного файла в качестве объекта используем не Объект.Ссылка, а реквизит СсылкаНового:
&НаСервере
Процедура ПеренестиФайлИзОснования(Знач ВыбранныйФайл)
ПрисоединенныйФайл = Справочники.ПрисоединенныеФайлы.СоздатьЭлемент();
ПрисоединенныйФайл.Наименование = ВыбранныйФайл.Наименование;
ПрисоединенныйФайл.Объект = ?(Объект.Ссылка.Пустая(), ЭтаФорма["СсылкаНового"], Объект.Ссылка);
ПрисоединенныйФайл.ИмяФайла = ВыбранныйФайл.ИмяФайла;
ПрисоединенныйФайл.Хранилище = ВыбранныйФайл.Хранилище;
ПрисоединенныйФайл.Записать();
КонецПроцедуры
А теперь главное, что почерпнуто из форумов: полученную ссылку нового нужно присвоить в событии ПередЗаписьюНаСервере:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// +++ Этот код только для проверки текущего релиза 1С - вдруг поправили, в основном не нужен
СсылкаНового = ТекущийОбъект.ПолучитьСсылкуНового();
Если Не СсылкаНового.Пустая() Тогда
Сообщить("Ух-ты! В вашем релизе что-то работает по другому, ПолучитьСсылкуНового работает!");
КонецЕсли;
// ---
Если ТекущийОбъект.ЭтоНовый() И Не ЭтаФорма["СсылкаНового"].Пустая() Тогда
ТекущийОбъект.УстановитьСсылкуНового(ЭтаФорма["СсылкаНового"]);
КонецЕсли;
КонецПроцедуры
Тогда записанный объект наконец-таки получит подобранную ранее ссылку!
Ну и чтобы не хранить прикрепленные файлы без записанного владельца, при закрытии удаляем запись о файле, если документ так и не был записан:
&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
Если Объект.Ссылка.Пустая() И Не ЭтаФорма["СсылкаНового"].Пустая() Тогда
Если ЗавершениеРаботы Тогда
Отказ = Истина;
ТекстПредупреждения = "Сперва сохраните или закройте указанный счет";
Активизировать();
Иначе
УдалитьПрисоединенныйФайл();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура УдалитьПрисоединенныйФайл()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПрисоединенныеФайлы.Ссылка КАК Ссылка
|ИЗ
| Справочник.ПрисоединенныеФайлы КАК ПрисоединенныеФайлы
|ГДЕ
| ПрисоединенныеФайлы.Объект = &СсылкаНового";
Запрос.УстановитьПараметр("СсылкаНового", ЭтаФорма["СсылкаНового"]);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
УстановитьПривилегированныйРежим(Истина);
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
ПрисоединенныйФайл = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
ПрисоединенныйФайл.ОбменДанными.Загрузка = Истина;
ПрисоединенныйФайл.Удалить();
КонецЦикла;
КонецПроцедуры
Обратите внимание! В том, что касается конфигурации для примера, то там два типа документов и один справочник (присоединенные файлы). Чтобы испытать пример, нужно создать служебную записку и прикрепить к ней два и более PDF-файлов, а затем на основании этой служебки сделать счет на оплату. Чтобы исключить неизбежные ошибки при просмотре приложенного к счету pdf, использую не встроенный просмотрщик, а основанный на библиотеке pdf.js, выцарапанный у ИИ. В интернете есть статьи с полноценным просмотром pdf на той же библиотеке, но они работают помедленней.
Ну и, в конце, мне интересно ваше мнение, какое утверждение Вы считаете правильным:
1. Все время так делаю, стоило ли статью писать?
2. Ух-ты! Так это все-таки возможно!
3. Все это неправильно, нужно переносить выбор присоединенного счета в событие ПослеЗаписи! Иначе при завершении работы может остаться хвост.
4. Другое (в комментарии)
Вступайте в нашу телеграмм-группу Инфостарт