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

Как правило, на ней выводят наименование внешней обработки, которое повторяет ее же название в самом справочнике. Это в лучшем случае. Почему бы не выводить сюда же историю версий?
Итак, поехали.
Создаем внешнюю обработку, заполняем Имя и Синоним, а текущую версию указываем в поле Комментарий.
В метаданные внешней обработки добавляем два макета: Описание и ИсторияИзменений.

В макете Описание (тип макета: ТекстовыйДокумент) размещаем краткое или подробное описание внешней обработки, её назначение, особенности использования и т.д. Кому как нравится.

В макете ИсторияИзменений (тип макета: ТабличныйДокумент) создаем таблицу, в которую будем добавлять информацию о вносимых нами изменениях.

В модуле объекта размещаем функции, для получения данных из этих макетов:
// Получает из макета Описание данные с описанием обработки.
//
// Возвращаемое значение:
// Строка - описание внешней обработки.
//
Функция ПолучитьОписаниеОбработки()
Возврат ПолучитьМакет("Описание").ПолучитьТекст();
КонецФункции
// Получает из макета ИсторияИзменений данные с историей версий обработки.
//
// Возвращаемое значение:
// Массив - массив структур, с записями о версиях внешней обработки:
// *Версия - Строка - версия обработки;
// *Дата - Строка - дата версии;
// *Автор - Строка - автор версии;
// *Описание - Строка - описание изменений;
//
Функция ПолучитьИсториюИзмененийОбработки()
ИсторияИзменений = Новый Массив;
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ПолучитьМакет("ИсторияИзменений").Область());
ДанныеИсторииИзменений = Построитель.Результат.Выгрузить();
Для каждого ЗаписьИсторииИзменений Из ДанныеИсторииИзменений Цикл
ДобавитьЗаписьИсторииИзменений(ИсторияИзменений,
ЗаписьИсторииИзменений.Версия,
ЗаписьИсторииИзменений.Дата,
ЗаписьИсторииИзменений.Автор,
ЗаписьИсторииИзменений.Описание);
КонецЦикла;
Возврат ИсторияИзменений;
КонецФункции
// Добавляет в массив структуру, содержащую информацию о версии.
//
// Параметры:
// ИсторияИзменений - Массив - массив, в который добавляется структура с информацией о версии;
// НомерВерсии - Строка - номер версии;
// ДатаВерсии - Строка - дата версии;
// АвторИзменений - Строка - автор версии;
// ОписаниеИзменений - Строка - описание внесенных изменений.
//
Процедура ДобавитьЗаписьИсторииИзменений(ИсторияИзменений, НомерВерсии, ДатаВерсии, АвторИзменений, ОписаниеИзменений)
Изменение = Новый Структура();
Изменение.Вставить("НомерВерсии", НомерВерсии);
Изменение.Вставить("ДатаВерсии", ДатаВерсии);
Изменение.Вставить("АвторИзменений", АвторИзменений);
Изменение.Вставить("ОписаниеИзменений", ОписаниеИзменений);
ИсторияИзменений.Добавить(Изменение);
КонецПроцедуры
В функции ПолучитьИсториюИзмененийОбработки, вместо того, чтобы обходить таблицу значений в цикле и формировать для каждой записи структуру, можно использовать процедуру из БСП:
ОбщегоНазначения.ТаблицаЗначенийВМассив(ДанныеИсторииИзменений, ИсторияИзменений);
Добавляем функцию, которая соберет полученные данные и преобразует их в строковое представление:
// Формирует описание и историю изменений внешней обработки.
// Используется для отображения информации на вкладке "Дополнительная информация" справочника ДополнительныеОтчетыИОбработки.
// и для вывода на странице формы обработки "О программе".
//
// Параметры:
// НеСокращать - Булево - сокращать длину описания обработки, либо выводить полностью
// *Истина - сокращать длину описания обработки;
// *Ложь - не сокращать длину описания обработки;
//
// Возвращаемое значение:
// Строка - описание обработки.
//
Функция СоздатьОписание(НеСокращать = Ложь) Экспорт
Если НеСокращать Тогда
МаксДлина = 100000;
Иначе
Информация = Метаданные.НайтиПоПолномуИмени("Справочник.ДополнительныеОтчетыИОбработки").Реквизиты.Найти("Информация");
МаксДлина = Информация.Тип.КвалификаторыСтроки.Длина;
КонецЕсли;
Описание = ПолучитьОписаниеОбработки();
ДополнительнаяИнформация = Новый Массив;
ДополнительнаяИнформация.Добавить("Описание:" + Символы.ПС);
ДополнительнаяИнформация.Добавить(Описание);
ДополнительнаяИнформация.Добавить("");
ДополнительнаяИнформация.Добавить("История изменений:");
ПределДлины = МаксДлина - СтрДлина(СтрСоединить(ДополнительнаяИнформация));
Для каждого ЗаписьИстории Из ПолучитьИсториюИзмененийОбработки() Цикл
Если ПределДлины <= 0 Тогда
Продолжить;
КонецЕсли;
ТекстЗаписи = СтрШаблон("версия %1 от %2 г. (%3): %4.",
ЗаписьИстории.НомерВерсии,
ЗаписьИстории.ДатаВерсии,
ЗаписьИстории.АвторИзменений,
ЗаписьИстории.ОписаниеИзменений);
ДлинаЗаписи = СтрДлина(ТекстЗаписи);
ПределДлины = ПределДлины - ДлинаЗаписи;
Если ПределДлины > ДлинаЗаписи Тогда
ДополнительнаяИнформация.Добавить(ТекстЗаписи);
КонецЕсли;
КонецЦикла;
Возврат СтрСоединить(ДополнительнаяИнформация, Символы.ПС);
КонецФункции
Так как полученное описание будет хранится в реквизите Информация справочника ДополнительныеОтчетыИОбработки, то его необходимо сократить до длины этого реквизита, чтобы описание не обрывалось на половине слова. Для этого получаем длину реквизита Информация из метаданных, а в функцию СоздатьОписание добавляем параметр НеСокращать, со значением по умолчанию Ложь. Таким образом сохраняем для себя возможность получения полного описания без обрезки его длины.
В функции СведенияОВнешнейОбработке вызываем наш код:
#Область Регистрация
Функция СведенияОВнешнейОбработке() Экспорт
ИнформацияОбОбработке = ИнформацияОбОбработке(); // Отображается на вкладке "Дополнительная информация".
ВерсияБСП = СтандартныеПодсистемыСервер.ВерсияБиблиотеки();
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке(ВерсияБСП);
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Наименование = ИнформацияОбОбработке.Наименование;
ПараметрыРегистрации.Версия = ИнформацияОбОбработке.Версия;
ПараметрыРегистрации.Информация = ИнформацияОбОбработке.Описание;
ПараметрыРегистрации.БезопасныйРежим = Ложь;
ДобавитьКоманду(ПараметрыРегистрации.Команды, "Выполнить процедуру модуля объекта",
"ВыполнитьПроцедуруМодуляОбъекта",
ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода());
ДобавитьКоманду(ПараметрыРегистрации.Команды, "Открыть форму обработки", "ОткрытьФормуОбработки",
ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы(),
Истина);
Возврат ПараметрыРегистрации;
КонецФункции
Процедура ДобавитьКоманду(ТаблицаКоманд, Представление, Идентификатор, Использование = "ОткрытиеФормы", ПоказыватьОповещение = Ложь, Модификатор = "ПечатьMXL")
НоваяКоманда = ТаблицаКоманд.Добавить();
НоваяКоманда.Представление = Представление;
НоваяКоманда.Идентификатор = Идентификатор;
НоваяКоманда.Использование = Использование;
НоваяКоманда.ПоказыватьОповещение = ПоказыватьОповещение;
НоваяКоманда.Модификатор = Модификатор;
КонецПроцедуры
#КонецОбласти
#Область ДополнительнаяИнформация
Функция ДанныеВнешнейОбработки()
МетаданныеОбъекта = ЭтотОбъект.Метаданные();
ДанныеОбработки = Новый Структура;
ДанныеОбработки.Вставить("Имя", МетаданныеОбъекта.Имя);
ДанныеОбработки.Вставить("Синоним", МетаданныеОбъекта.Синоним);
ДанныеОбработки.Вставить("Комментарий", МетаданныеОбъекта.Комментарий);
Возврат ДанныеОбработки;
КонецФункции
// Создает структуру с информацией об обработке
//
// Возвращаемое значение:
// Структура - структура с информацией об обработке, вида:
// *Наименование - Строка - наименование обработки;
// *Версия - Строка - верси обработки;
// *Описание - Строка - описание обработки.
//
Функция ИнформацияОбОбработке()
ПараметрыОбработки = ДанныеВнешнейОбработки();
Наименование = ?(ЗначениеЗаполнено(ПараметрыОбработки.Синоним), ПараметрыОбработки.Синоним, ПараметрыОбработки.Имя);
Версия = ПараметрыОбработки.Комментарий;
Информация = Новый Структура;
Информация.Вставить("Наименование", Наименование);
Информация.Вставить("Версия", Версия);
Информация.Вставить("Описание", СоздатьОписание());
Возврат Информация;
КонецФункции
#КонецОбласти
Устанавливаем внешнюю обработку в базу и получаем наглядное описание и историю версий:

Так как внешняя обработка не всегда устанавливается в базу, то выведем это же описание на форму обработки.
Добавляем страницу формы О Программе и строковый реквизит формы Описание.

В модуле формы вызываем заполнение этого реквизита из модуля объекта:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Заполнение страницы "О программе".
ЗаполнитьОписаниеНаСервере();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьОписаниеНаСервере()
МодульОбработки = РеквизитФормыВЗначение("Объект");
Описание = МодульОбработки.СоздатьОписание(Истина);
КонецПроцедуры
Здесь как раз и пригодится добавленный ранее в функцию СоздатьОписание параметр НеСокращать.
В итоге, получаем страницу О программе с описанием и историей изменений.

Перейдем к хранению настроек.
Выбор места для хранения будет зависеть от того, установлена обработка в справочник ДополнительныеОтчетыИОбработки или нет. Если установлена, то будем хранить настройки в реквизите ДополнительнаяОбработка.ХранилищеНастроек , если не установлена - то в ХранилищеОбщихНастроек текущего пользователя.
Добавляем процедуру в модуль объекта:
Процедура СохранитьНастройки() Экспорт
Настройки = ПодготовитьНастройкиДляСохранения();
// СОХРАНЕНИЕ НАСТРОЕК ОБРАБОТКИ.
ДополнительнаяОбработка = СсылкаНаДополнительнуюОбработку();
// Если обработка добавлена в справочник ДополнительныеОтчетыИОбработки, то загружаем настройки из справочника,
// если нет - то в ХранилищеОбщихНастроек конфигурации для текущего пользователя.
Если Не ДополнительнаяОбработка = Неопределено Тогда
ДополнительныеОтчетыИОбработки.СохранитьНастройки(ДополнительнаяОбработка, Настройки);
Иначе
КлючНастроек = КлючНастроекОбработки();
ОбщегоНазначения.ХранилищеОбщихНастроекСохранить(КлючНастроек, КлючНастроек, Настройки,, ПараметрыСеанса.ТекущийПользователь);
КонецЕсли;
КонецПроцедуры
// Возвращает ссылку на обработку в справочнике ДополнительныеОтчетыИОбработки по имени обработки.
//
// Возвращаемое значение:
// Неопределено, СправочникСсылка - ссылка на элемент справочника ДополнительныеОтчетыИОбработки.
//
Функция СсылкаНаДополнительнуюОбработку()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ДополнительныеОтчетыИОбработки.Ссылка КАК Ссылка
|ИЗ
| Справочник.ДополнительныеОтчетыИОбработки КАК ДополнительныеОтчетыИОбработки
|ГДЕ
| ДополнительныеОтчетыИОбработки.ИмяОбъекта = &ИмяОбъекта";
Запрос.УстановитьПараметр("ИмяОбъекта", ДанныеВнешнейОбработки().Имя);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.Ссылка;
КонецФункции
// Формирует ключ для сохранения настроек обработки в общем хранилище.
//
// Возвращаемое значение:
// Строка - ключ настроек для обработки.
//
Функция КлючНастроекОбработки()
Возврат СтрШаблон("ВнешняяОбработка.%1", ДанныеВнешнейОбработки().Имя);
КонецФункции
Функция ПодготовитьНастройкиДляСохранения()
// Добавить те реквизиты обработки, которые необходимо сохранять в настройках.
Настройки = Новый Соответствие;
Настройки.Вставить("Реквизит1", Реквизит1);
Возврат Настройки;
КонецФункции
Аналогичным образом загружаем ранее сохраненные настройки:
Функция ЗагрузитьНастройки() Экспорт
Перем Настройки;
// ВОССТАНОВЛЕНИЕ НАСТРОЕК ОБРАБОТКИ.
ДополнительнаяОбработка = СсылкаНаДополнительнуюОбработку();
// Если обработка добавлена в справочник ДополнительныеОтчетыИОбработки, то загружаем настройки из справочника,
// если нет - то загружаем из ХранилищеОбщихНастроек конфигурации для текущего пользователя.
Если Не ДополнительнаяОбработка = Неопределено Тогда
Настройки = ДополнительныеОтчетыИОбработки.ЗагрузитьНастройки(ДополнительнаяОбработка);
КонецЕсли;
Если ДополнительнаяОбработка = Неопределено Или Настройки = Неопределено Тогда
КлючНастроек = КлючНастроекОбработки();
Настройки = ОбщегоНазначения.ХранилищеОбщихНастроекЗагрузить(КлючНастроек, КлючНастроек,,, ПараметрыСеанса.ТекущийПользователь);
КонецЕсли;
Возврат ВосстановитьНастройкиПослеЗагрузки(Настройки);
КонецФункции
Функция ВосстановитьНастройкиПослеЗагрузки(Настройки)
Результат = Истина;
// Заполнить значения реквизитов обработки значениями, полученными из сохраненных в настройках.
Если ТипЗнч(Настройки) = Тип("Соответствие") Тогда
Реквизит1 = Настройки.Получить("Реквизит1");
// Проверка корректности восстановления настроек.
Если Не ЗначениеЗаполнено(Реквизит1) Тогда
Результат = Ложь;
КонецЕсли;
Иначе
Результат = Ложь;
КонецЕсли;
Возврат Результат;
КонецФункции
Работать будет везде, где есть БСП, но при необходимости можно допилить под любую конфигурацию без БСП.
На этом все. Осталось приучить себя не забывать заполнять макет ИсторияИзменений.
Проверено на следующих конфигурациях и релизах:
- 1С:Библиотека стандартных подсистем, редакция 3.1, релизы 3.1.11.323
- Бухгалтерия предприятия, редакция 3.0, релизы 3.0.181.10
- Зарплата и управление персоналом КОРП, редакция 3.1, релизы 3.1.35.48
- 1С:Управление холдингом 3.2 (русский и английский интерфейсы), релизы 3.2.10.42
- Управление нашей фирмой, редакция 3.0, релизы 3.0.12.185
- Управление торговлей, редакция 11, релизы 11.5.24.62
Вступайте в нашу телеграмм-группу Инфостарт