Константы 1С хранят одно значение на всю информационную базу: дату начала обмена, порог согласования заказа, флажок включения механизма. Ниже — код для платформы 8.3: чтение и запись значения константы, модуль менеджера значения, набор констант, запрос, права, кэширование и функциональные опции. Имена констант и документов в примерах условные — подставьте объекты своей конфигурации.
Глобальное свойство Константы — менеджер всех констант, через точку берётся менеджер конкретной. Метод Получить() читает значение из базы, Установить(Значение) записывает его. Свойство доступно на сервере, в толстом клиенте и во внешнем соединении, поэтому код размещают в серверном общем модуле.
// Общий модуль НастройкиУчетаСервер: флажок «Сервер», без «Вызов сервера».
// Имена констант в примерах условные — подставьте объекты своей конфигурации.
// Возвращает дату начала обмена; пустая константа — начало текущего года.
Функция ДатаНачалаОбмена() Экспорт
ДатаНачала = Константы.ДатаНачалаОбмена.Получить();
Если Не ЗначениеЗаполнено(ДатаНачала) Тогда
ДатаНачала = НачалоГода(ТекущаяДатаСеанса());
КонецЕсли;
Возврат ДатаНачала;
КонецФункции
// Записывает дату начала обмена, только если она изменилась.
Процедура УстановитьДатуНачалаОбмена(НоваяДата) Экспорт
Если Не ЗначениеЗаполнено(НоваяДата) Тогда
ВызватьИсключение "Не заполнена дата начала обмена.";
КонецЕсли;
ДатаДляЗаписи = НачалоДня(НоваяДата);
Если Константы.ДатаНачалаОбмена.Получить() <> ДатаДляЗаписи Тогда
Константы.ДатаНачалаОбмена.Установить(ДатаДляЗаписи);
КонецЕсли;
КонецПроцедуры
// Возвращает значение константы по имени, например из настроек загрузки.
Функция ЗначениеКонстанты(ИмяКонстанты) Экспорт
Если Метаданные.Константы.Найти(ИмяКонстанты) = Неопределено Тогда
ВызватьИсключение СтрШаблон("В конфигурации нет константы %1.", ИмяКонстанты);
КонецЕсли;
Возврат Константы[ИмяКонстанты].Получить();
КонецФункции
ЗначениеЗаполнено().Установить() значение сравнивают со старым: каждая запись — это обработчики модуля менеджера значения и регистрация изменений для обмена.Константы[ИмяКонстанты] обращается к константе по имени из строки, а проверка через Метаданные.Константы.Найти() даёт понятный текст ошибки.ЗначениеКонстанты() прочитает любую константу.В процедуре с директивой &НаКлиенте обращение к Константы не скомпилируется: «Переменная не определена (Константы)». Значение получают на сервере — при создании формы или отдельным вызовом.
// Модуль формы документа ЗаказКлиента. Реквизит формы ПорогСогласования (Число).
// Константа ПорогКрупногоЗаказа (Число) — условное имя.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ПорогСогласования = Константы.ПорогКрупногоЗаказа.Получить();
КонецПроцедуры
&НаКлиенте
Процедура СуммаДокументаПриИзменении(Элемент)
// Строка Константы.ПорогКрупногоЗаказа.Получить() здесь не скомпилируется:
// в клиентском контексте свойства Константы нет.
Если ПорогСогласования > 0 И Объект.СуммаДокумента >= ПорогСогласования Тогда
ПоказатьПредупреждение(, "Сумма заказа требует согласования руководителя.");
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьПорог(Команда)
ПорогСогласования = ПорогКрупногоЗаказа();
ПоказатьОповещениеПользователя("Порог согласования обновлён");
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПорогКрупногоЗаказа()
Возврат Константы.ПорогКрупногоЗаказа.Получить();
КонецФункции
Чтение в ПриСозданииНаСервере не требует отдельного вызова: значение приходит на клиент вместе с данными формы. Функция &НаСервереБезКонтекста нужна, если значение могли изменить, пока форма открыта, — она не передаёт на сервер данные формы. Если настройка нужна многим формам, читайте её через общий модуль с повторным использованием (пример ниже).
Обработчики ПередЗаписью и ПриЗаписи размещают в модуле менеджера значения — он открывается из контекстного меню константы в дереве конфигурации. Модуль срабатывает при записи и из кода, и из формы констант.
// Модуль менеджера значения константы ЛимитСкидкиПроцент (тип Число, условное имя).
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если Значение < 0 Или Значение > 50 Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Лимит скидки должен быть от 0 до 50 процентов.";
Сообщение.Сообщить();
Отказ = Истина;
Возврат;
КонецЕсли;
// В базе пока лежит старое значение: сохраним его для журнала.
ДополнительныеСвойства.Вставить("СтароеЗначение", Константы.ЛимитСкидкиПроцент.Получить());
КонецПроцедуры
Процедура ПриЗаписи(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
СтароеЗначение = ДополнительныеСвойства.СтароеЗначение;
Если СтароеЗначение <> Значение Тогда
ЗаписьЖурналаРегистрации("Настройки.ЛимитСкидки", УровеньЖурналаРегистрации.Информация,
Метаданные.Константы.ЛимитСкидкиПроцент, ,
СтрШаблон("Лимит скидки изменён: %1 -> %2", СтароеЗначение, Значение));
КонецЕсли;
КонецПроцедуры
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
Значение — то, что собираются записать. В ПередЗаписью база ещё хранит старое значение, его и возвращает Получить().Отказ = Истина отменяет запись: вызов Установить() или Записать() закончится исключением.ОбменДанными.Загрузка стоит первой, чтобы обмен и загрузка данных не упирались в бизнес-проверки.Метод СоздатьМенеджерЗначения() возвращает объект со свойствами Значение, ОбменДанными, ДополнительныеСвойства и методами Прочитать(), Записать() — он нужен, когда запись надо настроить. Константы.СоздатьНабор() читает и записывает несколько констант одним объектом.
// Общий модуль НастройкиУчетаСервер (продолжение). Имена констант условные.
// Записывает константу без бизнес-логики: для обработчиков обновления и загрузки.
Процедура ЗаписатьКонстантуБезПроверок(ИмяКонстанты, НовоеЗначение) Экспорт
МенеджерЗначения = Константы[ИмяКонстанты].СоздатьМенеджерЗначения();
МенеджерЗначения.Значение = НовоеЗначение;
МенеджерЗначения.ОбменДанными.Загрузка = Истина;
МенеджерЗначения.Записать();
КонецПроцедуры
// Записывает две настройки продаж через набор констант.
Процедура ЗаписатьНастройкиПродаж(Порог, Лимит) Экспорт
Набор = Константы.СоздатьНабор("ПорогКрупногоЗаказа,ЛимитСкидкиПроцент");
Набор.Прочитать();
Если Набор.ПорогКрупногоЗаказа = Порог И Набор.ЛимитСкидкиПроцент = Лимит Тогда
Возврат;
КонецЕсли;
Набор.ПорогКрупногоЗаказа = Порог;
Набор.ЛимитСкидкиПроцент = Лимит;
Попытка
Набор.Записать();
Исключение
ЗаписьЖурналаРегистрации("Настройки.ЗаписьНастроекПродаж", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
ОбменДанными.Загрузка = Истина не отключает обработчики: они вызываются, но в модуле из предыдущего примера сразу выходят по этому флагу.СоздатьНабор() перечислены только нужные константы; без параметра набор включит все константы конфигурации.Отказ, Записать() вызовет исключение — фиксируем его в журнале регистрации и пробрасываем выше.Форма констант — общая форма, которую конструктор создаёт с типом «Форма констант»: основной реквизит НаборКонстант имеет тип КонстантыНабор. Константы перетаскивают из реквизита на форму, команда «Записать» сохраняет набор. Форму назначают в свойстве конфигурации «Основная форма констант» или открывают командой из раздела администрирования.
В языке запросов каждая константа — таблица Константа.Имя с одним полем Значение. Простейший запрос — ВЫБРАТЬ Порог.Значение ИЗ Константа.ПорогКрупногоЗаказа КАК Порог, но чаще константу присоединяют к основной таблице левым соединением с условием ИСТИНА.
// Серверный общий модуль. Документ ЗаказКлиента и константа ПорогКрупногоЗаказа — условные имена.
Функция ЗаказыСПризнакомСогласования(НачалоПериода, КонецПериода) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказы.Ссылка КАК Заказ,
| Заказы.СуммаДокумента КАК СуммаЗаказа,
| ВЫБОР
| КОГДА ЕСТЬNULL(ПорогЗаказа.Значение, 0) > 0
| И Заказы.СуммаДокумента >= ПорогЗаказа.Значение
| ТОГДА ИСТИНА
| ИНАЧЕ ЛОЖЬ
| КОНЕЦ КАК ТребуетсяСогласование
|ИЗ
| Документ.ЗаказКлиента КАК Заказы
| ЛЕВОЕ СОЕДИНЕНИЕ Константа.ПорогКрупногоЗаказа КАК ПорогЗаказа
| ПО ИСТИНА
|ГДЕ
| Заказы.Проведен
| И Заказы.Дата МЕЖДУ &НачалоПериода И &КонецПериода
|
|УПОРЯДОЧИТЬ ПО
| СуммаЗаказа УБЫВ";
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(НачалоПериода));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
ИСТИНА добавляет значение константы к каждому заказу. Внутреннее соединение потеряло бы все заказы, если в таблице константы нет записи.ЕСТЬNULL(ПорогЗаказа.Значение, 0) > 0 защищает от незаданного порога: без этой проверки при нулевой константе согласования потребовал бы каждый заказ.Запрос.УстановитьПараметр("Порог", Константы.ПорогКрупногоЗаказа.Получить()). Таблица константы удобна там, где текст запроса живёт отдельно от кода, — в динамическом списке и схеме компоновки данных.| Право в роли | Что разрешает |
|---|---|
| Чтение | Получить(), Прочитать(), таблица константы в запросе |
| Изменение | Установить(), Записать() менеджера значения и набора |
| Просмотр | видеть значение в форме |
| Редактирование | менять значение в форме |
Права на новую константу автоматически получают только роли с флажком «Устанавливать права для новых объектов», обычно это «Полные права». Отсюда классика: у администратора код работает, у менеджера — «Нарушение прав доступа!». Ниже форма заказа из раздела про клиент, переделанная для пользователя без прав на константы.
// Модуль формы документа ЗаказКлиента. Реквизит формы ЛимитСкидки (Число)
// выведен рядом с полем скидки. Имена констант условные.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЕстьПраво = ПравоДоступа("Чтение", Метаданные.Константы.ЛимитСкидкиПроцент);
Элементы.ЛимитСкидки.Видимость = ЕстьПраво;
Если ЕстьПраво Тогда
ЛимитСкидки = Константы.ЛимитСкидкиПроцент.Получить();
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура СуммаДокументаПриИзменении(Элемент)
Если НужноСогласование(Объект.СуммаДокумента) Тогда
ПоказатьПредупреждение(, "Сумма заказа требует согласования руководителя.");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция НужноСогласование(СуммаЗаказа)
// Права на порог у пользователя нет, а видеть его не нужно:
// читаем в привилегированном режиме и возвращаем только ответ.
УстановитьПривилегированныйРежим(Истина);
Порог = Константы.ПорогКрупногоЗаказа.Получить();
УстановитьПривилегированныйРежим(Ложь);
Возврат Порог > 0 И СуммаЗаказа >= Порог;
КонецФункции
ПравоДоступа() проверяет право заранее: поле лимита скрывается вместо системной ошибки.Истина или Ложь, сам порог пользователь не видит.УстановитьПривилегированныйРежим() безопаснее: без проверки прав выполняется только нужный фрагмент.Настройку, которую читают при каждом изменении поля, кэшируют в общем модуле с повторным использованием возвращаемых значений. Флажки и режимы таких модулей разобраны в статье про общие модули 1С.
// Общий модуль НастройкиПродажПовтИсп. Флажки: «Сервер», «Вызов сервера».
// Повторное использование возвращаемых значений: «На время сеанса».
// Возвращает ФиксированнаяСтруктура с ключами ПорогКрупногоЗаказа и ЛимитСкидкиПроцент.
Функция НастройкиПродаж() Экспорт
УстановитьПривилегированныйРежим(Истина);
Набор = Константы.СоздатьНабор("ПорогКрупногоЗаказа,ЛимитСкидкиПроцент");
Набор.Прочитать();
УстановитьПривилегированныйРежим(Ложь);
Настройки = Новый Структура;
Настройки.Вставить("ПорогКрупногоЗаказа", Набор.ПорогКрупногоЗаказа);
Настройки.Вставить("ЛимитСкидкиПроцент", Набор.ЛимитСкидкиПроцент);
Возврат Новый ФиксированнаяСтруктура(Настройки);
КонецФункции
// Модуль формы заказа: первый вызов идёт на сервер, следующие берут значение из кэша.
&НаКлиенте
Процедура СкидкаПроцентПриИзменении(Элемент)
Лимит = НастройкиПродажПовтИсп.НастройкиПродаж().ЛимитСкидкиПроцент;
Если Объект.СкидкаПроцент > Лимит Тогда
Объект.СкидкаПроцент = Лимит;
ПоказатьПредупреждение(, СтрШаблон("Скидка уменьшена до лимита %1.", Лимит));
КонецЕсли;
КонецПроцедуры
Функцию модуля с флажком «Вызов сервера» платформа кэширует и на клиенте: повторный вызов из формы не обращается к серверу. Ловушки такого кэша:
ОбновитьПовторноИспользуемыеЗначения() чистит кэш только своего сеанса.Структура вызывающий код может поправить, и испорченное значение получат следующие вызовы. Возвращайте ФиксированнаяСтруктура.ТекущаяДатаСеанса() — каждый вызов создаст новую запись.Если настройка должна действовать у всех сразу, выберите режим «На время вызова» или читайте константу напрямую: одно чтение за серверный вызов стоит дёшево.
Функциональная опция включает и отключает реквизиты, команды и подсистемы. Её значение хранится в константе типа Булево, указанной в свойстве опции «Хранение». Когда константа равна Ложь, объекты из состава опции исчезают из интерфейса.
// Общая форма НастройкиПродаж. Реквизит формы ИспользоватьСогласование (Булево) выведен флажком.
// Константа ИспользоватьСогласованиеСкидок (Булево) хранит опцию СогласованиеСкидок. Имена условные.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ИспользоватьСогласование = Константы.ИспользоватьСогласованиеСкидок.Получить();
КонецПроцедуры
&НаКлиенте
Процедура ИспользоватьСогласованиеПриИзменении(Элемент)
ЗаписатьОпцию(ИспользоватьСогласование);
// Сбрасываем кэш текущего сеанса и перестраиваем командный интерфейс.
ОбновитьПовторноИспользуемыеЗначения();
ОбновитьИнтерфейс();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаписатьОпцию(Включить)
Если Константы.ИспользоватьСогласованиеСкидок.Получить() <> Включить Тогда
Константы.ИспользоватьСогласованиеСкидок.Установить(Включить);
КонецЕсли;
КонецПроцедуры
// Модуль объекта документа ЗаказКлиента: реквизит Согласовал обязателен,
// только когда опция включена.
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если ПолучитьФункциональнуюОпцию("СогласованиеСкидок") Тогда
ПроверяемыеРеквизиты.Добавить("Согласовал");
КонецЕсли;
КонецПроцедуры
ПолучитьФункциональнуюОпцию() читает опцию на сервере. Если у опции включено свойство «Привилегированный режим при получении», право на чтение константы пользователю не нужно.ОбновитьПовторноИспользуемыеЗначения() и ОбновитьИнтерфейс() — текущий пользователь сразу видит новый интерфейс. Остальные увидят его после перезапуска программы.&НаКлиенте или клиентском общем модуле. Перенесите чтение на сервер.Получить() или выполнении запроса. В ролях пользователя нет права «Чтение» на константу — типично для констант, добавленных доработкой. Добавьте право в роль или читайте значение в привилегированном режиме.ПередЗаписью нет проверки ОбменДанными.Загрузка, и бизнес-проверка отклоняет загружаемое значение.Получить() вызывается в цикле — это обращение к базе на каждой итерации. Прочитайте значение один раз до цикла.Напрямую нельзя: на тонком и веб-клиенте свойства Константы нет. Прочитайте значение в ПриСозданииНаСервере, вызовите функцию &НаСервереБезКонтекста или общий модуль с флажком «Вызов сервера».
В типовых конфигурациях — в разделе «Администрирование». Если нужной панели нет, включите в параметрах программы команду «Все функции» и откройте ветку «Константы».
Константа хранит одно значение без истории. Если значение зависит от организации, склада или даты, нужен регистр сведений. Пароли и токены в константе не храните — для них есть безопасное хранилище БСП.
Да, расширение может содержать собственные константы со своим модулем менеджера значения. Права на них задают в роли расширения, иначе пользователи получат «Нарушение прав доступа!».
Если настройку нужно встроить в типовую конфигурацию с правами, панелью администрирования и функциональной опцией, поручите это специалисту через услуги доработки 1С. Опишите задачу в форме размещения задания — исполнители предложат решение через расширение, без снятия конфигурации с поддержки.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.