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