Как в 1С программно ограничить прикрепление файла, если он уже существует?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе работы с 1С часто возникает задача автоматического формирования и прикрепления печатных форм к документам. Типичный пример — создание спецификации к заказу клиента. Однако, если этот механизм срабатывает при каждом сохранении документа, это приводит к созданию множества дубликатов одного и того же файла. Рассмотрим, как правильно организовать проверку и прикреплять файл только один раз.

Проанализируем ситуацию: у нас есть код, который формирует и прикрепляет файл, но делает это постоянно, создавая лишние копии. Наша цель — модифицировать этот код так, чтобы он сначала проверял, не был ли файл с таким же именем прикреплен ранее, и только в случае его отсутствия выполнял добавление.

Анализ исходного кода и типичные ошибки

Давайте посмотрим на первоначальный вариант кода и разберем его ключевые недостатки.


&НаСервере
Процедура ПрикрепитьФайлНаСервере(Рез)
	// ... (пропущена часть кода)
	Если ЕстьПрикрепленныеФайлы(Объект.Ссылка) Тогда	
		Попытка
			РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресВХранилище);	 
		Исключение
			ОбщегоНазначения.СообщитьПользователю("Не удалось добавить файл" + ОписаниеОшибки());
		КонецПопытки;													 
		ОбщегоНазначения.СообщитьПользователю("Файл " + ПараметрыФайла.ИмяБезРасширения + " успешно добавлен");
		Возврат;
	Прервать;
	КонецЕсли;
	// ...
КонецПроцедуры 

Функция ЕстьПрикрепленныеФайлы(Ссылка) Экспорт
	МассивФайлов = Объект.ПрикрепленныеФайлы.ПолучитьФайл();
	Возврат МассивФайлов.Количество()>0;
КонецФункции

В этом коде есть две фундаментальные проблемы:

  1. Неверная логика условия. Конструкция Если ЕстьПрикрепленныеФайлы(...) Тогда означает, что файл будет добавлен, только если к документу уже прикреплен хотя бы один файл. Для решения нашей задачи логику нужно инвертировать с помощью оператора НЕ.
  2. Некорректная проверка. Функция ЕстьПрикрепленныеФайлы проверяет наличие любых прикрепленных файлов у документа. Это неправильно. Представьте, что пользователь вручную прикрепил скан договора. В этом случае наша функция решит, что файлы уже есть, и не прикрепит нужную спецификацию. Проверять нужно не наличие файлов в целом, а наличие файла с конкретным именем, например, "Спецификация к заказу".

Правильное решение: Проверка наличия файла по имени

Чтобы реализовать корректную проверку, воспользуемся возможностями Библиотеки стандартных подсистем (БСП), которая встроена в большинство современных конфигураций, включая "Управление торговлей 11.5". Нам понадобится общий модуль РаботаСФайламиСлужебный.

Разберем решение по шагам.

Шаг 1. Создаем функцию для точной проверки

Вместо общей функции напишем новую, которая будет искать файл с заданным именем для конкретного документа-владельца.


&НаСервере
Функция СуществуетПрикрепленныйФайлСИменем(ВладелецФайла, ИмяФайлаДляПроверки)
    
    // Получаем все присоединенные файлы для указанного объекта-владельца
    // Используем для этого стандартную функцию БСП
    МассивФайлов = РаботаСФайламиСлужебный.ВсеПодчиненныеФайлы(ВладелецФайла);
    
    // Перебираем полученный массив файлов
    Для Каждого Файл Из МассивФайлов Цикл
        // Сравниваем наименование каждого файла с искомым.
        // Используем Врег() для сравнения без учета регистра символов.
        Если Врег(Файл.Наименование) = Врег(ИмяФайлаДляПроверки) Тогда
            // Если файл найден, сразу возвращаем Истина и выходим из функции
            Возврат Истина;
        КонецЕсли;
    КонецЦикла;
    
    // Если цикл завершился, а файл не был найден, возвращаем Ложь
    Возврат Ложь;
    
КонецФункции

Разберем подробнее:

Шаг 2. Встраиваем проверку в основную процедуру

Теперь, когда у нас есть надежный инструмент для проверки, изменим основную процедуру прикрепления файла. Логика будет такой: "если файл с нужным именем НЕ существует, то добавляем его".


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

Ключевые изменения:

Альтернативный подход: Обновление существующего файла (версионирование)

В некоторых случаях задача может стоять иначе. Например, если данные в "Заказе клиента" изменились, то и печатная форма спецификации должна обновиться. В этом случае просто не добавлять новый файл — не лучшее решение. Правильнее было бы найти старый файл спецификации и заменить его содержимое на новое.

Такой подход гарантирует, что у документа всегда будет только один файл спецификации, но он будет содержать самую актуальную информацию.

Алгоритм действий для этого будет сложнее:

  1. Найти ссылку на существующий файл. Для этого нужно модифицировать нашу функцию проверки так, чтобы она возвращала не просто Истина/Ложь, а ссылку на найденный файл в справочнике присоединенных файлов (например, СправочникСсылка.ИмяСправочникаФайлов).
  2. Проверить результат. Если функция вернула ссылку (т.е. файл найден), то мы обновляем его.
  3. Обновить файл. Используя полученную ссылку и новые двоичные данные, нужно вызвать соответствующие процедуры БСП для редактирования файла, например, РаботаСФайлами.РедактироватьФайл.
  4. Добавить новый. Если функция не вернула ссылку (файл не найден), то мы добавляем его как новый, используя уже рассмотренный нами код с РаботаСФайлами.ДобавитьФайл.

Этот метод более гибок, но требует более глубокой проработки. Для простой задачи "прикрепить один раз и больше не трогать" отлично подходит первый рассмотренный нами способ. Для поиска готовых примеров программной работы с подсистемами можно использовать справочник по методам БСП с примерами вызова.

← На главную