Содержит вариант настроек компоновки данных.
Полное описание, параметры и ограничения
ВариантНастроекКомпоновкиДанных (DataCompositionSettingsVariant)
ВариантНастроекКомпоновкиДанных (DataCompositionSettingsVariant)
Доступен, начиная с версии 8.2.
Свойства:
Имя (Name)
Настройки (Settings)
Представление (Presentation)
Описание:
Содержит вариант настроек компоновки данных.
Доступность:
Сервер, толстый клиент, внешнее соединение, мобильное приложение (сервер), мобильный автономный сервер.
См. также:
ВариантыНастроекКомпоновкиДанных, метод Получить
ВариантыНастроекКомпоновкиДанных, метод Добавить
ВариантыНастроекКомпоновкиДанных, метод Вставить
ВариантыНастроекКомпоновкиДанных, метод Удалить
ВариантыНастроекКомпоновкиДанных, метод Индекс
ВариантыНастроекКомпоновкиДанных, метод Сдвинуть
Использование в версии:
Доступен, начиная с версии 8.2.
Методическая информация
Практические примеры
Два локальных варианта: Сдвинуть объектом, получить новый первый и восстановить
Собственная схема пакетов создаёт Подробно85 и Кратко85, а не использует сохранённые UUID. НастройкиПоУмолчанию по native принадлежат первому варианту. На сервере переносится настоящий ВариантНастроекКомпоновкиДанных; фактические индексы, имена, представления и полный выбор проверяются до загрузки в реальный отчёт. Затем возвращается именно исходный собственный порядок. Числа и внешний вид результата проверяются отдельно вручную; запуск 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 тип параметра ТабличныйДокумент и маршрут штатной компоновки. Координаты вывода не предполагаются: полный состав реальных строк и значения читатель проверит в ПолеРезультата вручную.
Добавьте реквизит КраткийПервый (Булево). Только модуль устанавливает его после успешной фактической проверки собственного порядка.
Полный supporting-блок запуска вставьте в модуль управляемого приложения этой новой пустой конфигурации; ПриНачалеРаботыСистемы вызывает только Отчет.УчебныеЛокальныеВарианты85.Форма.ЛокальныйПорядок85. Для разных уроков запускайте соответствующий полный блок, не три обработчика одинакового имени сразу.
После всех подготовок метаданных, реквизитов, событий, команд, полных модулей формы/пульта/управляемого приложения и прав роли автор стенда в конфигураторе сохраняет конфигурацию и выполняет Конфигурация → Обновить конфигурацию базы данных (F7). Подтвердите обновление именно новой учебной базы. Это действие автора стенда, а не требование административных прав у учебного пользователя. После F7 проверьте назначение роли ПакетыУчебные85 пользователю АвторВариантов85 и только затем запускайте собственный управляемый сеанс этим пользователем.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Попытка
ПроверитьУчебнуюСреду();
Если ЭтаФорма.ТипФормыОтчета <> ТипФормыОтчета.Основная Тогда
ВызватьИсключение "Нужна собственная управляемая форма отчёта Основная";
КонецЕсли;
ЭтаФорма.РежимБлокировкиПриОткрытииОкна = РежимБлокировкиПриОткрытииОкнаФормы.НеБлокировать;
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
ОбъектОтчета.СхемаКомпоновкиДанных = СоздатьСобственнуюСхему();
ОбъектОтчета.КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(ОбъектОтчета.СхемаКомпоновкиДанных));
ОбъектОтчета.КомпоновщикНастроек.ЗагрузитьНастройки(ОбъектОтчета.СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
ЭтаФорма.ЗначениеВРеквизитФормы(ОбъектОтчета, "Отчет");
ЭтаФорма.СобытийДо = 0;
ЭтаФорма.СобытийПосле = 0;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Собственная схема готова; числа и внешний вид не проверены";
ПроверитьПорядок(ОбъектОтчета.СхемаКомпоновкиДанных, Ложь);
ЭтаФорма.КраткийПервый = Ложь;
Исключение
Отказ = Истина;
ВызватьИсключение "Подготовка остановлена: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьУчебнуюСреду()
Если ИмяПользователя() <> "АвторВариантов85" Тогда
ВызватьИсключение "Нужен отдельный новый именованный пользователь АвторВариантов85";
КонецЕсли;
Если КлиентскоеПриложение.ТекущийВариантИнтерфейса() <> ВариантИнтерфейсаКлиентскогоПриложения.Такси Тогда
ВызватьИсключение "Нужен собственный толстый управляемый сеанс Такси";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СоздатьСобственнуюСхему()
Схема = Новый СхемаКомпоновкиДанных;
Источник = Схема.ИсточникиДанных.Добавить();
Источник.Имя = "ИсточникПакетов85";
Источник.ТипИсточникаДанных = "Local";
Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
Набор.Имя = "Пакеты85";
Набор.ИсточникДанных = Источник.Имя;
Набор.АвтоЗаполнениеДоступныхПолей = Истина;
Набор.Запрос = "ВЫБРАТЬ ""ПакетА"" КАК Пакет, 3 КАК Количество, 60 КАК Сумма
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ""ПакетБ"", 1, 20
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ""ПакетВ"", 6, 120";
Схема.ВариантыНастроек.Очистить();
Подробный = Схема.ВариантыНастроек.Добавить();
Подробный.Имя = "Подробно85";
Подробный.Представление = "Все три поля пакетов";
ЗаполнитьНастройки(Подробный.Настройки, "Пакет,Количество,Сумма");
Краткий = Схема.ВариантыНастроек.Добавить();
Краткий.Имя = "Кратко85";
Краткий.Представление = "Пакет и сумма";
ЗаполнитьНастройки(Краткий.Настройки, "Пакет,Сумма");
Возврат Схема;
КонецФункции
&НаСервереБезКонтекста
Процедура ЗаполнитьНастройки(Настройки, ИменаПолей)
Для Каждого ИмяПоля Из СтрРазделить(ИменаПолей, ",") Цикл
Выбранное = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
Выбранное.Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);
Выбранное.Использование = Истина;
КонецЦикла;
Детали = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
Детали.Использование = Истина;
АвтоВыбор = Детали.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
АвтоВыбор.Использование = Истина;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьПолныйВыбор(Настройки, ИменаПолей)
Если ТипЗнч(Настройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Нет типизированных настроек выбора";
КонецЕсли;
Ожидаемые = СтрРазделить(ИменаПолей, ",");
Если Настройки.Выбор.Элементы.Количество() <> Ожидаемые.Количество() Тогда
ВызватьИсключение "Изменился полный состав выбранных полей";
КонецЕсли;
Для Индекс = 0 По Ожидаемые.Количество() - 1 Цикл
ПолеВыбора = Настройки.Выбор.Элементы.Получить(Индекс);
Если ТипЗнч(ПолеВыбора) <> Тип("ВыбранноеПолеКомпоновкиДанных") Тогда
ВызватьИсключение "В выборе появился неподдерживаемый элемент";
КонецЕсли;
Если ПолеВыбора.Поле <> Новый ПолеКомпоновкиДанных(Ожидаемые[Индекс]) Или ТипЗнч(ПолеВыбора.Использование) <> Тип("Булево") Или Не ПолеВыбора.Использование Тогда
ВызватьИсключение "Не совпало поле или его использование";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервере
Процедура ПриКомпоновкеРезультата(СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СобытийДо = ЭтаФорма.СобытийДо + 1;
КонецПроцедуры
&НаСервере
Процедура ПослеКомпоновкиРезультата(Результат, СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.СобытийПосле = ЭтаФорма.СобытийПосле + 1;
Если ТипЗнч(Результат) <> Тип("ТабличныйДокумент") Тогда
ВызватьИсключение "Событие формы не передало фактический ТабличныйДокумент";
КонецЕсли;
ЭтаФорма.МаршрутКомпоновки = Истина;
КонецПроцедуры
&НаКлиенте
Процедура СформироватьДляРучнойСверки()
До = ЭтаФорма.СобытийДо;
После = ЭтаФорма.СобытийПосле;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СкомпоноватьРезультат(РежимКомпоновкиРезультата.Непосредственно);
Если Не ЭтаФорма.МаршрутКомпоновки Или ЭтаФорма.СобытийДо <> До + 1 Или ЭтаФорма.СобытийПосле <> После + 1 Тогда
ВызватьИсключение "Не подтверждён маршрут событий формы";
КонецЕсли;
Сообщить("Подтверждён только маршрут компоновки. Строки, поля и числа actual результата проверьте вручную");
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьПорядок(Схема, КраткийПервый)
Варианты = Схема.ВариантыНастроек;
Если Варианты.Количество() <> 2 Тогда
ВызватьИсключение "Собственная коллекция должна содержать ровно два варианта";
КонецЕсли;
Первый = Варианты.Получить(0);
Второй = Варианты.Получить(1);
Если Варианты.Индекс(Первый) <> 0 Или Варианты.Индекс(Второй) <> 1 Тогда
ВызватьИсключение "Не совпали фактические индексы объектов";
КонецЕсли;
Если Первый.Имя <> ?(КраткийПервый, "Кратко85", "Подробно85") Или Второй.Имя <> ?(КраткийПервый, "Подробно85", "Кратко85") Тогда
ВызватьИсключение "Не совпал полный порядок собственных вариантов";
КонецЕсли;
Если Первый.Представление <> ?(КраткийПервый, "Пакет и сумма", "Все три поля пакетов") Или Второй.Представление <> ?(КраткийПервый, "Все три поля пакетов", "Пакет и сумма") Тогда
ВызватьИсключение "Изменились собственные представления вариантов";
КонецЕсли;
ПроверитьПолныйВыбор(Первый.Настройки, ?(КраткийПервый, "Пакет,Сумма", "Пакет,Количество,Сумма"));
ПроверитьПолныйВыбор(Второй.Настройки, ?(КраткийПервый, "Пакет,Количество,Сумма", "Пакет,Сумма"));
ПроверитьПолныйВыбор(Схема.НастройкиПоУмолчанию, ?(КраткийПервый, "Пакет,Сумма", "Пакет,Количество,Сумма"));
КонецПроцедуры
&НаСервере
Процедура ПереставитьСобственныйВариант(КраткийПервый)
ПроверитьУчебнуюСреду();
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
Схема = ОбъектОтчета.СхемаКомпоновкиДанных;
ПроверитьПорядок(Схема, ЭтаФорма.КраткийПервый);
Если ЭтаФорма.КраткийПервый <> КраткийПервый Тогда
Варианты = Схема.ВариантыНастроек;
Перемещаемый = Варианты.Получить(1);
Варианты.Сдвинуть(Перемещаемый, -1);
Если Варианты.Индекс(Перемещаемый) <> 0 Тогда
ВызватьИсключение "Настоящий Сдвинуть объектом не переместил выбранный вариант";
КонецЕсли;
КонецЕсли;
ПроверитьПорядок(Схема, КраткийПервый);
ОбъектОтчета.КомпоновщикНастроек.ЗагрузитьНастройки(Схема.НастройкиПоУмолчанию);
ПроверитьПолныйВыбор(ОбъектОтчета.КомпоновщикНастроек.ПолучитьНастройки(), ?(КраткийПервый, "Пакет,Сумма", "Пакет,Количество,Сумма"));
ЭтаФорма.ЗначениеВРеквизитФормы(ОбъектОтчета, "Отчет");
ЭтаФорма.КраткийПервый = КраткийПервый;
ЭтаФорма.СостояниеУрока = ?(КраткийПервый, "Краткий вариант действительно первый", "Исходный Подробно85 действительно восстановлен первым");
КонецПроцедуры
&НаКлиенте
Процедура КраткийПервым(Команда)
Попытка
ПереставитьСобственныйВариант(Истина);
СформироватьДляРучнойСверки();
Исключение
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Перестановка или компоновка не подтверждена: " + ОписаниеОшибки();
КонецПопытки;
Сообщить(ЭтаФорма.СостояниеУрока);
КонецПроцедуры
&НаКлиенте
Процедура ВосстановитьПодробный(Команда)
Попытка
ПереставитьСобственныйВариант(Ложь);
СформироватьДляРучнойСверки();
Исключение
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СостояниеУрока = "Восстановление или компоновка не подтверждены: " + ОписаниеОшибки();
КонецПопытки;
Сообщить(ЭтаФорма.СостояниеУрока);
КонецПроцедурыПолный запуск собственного стенда
Модуль управляемого приложения новой конфигурации УчебныеВариантыПакетов85; событие ПриНачалеРаботыСистемы
Толстый клиент, управляемое приложение
Процедура ПриНачалеРаботыСистемы()
ОткрытьФорму("Отчет.УчебныеЛокальныеВарианты85.Форма.ЛокальныйПорядок85", , , Новый УникальныйИдентификатор);
КонецПроцедурыРазбор по шагам
Подготовьте новую базу/пользователя и полную форму, вставьте её модуль и соответствующий запуск. Здесь выполнены только статические и модельные проверки, не запуск платформы.
Запустите собственный толстый управляемый сеанс. Проверка исходного порядка требует ровно два реально созданных варианта: Подробно85 индекс0, Кратко85 индекс1; иной состав останавливает создание формы.
Нажмите КраткийПервым. Код получает именно объект второго варианта и вызывает Сдвинуть(Перемещаемый,-1), не передаёт индекс вместо объекта.
После переноса должны совпасть фактические индексы0/1, оба собственных имени/представления и оба полных выбора. НастройкиПоУмолчанию должны содержать Пакет,Сумма.
В actual компоновщик загружается новая настройка первого варианта; его effective выбор проверяется полностью перед штатной компоновкой.
В ПолеРезультата вручную проверьте все три детальные строки и ровно два выбранных поля: ПакетА/60, ПакетБ/20, ПакетВ/120. Порядок самих записей запросом не задан; сверяйте состав, не координаты.
Нажмите ВосстановитьПодробный. Теперь второй объект Подробно85 перемещается на первое место, возвращаются исходные индексы, оба полных выбора и подробные настройки по умолчанию.
В actual результате вручную проверьте состав ПакетА/3/60, ПакетБ/1/20, ПакетВ/6/120 и три выбранных поля. Повторный возврат не должен менять уже восстановленный порядок.
Как проверить результат
Нет constructor ВариантНастроекКомпоновкиДанных: объекты получены только Добавить()/Получить().
Readonly Настройки и НастройкиПоУмолчанию не переприсваиваются; изменяется собственная коллекция и содержимое своего объекта настроек.
Сдвинуть использует VariantObject и числовое смещение, затем реальные Индекс и Получить подтверждают полный порядок.
Флаг маршрута требует actual события и ТабличныйДокумент, но не доказывает реальные значения; визуальные и числовые результаты — ручные.
Оба обратных действия проверяют исходный состав собственных настроек, не предполагают начальные элементы конструктора схемы.
Ожидаемый результат
Будущий успешный опыт: краткий объект стал первым, изменился default и effective выбор; подробный порядок затем восстановлен. Два actual вывода сверены вручную. Сейчас runtime0.
На что обратить внимание
Очистить применяется только к ВариантыНастроек новой схемы в памяти, не к внутреннему хранилищу и не к чужим сохранённым вариантам.
Не присваивайте readonly Вариант.Настройки или Схема.НастройкиПоУмолчанию.
Это не УстановитьТекущийВариант: локальный объект и его имя не являются ключом записи отчётного хранилища.
Нельзя заменить Сдвинуть объектом на выдуманный overload с индексом.
Схема не задаёт числового итога или порядка детальных записей; общий итог200 здесь не обещается.
Служебные проверки состава и событий не являются доказательством actual чисел или отображения.
Платформа может внутренне сохранять состояние формы; отсутствие явного Save в первом опыте не означает отсутствия всех внутренних операций.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Создать два настоящих своих варианта, переключить А→Б→А и удалить только их
Будущий BSL только новой базы и нового пользователя создаёт две реальные записи стандартного внутреннего хранилища. Ключ допускается к УстановитьТекущийВариант только после Save, Load, полного typed XML-сравнения НастройкиКомпоновкиДанных и сохранённого описания. Actual ключ/представление формы и полный effective выбор проверяются отдельно. Числа и визуальный результат сверяются вручную, не выводятся из флагов; полный собственный пульт закрывает отчёт до точечного удаления. Здесь записей и runtime0.
Где и как запускать
Смешанный управляемый: толстый клиент 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 тип параметра ТабличныйДокумент и маршрут штатной компоновки. Координаты вывода не предполагаются: полный состав реальных строк и значения читатель проверит в ПолеРезультата вручную.
В report-форме дополнительно реквизиты XMLА и XMLБ — Строка неограниченная. Это полные строковые снимки сериализованного состояния собственных actual настроек, а не адреса файлов.
Метаданные → Общие формы: создайте управляемую ПультСохраненныхВариантов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_" + ЭтаФорма.ОбластьКлючей + "_";
ЭтаФорма.КлючА = ЭтаФорма.ПрефиксКлючей + "А";
ЭтаФорма.КлючБ = ЭтаФорма.ПрефиксКлючей + "Б";
ЭтаФорма.КлючБазы = "";
ЭтаФорма.СозданА = Ложь;
ЭтаФорма.СозданБ = Ложь;
ЭтаФорма.СозданБаза = Ложь;
ЭтаФорма.ОчиститьА = Ложь;
ЭтаФорма.ОчиститьБ = Ложь;
ЭтаФорма.ОчиститьБазу = Ложь;
ЭтаФорма.ХранилищеПодтверждено = Ложь;
Исключение
Отказ = Истина;
ВызватьИсключение "Подготовка остановлена: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьУчебнуюСреду()
Если ИмяПользователя() <> "АвторВариантов85" Тогда
ВызватьИсключение "Нужен отдельный новый именованный пользователь АвторВариантов85";
КонецЕсли;
Если КлиентскоеПриложение.ТекущийВариантИнтерфейса() <> ВариантИнтерфейсаКлиентскогоПриложения.Такси Тогда
ВызватьИсключение "Нужен собственный толстый управляемый сеанс Такси";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СоздатьСобственнуюСхему()
Схема = Новый СхемаКомпоновкиДанных;
Источник = Схема.ИсточникиДанных.Добавить();
Источник.Имя = "ИсточникПакетов85";
Источник.ТипИсточникаДанных = "Local";
Набор = Схема.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
Набор.Имя = "Пакеты85";
Набор.ИсточникДанных = Источник.Имя;
Набор.АвтоЗаполнениеДоступныхПолей = Истина;
Набор.Запрос = "ВЫБРАТЬ ""ПакетА"" КАК Пакет, 3 КАК Количество, 60 КАК Сумма
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ""ПакетБ"", 1, 20
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ ""ПакетВ"", 6, 120";
Схема.ВариантыНастроек.Очистить();
Подробный = Схема.ВариантыНастроек.Добавить();
Подробный.Имя = "Подробно85";
Подробный.Представление = "Все три поля пакетов";
ЗаполнитьНастройки(Подробный.Настройки, "Пакет,Количество,Сумма");
Краткий = Схема.ВариантыНастроек.Добавить();
Краткий.Имя = "Кратко85";
Краткий.Представление = "Пакет и сумма";
ЗаполнитьНастройки(Краткий.Настройки, "Пакет,Сумма");
Возврат Схема;
КонецФункции
&НаСервереБезКонтекста
Процедура ЗаполнитьНастройки(Настройки, ИменаПолей)
Для Каждого ИмяПоля Из СтрРазделить(ИменаПолей, ",") Цикл
Выбранное = Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
Выбранное.Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);
Выбранное.Использование = Истина;
КонецЦикла;
Детали = Настройки.Структура.Добавить(Тип("ГруппировкаКомпоновкиДанных"));
Детали.Использование = Истина;
АвтоВыбор = Детали.Выбор.Элементы.Добавить(Тип("АвтоВыбранноеПолеКомпоновкиДанных"));
АвтоВыбор.Использование = Истина;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПроверитьПолныйВыбор(Настройки, ИменаПолей)
Если ТипЗнч(Настройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Нет типизированных настроек выбора";
КонецЕсли;
Ожидаемые = СтрРазделить(ИменаПолей, ",");
Если Настройки.Выбор.Элементы.Количество() <> Ожидаемые.Количество() Тогда
ВызватьИсключение "Изменился полный состав выбранных полей";
КонецЕсли;
Для Индекс = 0 По Ожидаемые.Количество() - 1 Цикл
ПолеВыбора = Настройки.Выбор.Элементы.Получить(Индекс);
Если ТипЗнч(ПолеВыбора) <> Тип("ВыбранноеПолеКомпоновкиДанных") Тогда
ВызватьИсключение "В выборе появился неподдерживаемый элемент";
КонецЕсли;
Если ПолеВыбора.Поле <> Новый ПолеКомпоновкиДанных(Ожидаемые[Индекс]) Или ТипЗнч(ПолеВыбора.Использование) <> Тип("Булево") Или Не ПолеВыбора.Использование Тогда
ВызватьИсключение "Не совпало поле или его использование";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолныйТипизированныйXML(Настройки)
Если ТипЗнч(Настройки) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Ожидался полный тип НастройкиКомпоновкиДанных";
КонецЕсли;
Писатель = Новый ЗаписьXML;
Писатель.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Писатель, Настройки, НазначениеТипаXML.Явное);
Текст = Писатель.Закрыть();
Если ТипЗнч(Текст) <> Тип("Строка") Или Текст = "" Тогда
ВызватьИсключение "Сериализация полного объекта не дала XML";
КонецЕсли;
Читатель = Новый ЧтениеXML;
Читатель.УстановитьСтроку(Текст);
Копия = СериализаторXDTO.ПрочитатьXML(Читатель, Тип("НастройкиКомпоновкиДанных"));
Читатель.Закрыть();
Если ТипЗнч(Копия) <> Тип("НастройкиКомпоновкиДанных") Тогда
ВызватьИсключение "Полный XML не восстановил тип настроек";
КонецЕсли;
Писатель = Новый ЗаписьXML;
Писатель.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(Писатель, Копия, НазначениеТипаXML.Явное);
Если Писатель.Закрыть() <> Текст Тогда
ВызватьИсключение "Полный typed XML roundtrip нестабилен; ключ не допускается к setter";
КонецЕсли;
Возврат Текст;
КонецФункции
&НаСервере
Процедура ПроверитьСвоиКлючи()
ПроверитьУчебнуюСреду();
Если ЭтаФорма.ПользовательОпытов <> ИмяПользователя() Или ЭтаФорма.ПользовательОпытов = "" Тогда
ВызватьИсключение "Изменился собственный именованный пользователь";
КонецЕсли;
Если ЭтаФорма.ОбластьКлючей = "" Или ЭтаФорма.ПрефиксКлючей <> "УчебныеПакеты85_" + ЭтаФорма.ОбластьКлючей + "_" Тогда
ВызватьИсключение "Повреждён собственный namespace ключей";
КонецЕсли;
Для Каждого Ключ Из СтрРазделить(ЭтаФорма.КлючА + "," + ЭтаФорма.КлючБ + "," + ЭтаФорма.КлючБазы, ",") Цикл
Если Ключ <> "" И Лев(Ключ, СтрДлина(ЭтаФорма.ПрефиксКлючей)) <> ЭтаФорма.ПрефиксКлючей Тогда
ВызватьИсключение "Обнаружен ключ вне созданного namespace";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция ПолучитьКвитанциюОчистки() Экспорт
ПроверитьСвоиКлючи();
Возврат Новый Структура("Объект,Область,Префикс,Пользователь,КлючА,КлючБ,КлючБазы,СозданА,СозданБ,СозданБаза,ОчиститьА,ОчиститьБ,ОчиститьБазу", "Отчет.УчебныеСохраненныеВарианты85", ЭтаФорма.ОбластьКлючей, ЭтаФорма.ПрефиксКлючей, ЭтаФорма.ПользовательОпытов, ЭтаФорма.КлючА, ЭтаФорма.КлючБ, ЭтаФорма.КлючБазы, ЭтаФорма.СозданА, ЭтаФорма.СозданБ, ЭтаФорма.СозданБаза, ЭтаФорма.ОчиститьА, ЭтаФорма.ОчиститьБ, ЭтаФорма.ОчиститьБазу);
КонецФункции
&НаСервере
Процедура ПриКомпоновкеРезультата(СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СобытийДо = ЭтаФорма.СобытийДо + 1;
КонецПроцедуры
&НаСервере
Процедура ПослеКомпоновкиРезультата(Результат, СтандартнаяОбработка)
СтандартнаяОбработка = Истина;
ЭтаФорма.СобытийПосле = ЭтаФорма.СобытийПосле + 1;
Если ТипЗнч(Результат) <> Тип("ТабличныйДокумент") Тогда
ВызватьИсключение "Событие формы не передало фактический ТабличныйДокумент";
КонецЕсли;
ЭтаФорма.МаршрутКомпоновки = Истина;
КонецПроцедуры
&НаКлиенте
Процедура СформироватьДляРучнойСверки()
До = ЭтаФорма.СобытийДо;
После = ЭтаФорма.СобытийПосле;
ЭтаФорма.МаршрутКомпоновки = Ложь;
ЭтаФорма.СкомпоноватьРезультат(РежимКомпоновкиРезультата.Непосредственно);
Если Не ЭтаФорма.МаршрутКомпоновки Или ЭтаФорма.СобытийДо <> До + 1 Или ЭтаФорма.СобытийПосле <> После + 1 Тогда
ВызватьИсключение "Не подтверждён маршрут событий формы";
КонецЕсли;
Сообщить("Подтверждён только маршрут компоновки. Строки, поля и числа actual результата проверьте вручную");
КонецПроцедуры
&НаСервере
Процедура СохранитьИПроверитьСвоиВарианты()
ПроверитьСвоиКлючи();
Если ЭтаФорма.СозданА Или ЭтаФорма.СозданБ Или ЭтаФорма.ОчиститьА Или ЭтаФорма.ОчиститьБ Тогда
ВызватьИсключение "Повторное Save запрещено: завершите этот опыт и точечную очистку через пульт";
КонецЕсли;
ЭтаФорма.ХранилищеПодтверждено = Ложь;
Попытка
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
Схема = ОбъектОтчета.СхемаКомпоновкиДанных;
ЭтаФорма.XMLА = ПолныйТипизированныйXML(Схема.ВариантыНастроек.Получить(0).Настройки);
ЭтаФорма.XMLБ = ПолныйТипизированныйXML(Схема.ВариантыНастроек.Получить(1).Настройки);
Хранилище = ПолучитьСтандартноеХранилищеВариантовОтчетов();
Объект = "Отчет.УчебныеСохраненныеВарианты85";
Если Хранилище.Загрузить(Объект, ЭтаФорма.КлючА, , ЭтаФорма.ПользовательОпытов) <> Неопределено Или Хранилище.Загрузить(Объект, ЭтаФорма.КлючБ, , ЭтаФорма.ПользовательОпытов) <> Неопределено Тогда
ВызватьИсключение "Save остановлен: один из новых ключей уже существует";
КонецЕсли;
Описание = Новый ОписаниеНастроек;
Описание.Представление = "Сохранённый подробный пакет85";
ЭтаФорма.ОчиститьА = Истина;
Хранилище.Сохранить(Объект, ЭтаФорма.КлючА, Схема.ВариантыНастроек.Получить(0).Настройки, Описание, ЭтаФорма.ПользовательОпытов);
ЭтаФорма.СозданА = Истина;
ПроверитьЗаписанныйВариант(Хранилище, ЭтаФорма.КлючА, ЭтаФорма.XMLА, "Сохранённый подробный пакет85");
Описание.Представление = "Сохранённый краткий пакет85";
ЭтаФорма.ОчиститьБ = Истина;
Хранилище.Сохранить(Объект, ЭтаФорма.КлючБ, Схема.ВариантыНастроек.Получить(1).Настройки, Описание, ЭтаФорма.ПользовательОпытов);
ЭтаФорма.СозданБ = Истина;
ПроверитьЗаписанныйВариант(Хранилище, ЭтаФорма.КлючБ, ЭтаФорма.XMLБ, "Сохранённый краткий пакет85");
ЭтаФорма.ХранилищеПодтверждено = Истина;
Исключение
ЭтаФорма.ХранилищеПодтверждено = Ложь;
ЭтаФорма.СостояниеУрока = "Save/readback остановлен: " + ОписаниеОшибки() + ". Нормальный серверный возврат сохраняет отметки завершённых Save для квитанции";
ЭтаФорма.СостояниеУрока = ЭтаФорма.СостояниеУрока + СтрШаблон(". Свои pending ключи: %1 [%2], %3 [%4]; очистка ещё не подтверждена", ЭтаФорма.КлючА, ЭтаФорма.ОчиститьА, ЭтаФорма.КлючБ, ЭтаФорма.ОчиститьБ);
КонецПопытки;
КонецПроцедуры
&НаСервере
Процедура ПроверитьЗаписанныйВариант(Хранилище, Ключ, ОжидаемыйXML, Представление)
Описание = Новый ОписаниеНастроек;
Прочитано = Хранилище.Загрузить("Отчет.УчебныеСохраненныеВарианты85", Ключ, Описание, ЭтаФорма.ПользовательОпытов);
Если Прочитано = Неопределено Тогда
ВызватьИсключение "После Save запись не найдена; setter запрещён";
КонецЕсли;
Если ПолныйТипизированныйXML(Прочитано) <> ОжидаемыйXML Или ТипЗнч(Описание.Представление) <> Тип("Строка") Или Описание.Представление <> Представление Тогда
ВызватьИсключение "Не совпали полный typed payload или описание сохранённого варианта";
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ЗагрузитьСвойСохраненныйВариант(Краткий)
ПроверитьСвоиКлючи();
Если Не ЭтаФорма.ХранилищеПодтверждено Тогда
ВызватьИсключение "Сначала Save+Load+полное typed сравнение обоих вариантов";
КонецЕсли;
Ключ = ?(Краткий, ЭтаФорма.КлючБ, ЭтаФорма.КлючА);
Представление = ?(Краткий, "Сохранённый краткий пакет85", "Сохранённый подробный пакет85");
ПроверитьЗаписанныйВариант(ПолучитьСтандартноеХранилищеВариантовОтчетов(), Ключ, ?(Краткий, ЭтаФорма.XMLБ, ЭтаФорма.XMLА), Представление);
ЭтаФорма.УстановитьТекущийВариант(Ключ);
Если ТипЗнч(ЭтаФорма.КлючТекущегоВарианта) <> Тип("Строка") Или ЭтаФорма.КлючТекущегоВарианта <> Ключ Или ТипЗнч(ЭтаФорма.ПредставлениеТекущегоВарианта) <> Тип("Строка") Или ЭтаФорма.ПредставлениеТекущегоВарианта <> Представление Тогда
ВызватьИсключение "Setter не подтвердил реальный ключ и сохранённое представление";
КонецЕсли;
ОбъектОтчета = ЭтаФорма.РеквизитФормыВЗначение("Отчет");
Если ПолныйТипизированныйXML(ОбъектОтчета.КомпоновщикНастроек.Настройки) <> ?(Краткий, ЭтаФорма.XMLБ, ЭтаФорма.XMLА) Тогда
ВызватьИсключение "В actual основных настройках формы изменился полный сохранённый вариант";
КонецЕсли;
ПроверитьПолныйВыбор(ОбъектОтчета.КомпоновщикНастроек.ПолучитьНастройки(), ?(Краткий, "Пакет,Сумма", "Пакет,Количество,Сумма"));
ЭтаФорма.СостояниеУрока = "Подтверждены Save/Load, setter и полный 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", , , Новый УникальныйИдентификатор);
КонецПроцедурыРазбор по шагам
Подготовьте новую базу, именованного пользователя, право СохранениеДанныхПользователя, report-форму, отдельный пульт и полный запуск. Ни один из этих блоков здесь не исполнялся.
Откройте отчёт исключительно кнопкой пульта. ПриСоздании строит свою схему и генерирует новый строковый namespace; сгенерированные строки пока не считаются существующими вариантами.
Нажмите СоздатьСвоиВарианты. До записи код получает полный XML обоих actual объектов, typed roundtrip требует тождественный XML; неканоническая или неподдержанная сериализация даёт отказ, не ложный успех.
Load обоих новых ключей до Save должен вернуть Неопределено. Иначе ничего не перезаписывается. Native object namespace: ровно Отчет.УчебныеСохраненныеВарианты85.
Оба успешных Save фиксируются до readback; Load должен восстановить НастройкиКомпоновкиДанных, весь сериализованный объект и своё описание. Только затем разрешается setter с КлючА.
Форма должна показать actual ключ/представление подробного варианта; effective выбор — Пакет,Количество,Сумма. После штатной компоновки вручную сверяйте три реальные строки А/3/60, Б/1/20, В/6/120.
Нажмите ВыбратьКраткий: повторный readback до setter, затем actual КлючБ/описание и полный effective выбор Пакет,Сумма. В actual выводе вручную сверяйте А/60, Б/20, В/120.
Нажмите ВернутьПодробный: повторите A-key, представление, три effective поля и ручную сверку actual результата. Не интерпретируйте изменение ключа как числовое доказательство.
Вернитесь в независимый пульт и нажмите ЗакрытьИУдалитьСозданное. Он получает квитанцию только своей формы, закрывает её, требует Открыта()=Ложь и удаляет только отмеченные pending ключи А/Б собственных Save-попыток; readback каждого — Неопределено. Возможная частичная запись при исключении Save тоже остаётся в квитанции.
При частичной ошибке cleanup квитанция не сбрасывается: можно повторить ту же узкую очистку. Не запускайте новый опыт до её завершения и не передавайте произвольные ключи.
Как проверить результат
Порядок Save(object,key,value,description,user) и Load(object,key,outputDescription,user) совпадает с HBK.
До каждого setter есть actual readback + полный typed payload + описание; UUID сам по себе не разрешает setter.
XML используется только для типа Settings, для которого native прямо разрешает XML/XDTO; нет записи файла, строки не нормализуются ради успеха.
Actual ключ/представление и полный effective выбор проверены; маршрут событий не выдаётся за правильность числа.
Пульт отдельно закрывает свой экземпляр и проверяет Открыта до Delete с тремя непустыми string-аргументами.
Очистка разрешена только отмеченным pending ключам своих Save-попыток, отсутствовавшим перед Save; actual завершённый Save и разрешённый после typed readback ключ — отдельные состояния. Readback после cleanup должен вернуть Неопределено.
Ожидаемый результат
Будущий проверенный путь: две реальные собственные записи → A/B/A report-setter → ручная сверка actual выводов → закрытие собственного экземпляра → Delete только A/B с отсутствием при readback. Здесь это только подготовленный код; runtime0.
На что обратить внимание
Сохраняющий сценарий допустим только в совершенно новой отдельной базе/у нового именованного пользователя; не запускайте его в рабочей базе.
Метаданные хранилищ должны быть незаданы; стандартный менеджер и отчётная форма иначе могут использовать разные хранилища.
Полный XML сравнивает сериализованное состояние Settings, а не доступные поля/кэш редактора. Native не обещает canonical XML: нестабильность означает отказ до setter, не обрезанное сравнение.
Setter также загружает пользовательские настройки, использованные с вариантом последними. Новый собственный ключ и отсутствие других действий — необходимое ограничение стенда.
Не проверяем и не обещаем автоматическое изменение ВариантМодифицирован/ПользовательскиеНастройкиМодифицированы.
Не закрывайте отчёт вручную и не изменяйте квитанцию: восстановление ownership чужого/старого закрытого экземпляра не предусмотрено.
Системные текущие ключи и last-user-settings платформа может писать сама; Delete двух собственных записей не очищает всю историю или профиль.
Ни одного Удалить с Неопределено или пустым пользовательским именем: каждый такой аргумент расширил бы удаление.
Флаги и effective выбор не доказывают числовой или визуальный результат; необходим будущий полный ручной протокол actual документа.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.