Тип: ПараметрКомпоновкиДанных. Параметр, значение которого предоставляется. Данное свойство недоступно у объектов, содержащихся в коллекции пользовательских настроек компоновки данных.
Полное описание, параметры и ограничения
ЗначениеПараметраНастроекКомпоновкиДанных.Параметр (DataCompositionSettingsParameterValue.Parameter)
ЗначениеПараметраНастроекКомпоновкиДанных (DataCompositionSettingsParameterValue)
Параметр (Parameter)
Доступен, начиная с версии 8.2.
Использование:
Чтение и запись.
Описание:
Тип: ПараметрКомпоновкиДанных.
Параметр, значение которого предоставляется.
Данное свойство недоступно у объектов, содержащихся в коллекции пользовательских настроек компоновки данных.
Доступность:
Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.
Примечание:
Может быть изменен только в том случае, если владеющая им коллекция значений параметров не связана с доступными параметрами. В противном случае генерируется исключение.
Использование в версии:
Доступен, начиная с версии 8.2.
Методическая информация
Практические примеры
Январь и март: настоящий календарный пробел февраля и устойчивые цвета по date-ключам
Полный memory процесс: свой typed источник → настройки/доступные поля → compiled period addition → фактические native ячейки и диаграммы. Февраль — пробел источника, не сгенерированная продажа.
Где и как запускать
Полный серверный общий модуль УчебныеМесяцы85, вызываемый собственной управляемой формой в новой файловой ИБ .1343. Только WindowsThickManaged; ValueAppearance не исполняется в thin/web/external context.
Подготовка
Задача: две настоящие продажи в январе и марте. В феврале продаж нет. СКД должна показать календарный пробел, не добавляя нулевую запись в исходник, а одинаковые date-ключи диаграмм должны сохранить native цвета при перестановке серий.
Вручную создайте НОВУЮ пустую файловую ИБ платформы 8.5.1.1343 только по пути C:\1C85_OwnMonthGap\e9b935fa-64d8-4d5f-a190-01726ddc40ac\Base. Если путь/регистрация уже заняты, остановитесь. Здесь ИБ, каталог, роль, пользователь и модули фактически не создавались. UUID каталога — собственная метка стенда, не UUID ИБ.
Конфигуратор: новая конфигурация УчебныеМесяцыЦвета85, режим совместимости НеИспользовать, основной режим запуска УправляемоеПриложение. Запуск вручную только толстым клиентом с управляемым приложением. Никаких прикладных справочников, документов, регистров, отчётов, хранилищ, расширений и импортов из рабочих конфигураций.
Создайте одну свою роль УчебныйАдминистратор85: Администрирование и права запуска толстого управляемого клиента/просмотра своей формы. Создайте ровно одного собственного реального пользователя УчебныйАдминистратор85 с этой ролью, войдите им в один сеанс. GetUsers требует административного права. Код сверяет настоящий UUID пользователя с единственным элементом native массива; placeholder UUID не нужен.
Создайте один общий модуль УчебныеМесяцы85: Глобальный Нет; Сервер Да; Клиент управляемое приложение Нет; Клиент обычное приложение Нет; Внешнее соединение Нет; Вызов сервера Нет; Привилегированный Нет; повторное использование возвращаемых значений НеИспользовать. Вставьте целиком CODE. Его экспорт вызывается только серверной частью собственной формы.
Создайте управляемую общую форму МесяцыЦвета85 без основного реквизита. Реквизиты До85/После85 — ТабличныйДокумент; Прямая85/Переставленная85 — Диаграмма; Статус85 — Строка неограниченной длины; Остановка85 — Булево, начальное значение Ложь. Два поля табличного документа/два поля диаграммы связаны с одноимёнными реквизитами, readonly для пользователя. Статус многострочный readonly. Никаких других форм.
Одна команда формы Сформировать85: Действие → Сформировать85(Команда), одна кнопка с Команда=Сформировать85. Вставьте целиком FORM. В корне собственной конфигурации → Открыть модуль управляемого приложения вставьте целиком APPLICATION: native ПриНачалеРаботыСистемы() без аргументов открывает только эту общую форму. Событие вручную не вызывайте. После будущего ручного обновления своей ИБ запустите толстый управляемый клиент и нажмите настоящую кнопку один раз. Это авторская инструкция, реального открытия здесь нет.
Сам источник создаётся в памяти: три typed колонки UUID85/Период85/Сумма85, две строки 2026-01-01/1000 и 2026-03-01/2000 с одним новым UUID пакета. В исходнике НЕТ февральской строки. До/после каждого native вывода сверяется вся схема и каждая из 2×3 ячеек, итог 3000.
Схема создаёт objectdataset СвоиМесяцы85. Два schema date-параметра Начало85=2026-01-01, Конец85=2026-03-31 включаются в доступные поля. Add/смена Parameter делаются ТОЛЬКО в новых unbound Настройках до LoadSettings, не в связанной native коллекции.
ИсточникДоступныхНастроекКомпоновкиДанных(Схема) → Initialize → LoadSettings → actual Composer.Settings. ДоступныеПоляПолейГруппировок реально проверяют date Период85, ДоступныеПоляДополненияПериода — date-поля ПараметрыДанных.Начало85/Конец85. Нет самодельных available collections и зависимости от совпадения имени переменной.
Компилятор выдаёт реальный связанный макет; рекурсивный обход actual Тело/Группировка находит единственный Период85. Только его readonly ДополнениеПериода даёт внутренний тип. Начало/Конец читаются из actual compiled объектa; режим Месяц и exact dates должны совпасть. ГруппировкаРесурса False, ТипГруппировки Элементы, НаборДанныхИерархии пустой проверяются, а не бессмысленно присваиваются для покрытия.
ОформлениеЗначений НЕ имеет документированного конструктора. Маршрут: свой Новый native OutputProcessor → его typed ОформлениеЗначений. Native не гарантирует начальную пустоту: Type и GetAll.Count=0 обоих свежих собственных процессоров обязательны. После первой своей записи контрольный map должен остаться пустым; это проверка этих двух экземпляров, не универсальное доказательство глобального устройства. При Undefined/nonempty/shared эффекте — отказ, без чужого Clear и слепого отката.
Для января/марта задаются explicit RGB, февраль Set(date) получает настоящий свободный numeric индекс. Его номер не считается равным 0. Повторный Set без значения не меняет ключ. Full GetAll и typed Date/String GetAll проверяют весь whitelist: три date-ключа и свой строковый marker.
УстановитьВсе получает полный собственный payload, затем readback. Clear(Type(Date),True) удаляет только numeric февраль, сохраняет nonnumeric RGB января/марта и другой key-type. Это не clear всего объекта и не удаление исходных продаж. После проверки февраль явно серый.
Native output действительно формирует 2→3 месяца. Reader находит реальные заголовки, typed Date/числа либо явно форматированный ISO/text, исключает лишние итоги/дубликаты и суммирует actual суммы 3000. Пустой февральский ресурс отмечается Пробел=True и сохраняется отдельно; 0 используется только для суммы и диаграммы пробела, не как выдуманная запись источника.
Две собственные native диаграммы используют actual месячный результат: январь/февраль/март и март/январь/февраль. Native FillSeriesColors не возвращает ОформлениеЗначений. Проверяются все real Series.Value/Series.Color и Chart.GetValue; не пиксели, качество отрисовки, палитра ОС или сохранность произвольного промышленного отчёта.
При будущей ручной ошибке форма sticky fail-stop на client и server границах. Не обещается атомарность memory/UI присваиваний; автоматического retry/restore/clear нет. Закройте собственную форму и исследуйте причину. Здесь только авторство и статические проверки; actual 1С/compile/DB/UI/файлы/сеть/печать/экспорт/настройки/backup0.
Процедура ПроверитьСвойСтенд85() Экспорт
Если СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1C85_OwnMonthGap\e9b935fa-64d8-4d5f-a190-01726ddc40ac\Base"";" Тогда
ВызватьИсключение "Только собственная новая файловая учебная ИБ";
КонецЕсли;
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Тогда
ВызватьИсключение "Не совпали версия платформы или собственная конфигурация";
КонецЕсли;
Если Метаданные.ОбщиеМодули.Количество() <> 1 Или Метаданные.ОбщиеМодули.Найти("УчебныеМесяцы85") = Неопределено
Или Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("МесяцыЦвета85") = Неопределено
Или Метаданные.Роли.Количество() <> 1 Или Метаданные.Роли.Найти("УчебныйАдминистратор85") = Неопределено Тогда
ВызватьИсключение "Нужны ровно свои общий модуль, управляемая общая форма и роль";
КонецЕсли;
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0
Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0
Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0
Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0
Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0
Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0
Или Метаданные.Обработки.Количество() <> 0 Или Метаданные.Отчеты.Количество() <> 0
Или Метаданные.Константы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0
Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Или Метаданные.ХранилищаНастроек.Количество() <> 0
Или Метаданные.ОбщиеМакеты.Количество() <> 0 Или Метаданные.ПараметрыСеанса.Количество() <> 0 Тогда
ВызватьИсключение "Своя пустая прикладная схема без чужих данных и хранилищ";
КонецЕсли;
Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
ВызватьИсключение "Стенд только без расширений";
КонецЕсли;
Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
Если Текущий = Неопределено Или Пользователи.Количество() <> 1 Тогда
ВызватьИсключение "Нужен единственный собственный реальный пользователь ИБ";
КонецЕсли;
Если Текущий.Имя <> "УчебныйАдминистратор85"
Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "Не совпал реальный UUID собственного пользователя ИБ";
КонецЕсли;
КонецПроцедуры
Функция СоздатьИсточник85(UUIDПакета)
Источник = Новый ТаблицаЗначений;
Источник.Колонки.Добавить("UUID85", Новый ОписаниеТипов("УникальныйИдентификатор"));
Источник.Колонки.Добавить("Период85", Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));
Источник.Колонки.Добавить("Сумма85", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(9, 0, ДопустимыйЗнак.Неотрицательный)));
Для Номер = 0 По 1 Цикл
Запись = Источник.Добавить();
Запись.UUID85 = UUIDПакета;
Запись.Период85 = Дата(2026, ?(Номер = 0, 1, 3), 1);
Запись.Сумма85 = ?(Номер = 0, 1000, 2000);
КонецЦикла;
Возврат Источник;
КонецФункции
Процедура ПроверитьИсточник85(Источник, UUIDПакета)
Если ТипЗнч(Источник) <> Тип("ТаблицаЗначений") Или ТипЗнч(UUIDПакета) <> Тип("УникальныйИдентификатор")
Или Источник.Количество() <> 2 Или Источник.Колонки.Количество() <> 3 Тогда
ВызватьИсключение "Нужны ровно собственные две исходные строки и три типизированные колонки";
КонецЕсли;
Эталон = СоздатьИсточник85(UUIDПакета);
Для Индекс = 0 По 2 Цикл
Колонка = Источник.Колонки.Получить(Индекс);
ОжидаемаяКолонка = Эталон.Колонки.Получить(Индекс);
Если Колонка.Имя <> ОжидаемаяКолонка.Имя Или Колонка.ТипЗначения <> ОжидаемаяКолонка.ТипЗначения Тогда
ВызватьИсключение "Изменилась полная схема собственного источника";
КонецЕсли;
КонецЦикла;
Для Индекс = 0 По 1 Цикл
Запись = Источник.Получить(Индекс);
Если Запись.UUID85 <> UUIDПакета Или Запись.Период85 <> Дата(2026, ?(Индекс = 0, 1, 3), 1)
Или Запись.Сумма85 <> ?(Индекс = 0, 1000, 2000) Тогда
ВызватьИсключение "Изменились свои UUID, даты или суммы; февральскую запись не добавляем";
КонецЕсли;
КонецЦикла;
Если Источник.Итог("Сумма85") <> 3000 Тогда
ВызватьИсключение "Сумма двух настоящих исходных записей должна быть 3000";
КонецЕсли;
КонецПроцедуры
Функция СоздатьСхему85(Источник)
Схема = Новый СхемаКомпоновкиДанных;
Локальный = Схема.ИсточникиДанных.Добавить();
Локальный.Имя = "СвойИсточник85";
Локальный.ТипИсточникаДанных = "Local";
Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
Набор.Имя = "СвоиМесяцы85";
Набор.ИмяОбъекта = "СвоиМесяцы85";
Набор.ИсточникДанных = Локальный.Имя;
Для Каждого Колонка Из Источник.Колонки Цикл
Поле = Набор.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
Поле.Поле = Колонка.Имя;
Поле.ПутьКДанным = Колонка.Имя;
Поле.Заголовок = Колонка.Имя;
Поле.ТипЗначения = Колонка.ТипЗначения;
Если Колонка.Имя = "Период85" Тогда
Поле.Оформление.УстановитьЗначениеПараметра("Формат", "ДФ=yyyy-MM-dd");
ИначеЕсли Колонка.Имя = "Сумма85" Тогда
Поле.Оформление.УстановитьЗначениеПараметра("Формат", "ЧДЦ=0;ЧГ=0");
Итог = Схема.ПоляИтога.Добавить();
Итог.ПутьКДанным = Колонка.Имя;
Итог.Выражение = "Сумма(Сумма85)";
КонецЕсли;
КонецЦикла;
Для Номер = 0 По 1 Цикл
Параметр = Схема.Параметры.Добавить();
Параметр.Имя = ?(Номер = 0, "Начало85", "Конец85");
Параметр.ТипЗначения = Источник.Колонки.Найти("Период85").ТипЗначения;
Параметр.Значение = ?(Номер = 0, Дата(2026, 1, 1), Дата(2026, 3, 31));
Параметр.Использование = ИспользованиеПараметраКомпоновкиДанных.Всегда;
Параметр.ВключатьВДоступныеПоля = Истина;
КонецЦикла;
Возврат Схема;
КонецФункции
Функция ПодготовитьНастройки85(Схема, Дополнять)
Настройки = Новый НастройкиКомпоновкиДанных;
Если Настройки.ПараметрыДанных.ДоступныеПараметры <> Неопределено Тогда
ВызватьИсключение "Добавление параметров разрешено только в собственной новой несвязанной коллекции";
КонецЕсли;
Для Номер = 0 По 1 Цикл
ЗначениеПараметра = Настройки.ПараметрыДанных.Элементы.Добавить();
ЗначениеПараметра.Параметр = Новый ПараметрКомпоновкиДанных(?(Номер = 0, "Начало85", "Конец85"));
ЗначениеПараметра.Значение = ?(Номер = 0, Дата(2026, 1, 1), Дата(2026, 3, 31));
ЗначениеПараметра.Использование = Истина;
КонецЦикла;
Группа = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
Группа.Имя = "СвоиМесяцы85";
Группа.Использование = Истина;
Для Каждого Имя Из СтрРазделить("Период85,Сумма85", ",") Цикл
Выбор = Группа.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
Выбор.Поле = Новый ПолеКомпоновкиДанных(Имя);
Выбор.Использование = Истина;
КонецЦикла;
ПолеГруппы = Группа.ПоляГруппировки.Элементы.Добавить(Тип("ПолеГруппировкиКомпоновкиДанных"));
ПолеГруппы.Поле = Новый ПолеКомпоновкиДанных("Период85");
ПолеГруппы.ТипГруппировки = ТипГруппировкиКомпоновкиДанных.Элементы;
ПолеГруппы.Использование = Истина;
ПолеГруппы.ТипДополнения = ?(Дополнять, ТипДополненияПериодаКомпоновкиДанных.Месяц, ТипДополненияПериодаКомпоновкиДанных.БезДополнения);
ПолеГруппы.НачалоПериода = Новый ПолеКомпоновкиДанных("ПараметрыДанных.Начало85");
ПолеГруппы.КонецПериода = Новый ПолеКомпоновкиДанных("ПараметрыДанных.Конец85");
Настройки.ПараметрыВывода.УстановитьЗначениеПараметра("РасположениеОбщихИтогов", РасположениеИтоговКомпоновкиДанных.Нет);
Группа.ПараметрыВывода.УстановитьЗначениеПараметра("РасположениеИтогов", РасположениеИтоговКомпоновкиДанных.Нет);
Порядок = Группа.Порядок.Элементы.Добавить(Тип("ЭлементПорядкаКомпоновкиДанных"));
Порядок.Поле = Новый ПолеКомпоновкиДанных("Период85");
Порядок.ТипУпорядочивания = НаправлениеСортировкиКомпоновкиДанных.Возр;
Порядок.Использование = Истина;
Компоновщик = Новый КомпоновщикНастроекКомпоновкиДанных;
ДоступныйИсточник = Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема);
Компоновщик.Инициализировать(ДоступныйИсточник);
Компоновщик.ЗагрузитьНастройки(Настройки);
Связанные = Компоновщик.Настройки;
Если Связанные.Структура.Количество() <> 1 Тогда
ВызватьИсключение "Нужна одна реальная связанная месячная группировка";
КонецЕсли;
СвояГруппа = Связанные.Структура.Получить(0);
Если ТипЗнч(СвояГруппа) <> Тип("ГруппировкаКомпоновкиДанных") Или СвояГруппа.Имя <> "СвоиМесяцы85"
Или СвояГруппа.ПоляГруппировки.Элементы.Количество() <> 1 Тогда
ВызватьИсключение "Не совпал фактический владелец настроек своей группы";
КонецЕсли;
ПоляГруппы = СвояГруппа.ПоляГруппировки;
ДоступныеГруппы = ПоляГруппы.ДоступныеПоляПолейГруппировок;
ДоступныеГраницы = ПоляГруппы.ДоступныеПоляДополненияПериода;
Если ТипЗнч(ДоступныеГруппы) <> Тип("ДоступныеПоляКомпоновкиДанных")
Или ТипЗнч(ДоступныеГраницы) <> Тип("ДоступныеПоляКомпоновкиДанных") Тогда
ВызватьИсключение "Источник не связал реальные доступные поля месячной группы и границ";
КонецЕсли;
ДатаГруппы = ДоступныеГруппы.НайтиПоле(Новый ПолеКомпоновкиДанных("Период85"));
Если ТипЗнч(ДатаГруппы) <> Тип("ДоступноеПолеКомпоновкиДанных")
Или Не ДатаГруппы.ТипЗначения.СодержитТип(Тип("Дата")) Тогда
ВызватьИсключение "Своё поле группировки не является доступной датой";
КонецЕсли;
Для Номер = 0 По 1 Цикл
Имя = ?(Номер = 0, "Начало85", "Конец85");
Граница = ДоступныеГраницы.НайтиПоле(Новый ПолеКомпоновкиДанных("ПараметрыДанных." + Имя));
Если ТипЗнч(Граница) <> Тип("ДоступноеПолеКомпоновкиДанных")
Или Не Граница.ТипЗначения.СодержитТип(Тип("Дата")) Тогда
ВызватьИсключение "Не найдена своя доступная дата-параметр для дополнения периода";
КонецЕсли;
ЗначениеГраницы = Связанные.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(Имя));
Если ЗначениеГраницы = Неопределено Или Не ЗначениеГраницы.Использование
Или ЗначениеГраницы.Значение <> ?(Номер = 0, Дата(2026, 1, 1), Дата(2026, 3, 31)) Тогда
ВызватьИсключение "Не совпало реальное значение собственной границы";
КонецЕсли;
КонецЦикла;
РеальноеПоле = ПоляГруппы.Элементы.Получить(0);
Если Строка(РеальноеПоле.Поле) <> "Период85"
Или РеальноеПоле.ТипДополнения <> ?(Дополнять, ТипДополненияПериодаКомпоновкиДанных.Месяц, ТипДополненияПериодаКомпоновкиДанных.БезДополнения)
Или Строка(РеальноеПоле.НачалоПериода) <> "ПараметрыДанных.Начало85"
Или Строка(РеальноеПоле.КонецПериода) <> "ПараметрыДанных.Конец85" Тогда
ВызватьИсключение "Реальные настройки месячного дополнения не совпали";
КонецЕсли;
Возврат Связанные;
КонецФункции
Процедура НайтиСвоёПолеМакета85(Тело, Найденные)
Для Каждого Часть Из Тело Цикл
Если ТипЗнч(Часть) <> Тип("ГруппировкаМакетаКомпоновкиДанных") Тогда
ВызватьИсключение "В собственном простом макете неожиданная часть тела";
КонецЕсли;
Для Каждого ПолеМакета Из Часть.Группировка Цикл
Если ТипЗнч(ПолеМакета) <> Тип("ЭлементГруппировкиМакетаКомпоновкиДанных") Тогда
ВызватьИсключение "Реальная коллекция группировки вернула другой тип";
КонецЕсли;
Если ПолеМакета.ИмяПоля = "Период85" Тогда
Найденные.Добавить(ПолеМакета);
КонецЕсли;
КонецЦикла;
НайтиСвоёПолеМакета85(Часть.Тело, Найденные);
КонецЦикла;
КонецПроцедуры
Функция Скомпилировать85(Схема, Настройки, Дополнять)
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
Макет = КомпоновщикМакета.Выполнить(Схема, Настройки);
Найденные = Новый Массив;
НайтиСвоёПолеМакета85(Макет.Тело, Найденные);
Если Найденные.Количество() <> 1 Тогда
ВызватьИсключение "Нужен единственный фактически скомпилированный Период85, не предполагаемый индекс тела";
КонецЕсли;
ПолеМакета = Найденные[0];
Если ПолеМакета.ГруппировкаРесурса Или ПолеМакета.ТипГруппировки <> ТипГруппировкиКомпоновкиДанных.Элементы
Или ПолеМакета.НаборДанныхИерархии <> "" Тогда
ВызватьИсключение "Месяц должен группировать дату, а не ресурс или неизвестную иерархию";
КонецЕсли;
Дополнение = ПолеМакета.ДополнениеПериода;
Если ТипЗнч(Дополнение) <> Тип("ДополнениеПериодаМакетаКомпоновкиДанных") Тогда
ВызватьИсключение "Нужен реальный дочерний объект дополнения из собственного макета";
КонецЕсли;
Если Дополнение.ТипДополнения <> ?(Дополнять, ТипДополненияПериодаКомпоновкиДанных.Месяц, ТипДополненияПериодаКомпоновкиДанных.БезДополнения) Тогда
ВызватьИсключение "Компилятор не подтвердил выбранный режим дополнения";
КонецЕсли;
Если Дополнять Тогда
Если ТипЗнч(Дополнение.Начало) <> Тип("Дата") Или ТипЗнч(Дополнение.Конец) <> Тип("Дата")
Или Дополнение.Начало <> Дата(2026, 1, 1) Или Дополнение.Конец <> Дата(2026, 3, 31) Тогда
ВызватьИсключение "Компилятор не разрешил свои date-параметры в точные даты границ";
КонецЕсли;
КонецЕсли;
Возврат Макет;
КонецФункции
Функция ВывестиМесяцы85(Макет, Источник, Вывод)
Процессор = Новый ПроцессорКомпоновкиДанных;
Процессор.Инициализировать(Макет, Новый Структура("СвоиМесяцы85", Источник));
Документ = Новый ТабличныйДокумент;
Вывод.ОтображатьПроцентВывода = Ложь;
Вывод.УстановитьДокумент(Документ);
Результат = Вывод.Вывести(Процессор, Ложь);
Если ТипЗнч(Результат) <> Тип("ТабличныйДокумент") Тогда
ВызватьИсключение "Нужен настоящий табличный результат native процессора";
КонецЕсли;
Возврат Результат;
КонецФункции
Функция ПрочитатьМесяцы85(Документ, Дополнять)
Если ТипЗнч(Документ) <> Тип("ТабличныйДокумент") Или Документ.ВысотаТаблицы = 0
Или Документ.ВысотаТаблицы > 40 Или Документ.ШиринаТаблицы > 20 Тогда
ВызватьИсключение "Неожиданный настоящий native результат для двух собственных записей";
КонецЕсли;
КолонкаДаты = 0;
КолонкаСуммы = 0;
Заголовки = 0;
Для СтрокаДокумента = 1 По Документ.ВысотаТаблицы Цикл
ДатаВСтроке = 0;
СуммаВСтроке = 0;
Для КолонкаДокумента = 1 По Документ.ШиринаТаблицы Цикл
Текст = СокрЛП(Документ.Область(СтрокаДокумента, КолонкаДокумента).Текст);
Если Текст = "Период85" Тогда
ДатаВСтроке = КолонкаДокумента;
ИначеЕсли Текст = "Сумма85" Тогда
СуммаВСтроке = КолонкаДокумента;
КонецЕсли;
КонецЦикла;
Если ДатаВСтроке > 0 И СуммаВСтроке > 0 Тогда
Заголовки = Заголовки + 1;
КолонкаДаты = ДатаВСтроке;
КолонкаСуммы = СуммаВСтроке;
КонецЕсли;
КонецЦикла;
Если Заголовки <> 1 Или КолонкаДаты >= КолонкаСуммы Тогда
ВызватьИсключение "Нужны единственные фактические заголовки даты и суммы без угадывания координат";
КонецЕсли;
Месяцы = Новый Соответствие;
Всего = 0;
Для СтрокаДокумента = 1 По Документ.ВысотаТаблицы Цикл
Для КолонкаДокумента = 1 По Документ.ШиринаТаблицы Цикл
Если КолонкаДокумента = КолонкаДаты Или КолонкаДокумента = КолонкаСуммы Тогда
Продолжить;
КонецЕсли;
ДругаяЯчейка = Документ.Область(СтрокаДокумента, КолонкаДокумента);
ДругоеЧисло = Неопределено;
Если ДругаяЯчейка.СодержитЗначение Тогда
Если ТипЗнч(ДругаяЯчейка.Значение) = Тип("Число") Тогда
ДругоеЧисло = ДругаяЯчейка.Значение;
КонецЕсли;
ИначеЕсли СокрЛП(ДругаяЯчейка.Текст) <> "" Тогда
Попытка
ДругоеЧисло = Число(ДругаяЯчейка.Текст);
Исключение
ДругоеЧисло = Неопределено;
КонецПопытки;
КонецЕсли;
Если ДругоеЧисло <> Неопределено Тогда
ВызватьИсключение "Неожиданные numeric ячейки вне своих двух native колонок";
КонецЕсли;
КонецЦикла;
ЯчейкаДаты = Документ.Область(СтрокаДокумента, КолонкаДаты);
ЯчейкаСуммы = Документ.Область(СтрокаДокумента, КолонкаСуммы);
ТекстДаты = СокрЛП(ЯчейкаДаты.Текст);
Период = Неопределено;
Если ЯчейкаДаты.СодержитЗначение Тогда
Если ТипЗнч(ЯчейкаДаты.Значение) = Тип("Дата") Тогда
Период = ЯчейкаДаты.Значение;
КонецЕсли;
КонецЕсли;
Если Период = Неопределено Тогда
Для Месяц85 = 1 По 3 Цикл
Если ТекстДаты = Формат(Дата(2026, Месяц85, 1), "ДФ=yyyy-MM-dd") Тогда
Период = Дата(2026, Месяц85, 1);
КонецЕсли;
КонецЦикла;
КонецЕсли;
ТекстСуммы = СокрЛП(ЯчейкаСуммы.Текст);
Если Период = Неопределено Тогда
Если ТекстСуммы <> "" И ТекстСуммы <> "Сумма85" Тогда
ВызватьИсключение "Есть ресурс без собственного месяца: дополнительный итог или неожиданная строка";
КонецЕсли;
Продолжить;
КонецЕсли;
Если Период <> Дата(2026, 1, 1) И Период <> Дата(2026, 2, 1) И Период <> Дата(2026, 3, 1)
Или Месяцы.Получить(Период) <> Неопределено Тогда
ВызватьИсключение "Чужая дата или повторная строка месяца в native результате";
КонецЕсли;
ЗначениеРесурса = Неопределено;
Если ЯчейкаСуммы.СодержитЗначение Тогда
ЗначениеРесурса = ЯчейкаСуммы.Значение;
ИначеЕсли ТекстСуммы <> "" Тогда
Попытка
ЗначениеРесурса = Число(ТекстСуммы);
Исключение
ВызватьИсключение "Свой ресурс не является числом или пустым значением";
КонецПопытки;
КонецЕсли;
Пробел = Период = Дата(2026, 2, 1);
Если Пробел Тогда
Если Не Дополнять Или (ТипЗнч(ЗначениеРесурса) <> Тип("Неопределено")
И ТипЗнч(ЗначениеРесурса) <> Тип("Null") И ТипЗнч(ЗначениеРесурса) <> Тип("Число")) Тогда
ВызватьИсключение "Февральский gap допускает только actual Undefined/Null или числовой0, не Bool/String/Date";
КонецЕсли;
Если ТипЗнч(ЗначениеРесурса) = Тип("Число") И ЗначениеРесурса <> 0 Тогда
ВызватьИсключение "Февраль отсутствует в источнике и не может содержать собственную продажу";
КонецЕсли;
Сумма = 0;
Иначе
Если ТипЗнч(ЗначениеРесурса) <> Тип("Число")
Или ЗначениеРесурса <> ?(Период = Дата(2026, 1, 1), 1000, 2000) Тогда
ВызватьИсключение "Не совпали фактические суммы января или марта";
КонецЕсли;
Сумма = ЗначениеРесурса;
КонецЕсли;
Месяцы.Вставить(Период, Новый Структура("Сумма,Пробел,Ресурс,ТекстРесурса", Сумма, Пробел, ЗначениеРесурса, ТекстСуммы));
Всего = Всего + Сумма;
КонецЦикла;
Если Месяцы.Количество() <> ?(Дополнять, 3, 2) Или Всего <> 3000
Или Месяцы.Получить(Дата(2026, 1, 1)) = Неопределено Или Месяцы.Получить(Дата(2026, 3, 1)) = Неопределено Тогда
ВызватьИсключение "Полный фактический native вывод не подтвердил 2→3 месяца и сумму 3000";
КонецЕсли;
Возврат Месяцы;
КонецФункции
Процедура ПроверитьСвоёОформление85(Оформление, ЧисловойФевраль, ИндексФевраля, БезФевраля)
Все = Оформление.ПолучитьВсе();
Даты = Оформление.ПолучитьВсе(Тип("Дата"));
Строки = Оформление.ПолучитьВсе(Тип("Строка"));
Если Все.Количество() <> ?(БезФевраля, 3, 4) Или Даты.Количество() <> ?(БезФевраля, 2, 3) Или Строки.Количество() <> 1
Или Строки.Получить("Маркер85") <> "e9b935fa-64d8-4d5f-a190-01726ddc40ac"
Или Оформление.Получить(Дата(2026, 1, 1)) <> Новый Цвет(34, 112, 180)
Или Оформление.Получить(Дата(2026, 3, 1)) <> Новый Цвет(39, 146, 95) Тогда
ВызватьИсключение "Полный whitelist четырёх собственных ключей и typed GetAll не совпал";
КонецЕсли;
Февраль = Оформление.Получить(Дата(2026, 2, 1));
Если БезФевраля Тогда
Если Февраль <> Неопределено Тогда
ВызватьИсключение "После Clear(Date,True) числовой февраль должен отсутствовать";
КонецЕсли;
ИначеЕсли ЧисловойФевраль Тогда
Если ТипЗнч(Февраль) <> Тип("Число") Или Февраль <> ИндексФевраля Тогда
ВызватьИсключение "Не сохранён действительно выделенный numeric индекс; его номер не угадываем";
КонецЕсли;
ИначеЕсли Февраль <> Новый Цвет(150, 150, 150) Тогда
ВызватьИсключение "Не подтверждён явный серый цвет отсутствующего месяца";
КонецЕсли;
КонецПроцедуры
Функция ПодготовитьСвоёОформление85(Вывод)
Оформление = Вывод.ОформлениеЗначений;
КонтрольныйВывод = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
КонтрольноеОформление = КонтрольныйВывод.ОформлениеЗначений;
Если ТипЗнч(Оформление) <> Тип("ОформлениеЗначений") Или ТипЗнч(КонтрольноеОформление) <> Тип("ОформлениеЗначений") Тогда
ВызватьИсключение "Native getter не дал typed объект: не выдумываем Новый ОформлениеЗначений";
КонецЕсли;
Если Оформление.ПолучитьВсе().Количество() <> 0 Или КонтрольноеОформление.ПолучитьВсе().Количество() <> 0 Тогда
ВызватьИсключение "Начальное состояние native map не подтверждено пустым; чужие значения не очищаем";
КонецЕсли;
Оформление.Установить(Дата(2026, 1, 1), Новый Цвет(34, 112, 180));
Если КонтрольноеОформление.ПолучитьВсе().Количество() <> 0 Тогда
ВызватьИсключение "Не подтверждена независимость двух собственных getter maps; слепого Clear/rollback нет";
КонецЕсли;
Оформление.Установить(Дата(2026, 3, 1), Новый Цвет(39, 146, 95));
ИндексФевраля = Оформление.Установить(Дата(2026, 2, 1));
Если ТипЗнч(ИндексФевраля) <> Тип("Число") Или ИндексФевраля < 0
Или Оформление.Установить(Дата(2026, 2, 1)) <> ИндексФевраля Тогда
ВызватьИсключение "Один собственный ключ должен сохранить настоящий выделенный индекс";
КонецЕсли;
Оформление.Установить("Маркер85", "e9b935fa-64d8-4d5f-a190-01726ddc40ac");
ПроверитьСвоёОформление85(Оформление, Истина, ИндексФевраля, Ложь);
ПолныйПакет = Оформление.ПолучитьВсе();
Оформление.УстановитьВсе(ПолныйПакет);
ПроверитьСвоёОформление85(Оформление, Истина, ИндексФевраля, Ложь);
Оформление.Очистить(Тип("Дата"), Истина);
ПроверитьСвоёОформление85(Оформление, Ложь, ИндексФевраля, Истина);
Оформление.Установить(Дата(2026, 2, 1), Новый Цвет(150, 150, 150));
ПроверитьСвоёОформление85(Оформление, Ложь, ИндексФевраля, Ложь);
Если КонтрольноеОформление.ПолучитьВсе().Количество() <> 0 Тогда
ВызватьИсключение "Контрольный map изменился после собственного полного процесса";
КонецЕсли;
Возврат Оформление;
КонецФункции
Функция ПостроитьСвоюДиаграмму85(Месяцы, Оформление, ОбратныйПорядок)
Если Месяцы.Количество() <> 3 Или Не Месяцы.Получить(Дата(2026, 2, 1)).Пробел Тогда
ВызватьИсключение "Диаграмма принимает только проверенный настоящий месячный native результат";
КонецЕсли;
Диаграмма = Новый Диаграмма;
Диаграмма.ТипДиаграммы = ТипДиаграммы.Гистограмма;
Точка = Диаграмма.Точки.Добавить("Сумма85");
Для Номер = 1 По 3 Цикл
Месяц85 = ?(ОбратныйПорядок, ?(Номер = 1, 3, ?(Номер = 2, 1, 2)), Номер);
ДатаСерии = Дата(2026, Месяц85, 1);
РеальныйМесяц = Месяцы.Получить(ДатаСерии);
Серия = Диаграмма.Серии.Добавить(Формат(ДатаСерии, "ДФ=yyyy-MM-dd"));
Серия.Значение = ДатаСерии;
Диаграмма.УстановитьЗначение(Точка, Серия, РеальныйМесяц.Сумма);
КонецЦикла;
Диаграмма.ЗаполнитьЦветаСерий(Оформление);
ПроверитьСвоёОформление85(Оформление, Ложь, 0, Ложь);
Всего = 0;
Если Диаграмма.Серии.Количество() <> 3 Или Диаграмма.Точки.Количество() <> 1 Тогда
ВызватьИсключение "Не совпал полный объём собственной диаграммы";
КонецЕсли;
Для Номер = 0 По 2 Цикл
Серия = Диаграмма.Серии.Получить(Номер);
Месяц85 = ?(ОбратныйПорядок, ?(Номер = 0, 3, ?(Номер = 1, 1, 2)), Номер + 1);
ДатаСерии = Дата(2026, Месяц85, 1);
РеальноеЗначение = Диаграмма.ПолучитьЗначение(Точка, Серия).Значение;
Если Серия.Значение <> ДатаСерии Или Серия.Цвет <> Оформление.Получить(ДатаСерии)
Или ТипЗнч(РеальноеЗначение) <> Тип("Число") Или РеальноеЗначение <> Месяцы.Получить(ДатаСерии).Сумма Тогда
ВызватьИсключение "Фактический logical date key, native цвет или значение серии не совпали";
КонецЕсли;
Всего = Всего + РеальноеЗначение;
КонецЦикла;
Если Всего <> 3000 Тогда
ВызватьИсключение "Настоящие значения диаграммы не подтвердили native сумму 3000";
КонецЕсли;
Возврат Диаграмма;
КонецФункции
Функция ВыполнитьСвойУрок85() Экспорт
ПроверитьСвойСтенд85();
UUIDПакета = Новый УникальныйИдентификатор;
Источник = СоздатьИсточник85(UUIDПакета);
ПроверитьИсточник85(Источник, UUIDПакета);
Схема = СоздатьСхему85(Источник);
НастройкиДо = ПодготовитьНастройки85(Схема, Ложь);
МакетДо = Скомпилировать85(Схема, НастройкиДо, Ложь);
ВыводДо = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ДокументДо = ВывестиМесяцы85(МакетДо, Источник, ВыводДо);
ПрочитатьМесяцы85(ДокументДо, Ложь);
ПроверитьИсточник85(Источник, UUIDПакета);
НастройкиПосле = ПодготовитьНастройки85(Схема, Истина);
МакетПосле = Скомпилировать85(Схема, НастройкиПосле, Истина);
ВыводПосле = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
Оформление = ПодготовитьСвоёОформление85(ВыводПосле);
ВыводПосле.ОформлениеЗначений = Оформление;
Если ВыводПосле.ОформлениеЗначений <> Оформление Тогда
ВызватьИсключение "Свой native output property не вернул присвоенный actual typed map";
КонецЕсли;
ДокументПосле = ВывестиМесяцы85(МакетПосле, Источник, ВыводПосле);
Месяцы = ПрочитатьМесяцы85(ДокументПосле, Истина);
Прямая = ПостроитьСвоюДиаграмму85(Месяцы, Оформление, Ложь);
Переставленная = ПостроитьСвоюДиаграмму85(Месяцы, Оформление, Истина);
ПроверитьИсточник85(Источник, UUIDПакета);
ПроверитьСвоёОформление85(Оформление, Ложь, 0, Ложь);
Возврат Новый Структура("До,После,Прямая,Переставленная,Протокол", ДокументДо, ДокументПосле, Прямая, Переставленная,
"Native вывод: 2 → 3 месяца, сумма 3000. Февраль — пробел источника, не новая продажа. Цвета проверены по native сериям; source 2×3 сохранён.");
КонецФункцииПолный модуль своей управляемой общей формы
Общие → Общие формы → МесяцыЦвета85 → Модуль
Windows thick managed client and server context form; own module only.
&НаКлиенте
Процедура Сформировать85(Команда)
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если Остановка85 Или ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Сформировать85 Тогда
ВызватьИсключение "Форма остановлена после ошибки: закройте её, не повторяйте частичные действия";
КонецЕсли;
Попытка
СформироватьНаСервере85();
Исключение
Остановка85 = Истина;
Статус85 = "Отказ: результат не подтверждён. Нет автоматического повтора, очистки или отката.";
ВызватьИсключение;
КонецПопытки;
#Иначе
ВызватьИсключение "Урок только для собственного толстого клиента с управляемым приложением";
#КонецЕсли
КонецПроцедуры
&НаСервере
Процедура СформироватьНаСервере85()
Если Остановка85 Тогда
ВызватьИсключение "Серверная граница также запрещает повтор после частичного отказа";
КонецЕсли;
Попытка
Пакет = УчебныеМесяцы85.ВыполнитьСвойУрок85();
До85 = Пакет.До;
После85 = Пакет.После;
Прямая85 = Пакет.Прямая;
Переставленная85 = Пакет.Переставленная;
Статус85 = Пакет.Протокол;
Исключение
Остановка85 = Истина;
ВызватьИсключение;
КонецПопытки;
КонецПроцедурыПолный модуль своего управляемого приложения
Своя конфигурация → Модуль управляемого приложения
Windows thick managed client, real OnStart event0; own application only.
Процедура ПриНачалеРаботыСистемы()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
ОткрытьФорму("ОбщаяФорма.МесяцыЦвета85");
#Иначе
ВызватьИсключение "Свой учебный сценарий только в толстом управляемом клиенте";
#КонецЕсли
КонецПроцедурыРазбор по шагам
Подготовьте только свой новый exact FileCF/единственного actual пользователя/общий модуль/форму.
Создайте и целиком проверьте две typed строки с новым UUID пакета; сумму 3000 вычисляют исходные записи.
В новых unbound настройках добавьте два собственных date-параметра, затем свяжите настоящей схемой и проверьте доступные date fields/actual bound values.
БезДополнения → actual compiled макет/вывод/reader подтверждают январь1000 и март2000 без февраля.
Месяц → новый actual compiled объект дополнения с точными датами. Native getter map получает guarded own-empty состояние; исполните полный Set/GetAll/SetAll/Clear(Type,True) workflow.
Прочитайте настоящие месяцы native output: январь1000, февраль-пробел, март2000; не добавляйте февральскую строку в ТаблицаЗначений.
Постройте две диаграммы из actual reader результата, проверив date keys, native значения и цвета каждой переставленной серии; снова сверяйте полный source.
Как проверить результат
Ожидаемые будущие ручные проверки: source2×3 сохранён, native месяцы2→3, actual сумма3000, February.Пробел=True.
GetAll() содержит4 своих ключа, GetAll(Date)3 и GetAll(String)1. Clear(Date,True) оставляет2 date RGB и marker, Feb Get=None. Финально опять4 ключа с explicitGrey.
Дата серии определяет цвет, не её индекс: January RGB34/112/180, March39/146/95, February150/150/150 в обеих диаграммах.
Замените в только своём исходнике доступное поле/границу/тип/UUID/входную сумму/повторное UI действие: нужен явный отказ, не готовый подставленный результат.
Неопределённый/непустой native map или непредвиденный layout — отказ. Статический PASS не доказывает runtime пустоту, renderer layout или успешный запуск 1С.
Ожидаемый результат
Ожидаемый будущий ручной результат: две настоящие исходные продажи на3000, в native отчёте3 календарных месяца с февральским пробелом, стабильные проверенные native цвета date-серий. RuntimeVerified=False: actual1С/compile/DB/UI/network/backup0.
На что обратить внимание
Readonly available-field/layout-container ссылки не заменяются. Наличие RW дочерних свойств не даёт права присваивать Элемент.ДополнениеПериода.
НачалоПериода/КонецПериода в настройках допускают date, field или enum; compiled Начало/Конец допускают date/enum, но не Field. Здесь native compiler обязан разрешить свои date-параметры в actual dates, иначе fail-stop.
Собственные карты не загружаются/не сохраняются в системное хранилище; правило ≤100 keys одного типа и LRU при записи не проверяется этим четырёхключевым memory примером.
Нельзя писать Новый ОформлениеЗначений или считать FillSeriesColors фабрикой. GetAll даёт соответствие, не новый ValueAppearance; неизвестный native default не стираем.
Сервер и толстый клиент поддерживают ValueAppearance методы; внешнее соединение поддерживает output property, но не эти методы, поэтому внешний контекст здесь не разрешён.
Нормализация пустого февральского ресурса в0 служит диаграмме пробела. Она не доказывает реальную февральскую продажу, не меняет источник и не обещает универсальный способ трактовать Null в рабочих данных.
Проверен authored source/static только; реальные 1С, БД, UI, print/export, внешние настройки, файлы и сеть здесь не запускались.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Два собственных профиля границ: настоящий вариант, полный user-состав и effective 0..9↔2..3
Минимальный профиль собственного отчёта содержит только Минимум/Максимум с реальными ID и представлениями основных настроек, оба числа — явные qualifiers1,0 неотрицательные и 0<=Минимум<=Максимум<=9. После Save/Load всего базового Settings и полного структурного typed состава обоих user-профилей разрешаются реальные report-setters. Сохранённая база остаётся прежней, effective границы меняются. Числа и строки actual результата сверяются отдельно вручную. Здесь никаких внутренних записей и запуска1С не было.
Где и как запускать
Смешанный управляемый: толстый клиент 8.5.1.1343 Такси и сервер
Подготовка
Только будущий ручной опыт: создайте совершенно новую пустую учебную информационную базу. Здесь 1С и BSL не запускались; runtime-проверок 0. Не переносите урок в рабочую конфигурацию.
В конфигураторе имя собственной конфигурации задайте УчебныеВариантыПакетов85; основное приложение — управляемое, Режим совместимости — Не использовать. Запуск: толстый клиент в режиме управляемого приложения, установленная платформа ровно 8.5.1.1343, интерфейс Такси, обычный режим основного окна. Обычный режим основного окна не означает обычное приложение: приложение остаётся управляемым. Проверки версии/имени/интерфейса не доказывают, каким исполняемым клиентом был запущен сеанс: проверьте способ запуска вручную.
Создайте нового отдельного пользователя АвторВариантов85 только в этой новой базе. Не переименовывайте и не используйте рабочего пользователя. Сеанс всегда запускайте им: guard проверяет точное ИмяПользователя().
Создайте собственную роль ПакетыУчебные85: доступ только к своему отчёту УчебныеГраницыПакетов85, его собственной форме и своему общему пульту, просмотр/использование форм. В правах корня конфигурации включите ТолстыйКлиент (ThickClient), РежимОсновногоОкнаОбычный (MainWindowModeNormal) и СохранениеДанныхПользователя (SaveUserData). После обновления конфигурации базы данных назначьте эту роль новому пользователю АвторВариантов85. Не выдавайте учебному пользователю Администрирование, АдминистрированиеДанных или ОбновлениеКонфигурацииБазыДанных. Отчёт не требует чтения или записи предметных объектов; локальный запрос состоит только из трёх константных строк.
У конфигурации свойства ХранилищеВариантовОтчетов и ХранилищеПользовательскихНастроекОтчетов оставьте незаданными. Это необходимое соответствие стандартному внутреннему хранилищу, которое получает авторский код; при собственном прикладном хранилище отчётный setter мог бы читать другое место.
Метаданные → Отчёты: создайте собственный УчебныеГраницыПакетов85. ОсновнаяСхемаКомпоновкиДанных в метаданных не нужна: полный модуль строит собственную схему в памяти и присваивает реальному ОтчетОбъект.СхемаКомпоновкиДанных. Никаких таблиц базы и внешних наборов нет.
В УчебныеГраницыПакетов85 → Формы создайте управляемую форму отчёта ПрофилиГраниц85 типа Основная. Не обычную форму. Укажите её основной формой отчёта.
Основной реквизит формы Отчет — ОтчетОбъект.УчебныеГраницыПакетов85, флаг Основной. Реквизит Результат — ТабличныйДокумент. Элемент ПолеРезультата — поле табличного документа, ПутьКДанным = Результат. Имена собственные, не предполагаются имена автоматически созданных элементов.
Добавьте реквизиты формы СостояниеУрока (Строка неограниченная), МаршрутКомпоновки (Булево), СобытийДо и СобытийПосле (Число 9,0 неотрицательное). Счётчики относятся только к маршруту событий, не к строкам или числам отчёта. Добавьте поле состояния с ПутьКДанным = СостояниеУрока.
В событиях именно формы назначьте ПриСозданииНаСервере → ПриСозданииНаСервере, ПриКомпоновкеРезультата → ПриКомпоновкеРезультата, ПослеКомпоновкиРезультата → ПослеКомпоновкиРезультата. Не создавайте эти обработчики в модуле объекта отчёта; его одноимённые события имеют другой контракт.
Создайте собственные команды формы и кнопки с действиями: СоздатьСвоиПрофили → СоздатьСвоиПрофили; УзкиеГраницы → УзкиеГраницы; ВернутьВсе → ВернутьВсе. Все имена обработчиков приведены в основном полном модуле. Штатные произвольные кнопки сохранения/загрузки не используйте в этом опыте.
Точное место основного блока: модуль управляемой формы Отчет.УчебныеГраницыПакетов85.Форма.ПрофилиГраниц85. Замените только модуль своей новой формы целиком, не добавляйте неизвестные общие модули и helpers.
Вся схема задаётся основным блоком: источник ИсточникПакетов85 типа Local, набор запроса Пакеты85 с АвтоЗаполнениеДоступныхПолей = Истина; Пакет (Строка), Количество (Число) и Сумма (Число) образуются константным запросом ПакетА/3/60, ПакетБ/1/20, ПакетВ/6/120. Детальные записи без промежуточных или общего итога. Поля выбора Подробно85: Пакет,Количество,Сумма; Кратко85: Пакет,Сумма.
Не привязывайте пригодность схемы или числовую правильность результата к служебному флагу. ПослеКомпоновкиРезультата проверяет только actual тип параметра ТабличныйДокумент и маршрут штатной компоновки. Координаты вывода не предполагаются: полный состав реальных строк и значения читатель проверит в ПолеРезультата вручную.
Добавьте реквизит XMLБазы (Строка неограниченная); полный typed XML-снимок только своего базового Settings. Параметры задаёт авторский модуль: дополнительных form-параметров и пользовательского ручного числового ввода нет.
Метаданные → Общие формы: создайте управляемую ПультПрофилейГраниц85 без основного реквизита и предметных данных. Команды/кнопки ОткрытьСвойОтчет → ОткрытьСвойОтчет и ЗакрытьИУдалитьСозданное → ЗакрытьИУдалитьСозданное. Событие ПриСозданииНаСервере назначьте одноимённому обработчику. Точное место supporting-блока: модуль общей управляемой формы ПультПрофилейГраниц85; вставьте полный блок именно туда целиком.
Пульт держит только свой реальный экземпляр РабочаяФорма, полученный с новым УникальныйИдентификатор в четвёртом аргументе ПолучитьФорму. Не открывайте второй отчёт с теми же ключами, не перезапускайте пульт до cleanup и не изменяйте профили через другие формы.
Полный supporting-блок запуска вставьте в модуль управляемого приложения этой новой пустой конфигурации; ПриНачалеРаботыСистемы вызывает только ОбщаяФорма.ПультПрофилейГраниц85. Для разных уроков запускайте соответствующий полный блок, не три обработчика одинакового имени сразу.
В форме добавьте реквизиты Строка неограниченная: ПользовательОпытов, ОбластьКлючей, ПрефиксКлючей, КлючА, КлючБ, КлючБазы; Булево: СозданА, СозданБ, СозданБаза, ОчиститьА, ОчиститьБ, ОчиститьБазу, ХранилищеПодтверждено. Сгенерированный UUID становится частью строкового namespace только для нового опыта; до фактических Save, Load и полного сравнения это не существующий вариант или профиль.
Сохраняющий код выполняет внутренние записи настроек только при вашем будущем запуске в этой новой базе. Пять аргументов Save: объект, ключ, actual настройки, ОписаниеНастроек с представлением, captured current пользователь; четыре аргумента Load: объект, ключ, output описание, тот же пользователь. Неопределено после Load — отсутствие записи и отказ, не объект настроек.
После precheck отсутствия собственного ключа, до вызова Save фиксируется Очистить* — ownership точного pending ключа; исключение Save не доказывает отсутствие возможной частичной записи. После нормально завершённого Save отдельно фиксируется Создан*. Только после всех typed readback разрешается ХранилищеПодтверждено. Ошибки Save/readback перехватываются внутри серверной процедуры с исходной диагностикой и нормальным возвратом формы; client False не продолжает setter. Квитанция сохраняет все точные pending ключи для узкой cleanup даже при сбое.
Не закрывайте отчёт вручную. Полный supporting-блок пульта получает actual квитанцию у собственного экземпляра, закрывает его и требует Открыта() = Ложь до серверной очистки. Не изменяйте квитанцию и не передавайте в cleanup произвольную структуру; это узкий стенд одного собственного пользователя, не сервис удаления пользовательских ключей.
Очистка удаляет только свои отмеченные pending ключи, отсутствовавшие перед собственным Save, включая возможную частичную запись при его исключении. Ровно три непустые строки: свой объект, свой ключ, свой current пользователь. Namespace и принадлежность квитанции проверяются до Delete; readback должен стать Неопределено. При сбое выводятся точные свои ключи/отметки, квитанция остаётся и очистка не объявляется завершённой. Системное хранилище, текущие ключи формы, историю и все настройки пользователя код не очищает.
После всех подготовок метаданных, реквизитов, событий, команд, полных модулей формы/пульта/управляемого приложения и прав роли автор стенда в конфигураторе сохраняет конфигурацию и выполняет Конфигурация → Обновить конфигурацию базы данных (F7). Подтвердите обновление именно новой учебной базы. Это действие автора стенда, а не требование административных прав у учебного пользователя. После F7 проверьте назначение роли ПакетыУчебные85 пользователю АвторВариантов85 и только затем запускайте собственный управляемый сеанс этим пользователем.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Попытка
ПроверитьУчебнуюСреду();
Если ЭтаФорма.ТипФормыОтчета <> ТипФормыОтчета.Основная Тогда
ВызватьИсключение "Нужна собственная управляемая форма отчёта Основная";
КонецЕсли;
ЭтаФорма.РежимБлокировкиПриОткрытииОкна = РежимБлокировкиПриОткрытииОкнаФормы.НеБлокировать;
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
ОбъектОтчета.СхемаКомпоновкиДанных = СоздатьСобственнуюСхему();
ОбъектОтчета.КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(ОбъектОтчета.СхемаКомпоновкиДанных));
ОбъектОтчета.КомпоновщикНастроек.ЗагрузитьНастройки(ОбъектОтчета.СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
ЭтаФорма.ЗначениеВРеквизитФормы(ОбъектОтчета, "Отчет");
ЭтаФорма.СобытийДо = 0;
ЭтаФорма.СобытийПосле = 0;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Собственная схема готова; числа и внешний вид не проверены";
ЭтаФорма.ПользовательОпытов = ИмяПользователя();
ЭтаФорма.ОбластьКлючей = Строка(Новый УникальныйИдентификатор);
ЭтаФорма.ПрефиксКлючей = "УчебныеПакеты85_" + ЭтаФорма.ОбластьКлючей + "_";
ЭтаФорма.КлючА = ЭтаФорма.ПрефиксКлючей + "А";
ЭтаФорма.КлючБ = ЭтаФорма.ПрефиксКлючей + "Б";
ЭтаФорма.КлючБазы = "";
ЭтаФорма.СозданА = Ложь;
ЭтаФорма.СозданБ = Ложь;
ЭтаФорма.СозданБаза = Ложь;
ЭтаФорма.ОчиститьА = Ложь;
ЭтаФорма.ОчиститьБ = Ложь;
ЭтаФорма.ОчиститьБазу = Ложь;
ЭтаФорма.ХранилищеПодтверждено = Ложь;
ЭтаФорма.КлючБазы = ЭтаФорма.ПрефиксКлючей + "База";
ЭтаФорма.XMLБазы = ПолныйТипизированныйXML(ОбъектОтчета.СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
ПроверитьОсновныеГраницы(ОбъектОтчета.КомпоновщикНастроек.Настройки, 0, 9);
Исключение
Отказ = Истина;
ВызватьИсключение "Подготовка остановлена: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьУчебнуюСреду()
Если ИмяПользователя() <> "АвторВариантов85" Тогда
ВызватьИсключение "Нужен отдельный новый именованный пользователь АвторВариантов85";
КонецЕсли;
Если КлиентскоеПриложение.ТекущийВариантИнтерфейса() <> ВариантИнтерфейсаКлиентскогоПриложения.Такси Тогда
ВызватьИсключение "Нужен собственный толстый управляемый сеанс Такси";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СоздатьСобственнуюСхему()
Схема = Новый СхемаКомпоновкиДанных;
Источник = Схема.ИсточникиДанных.Добавить();
Источник.Имя = "ИсточникПакетов85";
Источник.ТипИсточникаДанных = "Local";
Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
Набор.Имя = "Пакеты85";
Набор.ИсточникДанных = Источник.Имя;
Набор.АвтоЗаполнениеДоступныхПолей = Истина;
Набор.Запрос = "ВЫБРАТЬ Пакеты.Пакет, Пакеты.Количество, Пакеты.Сумма
|ИЗ
| (ВЫБРАТЬ ""ПакетА"" КАК Пакет, 3 КАК Количество, 60 КАК Сумма
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ ""ПакетБ"", 1, 20
| ОБЪЕДИНИТЬ ВСЕ
| ВЫБРАТЬ ""ПакетВ"", 6, 120) КАК Пакеты
|ГДЕ Пакеты.Количество >= &Минимум И Пакеты.Количество <= &Максимум";
Для Каждого ИмяГраницы Из СтрРазделить("Минимум,Максимум", ",") Цикл
ПараметрСхемы = Схема.Параметры.Добавить();
ПараметрСхемы.Имя = ИмяГраницы;
ПараметрСхемы.Заголовок = "Учебная граница " + ИмяГраницы;
ПараметрСхемы.ТипЗначения = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(1, 0, ДопустимыйЗнак.Неотрицательный));
ПараметрСхемы.Значение = ?(ИмяГраницы = "Минимум", 0, 9);
ПараметрСхемы.Использование = ИспользованиеПараметраКомпоновкиДанных.Всегда;
КонецЦикла;
Схема.ВариантыНастроек.Очистить();
Подробный = Схема.ВариантыНастроек.Добавить();
Подробный.Имя = "Подробно85";
Подробный.Представление = "Все три поля пакетов";
ЗаполнитьНастройки(Подробный.Настройки, "Пакет,Количество,Сумма");
Краткий = Схема.ВариантыНастроек.Добавить();
Краткий.Имя = "Кратко85";
Краткий.Представление = "Пакет и сумма";
ЗаполнитьНастройки(Краткий.Настройки, "Пакет,Сумма");
Возврат Схема;
КонецФункции
&НаСервереБезКонтекста
Процедура ЗаполнитьНастройки(Настройки, ИменаПолей)
Для Каждого ИмяПоля Из СтрРазделить(ИменаПолей, ",") Цикл
Выбранное = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
Выбранное.Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);
Выбранное.Использование = Истина;
КонецЦикла;
Детали = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
Детали.Использование = Истина;
АвтоВыбор = Детали.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
АвтоВыбор.Использование = Истина;
Для Каждого ИмяГраницы Из СтрРазделить("Минимум,Максимум", ",") Цикл
Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(ИмяГраницы, ?(ИмяГраницы = "Минимум", 0, 9));
Граница = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(ИмяГраницы));
Если Граница = Неопределено Тогда
ВызватьИсключение "Не создан собственный параметр " + ИмяГраницы;
КонецЕсли;
Граница.Использование = Истина;
Граница.ИдентификаторПользовательскойНастройки = "ГраницаПакетов85_" + ИмяГраницы;
Граница.ПредставлениеПользовательскойНастройки = "Количество: " + ИмяГраницы;
Граница.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьПолныйВыбор(Настройки, ИменаПолей)
Если ТипЗнч(Настройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Нет типизированных настроек выбора";
КонецЕсли;
Ожидаемые = СтрРазделить(ИменаПолей, ",");
Если Настройки.Выбор.Элементы.Количество() <> Ожидаемые.Количество() Тогда
ВызватьИсключение "Изменился полный состав выбранных полей";
КонецЕсли;
Для Индекс = 0 По Ожидаемые.Количество() - 1 Цикл
ПолеВыбора = Настройки.Выбор.Элементы.Получить(Индекс);
Если ТипЗнч(ПолеВыбора) <> Тип("ВыбранноеПолеКомпоновкиДанных") Тогда
ВызватьИсключение "В выборе появился неподдерживаемый элемент";
КонецЕсли;
Если ПолеВыбора.Поле <> Новый ПолеКомпоновкиДанных(Ожидаемые[Индекс]) Или ТипЗнч(ПолеВыбора.Использование) <> Тип("Булево") Или Не ПолеВыбора.Использование Тогда
ВызватьИсключение "Не совпало поле или его использование";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолныйТипизированныйXML(Настройки)
Если ТипЗнч(Настройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Ожидался полный тип НастройкиКомпоновкиДанных";
КонецЕсли;
Писатель = Новый ЗаписьXML;
Писатель.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Писатель, Настройки, НазначениеТипаXML.Явное);
Текст = Писатель.Закрыть();
Если ТипЗнч(Текст) <> Тип("Строка") Или Текст = "" Тогда
ВызватьИсключение "Сериализация полного объекта не дала XML";
КонецЕсли;
Читатель = Новый ЧтениеXML;
Читатель.УстановитьСтроку(Текст);
Копия = СериализаторXDTO.ПрочитатьXML(Читатель, Тип("НастройкиКомпоновкиДанных"));
Читатель.Закрыть();
Если ТипЗнч(Копия) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Полный XML не восстановил тип настроек";
КонецЕсли;
Писатель = Новый ЗаписьXML;
Писатель.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Писатель, Копия, НазначениеТипаXML.Явное);
Если Писатель.Закрыть() <> Текст Тогда
ВызватьИсключение "Полный typed XML roundtrip нестабилен; ключ не допускается к setter";
КонецЕсли;
Возврат Текст;
КонецФункции
&НаСервереБезКонтекста
Процедура ПроверитьСобственныеГраницы(Минимум, Максимум)
Если ТипЗнч(Минимум) <> Тип("Число") Или ТипЗнч(Максимум) <> Тип("Число") Тогда
ВызватьИсключение "Обе границы должны оставаться числами";
КонецЕсли;
Если Минимум <> Цел(Минимум) Или Максимум <> Цел(Максимум) Или Минимум < 0 Или Минимум > Максимум Или Максимум > 9 Тогда
ВызватьИсключение "Границы собственного опыта: целые 0 <= Минимум <= Максимум <= 9";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьПолныйСобственныйПрофиль(Профиль, Минимум, Максимум)
ПроверитьСобственныеГраницы(Минимум, Максимум);
Если ТипЗнч(Профиль) <> Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Не получен тип ПользовательскиеНастройкиКомпоновкиДанных";
КонецЕсли;
Если Профиль.Элементы.Количество() <> 2 Или ТипЗнч(Профиль.ДополнительныеСвойства) <> Тип("Структура") Или Профиль.ДополнительныеСвойства.Количество() <> 0 Тогда
ВызватьИсключение "Профиль не минимальный: требуется ровно два элемента и пустые дополнительные свойства";
КонецЕсли;
Дополнительные = Профиль.ДополнительныеНастройки;
Если ТипЗнч(Дополнительные) <> Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "ДополнительныеНастройки не имеют документированного типа";
КонецЕсли;
Если Дополнительные.Элементы.Количество() <> 0 Или ТипЗнч(Дополнительные.ДополнительныеСвойства) <> Тип("Структура") Или Дополнительные.ДополнительныеСвойства.Количество() <> 0 Тогда
ВызватьИсключение "В минимальном собственном профиле появились дополнительные настройки";
КонецЕсли;
Для Каждого ИмяГраницы Из СтрРазделить("Минимум,Максимум", ",") Цикл
Идентификатор = "ГраницаПакетов85_" + ИмяГраницы;
Элемент = Профиль.Элементы.Найти(Идентификатор);
Если ТипЗнч(Элемент) <> Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
ВызватьИсключение "Нет единственного собственного элемента " + Идентификатор;
КонецЕсли;
Если ТипЗнч(Элемент.ИдентификаторПользовательскойНастройки) <> Тип("Строка") Или Элемент.ИдентификаторПользовательскойНастройки <> Идентификатор Тогда
ВызватьИсключение "Изменился собственный ID элемента";
КонецЕсли;
Если ТипЗнч(Элемент.Значение) <> Тип("Число") Или Элемент.Значение <> ?(ИмяГраницы = "Минимум", Минимум, Максимум) Или ТипЗнч(Элемент.Использование) <> Тип("Булево") Или Не Элемент.Использование Тогда
ВызватьИсключение "Не совпали полный тип, значение или использование элемента";
КонецЕсли;
Если ТипЗнч(Элемент.РежимОтображения) <> Тип("РежимОтображенияЭлементаНастройкиКомпоновкиДанных") Или Элемент.РежимОтображения <> РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Авто Тогда
ВызватьИсключение "Не совпал полный typed режим user-профиля: нужен Авто, а не обещание интерфейса";
КонецЕсли;
КонецЦикла;
Для Каждого Элемент Из Профиль.Элементы Цикл
Если ТипЗнч(Элемент) <> Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
ВызватьИсключение "Профиль содержит неожиданный тип элемента";
КонецЕсли;
Если Элемент.ИдентификаторПользовательскойНастройки <> "ГраницаПакетов85_Минимум" И Элемент.ИдентификаторПользовательскойНастройки <> "ГраницаПакетов85_Максимум" Тогда
ВызватьИсключение "Профиль содержит чужой ID";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьОсновныеГраницы(Настройки, Минимум, Максимум, ПроверятьОсновнойРежим = Истина)
ПроверитьСобственныеГраницы(Минимум, Максимум);
Для Каждого ИмяГраницы Из СтрРазделить("Минимум,Максимум", ",") Цикл
Граница = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(ИмяГраницы));
Если ТипЗнч(Граница) <> Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
ВызватьИсключение "Не найден основной параметр " + ИмяГраницы;
КонецЕсли;
Если Граница.Параметр <> Новый ПараметрКомпоновкиДанных(ИмяГраницы) Или Граница.ИдентификаторПользовательскойНастройки <> "ГраницаПакетов85_" + ИмяГраницы Или Граница.ПредставлениеПользовательскойНастройки <> "Количество: " + ИмяГраницы Тогда
ВызватьИсключение "Не совпали основное имя, ID или представление границы";
КонецЕсли;
Если ТипЗнч(Граница.Значение) <> Тип("Число") Или Граница.Значение <> ?(ИмяГраницы = "Минимум", Минимум, Максимум) Или ТипЗнч(Граница.Использование) <> Тип("Булево") Или Не Граница.Использование Тогда
ВызватьИсключение "Не совпали effective числовая граница или её использование";
КонецЕсли;
Если ПроверятьОсновнойРежим Тогда
Если ТипЗнч(Граница.РежимОтображения) <> Тип("РежимОтображенияЭлементаНастройкиКомпоновкиДанных") Или Граница.РежимОтображения <> РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный Тогда
ВызватьИсключение "Основной режим должен оставаться собственным Обычный; user Авто получает его из основной настройки, UI ещё не проверен";
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СоздатьСобственныйПрофиль(Компоновщик, ОсновныеНастройки, Минимум, Максимум)
Компоновщик.ЗагрузитьНастройки(ОсновныеНастройки);
Профиль = Компоновщик.ПользовательскиеНастройки;
Для Каждого Элемент Из Профиль.Элементы Цикл
Если ТипЗнч(Элемент) <> Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
ВызватьИсключение "В user-копии неожиданный тип: нормализовать чужой граф запрещено";
КонецЕсли;
Элемент.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Авто;
КонецЦикла;
ПроверитьПолныйСобственныйПрофиль(Профиль, 0, 9);
Профиль.Элементы.Найти("ГраницаПакетов85_Минимум").Значение = Минимум;
Профиль.Элементы.Найти("ГраницаПакетов85_Максимум").Значение = Максимум;
ПроверитьПолныйСобственныйПрофиль(Профиль, Минимум, Максимум);
Возврат Профиль;
КонецФункции
&НаСервере
Процедура ПроверитьСвоиКлючи()
ПроверитьУчебнуюСреду();
Если ЭтаФорма.ПользовательОпытов <> ИмяПользователя() Или ЭтаФорма.ПользовательОпытов = "" Тогда
ВызватьИсключение "Изменился собственный именованный пользователь";
КонецЕсли;
Если ЭтаФорма.ОбластьКлючей = "" Или ЭтаФорма.ПрефиксКлючей <> "УчебныеПакеты85_" + ЭтаФорма.ОбластьКлючей + "_" Тогда
ВызватьИсключение "Повреждён собственный namespace ключей";
КонецЕсли;
Для Каждого Ключ Из СтрРазделить(ЭтаФорма.КлючА + "," + ЭтаФорма.КлючБ + "," + ЭтаФорма.КлючБазы, ",") Цикл
Если Ключ <> "" И Лев(Ключ, СтрДлина(ЭтаФорма.ПрефиксКлючей)) <> ЭтаФорма.ПрефиксКлючей Тогда
ВызватьИсключение "Обнаружен ключ вне созданного namespace";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция ПолучитьКвитанциюОчистки() Экспорт
ПроверитьСвоиКлючи();
Возврат Новый Структура("Объект,Область,Префикс,Пользователь,КлючА,КлючБ,КлючБазы,СозданА,СозданБ,СозданБаза,ОчиститьА,ОчиститьБ,ОчиститьБазу", "Отчет.УчебныеГраницыПакетов85", ЭтаФорма.ОбластьКлючей, ЭтаФорма.ПрефиксКлючей, ЭтаФорма.ПользовательОпытов, ЭтаФорма.КлючА, ЭтаФорма.КлючБ, ЭтаФорма.КлючБазы, ЭтаФорма.СозданА, ЭтаФорма.СозданБ, ЭтаФорма.СозданБаза, ЭтаФорма.ОчиститьА, ЭтаФорма.ОчиститьБ, ЭтаФорма.ОчиститьБазу);
КонецФункции
&НаСервере
Процедура ПриКомпоновкеРезультата(СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СобытийДо = ЭтаФорма.СобытийДо + 1;
КонецПроцедуры
&НаСервере
Процедура ПослеКомпоновкиРезультата(Результат, СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.СобытийПосле = ЭтаФорма.СобытийПосле + 1;
Если ТипЗнч(Результат) <> Тип("ТабличныйДокумент") Тогда
ВызватьИсключение "Событие формы не передало фактический ТабличныйДокумент";
КонецЕсли;
ЭтаФорма.МаршрутКомпоновки = Истина;
КонецПроцедуры
&НаКлиенте
Процедура СформироватьДляРучнойСверки()
До = ЭтаФорма.СобытийДо;
После = ЭтаФорма.СобытийПосле;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СкомпоноватьРезультат(РежимКомпоновкиРезультата.Непосредственно);
Если Не ЭтаФорма.МаршрутКомпоновки Или ЭтаФорма.СобытийДо <> До + 1 Или ЭтаФорма.СобытийПосле <> После + 1 Тогда
ВызватьИсключение "Не подтверждён маршрут событий формы";
КонецЕсли;
Сообщить("Подтверждён только маршрут компоновки. Строки, поля и числа actual результата проверьте вручную");
КонецПроцедуры
&НаСервере
Процедура СохранитьСвоиПрофили()
ПроверитьСвоиКлючи();
ЭтаФорма.ХранилищеПодтверждено = Ложь;
Если ЭтаФорма.СозданА Или ЭтаФорма.СозданБ Или ЭтаФорма.СозданБаза Или ЭтаФорма.ОчиститьА Или ЭтаФорма.ОчиститьБ Или ЭтаФорма.ОчиститьБазу Тогда
ВызватьИсключение "Повторное Save запрещено: используйте пульт очистки и новый экземпляр";
КонецЕсли;
Попытка
Объект = "Отчет.УчебныеГраницыПакетов85";
ХранилищеВариантов = ПолучитьСтандартноеХранилищеВариантовОтчетов();
ХранилищеПрофилей = ПолучитьСтандартноеХранилищеПользовательскихНастроекОтчетов();
ОбъектПрофилей = Объект + "/" + ЭтаФорма.КлючБазы;
Если ХранилищеВариантов.Загрузить(Объект, ЭтаФорма.КлючБазы, , ЭтаФорма.ПользовательОпытов) <> Неопределено Или ХранилищеПрофилей.Загрузить(ОбъектПрофилей, ЭтаФорма.КлючА, , ЭтаФорма.ПользовательОпытов) <> Неопределено Или ХранилищеПрофилей.Загрузить(ОбъектПрофилей, ЭтаФорма.КлючБ, , ЭтаФорма.ПользовательОпытов) <> Неопределено Тогда
ВызватьИсключение "Обнаружена существующая запись; её нельзя перезаписывать";
КонецЕсли;
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
Основные = ОбъектОтчета.СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
ПроверитьОсновныеГраницы(Основные, 0, 9);
ПроверитьПолныйВыбор(Основные, "Пакет,Количество,Сумма");
Если ПолныйТипизированныйXML(Основные) <> ЭтаФорма.XMLБазы Тогда
ВызватьИсключение "Базовый вариант изменился до сохранения";
КонецЕсли;
Все = СоздатьСобственныйПрофиль(ОбъектОтчета.КомпоновщикНастроек, Основные, 0, 9);
ПроверитьПолныйСобственныйПрофиль(Все, 0, 9);
Описание = Новый ОписаниеНастроек;
Описание.Представление = "База границ пакетов85";
ЭтаФорма.ОчиститьБазу = Истина;
ХранилищеВариантов.Сохранить(Объект, ЭтаФорма.КлючБазы, Основные, Описание, ЭтаФорма.ПользовательОпытов);
ЭтаФорма.СозданБаза = Истина;
ПроверитьЗаписаннуюБазу();
Описание.Представление = "Все количества 0..9";
ЭтаФорма.ОчиститьА = Истина;
ХранилищеПрофилей.Сохранить(ОбъектПрофилей, ЭтаФорма.КлючА, Все, Описание, ЭтаФорма.ПользовательОпытов);
ЭтаФорма.СозданА = Истина;
ПроверитьЗаписанныйПрофиль(ЭтаФорма.КлючА, 0, 9, "Все количества 0..9");
Узко = СоздатьСобственныйПрофиль(ОбъектОтчета.КомпоновщикНастроек, Основные, 2, 3);
ПроверитьПолныйСобственныйПрофиль(Узко, 2, 3);
Если ПолныйТипизированныйXML(Основные) <> ЭтаФорма.XMLБазы Тогда
ВызватьИсключение "Создание user-копии изменило исходный базовый вариант";
КонецЕсли;
Описание.Представление = "Только количества 2..3";
ЭтаФорма.ОчиститьБ = Истина;
ХранилищеПрофилей.Сохранить(ОбъектПрофилей, ЭтаФорма.КлючБ, Узко, Описание, ЭтаФорма.ПользовательОпытов);
ЭтаФорма.СозданБ = Истина;
ПроверитьЗаписанныйПрофиль(ЭтаФорма.КлючБ, 2, 3, "Только количества 2..3");
ПроверитьЗаписаннуюБазу();
ЭтаФорма.ХранилищеПодтверждено = Истина;
Исключение
ЭтаФорма.ХранилищеПодтверждено = Ложь;
ЭтаФорма.СостояниеУрока = "Save/readback профилей остановлен: " + ОписаниеОшибки() + ". Нормальный серверный возврат сохраняет отметки завершённых Save для квитанции";
ЭтаФорма.СостояниеУрока = ЭтаФорма.СостояниеУрока + СтрШаблон(". Свои pending ключи: %1 [%2], %3 [%4], база %5 [%6]; очистка ещё не подтверждена", ЭтаФорма.КлючА, ЭтаФорма.ОчиститьА, ЭтаФорма.КлючБ, ЭтаФорма.ОчиститьБ, ЭтаФорма.КлючБазы, ЭтаФорма.ОчиститьБазу);
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ПроверитьЗаписаннуюБазу()
Описание = Новый ОписаниеНастроек;
База = ПолучитьСтандартноеХранилищеВариантовОтчетов().Загрузить("Отчет.УчебныеГраницыПакетов85", ЭтаФорма.КлючБазы, Описание, ЭтаФорма.ПользовательОпытов);
Если База = Неопределено Тогда
ВызватьИсключение "Собственная база варианта после Save не найдена";
КонецЕсли;
Если ПолныйТипизированныйXML(База) <> ЭтаФорма.XMLБазы Или ТипЗнч(Описание.Представление) <> Тип("Строка") Или Описание.Представление <> "База границ пакетов85" Тогда
ВызватьИсключение "Не совпали полный typed payload базы или её описание";
КонецЕсли;
ПроверитьОсновныеГраницы(База, 0, 9);
КонецПроцедуры
&НаСервере
Процедура ПроверитьЗаписанныйПрофиль(Ключ, Минимум, Максимум, Представление)
Описание = Новый ОписаниеНастроек;
Профиль = ПолучитьСтандартноеХранилищеПользовательскихНастроекОтчетов().Загрузить("Отчет.УчебныеГраницыПакетов85/" + ЭтаФорма.КлючБазы, Ключ, Описание, ЭтаФорма.ПользовательОпытов);
Если Профиль = Неопределено Тогда
ВызватьИсключение "После Save собственный профиль не найден";
КонецЕсли;
ПроверитьПолныйСобственныйПрофиль(Профиль, Минимум, Максимум);
Если ТипЗнч(Описание.Представление) <> Тип("Строка") Или Описание.Представление <> Представление Тогда
ВызватьИсключение "Не совпало сохранённое представление профиля";
КонецЕсли;
ПроверитьЗаписаннуюБазу();
КонецПроцедуры
&НаСервере
Процедура ПрименитьСвойПрофиль(Узкий)
ПроверитьСвоиКлючи();
Если Не ЭтаФорма.ХранилищеПодтверждено Тогда
ВызватьИсключение "Нужны реальное Save/Load базы и обоих полностью проверенных профилей";
КонецЕсли;
Минимум = ?(Узкий, 2, 0);
Максимум = ?(Узкий, 3, 9);
Ключ = ?(Узкий, ЭтаФорма.КлючБ, ЭтаФорма.КлючА);
Представление = ?(Узкий, "Только количества 2..3", "Все количества 0..9");
ПроверитьЗаписанныйПрофиль(Ключ, Минимум, Максимум, Представление);
ЭтаФорма.УстановитьТекущийВариант(ЭтаФорма.КлючБазы);
Если ТипЗнч(ЭтаФорма.КлючТекущегоВарианта) <> Тип("Строка") Или ЭтаФорма.КлючТекущегоВарианта <> ЭтаФорма.КлючБазы Или ЭтаФорма.ПредставлениеТекущегоВарианта <> "База границ пакетов85" Тогда
ВызватьИсключение "Не подтверждён настоящий сохранённый базовый вариант";
КонецЕсли;
ЭтаФорма.УстановитьТекущиеПользовательскиеНастройки(Ключ);
Если ТипЗнч(ЭтаФорма.КлючТекущихПользовательскихНастроек) <> Тип("Строка") Или ЭтаФорма.КлючТекущихПользовательскихНастроек <> Ключ Или ТипЗнч(ЭтаФорма.ПредставлениеТекущихПользовательскихНастроек) <> Тип("Строка") Или ЭтаФорма.ПредставлениеТекущихПользовательскихНастроек <> Представление Тогда
ВызватьИсключение "Setter не подтвердил реальные ключ и представление профиля";
КонецЕсли;
Если ЭтаФорма.КлючТекущегоВарианта <> ЭтаФорма.КлючБазы Или ЭтаФорма.ПредставлениеТекущегоВарианта <> "База границ пакетов85" Тогда
ВызватьИсключение "При выборе профиля неожиданно изменился базовый вариант";
КонецЕсли;
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
Если ПолныйТипизированныйXML(ОбъектОтчета.КомпоновщикНастроек.Настройки) <> ЭтаФорма.XMLБазы Тогда
ВызватьИсключение "При выборе user-профиля изменились полные actual основные настройки базового варианта";
КонецЕсли;
ПроверитьПолныйСобственныйПрофиль(ОбъектОтчета.КомпоновщикНастроек.ПользовательскиеНастройки, Минимум, Максимум);
ПроверитьОсновныеГраницы(ОбъектОтчета.КомпоновщикНастроек.Настройки, 0, 9);
ПроверитьОсновныеГраницы(ОбъектОтчета.КомпоновщикНастроек.ПолучитьНастройки(), Минимум, Максимум, Ложь);
ПроверитьПолныйВыбор(ОбъектОтчета.КомпоновщикНастроек.ПолучитьНастройки(), "Пакет,Количество,Сумма");
ПроверитьЗаписаннуюБазу();
ЭтаФорма.СостояниеУрока = "Подтверждены полный профиль, сохранённая база и effective границы " + Представление + "; это не доказательство строк и чисел результата";
КонецПроцедуры
&НаКлиенте
Процедура СоздатьСвоиПрофили(Команда)
Попытка
СохранитьСвоиПрофили();
Если Не ЭтаФорма.ХранилищеПодтверждено Тогда
ВызватьИсключение ЭтаФорма.СостояниеУрока;
КонецЕсли;
ПрименитьСвойПрофиль(Ложь);
СформироватьДляРучнойСверки();
Исключение
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Создание профилей остановлено: " + ОписаниеОшибки() + ". Созданные записи учтены для точечной очистки";
КонецПопытки;
Сообщить(ЭтаФорма.СостояниеУрока);
КонецПроцедуры
&НаКлиенте
Процедура УзкиеГраницы(Команда)
Попытка
ПрименитьСвойПрофиль(Истина);
СформироватьДляРучнойСверки();
Исключение
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Узкие границы не подтверждены: " + ОписаниеОшибки();
КонецПопытки;
Сообщить(ЭтаФорма.СостояниеУрока);
КонецПроцедуры
&НаКлиенте
Процедура ВернутьВсе(Команда)
Попытка
ПрименитьСвойПрофиль(Ложь);
СформироватьДляРучнойСверки();
Исключение
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Возврат всех границ не подтверждён: " + ОписаниеОшибки();
КонецПопытки;
Сообщить(ЭтаФорма.СостояниеУрока);
КонецПроцедурыПолный независимый пульт и точечная очистка
Модуль общей управляемой формы ПультПрофилейГраниц85
Смешанный управляемый: толстый клиент и сервер
Перем РабочаяФорма;
Перем КвитанцияОчистки;
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Попытка
ПроверитьУчебнуюСреду();
ЭтаФорма.РежимБлокировкиПриОткрытииОкна = РежимБлокировкиПриОткрытииОкнаФормы.НеБлокировать;
Исключение
Отказ = Истина;
ВызватьИсключение ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьУчебнуюСреду()
Если ИмяПользователя() <> "АвторВариантов85" Тогда
ВызватьИсключение "Нужен отдельный новый именованный пользователь АвторВариантов85";
КонецЕсли;
Если КлиентскоеПриложение.ТекущийВариантИнтерфейса() <> ВариантИнтерфейсаКлиентскогоПриложения.Такси Тогда
ВызватьИсключение "Нужен собственный толстый управляемый сеанс Такси";
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОткрытьСвойОтчет(Команда)
Если КвитанцияОчистки <> Неопределено Тогда
ВызватьИсключение "Сначала завершите очистку предыдущей квитанции";
КонецЕсли;
Если РабочаяФорма <> Неопределено Тогда
Если РабочаяФорма.Открыта() Тогда
ВызватьИсключение "Собственный отчёт уже открыт";
КонецЕсли;
ВызватьИсключение "Не закрывайте отчёт вручную до получения квитанции; начните новый пульт только после собственной ручной проверки записей";
КонецЕсли;
РабочаяФорма = ПолучитьФорму("Отчет.УчебныеГраницыПакетов85.Форма.ПрофилиГраниц85", , ЭтаФорма, Новый УникальныйИдентификатор);
Если РабочаяФорма = Неопределено Тогда
ВызватьИсключение "Собственная форма отказала в создании";
КонецЕсли;
РабочаяФорма.Открыть();
КонецПроцедуры
&НаКлиенте
Процедура ЗакрытьИУдалитьСозданное(Команда)
Попытка
Если КвитанцияОчистки = Неопределено Тогда
Если РабочаяФорма = Неопределено Тогда
ВызватьИсключение "Нет собственного экземпляра отчёта";
КонецЕсли;
Если Не РабочаяФорма.Открыта() Тогда
ВызватьИсключение "Отчёт закрыли до получения квитанции; автоматическое удаление запрещено";
КонецЕсли;
КвитанцияОчистки = РабочаяФорма.ПолучитьКвитанциюОчистки();
КонецЕсли;
Если РабочаяФорма.Открыта() Тогда
РабочаяФорма.Закрыть();
КонецЕсли;
Если РабочаяФорма.Открыта() Тогда
ВызватьИсключение "Собственная форма ещё открыта; удаление запрещено";
КонецЕсли;
УдалитьПоСобственнойКвитанции(КвитанцияОчистки);
РабочаяФорма = Неопределено;
КвитанцияОчистки = Неопределено;
Сообщить("Проверено отсутствие только своих pending/созданных записей после точечного Delete и readback. Системные текущие ключи, история и весь профиль не очищались");
Исключение
Сообщить("Очистка не подтверждена: " + ОписаниеОшибки() + ". Квитанция сохранена для повторной узкой попытки, чужие записи не выбираются");
Если КвитанцияОчистки <> Неопределено Тогда
Сообщить(СтрШаблон("Непроверенная очистка своего объекта %1 пользователя %2: А=%3 pending=%4; Б=%5 pending=%6; база=%7 pending=%8", КвитанцияОчистки.Объект, КвитанцияОчистки.Пользователь, КвитанцияОчистки.КлючА, КвитанцияОчистки.ОчиститьА, КвитанцияОчистки.КлючБ, КвитанцияОчистки.ОчиститьБ, КвитанцияОчистки.КлючБазы, КвитанцияОчистки.ОчиститьБазу));
Иначе
Сообщить("Квитанция ещё не получена: автоматическое удаление не выполнялось. В собственном отчёте проверьте показанные pending ключи; не объявляйте опыт завершённым");
КонецЕсли;
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УдалитьПоСобственнойКвитанции(Квитанция)
ПроверитьУчебнуюСреду();
Если ТипЗнч(Квитанция) <> Тип("Структура") Тогда
ВызватьИсключение "Нужна квитанция реального собственного Save";
КонецЕсли;
Если Квитанция.Объект <> "Отчет.УчебныеГраницыПакетов85" Или Квитанция.Пользователь <> ИмяПользователя() Или Квитанция.Пользователь = "" Или Квитанция.Область = "" Тогда
ВызватьИсключение "Квитанция не принадлежит собственным отчёту, сеансу и пользователю";
КонецЕсли;
Если Квитанция.Префикс <> "УчебныеПакеты85_" + Квитанция.Область + "_" Или Квитанция.КлючА <> Квитанция.Префикс + "А" Или Квитанция.КлючБ <> Квитанция.Префикс + "Б" Тогда
ВызватьИсключение "Квитанция содержит ключ вне выделенного namespace";
КонецЕсли;
Если ТипЗнч(Квитанция.СозданА) <> Тип("Булево") Или ТипЗнч(Квитанция.СозданБ) <> Тип("Булево") Или ТипЗнч(Квитанция.СозданБаза) <> Тип("Булево") Тогда
ВызватьИсключение "Повреждены отметки завершённого Save";
КонецЕсли;
Если ТипЗнч(Квитанция.ОчиститьА) <> Тип("Булево") Или ТипЗнч(Квитанция.ОчиститьБ) <> Тип("Булево") Или ТипЗнч(Квитанция.ОчиститьБазу) <> Тип("Булево") Тогда
ВызватьИсключение "Повреждены отметки возможной записи собственных pending ключей";
КонецЕсли;
Если (Квитанция.СозданА И Не Квитанция.ОчиститьА) Или (Квитанция.СозданБ И Не Квитанция.ОчиститьБ) Или (Квитанция.СозданБаза И Не Квитанция.ОчиститьБазу) Тогда
ВызватьИсключение "У завершённого Save потеряна запись собственного ownership для cleanup";
КонецЕсли;
Если Квитанция.КлючБазы <> Квитанция.Префикс + "База" Тогда
ВызватьИсключение "Повреждён ключ созданного базового варианта";
КонецЕсли;
ОбъектПрофилей = Квитанция.Объект + "/" + Квитанция.КлючБазы;
ХранилищеПрофилей = ПолучитьСтандартноеХранилищеПользовательскихНастроекОтчетов();
Если Квитанция.ОчиститьА Тогда
УдалитьТолькоСозданнуюЗапись(ХранилищеПрофилей, ОбъектПрофилей, Квитанция.КлючА, Квитанция.Пользователь, Квитанция.Префикс);
КонецЕсли;
Если Квитанция.ОчиститьБ Тогда
УдалитьТолькоСозданнуюЗапись(ХранилищеПрофилей, ОбъектПрофилей, Квитанция.КлючБ, Квитанция.Пользователь, Квитанция.Префикс);
КонецЕсли;
Если Квитанция.ОчиститьБазу Тогда
УдалитьТолькоСозданнуюЗапись(ПолучитьСтандартноеХранилищеВариантовОтчетов(), Квитанция.Объект, Квитанция.КлючБазы, Квитанция.Пользователь, Квитанция.Префикс);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура УдалитьТолькоСозданнуюЗапись(Хранилище, Объект, Ключ, Пользователь, Префикс)
Если ТипЗнч(Объект) <> Тип("Строка") Или ТипЗнч(Ключ) <> Тип("Строка") Или ТипЗнч(Пользователь) <> Тип("Строка") Тогда
ВызватьИсключение "Удалить требует три конкретные строки";
КонецЕсли;
Если Объект = "" Или Ключ = "" Или Пользователь = "" Или Пользователь <> ИмяПользователя() Или Лев(Ключ, СтрДлина(Префикс)) <> Префикс Тогда
ВызватьИсключение "Широкое удаление или чужой ключ запрещены";
КонецЕсли;
Хранилище.Удалить(Объект, Ключ, Пользователь);
Если Хранилище.Загрузить(Объект, Ключ, , Пользователь) <> Неопределено Тогда
ВызватьИсключение "После точечного Удалить readback всё ещё нашёл запись";
КонецЕсли;
КонецПроцедурыПолный запуск собственного стенда
Модуль управляемого приложения новой конфигурации УчебныеВариантыПакетов85; событие ПриНачалеРаботыСистемы
Толстый клиент, управляемое приложение
Процедура ПриНачалеРаботыСистемы()
ОткрытьФорму("ОбщаяФорма.ПультПрофилейГраниц85", , , Новый УникальныйИдентификатор);
КонецПроцедурыРазбор по шагам
Подготовьте новый пустой стенд, нового пользователя, роль с СохранениеДанныхПользователя, свой отчёт/форму, отдельный пульт и соответствующий полный запуск. Здесь всё остаётся текстом, runtime0.
Откройте только собственный экземпляр через пульт. Полный модуль строит query с двумя настоящими schema-параметрами Минимум и Максимум; тип каждого — ОписаниеТипов("Число",КвалификаторыЧисла(1,0,Неотрицательный)).
Проверьте подготовку источника/полей/детальных записей. Для каждого основного значения устанавливаются ID ГраницаПакетов85_Минимум/Максимум и представления Количество: Минимум/Максимум; использование включено. LoadSettings заново получает user-копию на основе этих настроек.
Нажмите СоздатьСвоиПрофили. До Save профиль0..9 обязан иметь ровно два parameter-value элемента, только собственные uniqueID, Number значения, Bool использование=true, typed РежимОтображения=Авто; основные и дополнительные свойства пусты, actual ДополнительныеНастройки имеют0элементов/0свойств. Иной состав — отказ.
Реальный базовый вариант сначала записывается под КлючБазы и проверяется полным typed XML+описанием+границами0..9. Профили пишутся строго под native объектом Отчет.УчебныеГраницыПакетов85/реальныйКлючБазы, не под выдуманным UUID-вариантом.
Профиль Все0..9 сохраняется и целиком сверяется при readback; затем новый LoadSettings создаёт user-слой Узко2..3. В каждом профиле явно задаётся сохранённый режим Авто, затем меняются числовые Значение. Main режим Обычный остаётся прежним; Авто получает его из основных настроек, но это не ручная проверка UI. Readonly контейнеры, user.Параметр, user.Родитель, user.ЗначенияВложенныхПараметров и user.ПредставлениеПользовательскойНастройки не читаются/не переприсваиваются.
До report-setters оба полных user-профиля, их сохранённые представления и неизменность всего сохранённого базового Settings проверяются; после выбора реальные текущие ключи/представления и effective0..9 обязаны совпасть.
В actual ПолеРезультата вручную сверяйте все три детали ПакетА/3/60, ПакетБ/1/20, ПакетВ/6/120. Общего итога схема не задаёт. Флаг событий не делает эту сверку вместо вас.
Нажмите УзкиеГраницы: повторное полное Load-сравнение, настоящий текущий базовый вариант, текущий profile-key/представление; основная база остаётся0..9, actual effective становится2..3. В actual документе вручную должна остаться единственная полная деталь ПакетА/3/60.
Нажмите ВернутьВсе: actual effective0..9 и прежний базовый ключ/представление; вручную снова сверяйте все три детали. Не используйте автоимена клеток или ожидаемый Python-список как доказательство вывода.
В пульте ЗакрытьИУдалитьСозданное получает квитанцию, закрывает только свою форму и требует Открыта=false. Cleanup удаляет учтённые А/Б из report/base namespace, затем учтённую базу из report namespace; каждый readback — Неопределено.
Как проверить результат
Оба parameter ID и оба main-представления реально проверяются; их прежнее supporting-only использование не считалось API покрытием.
Полный user-состав проверяется до Save и после Load: тип, ровно2элемента, оба uniqueID, Number значения, Bool использование=true, собственный enum Авто, отсутствие неожиданных элементов и дополнительных свойств/настроек. Actual main Обычный — источник режима для user Авто по native; поле режима в числовой effective-копии не используется как обещание разрешения Авто. UI вручную; режим включён для полноты payload, не отдельного покрытия.
Для user-копии используются документированные Элементы.Найти(StringID); ПолучитьОбъектПоИдентификатору с типом ИдентификаторКомпоновкиДанных здесь не подменён строкой.
ПредставлениеПользовательскойНастройки и Параметр читаются только у основной настройки, не у user-объекта.
Числа ограничены собственными целыми0..9; явные qualifiers обязательны. Строка "3" или неверный ID не допускаются.
Полное базовое Settings + описание сохраняются неизменными, текущий базовый ключ проверен до и после user-setter; effective границы подтверждены actual компоновщиком.
Числовой/визуальный результат0..9/2..3/0..9 отдельно ручной; actual события показывают только маршрут, не данные.
Ожидаемый результат
Будущий результат: создан и fully readback-проверен свой базовый вариант и два минимальных user-профиля; report-setters меняют actual effective границы при сохранении базы; реальные детали сверены вручную, затем удалены только три созданные записи. Здесь runtime0 и никаких записей.
На что обратить внимание
Только новый именованный пользователь собственной новой базы; всё сохраняющее поведение — будущий ручной BSL, не исполнение здесь.
Это не универсальный comparer чужого графа UserSettings. Подготовка допускает только два своих параметра; неожиданные основные или дополнительные элементы/свойства приводят к отказу, не игнорируются.
Нативный тип UserSettings не обещает XML/XDTO: полный user-профиль сравнивается структурно, XML применяется только к документированному Settings.
ДополнительныеНастройки readonly UserSettings содержат элементы, отмеченные в отборе/условном оформлении; наша схема их не создаёт. Вложенный произвольный граф дополнительных настроек не поддерживается.
Не меняйте пользовательские ID вручную после создания; новый профиль должен оставаться exact составом своего базового варианта.
Если runtime LoadSettings неожиданно добавит элементы или дополнительные свойства, урок fail-closed остановится; нельзя удалить их для искусственного сообщения успех.
Сохранённый базовый вариант, основная настройка компоновщика и effective-результат — разные уровни; user0..9↔2..3 не переписывает сохранённую базу.
Закрытие/смена варианта может писать внутренние системные текущие настройки. Точечное удалениеА/Б/База не удаляет системную историю, весь профиль и не обещает отсутствие внутренних операций.
Ни один Delete не может использовать Неопределено или пустую строку вместо собственного объекта/ключа/пользователя.
Ожидаемые детали выведены из своего константного запроса для будущего ручного протокола; это не подтверждение actual табличного результата статическими тестами.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.