Описание проблемы.
Довольно часто встречаются ситуации, когда при разработке функционала приложения некоторые элементы справочников, ПВХ, документы, становятся своего рода константами. Как правило такие элементы не заводятся в качестве предопределенных данных.
Например, такая ситуация:
Торговая конфигурация, элементом номенклатуры заведена «Упаковка», по мере необходимости добавляется в документы реализации. Далее правила меняются, ставится задача включать упаковку во ВСЕ документы реализации, сделать это программно. Нужно в коде программы инициализировать упаковку как, своего рода, константу. Как поступить?
- Добавить ссылку на упаковку в константы.
- Завести предопределенный элемент номенклатуры (еще одна упаковка).
- Искать по коду, наименованию, реквизиту.
Все это не то. Для случая (1) — а если таких будет много? Плодить константы? Для случая (2) — явное дублирование сущностей, некрасиво. Для случая (3) — ненадежно. Отрезать пользователям возможность редактирования кода/наименования/реквизитов нельзя.
Методика решения.
Завести отдельный от основного функционала конфигурации механизм для хранения информации имеющей для разработчика характер констант. Доступ к изменению этой информации ограничить явно. Всем читать, только разработчику писать/изменять.
Сопоставление в коде можно производить по коду/наименованию элемента соответствующего ПВХ.
Объекты и процедуры метода.
- Создаем ПВХ, в типизацию которого включаем все нужное из конкретной конфигурации. Код в этом ПВХ уникален и является «синонимом» как константы.
- Создаем регистр сведений который будет хранить конкретные значения (в том числе множественные) для элементов ПВХ. Делаем его периодическим.
- Определяем механизм проверок для изменения кода ПВХ и записей регистра на предмет некорректного изменения. Можно, конечно, этого и не делать, ведь полный доступ будет иметь только разработчик. Он, конечно, знает что делает, но все ошибаются.
- Достаточно только одной функции для получения данных в модули:
// Получение значений пользовательских констант
//
// Параметры:
// Параметры - Структура - запрос каких значений. Неопределено тогда все последние.
// Ключи:
// НаДату - ДатаВремя - на срез значения (до дня). Пустая, вообще нет или неопределено это последнее.
// Имена - Массив - строки с именами ПВХ значений. Вообще нет или неопределено тогда все.
//
// Возвращаемое значение:
// Структура - Ключ - ИмяКонстанты.
// - Значение - единичное или массив
//
// Пример вызова:
//
// Имена = Новый Массив;
// Имена.Добавить("ПользователиГлавногоОтчета");
// Имена.Добавить("Ответственный_РНК");
// Имена.Добавить("Доставка");
// // Выборочно последние
// Параметры = Новый Структура("Имена", Имена);
// // Выборочно на 30-05-2014
// Параметры = Новый Структура("Имена, НаДату", Имена, Дата('20140530'));
// // Все на 30-05-2014
// Параметры = Новый Структура("НаДату", Дата('20140530'));
// // Все последние
// Параметры = Неопределено; // тоесть можно не передавать
//
Функция БК_ПолучитьЗначенияКонстант(Параметры = Неопределено) Экспорт
Если Параметры = Неопределено Тогда
НаДату = Неопределено;
Имена = Неопределено;
ВыбратьВсе = Истина;
Иначе
Если Параметры.Свойство("НаДату") Тогда
Если ЗначениеЗаполнено(Параметры.НаДату) Тогда
НаДату = Параметры.НаДату;
Иначе
НаДату = Неопределено;
КонецЕсли;
Иначе
НаДату = Неопределено;
КонецЕсли;
Если НЕ Параметры.Свойство("Имена") Тогда
Имена = Неопределено;
ВыбратьВсе = Истина;
Иначе
Имена = Параметры.Имена;
ВыбратьВсе = Ложь;
КонецЕсли;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ХранимыеЗначенияКонстантСрезПоследних.ЗначимаяКонстанта.Код КАК Код,
| ХранимыеЗначенияКонстантСрезПоследних.Значение,
| ХранимыеЗначенияКонстантСрезПоследних.ЗначимаяКонстанта.ИспользоватьСписком КАК ИспользоватьСписком,
| ХранимыеЗначенияКонстантСрезПоследних.ЗначениеСписка
|ИЗ
| РегистрСведений.БК_ХранимыеЗначенияКонстант.СрезПоследних(
| &НаДату,
| ВЫБОР
| КОГДА &ВыбратьВсе
| ТОГДА ИСТИНА
| ИНАЧЕ ЗначимаяКонстанта.Код В (&Имена)
| КОНЕЦ) КАК ХранимыеЗначенияКонстантСрезПоследних";
Запрос.УстановитьПараметр("НаДату", НаДату);
Запрос.УстановитьПараметр("Имена", Имена);
Запрос.УстановитьПараметр("ВыбратьВсе", ВыбратьВсе);
СтруктураВозврата = Новый Структура;
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат СтруктураВозврата;
КонецЕсли;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.ИспользоватьСписком Тогда
ЗначениеВыборки = Выборка.ЗначениеСписка.Получить();
Иначе
ЗначениеВыборки = Выборка.Значение;
КонецЕсли;
СтруктураВозврата.Вставить(Выборка.Код, ЗначениеВыборки);
КонецЦикла;
// Если выбираем все следует проверить заполненость всех имен
// Не найденные заполняем пустым значением типа
Если НЕ ВыбратьВсе Тогда
Если Имена.Количество()>СтруктураВозврата.Количество() Тогда
Для Каждого ИмяКонстанты Из Имена Цикл
Если НЕ СтруктураВозврата.Свойство(ИмяКонстанты) Тогда
СсылкаКонстанта = ПланыВидовХарактеристик.БК_ЗначенияКонстант.НайтиПоКоду(ИмяКонстанты);
ТипКонстанты = СсылкаКонстанта.ТипЗначения;
Если СсылкаКонстанта.ИспользоватьСписком Тогда
ЗначениеКонстанты = Новый Массив;
Иначе
ЗначениеКонстанты = ПолучитьПустуюСсылкуТипа(ТипКонстанты);
КонецЕсли;
СтруктураВозврата.Вставить(ИмяКонстанты, ЗначениеКонстанты);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЕсли;
Возврат СтруктураВозврата;
КонецФункции // БК_ПолучитьЗначенияКонстант()
Описание примера.
В выгрузке ИБ содержится два примера работы с механизмом:
- Для отчета «ГлавныйОтчет» при открытии формы выводится список пользователей, которые имеют право на его использование. Это пример константы имеющей списочный тип (массив).
- Для документа «РасходнаяНакладная» при записи получаем и записываем значения ответственного, доставку и упаковку.
Механизм простой, поэтому более детального описания не привожу.
Сделал у себя похожее решение достаточно давно, хотел выложить на инфостарт, но всё лень…
Принципиальные отличия от данного:
1. 2 разных ПВХ для констант-элементов и констант-массивов. Т.к. работа с ними в коде принципиально разная и при смене «типа» константы в прикладном коде будут ошибки. (Оба вида периодические как и тут).
2. Значения констант-массивов хранятся в табличной части справочника. Плюсы: есть типизация ТЧ по элементу ПВХ «из коробки», есть контроль ссылочной целостности (хранилище значений — зло). Для простоты для констант-массивов регистр сведений не используется, в том же справочнике и ссылка на ПВХ, и период.
3. Элементы ПВХ создаются только предопределённые. Никаких поисков по коду/наименованию. Почему — разработка ведётся в тестовых базах, и иначе будет хаос и г0внокод.
4. Для миграции значений «констант» в рабочую базу, есть выгрузка значений в текстовый документ, далее этот текст вставляется в общий макет конфигурации, далее при запуске рабочей базы незаполненные значения заполняются из этого макета. Естественно, ссылочные значения должны совпадать по ссылкам в рабочей и тестовой базе (элементы ПВХ сопоставляются по имени предопределенного).
5. Так же как и тут, получения значения через функцию общего модуля.