Объявляем собственные числовые границы МинЦена85/МаксЦена85 и полные выражения 50*2/100*7. Редактируем порядок, default и формулу, удаляем и восстанавливаем каталог, сверяем независимую копию. Запрос цены500 начинает использовать обе границы лишь после полного восстановления — без неизвестных имён на промежуточных этапах.
Где и как запускать
Полный серверный общий модуль УчебныеЗадачи новой пустой конфигурации УчебныйДиапазонЦен85; в1С не запускался.
Подготовка
НОВАЯ отдельная учебная база, не копия рабочей: точно8.5.1.1343, конфигурация УчебныйДиапазонЦен85, совместимость Не использовать. Нет бизнес-объектов, расширений, подписок и фоновых заданий; модули вручную пустые, кроме данного общего модуля.
Конфигуратор → Общие → Общие модули → УчебныеЗадачи: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Вставить весь основной модуль. Создать свою внешнюю обработку УчебныйДиапазонЦен85 → управляемая Форма: команда/кнопка Выполнить с действием Выполнить. Отдельный полный модуль формы дан ниже; реквизиты не нужны.
Будущая ручная подготовка вне опыта: завершить прежний свой сеанс, сохранить, Конфигурация → Обновить конфигурацию базы данных (F7), открыть свежий собственный клиент и свою обработку. Здесь F7, BSL, запросы и компоновка не запускались.
Код сам объявляет Local-источник СвоиЦены85 и набор Цены85 с буквальными A01/500, вручную заданными КодТовара Строка/Цена Число. Во время редактирования параметров запрос не содержит ссылок на параметры.
Цена и числовые defaults обеих границ имеют единый явный учебный тип: целые неотрицательные значения 0–999. Цена500, минимум100, максимум700 и временный максимум800 укладываются в три разряда. Квалификатор передаётся вторым аргументом ОписаниеТипов; это ограничение собственного конечного стенда, не правило цен рабочей базы.
Процедура ВыполнитьПример() Экспорт
ПроверитьСвойПустойСтенд();
Если ПривилегированныйРежим() Тогда
ВызватьИсключение "Привилегированный режим не нужен";
КонецЕсли;
Пусто = Новый Массив;
Имена = СтрРазделить("МинЦена85,МаксЦена85", ",");
Значения = Новый Массив;
Значения.Добавить(100);
Значения.Добавить(700);
Выражения = СтрРазделить("50 * 2|100 * 7", "|");
ОдинМинимум = Новый Массив;
ОдинМинимум.Добавить(100);
ОдинМаксимум = Новый Массив;
ОдинМаксимум.Добавить(700);
ОбратныеЗначения = Новый Массив;
ОбратныеЗначения.Добавить(700);
ОбратныеЗначения.Добавить(100);
Схема = СоздатьСвоюОсновуДиапазона();
Каталог = Схема.Параметры;
ПроверитьСвоиГраницы(Схема, Пусто, Пусто, Пусто, Ложь);
Минимум = Каталог.Добавить();
ЗаполнитьСвоюГраницу(Схема, Минимум, "МинЦена85", 100, "50 * 2");
ПроверитьСвоиГраницы(Схема, СтрРазделить("МинЦена85", ","), ОдинМинимум, СтрРазделить("50 * 2", "|"), Ложь);
Максимум = Каталог.Вставить(0);
ЗаполнитьСвоюГраницу(Схема, Максимум, "МаксЦена85", 700, "100 * 7");
ПроверитьСвоиГраницы(Схема, СтрРазделить("МаксЦена85,МинЦена85", ","), ОбратныеЗначения, СтрРазделить("100 * 7|50 * 2", "|"), Ложь);
Каталог.Сдвинуть(Максимум, 1);
ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, Ложь);
Максимум.Значение = 800;
Максимум.Выражение = "100 * 8";
ДругиеЗначения = Новый Массив;
ДругиеЗначения.Добавить(100);
ДругиеЗначения.Добавить(800);
ПроверитьСвоиГраницы(Схема, Имена, ДругиеЗначения, СтрРазделить("50 * 2|100 * 8", "|"), Ложь);
Максимум.Значение = 700;
Максимум.Выражение = "100 * 7";
ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, Ложь);
Копия = СоздатьСвоюОсновуДиапазона();
ВосстановитьСвоиГраницы(Копия);
Каталог.Удалить(Минимум);
ПроверитьСвоиГраницы(Схема, СтрРазделить("МаксЦена85", ","), ОдинМаксимум, СтрРазделить("100 * 7", "|"), Ложь);
ПроверитьСвоиГраницы(Копия, Имена, Значения, Выражения, Ложь);
НовыйМинимум = Каталог.Вставить(0);
ЗаполнитьСвоюГраницу(Схема, НовыйМинимум, "МинЦена85", 100, "50 * 2");
ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, Ложь);
Каталог.Очистить();
ПроверитьСвоиГраницы(Схема, Пусто, Пусто, Пусто, Ложь);
ПроверитьСвоиГраницы(Копия, Имена, Значения, Выражения, Ложь);
ВосстановитьСвоиГраницы(Схема);
ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, Ложь);
Набор = Схема.НаборыДанных.Найти("Цены85");
Если ТипЗнч(Набор) <> Тип("НаборДанныхЗапросСхемыКомпоновкиДанных") Тогда
ВызватьИсключение "Нужен собственный набор до привязки диапазона";
КонецЕсли;
Набор.Запрос = "ВЫБРАТЬ Данные.КодТовара КАК КодТовара, Данные.Цена КАК Цена ИЗ (ВЫБРАТЬ ""A01"" КАК КодТовара, 500 КАК Цена) КАК Данные ГДЕ Данные.Цена >= &МинЦена85 И Данные.Цена <= &МаксЦена85";
ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, Истина);
ПроверитьСвоиГраницы(Копия, Имена, Значения, Выражения, Ложь);
Сообщить("Числовые параметры 100/700 и их выражения восстановлены; запрос привязан только после этого");
КонецПроцедуры
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
Функция СвойЧисловойТипЦены()
Возврат Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(3, 0, ДопустимыйЗнак.Неотрицательный));
КонецФункции
Процедура ПроверитьСвоиКвалификаторыЦены(Описание)
Если ТипЗнч(Описание) <> Тип("ОписаниеТипов") Тогда
ВызватьИсключение "Нужно собственное числовое описание учебной цены или границы";
КонецЕсли;
Квалификаторы = Описание.КвалификаторыЧисла;
Если ТипЗнч(Квалификаторы) <> Тип("КвалификаторыЧисла") Или Квалификаторы.Разрядность <> 3
Или Квалификаторы.РазрядностьДробнойЧасти <> 0
Или Квалификаторы.ДопустимыйЗнак <> ДопустимыйЗнак.Неотрицательный Тогда
ВызватьИсключение "Учебная цена и её границы должны иметь целый неотрицательный тип от 0 до 999";
КонецЕсли;
КонецПроцедуры
Функция СоздатьСвоюОсновуДиапазона()
Схема = Новый СхемаКомпоновкиДанных;
Источник = Схема.ИсточникиДанных.Добавить();
Источник.Имя = "СвоиЦены85";
Источник.ТипИсточникаДанных = "Local";
Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
Если ТипЗнч(Набор) <> Тип("НаборДанныхЗапросСхемыКомпоновкиДанных") Тогда
ВызватьИсключение "Нужен собственный набор запроса";
КонецЕсли;
Набор.Имя = "Цены85";
Набор.ИсточникДанных = "СвоиЦены85";
Набор.АвтоЗаполнениеДоступныхПолей = Ложь;
Набор.Запрос = "ВЫБРАТЬ ""A01"" КАК КодТовара, 500 КАК Цена";
Имена = СтрРазделить("КодТовара,Цена", ",");
Типы = СтрРазделить("Строка,Число", ",");
Для Индекс = 0 По 1 Цикл
Поле = Набор.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
Если ТипЗнч(Поле) <> Тип("ПолеНабораДанныхСхемыКомпоновкиДанных") Тогда
ВызватьИсключение "Нужно собственное простое описание поля";
КонецЕсли;
Поле.Поле = Имена[Индекс];
Поле.ПутьКДанным = Имена[Индекс];
Если Типы[Индекс] = "Число" Тогда
Поле.ТипЗначения = СвойЧисловойТипЦены();
Иначе
Поле.ТипЗначения = Новый ОписаниеТипов("Строка");
КонецЕсли;
КонецЦикла;
ПроверитьСвоюОсновуДиапазона(Схема, Ложь);
Возврат Схема;
КонецФункции
Процедура ПроверитьСвоюОсновуДиапазона(Схема, ЗапросПривязан)
Если ТипЗнч(Схема) <> Тип("СхемаКомпоновкиДанных")
Или Схема.ИсточникиДанных.Количество() <> 1 Или Схема.НаборыДанных.Количество() <> 1 Тогда
ВызватьИсключение "Нужны прежние свои источник и набор";
КонецЕсли;
Источник = Схема.ИсточникиДанных.Получить(0);
Если ТипЗнч(Источник) <> Тип("ИсточникДанныхСхемыКомпоновкиДанных")
Или Источник.Имя <> "СвоиЦены85" Или Источник.ТипИсточникаДанных <> "Local" Тогда
ВызватьИсключение "Не совпал собственный источник";
КонецЕсли;
Набор = Схема.НаборыДанных.Получить(0);
Если ТипЗнч(Набор) <> Тип("НаборДанныхЗапросСхемыКомпоновкиДанных") Тогда
ВызватьИсключение "Нужен собственный набор запроса";
КонецЕсли;
ОжидаемыйЗапрос = "ВЫБРАТЬ ""A01"" КАК КодТовара, 500 КАК Цена";
Если ЗапросПривязан Тогда
ОжидаемыйЗапрос = "ВЫБРАТЬ Данные.КодТовара КАК КодТовара, Данные.Цена КАК Цена ИЗ (ВЫБРАТЬ ""A01"" КАК КодТовара, 500 КАК Цена) КАК Данные ГДЕ Данные.Цена >= &МинЦена85 И Данные.Цена <= &МаксЦена85";
КонецЕсли;
Если Набор.Имя <> "Цены85" Или Набор.ИсточникДанных <> "СвоиЦены85" Или Набор.АвтоЗаполнениеДоступныхПолей
Или Набор.Запрос <> ОжидаемыйЗапрос Или Набор.Поля.Количество() <> 2
Или Схема.НаборыДанных.Найти("Цены85") <> Набор Тогда
ВызватьИсключение "Не совпали весь запрос, поля, имя и поиск собственного набора";
КонецЕсли;
Имена = СтрРазделить("КодТовара,Цена", ",");
Типы = СтрРазделить("Строка,Число", ",");
Для Индекс = 0 По 1 Цикл
Поле = Набор.Поля.Получить(Индекс);
Если ТипЗнч(Поле) <> Тип("ПолеНабораДанныхСхемыКомпоновкиДанных")
Или Поле.Поле <> Имена[Индекс] Или Поле.ПутьКДанным <> Имена[Индекс]
Или ТипЗнч(Поле.ТипЗначения) <> Тип("ОписаниеТипов") Тогда
ВызватьИсключение "Не совпали полные собственные пути, порядок и типы полей";
КонецЕсли;
ПолныеТипы = Поле.ТипЗначения.Типы();
Если ПолныеТипы.Количество() <> 1 Или ПолныеТипы[0] <> Тип(Типы[Индекс]) Тогда
ВызватьИсключение "Не совпал полный набор типов собственного поля";
КонецЕсли;
Если Типы[Индекс] = "Число" Тогда
ПроверитьСвоиКвалификаторыЦены(Поле.ТипЗначения);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ЗаполнитьСвоюГраницу(Схема, Параметр, Имя, Значение, Выражение)
ПроверитьСвоюОсновуДиапазона(Схема, Ложь);
Если ТипЗнч(Параметр) <> Тип("ПараметрСхемыКомпоновкиДанных") Или Схема.Параметры.Индекс(Параметр) < 0 Тогда
ВызватьИсключение "Нужен текущий собственный параметр именно этой схемы";
КонецЕсли;
Если Имя <> "МинЦена85" И Имя <> "МаксЦена85" Тогда
ВызватьИсключение "В опыте объявляются только собственные границы цен";
КонецЕсли;
Если ТипЗнч(Значение) <> Тип("Число") Или ТипЗнч(Выражение) <> Тип("Строка") Тогда
ВызватьИсключение "Значение числовое, а полное выражение хранится строкой";
КонецЕсли;
Параметр.Имя = Имя;
Параметр.ТипЗначения = СвойЧисловойТипЦены();
Параметр.Значение = Значение;
Параметр.Выражение = Выражение;
Параметр.Использование = ИспользованиеПараметраКомпоновкиДанных.Авто;
КонецПроцедуры
Процедура ПроверитьСвоиГраницы(Схема, Имена, Значения, Выражения, ЗапросПривязан)
ПроверитьСвоюОсновуДиапазона(Схема, ЗапросПривязан);
Каталог = Схема.Параметры;
Если ТипЗнч(Каталог) <> Тип("ПараметрыСхемыКомпоновкиДанных")
Или Каталог.Количество() <> Имена.Количество() Или Значения.Количество() <> Имена.Количество()
Или Выражения.Количество() <> Имена.Количество() Тогда
ВызватьИсключение "Не совпал полный собственный состав границ";
КонецЕсли;
Для Индекс = 0 По Имена.Количество() - 1 Цикл
Параметр = Каталог.Получить(Индекс);
Если ТипЗнч(Параметр) <> Тип("ПараметрСхемыКомпоновкиДанных")
Или Параметр.Имя <> Имена[Индекс] Или ТипЗнч(Параметр.Значение) <> Тип("Число")
Или Параметр.Значение <> Значения[Индекс] Или ТипЗнч(Параметр.Выражение) <> Тип("Строка")
Или Параметр.Выражение <> Выражения[Индекс]
Или Параметр.Использование <> ИспользованиеПараметраКомпоновкиДанных.Авто
Или Каталог.Индекс(Параметр) <> Индекс Или Каталог[Индекс] <> Параметр
Или Каталог[Имена[Индекс]] <> Параметр Или Каталог.Найти(Имена[Индекс]) <> Параметр
Или ТипЗнч(Параметр.ТипЗначения) <> Тип("ОписаниеТипов") Тогда
ВызватьИсключение "Не совпали имена, числовые defaults, полные выражения, порядок и поиск границ";
КонецЕсли;
ПолныеТипы = Параметр.ТипЗначения.Типы();
Если ПолныеТипы.Количество() <> 1 Или ПолныеТипы[0] <> Тип("Число") Тогда
ВызватьИсключение "Границы имеют только собственный числовой тип";
КонецЕсли;
ПроверитьСвоиКвалификаторыЦены(Параметр.ТипЗначения);
КонецЦикла;
Если Каталог.Найти("НетТакойГраницы85") <> Неопределено Тогда
ВызватьИсключение "Отсутствующая собственная граница не должна находиться";
КонецЕсли;
Если ЗапросПривязан Тогда
Если Имена.Количество() <> 2 Или Имена[0] <> "МинЦена85" Или Имена[1] <> "МаксЦена85"
Или Значения[0] > Значения[1] Тогда
ВызватьИсключение "Привязанный запрос требует обеих восстановленных согласованных границ";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ВосстановитьСвоиГраницы(Схема)
Пусто = Новый Массив;
ПроверитьСвоиГраницы(Схема, Пусто, Пусто, Пусто, Ложь);
Минимум = Схема.Параметры.Добавить();
ЗаполнитьСвоюГраницу(Схема, Минимум, "МинЦена85", 100, "50 * 2");
Максимум = Схема.Параметры.Добавить();
ЗаполнитьСвоюГраницу(Схема, Максимум, "МаксЦена85", 700, "100 * 7");
КонецПроцедурыУчебныйДиапазонЦен85.Форма
Своя внешняя обработка УчебныйДиапазонЦен85 → управляемая Форма → Модуль
Полный отдельный модуль своей формы с серверным вызовом; здесь не запускался.
&НаКлиенте
Процедура Выполнить(Команда)
ВыполнитьНаСервере();
Сообщить("Числовые границы, полные выражения, порядок и безопасная привязка запроса проверены");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
УчебныеЗадачи.ВыполнитьПример();
КонецПроцедурыРазбор по шагам
Значение параметра — числовой default, а Выражение — строка, по которой вычисляется значение. СвойЧисловойТипЦены() задаёт Число с явными квалификаторами, а Использование.Авто задаётся отдельно. Собственные арифметические формулы 50 * 2 и 100 * 7 осмысленно соответствуют границам100/700, но движок здесь их не вычисляет.
Добавить минимум в конец; Вставить(0) добавить максимум перед ним. Полностью проверить обратный порядок, имена, defaults, выражения, типы и поиск. Сдвинуть(Максимум,1) принимает объект и относительное смещение, возвращая минимум/максимум.
Для максимума отдельно изменить default700→800 и полную формулу100 * 7→100 * 8; проверить оба значения и затем вернуть исходные. Сохранение default само по себе не доказывает правильность выражения.
Одиннадцать контрольных состояний оригинала сверяют всю собственную основу, полный текст запроса, все описания/типы полей, весь каталог параметров, имя/значение/выражение/enum, полный числовой тип, порядок, Индекс, обращение по индексу/имени и положительный/отрицательный Найти.
Заново построить независимую схему и обе её границы. Удалить минимум как объект, не индекс; старую ссылку не использовать. Вставить новый минимум, очистить собственный каталог при сохранённом запросе БЕЗ параметров, подтвердить0 и сохранённость копии, затем заново добавить обе границы.
Только после восстановления минимум100/максимум700 сменить запрос на настоящий внешний ВЫБРАТЬ ИЗ (своя буквальная строка) с ГДЕ Цена >= &МинЦена85 И Цена <= &МаксЦена85. Финальный контроль требует существующих двух согласованных границ. Копия остаётся с исходным запросом без привязки.
В УНФ настройка печатных форм действительно получает параметр через Найти, проверяет Неопределено, затем вызывает Удалить(ПараметрСхемы) и Сдвинуть(ПараметрСхемы,Смещение). Рабочая форма здесь не вызывается; используются только собственные определения.
ПроверитьСвоиКвалификаторыЦены сверяет Разрядность=3, РазрядностьДробнойЧасти=0 и ДопустимыйЗнак=Неотрицательный отдельно у поля Цена и у каждого числового параметра во всех прежних состояниях. КодТовара остаётся Строка. Исходные запросы, значения, выражения, безопасная поздняя привязка и независимая копия не меняются.
Как проверить результат
Будущий итог модели: каталог МинЦена85/МаксЦена85, тип каждого только Число, defaults100/700, полные строки50 * 2/100 * 7 и Авто. В оригинале запрос имеет обе параметрические границы; в копии тот же полный каталог и прежний непараметрический запрос.
По арифметике50*2=100,100*7=700, а число500 находится между этими значениями. Здесь выражения не исполнялись, запрос не запускался, строка результата и значения настроек не получены: literals/defaults не выдаются за вычисленный результат.
Будущий отрицательный контроль: после первоначального заполнения максимума изменить только Максимум.Выражение = "100 * 8", оставив default700 и эталон100 * 7. Полная проверка должна отказать при прежних размерах и именах. Вернуть код, сохранить/F7 вне опыта и открыть новый собственный сеанс; здесь контроль не выполнялся.
runtimeVerifiedScenarios=0. Только статическая сверка контрактов и итогового HTML. Нет исполнения 1С, рабочих данных, записи, сети, компоновщика или печати.
Ожидаемый результат
Содержательный опыт редактора двух вычисляемых числовых границ: полный жизненный цикл и привязка запроса без несуществующих параметров.
На что обратить внимание
Выражение хранит строку формулы, Значение — default. Их математическое соответствие объяснено, но фактическая оценка выражений и приоритет настроек компоновщика требуют отдельной runtime-проверки.
Вставить — абсолютный индекс, Сдвинуть — объект/относительное смещение, Удалить — объект. После удаления и очистки старые ссылки не используются; новые параметры создаются заново.
Во время неполного каталога запрос намеренно не ссылается на границы. Нельзя очистить объявления под запросом с &МинЦена85/&МаксЦена85 и назвать это готовой схемой. Финальная привязка выполняется только после полного восстановления.
Авто не обещает конкретное исполненное значение настройки. Пользовательские настройки, визуальный отчёт и реальная строка отбора этим примером не проверены.
ПараметрФункциональныхОпций — имя действительного параметра опции, отдельная задача с метаданными. Здесь оно не заполняется пустой или произвольной строкой ради покрытия.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.