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