ПользовательскиеНастройкиКомпоновкиДанных

Типы · DataCompositionUserSettings

Настройки, предназначенные для изменения пользователем.

Полное описание, параметры и ограничения

ПользовательскиеНастройкиКомпоновкиДанных (DataCompositionUserSettings)

ПользовательскиеНастройкиКомпоновкиДанных (DataCompositionUserSettings)

Доступен, начиная с версии 8.2.

Свойства:
ДополнительныеНастройки (AdditionalSettings)
ДополнительныеСвойства (AdditionalProperties)
Элементы (Items)

Методы:
ПолучитьИдентификаторПоОбъекту (GetIDByObject)
ПолучитьКоличествоИспользуемых (GetUsedCount)
ПолучитьОбъектПоИдентификатору (GetObjectByID)
ПолучитьОсновныеНастройкиПоИдентификаторуПользовательскойНастройки (GetMainSettingsByUserSettingID)

Конструкторы:
По умолчанию

Описание:

Настройки, предназначенные для изменения пользователем.

Доступность:

Тонкий клиент, веб-клиент, мобильный клиент, сервер, толстый клиент, внешнее соединение, мобильное приложение (клиент), мобильное приложение (сервер), мобильный автономный сервер.
Сериализуется.

См. также:
КомпоновщикНастроекКомпоновкиДанных, свойство ПользовательскиеНастройки
Расширение формы клиентского приложения для отчета, событие ПриСохраненииПользовательскихНастроекНаСервере
Расширение формы клиентского приложения для отчета, событие ПриЗагрузкеПользовательскихНастроекНаСервере
КомпоновщикНастроекКомпоновкиДанных, метод ЗагрузитьПользовательскиеНастройки
Расширение формы клиентского приложения для отчета

Использование в версии:

Доступен, начиная с версии 8.2.

Методическая информация

Практические примеры

Подготовить снимок состояния списка и ссылку на свой пустой справочник

Создаём конкретный пакет НастройкиТаблицыДинамическогоСписка, явно задаём все четыре свойства и сохраняем собственный XML-снимок. Меняем исходный пакет, проверяем сохранность восстановленной версии и используем её в серверном варианте получения навигационной ссылки.

Где и как запускать

Полный серверный общий модуль УчебнаяНавигация своего стенда УчебнаяСсылкаСписка85 и отдельный полный модуль формы. Ссылку не открывает; возможное сохранение её параметров только в собственной будущей учебной базе.

Подготовка

  1. НОВАЯ отдельная учебная база точно 8.5.1.1343, конфигурация УчебнаяСсылкаСписка85, совместимость Не использовать. Единственный справочник УчебныеТовары: неиерархический, без владельцев, собственных реквизитов и табличных частей, Код строка9, Наименование строка50. Записей нет. Других бизнес-объектов, расширений, подписок и фоновых заданий нет.

  2. Создайте управляемую форму списка справочника и назначьте её основной формой списка. Стандартная таблица формы связана с динамическим списком справочника. У этого пустого списка нет текущей записи: код не выдумывает ключ2, UUID или чужую ссылку.

  3. Общий модуль УчебнаяНавигация: Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет; вставьте полный основной модуль. Своя внешняя обработка УчебнаяСсылкаСписка85 → управляемая форма → команда/кнопка Выполнить с действием Выполнить. Полный отдельный модуль формы приведён ниже.

  4. Будущая ручная подготовка: сохранить конфигурацию, Конфигурация → Обновить конфигурацию базы данных (F7), открыть новый свой сеанс и свою обработку. Здесь форма, конфигурация, код, XML и навигация не запускались.

  5. ВАЖНО: получение ссылки с настройками не является гарантированно чистой операцией памяти. Платформа использует хранилище внешних данных навигационных ссылок для параметров. Будущий вызов разрешён только в этой собственной учебной базе; не запускайте в production и не распространяйте полученную ссылку как публичный адрес.

Функция ВыполнитьПример() Экспорт
    ПроверитьСвойСтендПрофилей();
    Настройки = Новый НастройкиТаблицыДинамическогоСписка;
    Настройки.ОтображениеТаблицы = ОтображениеТаблицы.Список;
    Настройки.ТекущаяСтрока = Неопределено;
    Настройки.ПользовательскиеНастройки = Новый ПользовательскиеНастройкиКомпоновкиДанных;
    Настройки.ФиксированныеНастройки = Новый НастройкиКомпоновкиДанных;
    ПроверитьСвойПакетСписка(Настройки, Истина);
    Снимок = ЗаписатьСвойСнимокСписка(Настройки);
    Копия = ПрочитатьСвойСнимокСписка(Снимок);
    Настройки.ФиксированныеНастройки = Неопределено;
    ПроверитьСвойПакетСписка(Настройки, Ложь);
    ПроверитьСвойПакетСписка(Копия, Истина);
    Если ТипЗнч(Снимок) <> Тип("Строка") Или ПустаяСтрока(Снимок) Тогда
        ВызватьИсключение "Нужен собственный непустой XML-снимок в памяти";
    КонецЕсли;
    Ссылка = ПолучитьНавигационнуюСсылку(Метаданные.Справочники.УчебныеТовары, Копия, "УчебныеТовары: список без выбранной строки и отборов");
    Если ТипЗнч(Ссылка) <> Тип("Строка") Или ПустаяСтрока(Ссылка) Тогда
        ВызватьИсключение "Не получена собственная навигационная ссылка";
    КонецЕсли;
    ПроверитьСвойПакетСписка(Копия, Истина);
    Сообщить("Снимок сохранил явные фиксированные настройки; исходный пакет теперь без них");
    Возврат Ссылка;
КонецФункции

Процедура ПроверитьСвойСтендПрофилей()
    Если Метаданные.Справочники.Количество() <> 1 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен свой новый стенд с единственным учебным справочником";
    КонецЕсли;
    Если Метаданные.Справочники[0].Имя <> "УчебныеТовары" Тогда
        ВызватьИсключение "Разрешён только собственный справочник УчебныеТовары";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвойПакетСписка(Настройки, СФиксированными)
    Если ТипЗнч(Настройки) <> Тип("НастройкиТаблицыДинамическогоСписка") Тогда
        ВызватьИсключение "Нужен конкретный собственный пакет состояния списка";
    КонецЕсли;
    Если ТипЗнч(Настройки.ОтображениеТаблицы) <> Тип("ОтображениеТаблицы")
        Или Настройки.ОтображениеТаблицы <> ОтображениеТаблицы.Список Тогда
        ВызватьИсключение "Пустой собственный неиерархический справочник показываем списком";
    КонецЕсли;
    Если Настройки.ТекущаяСтрока <> Неопределено Тогда
        ВызватьИсключение "У пустого собственного справочника нет выбранной строки";
    КонецЕсли;
    Если ТипЗнч(Настройки.ПользовательскиеНастройки) <> Тип("ПользовательскиеНастройкиКомпоновкиДанных") Тогда
        ВызватьИсключение "Нужны собственные типизированные пользовательские настройки";
    КонецЕсли;
    Если Настройки.ПользовательскиеНастройки.Элементы.Количество() <> 0 Тогда
        ВызватьИсключение "Пользовательские элементы этого собственного пакета должны быть пусты";
    КонецЕсли;
    Если СФиксированными Тогда
        Если ТипЗнч(Настройки.ФиксированныеНастройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
            ВызватьИсключение "Нужны собственные типизированные фиксированные настройки";
        КонецЕсли;
        Если Настройки.ФиксированныеНастройки.Отбор.Элементы.Количество() <> 0 Тогда
            ВызватьИсключение "Явный фиксированный отбор собственного пакета должен быть пуст";
        КонецЕсли;
    ИначеЕсли Настройки.ФиксированныеНастройки <> Неопределено Тогда
        ВызватьИсключение "Во второй версии фиксированные настройки не установлены";
    КонецЕсли;
КонецПроцедуры

Функция ЗаписатьСвойСнимокСписка(Настройки)
    ПроверитьСвойПакетСписка(Настройки, Истина);
    Запись = Новый ЗаписьXML;
    Запись.УстановитьСтроку();
    Попытка
        СериализаторXDTO.ЗаписатьXML(Запись, Настройки, НазначениеТипаXML.Явное);
        Возврат Запись.Закрыть();
    Исключение
        Запись.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
КонецФункции

Функция ПрочитатьСвойСнимокСписка(Текст)
    Чтение = Новый ЧтениеXML;
    Чтение.УстановитьСтроку(Текст);
    Попытка
        Настройки = СериализаторXDTO.ПрочитатьXML(Чтение, Тип("НастройкиТаблицыДинамическогоСписка"));
    Исключение
        Чтение.Закрыть();
        ВызватьИсключение;
    КонецПопытки;
    Чтение.Закрыть();
    ПроверитьСвойПакетСписка(Настройки, Истина);
    Возврат Настройки;
КонецФункции
УчебнаяСсылкаСписка85.Форма

Своя внешняя обработка УчебнаяСсылкаСписка85 → управляемая Форма → Модуль

Полный отдельный модуль своей формы; не выполнялся.

&НаКлиенте
Процедура Выполнить(Команда)
    Ссылка = ПодготовитьНаСервере();
    Сообщить(Ссылка);
    Сообщить("Ссылка не открывалась; состояние списка и снимок проверены");
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПодготовитьНаСервере()
    Возврат УчебнаяНавигация.ВыполнитьПример();
КонецФункции

Разбор по шагам

  1. Конструктор создаёт объект параметров, не сам динамический список и не форму. Все четыре значения заданы явно: Список, Неопределено для текущей строки, новая пустая пользовательская настройка и новая пустая фиксированная настройка.

  2. ОтображениеТаблицы — enum, не строка. Пустые пользовательские элементы означают отсутствие заданных пользовательских условий; пустой фиксированный отбор не является разрешением доступа и не отключает RLS.

  3. Перед записью проверяем конкретные типы, отсутствие текущего ключа и пустые коллекции. Сериализатору передаём только этот собственный пакет, не объект метаданных справочника: сериализация метаданных могла бы выгрузить доступные записи.

  4. ЗаписатьXML использует Явное назначение типа; ПрочитатьXML получает точный тип НастройкиТаблицыДинамическогоСписка. Читатель и писатель работают только со строками памяти и закрываются при ошибке и нормальном завершении.

  5. Исходным ФиксированныеНастройки задаём Неопределено, но восстановленный пакет должен сохранить настоящий объект НастройкиКомпоновкиДанных с пустым отбором. Это различие состояния, а не сравнение случайного порядка или префиксов XML.

  6. На сервере ПолучитьНавигационнуюСсылку принимает метаданные собственного справочника, конкретный восстановленный пакет и представление ссылки. Внешние бизнес-данные не передаются. Переход по ссылке и открытие формы в этом коде не выполняются.

  7. Возвращаем непустую строку в отдельный модуль своей формы. Не требуем заранее угаданного текста URL: параметры могут быть связаны со служебным хранилищем и конкретной базой. Получение строки не доказывает успешного открытия интерфейса.

Как проверить результат

  1. Будущий результат: исходный пакет имеет ФиксированныеНастройки=Неопределено; копия после XML по-прежнему содержит НастройкиКомпоновкиДанных, пустой фиксированный отбор, пустые пользовательские элементы, Список и Неопределено для строки.

  2. Будущий отрицательный контроль: после Копия = ПрочитатьСвойСнимокСписка(Снимок) вставьте Копия.ТекущаяСтрока = "2";. Не меняйте проверки и подготовку пустого списка. Проверка копии должна отклонить выдуманный строковый ключ ДО получения ссылки. После опыта восстановите весь модуль.

  3. Полученная строка — только ожидаемый будущий результат серверного API. Открытие ссылки, восстановление интерфейса, содержимое служебного хранилища и работа прав доступа здесь не проверялись.

  4. runtimeVerifiedScenarios=0. Сверены сигнатуры, типы, доступность, readonly и структура кода; фактические XML-снимок, независимость версии и навигационная ссылка в1С не получены.

Ожидаемый результат

Конкретный пакет параметров решает задачу снимка и подготовки перехода к своему списку; конструктор и все четыре свойства используются в полном проверяемом сценарии.

На что обратить внимание

  1. НастройкиТаблицыДинамическогоСписка не равен НастройкиОтображенияДинамическогоСписка: второй тип имеет другой контракт и не подставляется в этот конструктор или параметр навигации.

  2. Тип текущего ключа определяется реальным источником таблицы. У пустого собственного справочника нет выбранной строки; нельзя произвольно использовать число или строку2 для ссылочного источника.

  3. Пустой объект фиксированных настроек и Неопределено — разные состояния. Не удаляйте это различие при проверке снимка. Пользовательские и фиксированные параметры не являются способом обхода доступа к данным.

  4. XML-снимок относится к собственным известным типам в этой версии платформы, не к универсальному клонированию любого графа. Не принимайте чужой XML и не обещайте переносимость ссылок между базами.

  5. Получение ссылки с настройками может сохранять служебные параметры; ссылка не обязательно автономна и не обязана жить вечно. Этот урок не удаляет служебные записи и не измеряет срок их хранения.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Два собственных профиля границ: настоящий вариант, полный 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. Только будущий ручной опыт: создайте совершенно новую пустую учебную информационную базу. Здесь 1С и BSL не запускались; runtime-проверок 0. Не переносите урок в рабочую конфигурацию.

  2. В конфигураторе имя собственной конфигурации задайте УчебныеВариантыПакетов85; основное приложение — управляемое, Режим совместимости — Не использовать. Запуск: толстый клиент в режиме управляемого приложения, установленная платформа ровно 8.5.1.1343, интерфейс Такси, обычный режим основного окна. Обычный режим основного окна не означает обычное приложение: приложение остаётся управляемым. Проверки версии/имени/интерфейса не доказывают, каким исполняемым клиентом был запущен сеанс: проверьте способ запуска вручную.

  3. Создайте нового отдельного пользователя АвторВариантов85 только в этой новой базе. Не переименовывайте и не используйте рабочего пользователя. Сеанс всегда запускайте им: guard проверяет точное ИмяПользователя().

  4. Создайте собственную роль ПакетыУчебные85: доступ только к своему отчёту УчебныеГраницыПакетов85, его собственной форме и своему общему пульту, просмотр/использование форм. В правах корня конфигурации включите ТолстыйКлиент (ThickClient), РежимОсновногоОкнаОбычный (MainWindowModeNormal) и СохранениеДанныхПользователя (SaveUserData). После обновления конфигурации базы данных назначьте эту роль новому пользователю АвторВариантов85. Не выдавайте учебному пользователю Администрирование, АдминистрированиеДанных или ОбновлениеКонфигурацииБазыДанных. Отчёт не требует чтения или записи предметных объектов; локальный запрос состоит только из трёх константных строк.

  5. У конфигурации свойства ХранилищеВариантовОтчетов и ХранилищеПользовательскихНастроекОтчетов оставьте незаданными. Это необходимое соответствие стандартному внутреннему хранилищу, которое получает авторский код; при собственном прикладном хранилище отчётный setter мог бы читать другое место.

  6. Метаданные → Отчёты: создайте собственный УчебныеГраницыПакетов85. ОсновнаяСхемаКомпоновкиДанных в метаданных не нужна: полный модуль строит собственную схему в памяти и присваивает реальному ОтчетОбъект.СхемаКомпоновкиДанных. Никаких таблиц базы и внешних наборов нет.

  7. В УчебныеГраницыПакетов85 → Формы создайте управляемую форму отчёта ПрофилиГраниц85 типа Основная. Не обычную форму. Укажите её основной формой отчёта.

  8. Основной реквизит формы Отчет — ОтчетОбъект.УчебныеГраницыПакетов85, флаг Основной. Реквизит Результат — ТабличныйДокумент. Элемент ПолеРезультата — поле табличного документа, ПутьКДанным = Результат. Имена собственные, не предполагаются имена автоматически созданных элементов.

  9. Добавьте реквизиты формы СостояниеУрока (Строка неограниченная), МаршрутКомпоновки (Булево), СобытийДо и СобытийПосле (Число 9,0 неотрицательное). Счётчики относятся только к маршруту событий, не к строкам или числам отчёта. Добавьте поле состояния с ПутьКДанным = СостояниеУрока.

  10. В событиях именно формы назначьте ПриСозданииНаСервере → ПриСозданииНаСервере, ПриКомпоновкеРезультата → ПриКомпоновкеРезультата, ПослеКомпоновкиРезультата → ПослеКомпоновкиРезультата. Не создавайте эти обработчики в модуле объекта отчёта; его одноимённые события имеют другой контракт.

  11. Создайте собственные команды формы и кнопки с действиями: СоздатьСвоиПрофили → СоздатьСвоиПрофили; УзкиеГраницы → УзкиеГраницы; ВернутьВсе → ВернутьВсе. Все имена обработчиков приведены в основном полном модуле. Штатные произвольные кнопки сохранения/загрузки не используйте в этом опыте.

  12. Точное место основного блока: модуль управляемой формы Отчет.УчебныеГраницыПакетов85.Форма.ПрофилиГраниц85. Замените только модуль своей новой формы целиком, не добавляйте неизвестные общие модули и helpers.

  13. Вся схема задаётся основным блоком: источник ИсточникПакетов85 типа Local, набор запроса Пакеты85 с АвтоЗаполнениеДоступныхПолей = Истина; Пакет (Строка), Количество (Число) и Сумма (Число) образуются константным запросом ПакетА/3/60, ПакетБ/1/20, ПакетВ/6/120. Детальные записи без промежуточных или общего итога. Поля выбора Подробно85: Пакет,Количество,Сумма; Кратко85: Пакет,Сумма.

  14. Не привязывайте пригодность схемы или числовую правильность результата к служебному флагу. ПослеКомпоновкиРезультата проверяет только actual тип параметра ТабличныйДокумент и маршрут штатной компоновки. Координаты вывода не предполагаются: полный состав реальных строк и значения читатель проверит в ПолеРезультата вручную.

  15. Добавьте реквизит XMLБазы (Строка неограниченная); полный typed XML-снимок только своего базового Settings. Параметры задаёт авторский модуль: дополнительных form-параметров и пользовательского ручного числового ввода нет.

  16. Метаданные → Общие формы: создайте управляемую ПультПрофилейГраниц85 без основного реквизита и предметных данных. Команды/кнопки ОткрытьСвойОтчет → ОткрытьСвойОтчет и ЗакрытьИУдалитьСозданное → ЗакрытьИУдалитьСозданное. Событие ПриСозданииНаСервере назначьте одноимённому обработчику. Точное место supporting-блока: модуль общей управляемой формы ПультПрофилейГраниц85; вставьте полный блок именно туда целиком.

  17. Пульт держит только свой реальный экземпляр РабочаяФорма, полученный с новым УникальныйИдентификатор в четвёртом аргументе ПолучитьФорму. Не открывайте второй отчёт с теми же ключами, не перезапускайте пульт до cleanup и не изменяйте профили через другие формы.

  18. Полный supporting-блок запуска вставьте в модуль управляемого приложения этой новой пустой конфигурации; ПриНачалеРаботыСистемы вызывает только ОбщаяФорма.ПультПрофилейГраниц85. Для разных уроков запускайте соответствующий полный блок, не три обработчика одинакового имени сразу.

  19. В форме добавьте реквизиты Строка неограниченная: ПользовательОпытов, ОбластьКлючей, ПрефиксКлючей, КлючА, КлючБ, КлючБазы; Булево: СозданА, СозданБ, СозданБаза, ОчиститьА, ОчиститьБ, ОчиститьБазу, ХранилищеПодтверждено. Сгенерированный UUID становится частью строкового namespace только для нового опыта; до фактических Save, Load и полного сравнения это не существующий вариант или профиль.

  20. Сохраняющий код выполняет внутренние записи настроек только при вашем будущем запуске в этой новой базе. Пять аргументов Save: объект, ключ, actual настройки, ОписаниеНастроек с представлением, captured current пользователь; четыре аргумента Load: объект, ключ, output описание, тот же пользователь. Неопределено после Load — отсутствие записи и отказ, не объект настроек.

  21. После precheck отсутствия собственного ключа, до вызова Save фиксируется Очистить* — ownership точного pending ключа; исключение Save не доказывает отсутствие возможной частичной записи. После нормально завершённого Save отдельно фиксируется Создан*. Только после всех typed readback разрешается ХранилищеПодтверждено. Ошибки Save/readback перехватываются внутри серверной процедуры с исходной диагностикой и нормальным возвратом формы; client False не продолжает setter. Квитанция сохраняет все точные pending ключи для узкой cleanup даже при сбое.

  22. Не закрывайте отчёт вручную. Полный supporting-блок пульта получает actual квитанцию у собственного экземпляра, закрывает его и требует Открыта() = Ложь до серверной очистки. Не изменяйте квитанцию и не передавайте в cleanup произвольную структуру; это узкий стенд одного собственного пользователя, не сервис удаления пользовательских ключей.

  23. Очистка удаляет только свои отмеченные pending ключи, отсутствовавшие перед собственным Save, включая возможную частичную запись при его исключении. Ровно три непустые строки: свой объект, свой ключ, свой current пользователь. Namespace и принадлежность квитанции проверяются до Delete; readback должен стать Неопределено. При сбое выводятся точные свои ключи/отметки, квитанция остаётся и очистка не объявляется завершённой. Системное хранилище, текущие ключи формы, историю и все настройки пользователя код не очищает.

  24. После всех подготовок метаданных, реквизитов, событий, команд, полных модулей формы/пульта/управляемого приложения и прав роли автор стенда в конфигураторе сохраняет конфигурацию и выполняет Конфигурация → Обновить конфигурацию базы данных (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", , , Новый УникальныйИдентификатор);
КонецПроцедуры

Разбор по шагам

  1. Подготовьте новый пустой стенд, нового пользователя, роль с СохранениеДанныхПользователя, свой отчёт/форму, отдельный пульт и соответствующий полный запуск. Здесь всё остаётся текстом, runtime0.

  2. Откройте только собственный экземпляр через пульт. Полный модуль строит query с двумя настоящими schema-параметрами Минимум и Максимум; тип каждого — ОписаниеТипов("Число",КвалификаторыЧисла(1,0,Неотрицательный)).

  3. Проверьте подготовку источника/полей/детальных записей. Для каждого основного значения устанавливаются ID ГраницаПакетов85_Минимум/Максимум и представления Количество: Минимум/Максимум; использование включено. LoadSettings заново получает user-копию на основе этих настроек.

  4. Нажмите СоздатьСвоиПрофили. До Save профиль0..9 обязан иметь ровно два parameter-value элемента, только собственные uniqueID, Number значения, Bool использование=true, typed РежимОтображения=Авто; основные и дополнительные свойства пусты, actual ДополнительныеНастройки имеют0элементов/0свойств. Иной состав — отказ.

  5. Реальный базовый вариант сначала записывается под КлючБазы и проверяется полным typed XML+описанием+границами0..9. Профили пишутся строго под native объектом Отчет.УчебныеГраницыПакетов85/реальныйКлючБазы, не под выдуманным UUID-вариантом.

  6. Профиль Все0..9 сохраняется и целиком сверяется при readback; затем новый LoadSettings создаёт user-слой Узко2..3. В каждом профиле явно задаётся сохранённый режим Авто, затем меняются числовые Значение. Main режим Обычный остаётся прежним; Авто получает его из основных настроек, но это не ручная проверка UI. Readonly контейнеры, user.Параметр, user.Родитель, user.ЗначенияВложенныхПараметров и user.ПредставлениеПользовательскойНастройки не читаются/не переприсваиваются.

  7. До report-setters оба полных user-профиля, их сохранённые представления и неизменность всего сохранённого базового Settings проверяются; после выбора реальные текущие ключи/представления и effective0..9 обязаны совпасть.

  8. В actual ПолеРезультата вручную сверяйте все три детали ПакетА/3/60, ПакетБ/1/20, ПакетВ/6/120. Общего итога схема не задаёт. Флаг событий не делает эту сверку вместо вас.

  9. Нажмите УзкиеГраницы: повторное полное Load-сравнение, настоящий текущий базовый вариант, текущий profile-key/представление; основная база остаётся0..9, actual effective становится2..3. В actual документе вручную должна остаться единственная полная деталь ПакетА/3/60.

  10. Нажмите ВернутьВсе: actual effective0..9 и прежний базовый ключ/представление; вручную снова сверяйте все три детали. Не используйте автоимена клеток или ожидаемый Python-список как доказательство вывода.

  11. В пульте ЗакрытьИУдалитьСозданное получает квитанцию, закрывает только свою форму и требует Открыта=false. Cleanup удаляет учтённые А/Б из report/base namespace, затем учтённую базу из report namespace; каждый readback — Неопределено.

Как проверить результат

  1. Оба parameter ID и оба main-представления реально проверяются; их прежнее supporting-only использование не считалось API покрытием.

  2. Полный user-состав проверяется до Save и после Load: тип, ровно2элемента, оба uniqueID, Number значения, Bool использование=true, собственный enum Авто, отсутствие неожиданных элементов и дополнительных свойств/настроек. Actual main Обычный — источник режима для user Авто по native; поле режима в числовой effective-копии не используется как обещание разрешения Авто. UI вручную; режим включён для полноты payload, не отдельного покрытия.

  3. Для user-копии используются документированные Элементы.Найти(StringID); ПолучитьОбъектПоИдентификатору с типом ИдентификаторКомпоновкиДанных здесь не подменён строкой.

  4. ПредставлениеПользовательскойНастройки и Параметр читаются только у основной настройки, не у user-объекта.

  5. Числа ограничены собственными целыми0..9; явные qualifiers обязательны. Строка "3" или неверный ID не допускаются.

  6. Полное базовое Settings + описание сохраняются неизменными, текущий базовый ключ проверен до и после user-setter; effective границы подтверждены actual компоновщиком.

  7. Числовой/визуальный результат0..9/2..3/0..9 отдельно ручной; actual события показывают только маршрут, не данные.

Ожидаемый результат

Будущий результат: создан и fully readback-проверен свой базовый вариант и два минимальных user-профиля; report-setters меняют actual effective границы при сохранении базы; реальные детали сверены вручную, затем удалены только три созданные записи. Здесь runtime0 и никаких записей.

На что обратить внимание

  1. Только новый именованный пользователь собственной новой базы; всё сохраняющее поведение — будущий ручной BSL, не исполнение здесь.

  2. Это не универсальный comparer чужого графа UserSettings. Подготовка допускает только два своих параметра; неожиданные основные или дополнительные элементы/свойства приводят к отказу, не игнорируются.

  3. Нативный тип UserSettings не обещает XML/XDTO: полный user-профиль сравнивается структурно, XML применяется только к документированному Settings.

  4. ДополнительныеНастройки readonly UserSettings содержат элементы, отмеченные в отборе/условном оформлении; наша схема их не создаёт. Вложенный произвольный граф дополнительных настроек не поддерживается.

  5. Не меняйте пользовательские ID вручную после создания; новый профиль должен оставаться exact составом своего базового варианта.

  6. Если runtime LoadSettings неожиданно добавит элементы или дополнительные свойства, урок fail-closed остановится; нельзя удалить их для искусственного сообщения успех.

  7. Сохранённый базовый вариант, основная настройка компоновщика и effective-результат — разные уровни; user0..9↔2..3 не переписывает сохранённую базу.

  8. Закрытие/смена варианта может писать внутренние системные текущие настройки. Точечное удалениеА/Б/База не удаляет системную историю, весь профиль и не обещает отсутствие внутренних операций.

  9. Ни один Delete не может использовать Неопределено или пустую строку вместо собственного объекта/ключа/пользователя.

  10. Ожидаемые детали выведены из своего константного запроса для будущего ручного протокола; это не подтверждение actual табличного результата статическими тестами.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.