Итак, случилось то, что время от времени случается с каждым из нас, кроме самых лучших: появилась необходимость привязывать сканы к договорам.
Как известно, в любой типовой конфигурации имеется механизм, предназначенный для привязки к объектам ИБ файлов и изображений. Однако, как это обычно бывает, штатный механизм показался неудобным и было решено использовать костыли собственной разработки.
Для конкретики возьмем конфигурацию Управление производственным предприятием 1.3, в ней штатный механизм привязки изображений выглядит так, как нарисовано на первом скриншоте. Не устроил он в основном тем, что в нем нет возможности НЕ загружать в базу файлы (а ведь для хранения файлов уже давно был изобретен файлсервер, причем с разграничением прав доступа!). В своё оправдание могу сказать, что сканы на сетевом ресурсе к этому времени уже хранились (для каждого договора своя папка с произвольным количеством сканов), нужно было только обеспечить к ним быстрый доступ из 1С, а во вторых не хотелось увеличения размеров базы, бэкапов и обменов РИБ.
Итак, в первой попытке я, как котстылеписатель-рецидивист, написал обработку (она осталась с тех пор практически неизменной, кроме двух функций) и к ней в комплект - регистр сведений. Так же для работы нужно было немного изменить форму элемента справочника ДоговорыКонтрагентов. Вот комментарий из этотй версии:
//Для работы нужен регистр сведений
//ПутиКСканам
//Измерения: Объект (Тип:ЛюбаяСсылка)
//Ресурсы: Путь (Тип: Строка(100))
//так же в форму Справочник.ДоговорыКонтрагентов.ФормаСписка добавить кнопку "Сканы" (можно рядом с кнопкой "Файлы")
//и на неё повесить обработчик
//
//Процедура ДействияФормыДействиеСканыДоговоров(Кнопка)
// Если (ЭтоНовый()) Тогда
// Предупреждение("Сначала договор нужно записать!");
// Возврат;
// КонецЕсли;
// Обработка = Обработки.СканыДоговоровКонтрагентов.Создать();
// Обработка.ОткрытьФормуДоговора(Ссылка);
//КонецПроцедуры
а вот соответственно функции чтения/записи:
Функция ПолучитьПутьКСканам(Объект) Экспорт
Запрос = Новый Запрос("ВЫБРАТЬ
| ПутиКСканам.Путь
|ИЗ
| РегистрСведений.ПутиКСканам КАК ПутиКСканам
|ГДЕ
| ПутиКСканам.Объект = &Объект");
Запрос.УстановитьПараметр("Объект", Объект);
Выборка = Запрос.Выполнить().Выбрать();
Если (Выборка.Следующий()) Тогда
Если (прав(Выборка.Путь,1)="\") Тогда
возврат Выборка.Путь;
Иначе
возврат Выборка.Путь+"\";
КонецЕсли;
Иначе
возврат "";
КонецЕсли;
КонецФункции
Функция УстановитьПутьКСканам(Объект, Путь) Экспорт
МенеджерЗаписи = РегистрыСведений.ПутиКСканам.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = Объект;
МенеджерЗаписи.Путь = Путь;
МенеджерЗаписи.Записать();
КонецФункции
Видно, что для работы обработки необходимо добавление одного регистра, самой обработки и изменение формы. Но, во-первых, я нахожусь в РИБ, отстальные узлы мою разработку могут не оценить, во-вторых, это несколько затруднит обновление. Пробуем подойти к проблеме с другой стороны. Справочник ХранилищеДополнительнойИнформации имеет всё необходимое для счастья, нужно только немного изменить приведенные функции:
Функция ПолучитьПутьКСканам(Объект, ПолучитьСсылку = Ложь) Экспорт
//храним только путь к папке, поэтому тип - файл.
Запрос = Новый Запрос("ВЫБРАТЬ
| ХранилищеДополнительнойИнформации.ИмяФайла КАК Путь,
| ХранилищеДополнительнойИнформации.Ссылка
|ИЗ
| Справочник.ХранилищеДополнительнойИнформации КАК ХранилищеДополнительнойИнформации
|ГДЕ
| ХранилищеДополнительнойИнформации.Объект = &Объект
| И ХранилищеДополнительнойИнформации.ВидДанных = ЗНАЧЕНИЕ(Перечисление.ВидыДополнительнойИнформацииОбъектов.Файл)
| И ХранилищеДополнительнойИнформации.ПометкаУдаления = ЛОЖЬ
| И ХранилищеДополнительнойИнформации.Наименование = ""ПутьКСканам""");
Запрос.УстановитьПараметр("Объект", Объект);
Выборка = Запрос.Выполнить().Выбрать();
Если (Выборка.Следующий()) Тогда
Если (ПолучитьСсылку) Тогда
возврат Выборка.Ссылка;
КонецЕсли;
Если (прав(Выборка.Путь,1)="\") Тогда
возврат Выборка.Путь;
Иначе
возврат Выборка.Путь+"\";
КонецЕсли;
Иначе
возврат "";
КонецЕсли;
КонецФункции
Функция УстановитьПутьКСканам(Объект, Путь) Экспорт
Если (не ЗначениеЗаполнено(Путь)) Тогда
возврат 0;
КонецЕсли;
СпрСсылка = ПолучитьПутьКСканам(Объект, Истина);
Если (не ЗначениеЗаполнено(СпрСсылка)) Тогда
Спр = Справочники.ХранилищеДополнительнойИнформации.СоздатьЭлемент();
Спр.ВидДанных = Перечисления.ВидыДополнительнойИнформацииОбъектов.Файл;
Спр.Объект = Объект;
Спр.Наименование = "ПутьКСканам";
Иначе
Спр = СпрСсылка.ПолучитьОбъект();
КонецЕсли;
Спр.ИмяФайла = Путь;
Спр.Записать();
КонецФункции
Регистр нам больше не нужен, отсталось куда-то прицепить саму обработку. Я её переделал во внешнюю печатную форму для справочника Контрагенты, для чего пришлось внести еще немного изменений - изначально форма показывала сканы только одного договора, пришлось добавить выбор договоров текущего контрагента. Естественно, при такой реализации есть особенность (а для кого-то может и недостаток): договор необходимо записать отдельно, в другой форме, перед тем, как пользоваться обработкой.
Как выглядит результат, можно посмотреть на скриншоте №2.
Чуть не забыл: все пути хранятся относительно корневого каталога, который в свою очередь хранится так же, как эти пути, но не для договора, а для организации. Сделано так вовсе не для экономии места путем хранени более коротких строк, а для того, чтобы можно было легко изменить путь, если сканы переедут на другой сервер.
Прикладываю обработку, которая совершенно точно работает в УПП 1.3.51.4. Для работы в несовместимой конфигурации достатотчно изменить приведенные две функции (добавив регистр сведений, от которого я отказался, либо использовав регистр ЗначенияСвойствОбъектов - лично мне показалось, что строка в нем коротковата).