Глобальный контекст.ПараметрЗапуска

Свойства · LaunchParameter

Тип: Строка. Используется для доступа к параметру запуска, передаваемому через ключ командной строки /C.

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

Глобальный контекст.ПараметрЗапуска (Global context.LaunchParameter)

Глобальный контекст (Global context)

ПараметрЗапуска (LaunchParameter)

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

Использование:
Только чтение.
Описание:
Тип: Строка.
Используется для доступа к параметру запуска, передаваемому через ключ командной строки /C.
Доступность:

Тонкий клиент, веб-клиент, мобильный клиент, толстый клиент, мобильное приложение (клиент).

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

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

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

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

Свое клиентское приложение: учебное окно750 и возврат исходного оформления за два настоящих запуска

Настоящий readonly global КлиентскоеПриложение, не неизвестный исходный объект. Window/OS setters работают только внутри настоящего BeforeStart, заголовки — после открытия своего окна. Реальный baseline сохраняется в одном собственном user-scoped ключе и проверенно возвращается при втором ручном старте.

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

Главный APPLICATION целиком в реальный модуль управляемого приложения own УчебноеОкно85. Window/OS setters прямо в ПередНачаломРаботыСистемы(Отказ), title setters после появления окна. SERVER отдельно server-call общий модуль, FORM отдельно actual общая управляемая форма. Два ручных own WindowsThinTaxi/FileIB запуска.

Подготовка

  1. Подготовьте отдельную собственную Windows VM с платформой8.5.1.1343, тонким клиентом и управляемым интерфейсом Такси. Не используйте интерфейс Версия8_5 для этого опыта: native OS-caption setter там игнорируется. Это собственный клиент, не перебор/подключение чужих процессов или COM.

  2. Вручную создайте новый canonical nonzero UUID-marker и собственную пустую FileIB C:\1c-labs\Уч85Окно_<UUID>\. Имя конфигурации УчебноеОкно85. В списке баз зарегистрируйте строго File="C:\1c-labs\Уч85Окно_<UUID>\";. Path-marker не является UUID самой информационной базы; реальный UUID базы в коде не измеряется. Состояние.База содержит только эту метку пути. Другие пути/параметры отвергаются, строка соединения не печатается.

  3. Создайте ровно одного настоящего пользователя IB Уч85Окно_<UUID> с правами чтения списка пользователей и СохранениеДанныхПользователя в этой учебной базе. Список и UUID реального текущего пользователя ИБ проверяются; Состояние.Пользователь сохраняет actualIBUserUUID из ТекущийПользователь().УникальныйИдентификатор, не UUID базы. Это важно, поскольку native settings связаны с именем пользователя и имя может повторно использовать другой IBUser.

  4. Конфигурация пустая: справочников/документов/регистров/общих реквизитов/разделителей/подписок/регламентных заданий/ботов/констант/расширений нет. Не меняйте типовую конфигурацию. Добавьте только указанные ниже свой общий модуль и свою одну общую управляемую форму; другие стартовые модули/обработчики отсутствуют.

  5. Конфигуратор → свойства конфигурации: управляемое приложение, интерфейс Такси. Первый baseline должен иметь Обычный режим окна и настоящий Boolean отображения заголовкаОС: принимаются и True, и False. Учебное значение — противоположное реально полученному, а не guessed default. Код не принимает kiosk/fullscreen baseline. Два исходных текста берутся реальными getters.

  6. Конфигуратор → Общие → Общие модули → УчебноеОкно85: Сервер/Вызов сервера=Да, Клиент/Привилегированный/Глобальный=Нет. Вставьте полный SERVER. ХранилищеСистемныхНастроек доступно серверу, не тонкому клиенту. Работа только с собственным объектным ключом Уч85Окно85_<marker> и ключом настройки СвойЦиклОкна85; ИмяПользователя не передается, поэтому native использует текущего пользователя.

  7. Конфигуратор → Общие → Общие формы → УчебноеОкно85: управляемая форма. Создайте параметры формы МеткаБазы/Nonce (Строка36), реквизиты с теми же именами (Строка36) и Подтверждение (Строка100). Создайте команды ПроверитьОкно/ВернутьСвоиЗаголовки, разместите кнопки и поле подтверждения. Вставьте FORM целиком; событие ПриСозданииНаСервере имеет2параметра и переносит собственные startup parameters в реквизиты.

  8. Конфигуратор → Конфигурация → Открыть модуль управляемого приложения: вставьте APPLICATION целиком. Native ПередНачаломРаботыСистемы(Отказ) настраивает окно до его появления; ПриНачалеРаботыСистемы() после открытия проверяет оформление, задает свои заголовки и открывает только свою общую форму. Не вызывайте эти процедуры вручную и не переносите window/OS setters в форму или обычный helper.

  9. Первый ручной запуск выполните тонким клиентом этой своей базы, задав дополнительный параметр запуска /C"Уч85Окно|<ваш UUID>|ОПЫТ85". ПараметрЗапуска native получает именно /C. Без точных трех частей старт отклоняется; это осознанная учебная фаза, не автоизменение при любом открытии произвольной базы.

  10. Первый BeforeStart сохраняет реально полученные Normal/Boolean OS/two captions в собственном ключе для actual IBUser, затем ставит РабочееМесто и противоположное отображение заголовкаОС. При существующем ключе опыт не повторяется и baseline не перезаписывается. Main-window mode и OS-caption setters оба разрешены только в этом событии.

  11. В РабочемМесте скрываются системное меню и многие панели/горячие клавиши; поэтому ПриНачалеРаботыСистемы открывает заранее подготовленную общую форму, а не требует открыть внешнюю обработку через скрытое меню. Закрытие главного окна остается доступным. Это не киоск/forcefullscreen и не запрет на работу ОС.

  12. После открытия окна native getters проверяют РабочееМесто/свое противоположное значение OS и исходные тексты. Затем задаются собственные заголовок Уч85Окно|Книга750|nonce и краткий Книга750|nonce, оба отдельно читаются. Краткий заголовок вставляется перед системным и отделяется точкой: getter возвращает свое значение, не весь нарисованный ОС-заголовок.

  13. Откройте автоматически показанную свою форму, нажмите ПроверитьОкно и осмотрите настоящее окно вручную. Введите ВОЗВРАТ МОИХ ЗАГОЛОВКОВ85 и нажмите ВернутьСвоиЗаголовки один раз. Возврат разрешен лишь при exact own caption/short/mode/OS/nonce. Два текста возвращаются к real baseline и читаются; если кто-то изменил оформление, код не перезаписывает его.

  14. После подтвержденной фазы ЗаголовкиВозвращены вручную закройте только собственное приложение. Не называйте это полным возвратом окна: Mode/OS нельзя изменить из формы. Сохраненная запись не удаляется. Не запускайте параллельные сеансы и не меняйте конфигурацию/пользователя/интерфейс между двумя стартами.

  15. Второй ручной запуск той же базы/пользователя задайте с /C"Уч85Окно|<тот же UUID-marker пути>|ВОЗВРАТ85". Native BeforeStart проверяет сохраненный actualIBUserUUID реального текущего пользователя ИБ и nonce, фазу и исходные тексты. Режим окна может уже быть исходным из нового запуска либо оставаться нашим РабочимМестом; иные режимы отвергаются. Возвращаются сохраненные Normal/исходный Boolean OS, не guessed defaults.

  16. Второй native OnStart после открытия проверяет фактические mode/OS/caption/short и только затем сохраняет Завершен. Пользователь отдельно осматривает окно. Font getter дает вариант шрифта, не пиксельный размер/имя установленного шрифта; ТипПриложения — настоящий тонкий клиент.

  17. КлиентСИспользованиемАвтономногоСервера по точной native справке проверяет способность данного типа клиента работать с автономным сервером, не факт подключения. В этом fixture явно FileIB; значениеBoolean не объявляется живым соединением с автономным сервером, и сервер не запускается.

  18. Любая ошибка/cancel может оставить собственный state/оформление частично измененными. Ключи/phase не являются общей транзакцией или доказательством скриншота; автоматического blindrestore/retry/deleteall нет. При неизвестном/частичном результате остановитесь и вручную проверьте только свой стенд. При авторстве реальные1С/настройкиБД/UI/процессы/сеть/файлы не изменялись, backup0.

Перем СвояМеткаОкна85;
Перем СвойСтартОкна85;
Перем СвойСнимокОкна85;

Процедура ПередНачаломРаботыСистемы(Отказ)
#Если ТонкийКлиент Тогда
    Части = СтрРазделить(ПараметрЗапуска, "|", Ложь);
    Если Части.Количество() <> 3 Или Части[0] <> "Уч85Окно"
        Или (Части[2] <> "ОПЫТ85" И Части[2] <> "ВОЗВРАТ85") Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    СвояМеткаОкна85 = Части[1];
    СвойСтартОкна85 = Части[2];
    Если ТипЗнч(КлиентскоеПриложение) <> Тип("КлиентскоеПриложение")
        Или КлиентскоеПриложение.ТипПриложения() <> ТипКлиентскогоПриложения.ТонкийКлиент
        Или КлиентскоеПриложение.ТекущийВариантИнтерфейса() <> ВариантИнтерфейсаКлиентскогоПриложения.Такси
        Или ТипЗнч(КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС()) <> Тип("Булево") Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    Если СвойСтартОкна85 = "ОПЫТ85" Тогда
        СвойСнимокОкна85 = УчебноеОкно85.СохранитьПервоеСостояниеОкна85(СвояМеткаОкна85,
            КлиентскоеПриложение.ПолучитьРежимОсновногоОкна(), КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС(),
            КлиентскоеПриложение.ПолучитьЗаголовок(), КлиентскоеПриложение.ПолучитьКраткийЗаголовок());
        ТребуемоеОкно = РежимОсновногоОкнаКлиентскогоПриложения.РабочееМесто;
        ТребуемыйОС = СвойСнимокОкна85.СвойЗаголовокОС;
    Иначе
        СвойСнимокОкна85 = УчебноеОкно85.ПолучитьСвоеСостояниеОкна85(СвояМеткаОкна85);
        Если СвойСнимокОкна85.Фаза <> "ЗаголовкиВозвращены"
            Или КлиентскоеПриложение.ПолучитьЗаголовок() <> СвойСнимокОкна85.Заголовок
            Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> СвойСнимокОкна85.КраткийЗаголовок Тогда
            Отказ = Истина;
            Возврат;
        КонецЕсли;
        ТекущееОкно = КлиентскоеПриложение.ПолучитьРежимОсновногоОкна();
        Если ТекущееОкно <> СвойСнимокОкна85.РежимОкна
            И ТекущееОкно <> РежимОсновногоОкнаКлиентскогоПриложения.РабочееМесто Тогда
            Отказ = Истина;
            Возврат;
        КонецЕсли;
        СвойСнимокОкна85 = УчебноеОкно85.ПеревестиСвоюФазуОкна85(СвояМеткаОкна85, СвойСнимокОкна85.Nonce, "ЗаголовкиВозвращены", "ВозвратНачат");
        ТребуемоеОкно = СвойСнимокОкна85.РежимОкна;
        ТребуемыйОС = СвойСнимокОкна85.ЗаголовокОС;
    КонецЕсли;
    КлиентскоеПриложение.УстановитьРежимОсновногоОкна(ТребуемоеОкно);
    КлиентскоеПриложение.УстановитьОтображениеЗаголовкаОС(ТребуемыйОС);
    Если КлиентскоеПриложение.ПолучитьРежимОсновногоОкна() <> ТребуемоеОкно
        Или КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС() <> ТребуемыйОС Тогда
        Отказ = Истина;
    КонецЕсли;
#Иначе
    Отказ = Истина;
#КонецЕсли
КонецПроцедуры

Процедура ПриНачалеРаботыСистемы()
    Если СвойСнимокОкна85 = Неопределено Тогда
        ВызватьИсключение "Own native BeforeStart не подготовил настоящий сохраненный baseline";
    КонецЕсли;
    Свежий = УчебноеОкно85.ПолучитьСвоеСостояниеОкна85(СвояМеткаОкна85);
    Если Свежий.Nonce <> СвойСнимокОкна85.Nonce Тогда
        ВызватьИсключение "Собственный старт получил чужой nonce";
    КонецЕсли;
    Если СвойСтартОкна85 = "ОПЫТ85" Тогда
        Если Свежий.Фаза <> "Подготовлен" Или КлиентскоеПриложение.ПолучитьРежимОсновногоОкна() <> РежимОсновногоОкнаКлиентскогоПриложения.РабочееМесто
            Или КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС() <> Свежий.СвойЗаголовокОС
            Или КлиентскоеПриложение.ПолучитьЗаголовок() <> Свежий.Заголовок
            Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> Свежий.КраткийЗаголовок Тогда
            ВызватьИсключение "Actual own first main-window/baseline не подтвержден; не перезаписываем заголовки";
        КонецЕсли;
        КлиентскоеПриложение.УстановитьЗаголовок(Свежий.СвойЗаголовок);
        КлиентскоеПриложение.УстановитьКраткийЗаголовок(Свежий.СвойКраткий);
        Если КлиентскоеПриложение.ПолучитьЗаголовок() <> Свежий.СвойЗаголовок
            Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> Свежий.СвойКраткий Тогда
            ВызватьИсключение "Own заголовки могли измениться частично, но отдельно не подтверждены. Повтора/автоrestore нет";
        КонецЕсли;
        СвойСнимокОкна85 = УчебноеОкно85.ПеревестиСвоюФазуОкна85(СвояМеткаОкна85, Свежий.Nonce, "Подготовлен", "Показан");
    Иначе
        Если Свежий.Фаза <> "ВозвратНачат" Или КлиентскоеПриложение.ПолучитьРежимОсновногоОкна() <> Свежий.РежимОкна
            Или КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС() <> Свежий.ЗаголовокОС
            Или КлиентскоеПриложение.ПолучитьЗаголовок() <> Свежий.Заголовок
            Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> Свежий.КраткийЗаголовок Тогда
            ВызватьИсключение "Исходный real saved own UI baseline после второго старта не подтвержден";
        КонецЕсли;
        СвойСнимокОкна85 = УчебноеОкно85.ПеревестиСвоюФазуОкна85(СвояМеткаОкна85, Свежий.Nonce, "ВозвратНачат", "Завершен");
    КонецЕсли;
    Шрифт = КлиентскоеПриложение.ТекущийВариантОсновногоШрифта();
    ВозможенАвтономный = КлиентскоеПриложение.КлиентСИспользованиемАвтономногоСервера();
    Если ТипЗнч(Шрифт) <> Тип("ВариантОсновногоШрифтаКлиентскогоПриложения") Или ТипЗнч(ВозможенАвтономный) <> Тип("Булево") Тогда
        ВызватьИсключение "Native font/capability types не совпали";
    КонецЕсли;
    Сообщить("Свой thin-client: " + Строка(КлиентскоеПриложение.ТипПриложения()) + "; основной шрифт: " + Строка(Шрифт));
    Сообщить("Способность этого типа клиента работать с автономным сервером: " + Строка(ВозможенАвтономный) + ". Это НЕ факт подключения: наш fixture использует FileIB");
    Сообщить("Own phase: " + СвойСнимокОкна85.Фаза + "; nonce: " + СвойСнимокОкна85.Nonce);
    ОткрытьФорму("ОбщаяФорма.УчебноеОкно85", Новый Структура("МеткаБазы,Nonce", СвояМеткаОкна85, СвойСнимокОкна85.Nonce));
КонецПроцедуры
Полный серверный модуль собственного baseline/phase в одном current-user system-settings ключе

Конфигуратор → Общие → Общие модули → УчебноеОкно85 → Модуль.

Серверный server-call общий модуль; exact ownIB/current realuser и только own scoped native settings. Window/OS client setters здесь отсутствуют.

Функция СохранитьПервоеСостояниеОкна85(МеткаБазы, ИсходноеОкно, ИсходныйОС, ИсходныйЗаголовок, ИсходныйКраткий) Экспорт
    Паспорт = ПроверитьСвоюБазуОкна85(МеткаБазы);
    Если ХранилищеСистемныхНастроек.Загрузить(Паспорт.КлючОбъекта, "СвойЦиклОкна85") <> Неопределено Тогда
        ВызватьИсключение "Own namespace уже содержит состояние; первый запуск не повторяется";
    КонецЕсли;
    Если ТипЗнч(ИсходноеОкно) <> Тип("РежимОсновногоОкнаКлиентскогоПриложения")
        Или ИсходноеОкно <> РежимОсновногоОкнаКлиентскогоПриложения.Обычный
        Или ТипЗнч(ИсходныйОС) <> Тип("Булево")
        Или ТипЗнч(ИсходныйЗаголовок) <> Тип("Строка") Или СтрДлина(ИсходныйЗаголовок) > 512
        Или ТипЗнч(ИсходныйКраткий) <> Тип("Строка") Или СтрДлина(ИсходныйКраткий) > 512 Тогда
        ВызватьИсключение "Нужен реальный Normal/Boolean OScaption собственный baseline и две исходные строки";
    КонецЕсли;
    Nonce = Строка(Новый УникальныйИдентификатор);
    Состояние = Новый Структура("База,Пользователь,Nonce,РежимОкна,ЗаголовокОС,СвойЗаголовокОС,Заголовок,КраткийЗаголовок,СвойЗаголовок,СвойКраткий,Фаза",
        МеткаБазы, Паспорт.Пользователь, Nonce, ИсходноеОкно, ИсходныйОС, Не ИсходныйОС, ИсходныйЗаголовок, ИсходныйКраткий,
        "Уч85Окно | Книга3×250=750 | " + Nonce, "Книга750 | " + Nonce, "Подготовлен");
    ХранилищеСистемныхНастроек.Сохранить(Паспорт.КлючОбъекта, "СвойЦиклОкна85", Состояние);
    Свежий = ПолучитьСвоеСостояниеОкна85(МеткаБазы);
    Если Свежий.Nonce <> Nonce Или Свежий.Фаза <> "Подготовлен" Тогда
        ВызватьИсключение "Запись своего baseline могла произойти, но отдельно не подтверждена; не повторяйте";
    КонецЕсли;
    Возврат Свежий;
КонецФункции

Функция ПолучитьСвоеСостояниеОкна85(МеткаБазы) Экспорт
    Паспорт = ПроверитьСвоюБазуОкна85(МеткаБазы);
    Состояние = ХранилищеСистемныхНастроек.Загрузить(Паспорт.КлючОбъекта, "СвойЦиклОкна85");
    Если ТипЗнч(Состояние) <> Тип("Структура") Тогда
        ВызватьИсключение "Собственный real saved baseline не найден";
    КонецЕсли;
    Если Состояние.База <> МеткаБазы Или Состояние.Пользователь <> Паспорт.Пользователь
        Или ТипЗнч(Состояние.Nonce) <> Тип("Строка") Или СтрДлина(Состояние.Nonce) <> 36
        Или Состояние.РежимОкна <> РежимОсновногоОкнаКлиентскогоПриложения.Обычный
        Или ТипЗнч(Состояние.ЗаголовокОС) <> Тип("Булево") Или ТипЗнч(Состояние.СвойЗаголовокОС) <> Тип("Булево")
        Или Состояние.СвойЗаголовокОС <> (Не Состояние.ЗаголовокОС) Или ТипЗнч(Состояние.Заголовок) <> Тип("Строка")
        Или ТипЗнч(Состояние.КраткийЗаголовок) <> Тип("Строка") Или СтрДлина(Состояние.Заголовок) > 512
        Или СтрДлина(Состояние.КраткийЗаголовок) > 512 Тогда
        ВызватьИсключение "Own namespace/current actualIBUserUUID/baseline passport изменен";
    КонецЕсли;
    UUIDNonce = Новый УникальныйИдентификатор(Состояние.Nonce);
    Если Состояние.Nonce <> Строка(UUIDNonce) Или UUIDNonce = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000")
        Или Состояние.СвойЗаголовок <> "Уч85Окно | Книга3×250=750 | " + Состояние.Nonce
        Или Состояние.СвойКраткий <> "Книга750 | " + Состояние.Nonce Тогда
        ВызватьИсключение "Собственная учебная строка/nonce не подтвердились";
    КонецЕсли;
    Возврат Состояние;
КонецФункции

Функция ПеревестиСвоюФазуОкна85(МеткаБазы, Nonce, ИзФазы, ВФазу) Экспорт
    Паспорт = ПроверитьСвоюБазуОкна85(МеткаБазы);
    Состояние = ПолучитьСвоеСостояниеОкна85(МеткаБазы);
    Если Состояние.Nonce <> Nonce Или Состояние.Фаза <> ИзФазы Тогда
        ВызватьИсключение "Чужой/старый nonce или повтор own phase не принимается";
    КонецЕсли;
    Допустимо = (ИзФазы = "Подготовлен" И ВФазу = "Показан")
        Или (ИзФазы = "Показан" И ВФазу = "ЗаголовкиВозвращены")
        Или (ИзФазы = "ЗаголовкиВозвращены" И ВФазу = "ВозвратНачат")
        Или (ИзФазы = "ВозвратНачат" И ВФазу = "Завершен");
    Если Не Допустимо Тогда
        ВызватьИсключение "Переход не входит в собственный цикл двух ручных запусков";
    КонецЕсли;
    Состояние.Фаза = ВФазу;
    ХранилищеСистемныхНастроек.Сохранить(Паспорт.КлючОбъекта, "СвойЦиклОкна85", Состояние);
    Свежий = ПолучитьСвоеСостояниеОкна85(МеткаБазы);
    Если Свежий.Фаза <> ВФазу Или Свежий.Nonce <> Nonce Тогда
        ВызватьИсключение "Переход own phase мог сохраниться, но отдельно не подтвержден; автоматического повтора нет";
    КонецЕсли;
    Возврат Свежий;
КонецФункции

Функция ПроверитьСвоюБазуОкна85(МеткаБазы)
    ПроверитьСвойПустойСтенд();
    UUIDМетки = Новый УникальныйИдентификатор(МеткаБазы);
    Если МеткаБазы <> Строка(UUIDМетки) Или UUIDМетки = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
        ВызватьИсключение "Own file-path marker должен быть canonical nonzero UUID; это метка пути, не UUID базы и не UUID реального пользователя ИБ";
    КонецЕсли;
    Соединение = "File=""C:\1c-labs\Уч85Окно_" + МеткаБазы + "\"";";
    Если СтрокаСоединенияИнформационнойБазы() <> Соединение Или ПривилегированныйРежим() Тогда
        ВызватьИсключение "Нужна только точная собственная новая FileIB без privileged. Connection string не выводится";
    КонецЕсли;
    Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
    Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
    Если Пользователи.Количество() <> 1 Или Текущий = Неопределено Тогда
        ВызватьИсключение "Нужен единственный real ownIBUser";
    КонецЕсли;
    Если Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор
        Или Текущий.Имя <> "Уч85Окно_" + МеткаБазы Или Метаданные.ОбщиеФормы.Количество() <> 1
        Или Метаданные.ОбщиеФормы.УчебноеОкно85.Имя <> "УчебноеОкно85"
        Или Метаданные.Боты.Количество() <> 0 Или Метаданные.Константы.Количество() <> 0 Тогда
        ВызватьИсключение "Own actual user/sole common form/empty metadata не подтверждены";
    КонецЕсли;
    Возврат Новый Структура("КлючОбъекта,Пользователь", "Уч85Окно85_" + МеткаБазы, Строка(Текущий.УникальныйИдентификатор));
КонецФункции

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

Конфигуратор → Общие → Общие формы → УчебноеОкно85 → Модуль.

Клиент-серверный модуль actual общей управляемой формы. Прямые window/OS setters запрещены; settings остаются серверными.

Перем ВозвратЗаголовковНачат85;

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    МеткаБазы = Параметры.МеткаБазы;
    Nonce = Параметры.Nonce;
    Состояние = УчебноеОкно85.ПолучитьСвоеСостояниеОкна85(МеткаБазы);
    Если Состояние.Nonce <> Nonce Тогда
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьОкно(Команда)
    Состояние = ПолучитьСостояниеНаСервере85();
    Если КлиентскоеПриложение.ТипПриложения() <> ТипКлиентскогоПриложения.ТонкийКлиент Тогда
        ВызватьИсключение "Это не наш собственный тонкий клиент";
    КонецЕсли;
    Сообщить("Сохраненная own phase: " + Состояние.Фаза + "; actual window: " + Строка(КлиентскоеПриложение.ПолучитьРежимОсновногоОкна())
        + "; actual OS caption: " + Строка(КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС()));
КонецПроцедуры

&НаКлиенте
Процедура ВернутьСвоиЗаголовки(Команда)
    Если ВозвратЗаголовковНачат85 = Истина Или Подтверждение <> "ВОЗВРАТ МОИХ ЗАГОЛОВКОВ85" Тогда
        ВызватьИсключение "Own возврат заголовков одноразовый и требует отдельной фразы";
    КонецЕсли;
    Состояние = ПолучитьСостояниеНаСервере85();
    Если Состояние.Фаза <> "Показан" Или КлиентскоеПриложение.ТипПриложения() <> ТипКлиентскогоПриложения.ТонкийКлиент
        Или КлиентскоеПриложение.ПолучитьЗаголовок() <> Состояние.СвойЗаголовок
        Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> Состояние.СвойКраткий
        Или КлиентскоеПриложение.ПолучитьРежимОсновногоОкна() <> РежимОсновногоОкнаКлиентскогоПриложения.РабочееМесто
        Или КлиентскоеПриложение.ПолучитьОтображениеЗаголовкаОС() <> Состояние.СвойЗаголовокОС Тогда
        ВызватьИсключение "Текущее оформление уже не наш checked snapshot; чужие/частичные значения не перезаписываются";
    КонецЕсли;
    ВозвратЗаголовковНачат85 = Истина;
    КлиентскоеПриложение.УстановитьЗаголовок(Состояние.Заголовок);
    КлиентскоеПриложение.УстановитьКраткийЗаголовок(Состояние.КраткийЗаголовок);
    Если КлиентскоеПриложение.ПолучитьЗаголовок() <> Состояние.Заголовок
        Или КлиентскоеПриложение.ПолучитьКраткийЗаголовок() <> Состояние.КраткийЗаголовок Тогда
        ВызватьИсключение "Own возврат мог произойти частично, но отдельно не подтвержден; не повторяйте";
    КонецЕсли;
    ПодтвердитьЗаголовкиНаСервере85();
    Сообщить("Только два own заголовка возвращены. Window-mode/OS-caption setters из формы запрещены: их восстановит следующий отдельный native BeforeStart с ВОЗВРАТ85");
КонецПроцедуры

&НаСервере
Функция ПолучитьСостояниеНаСервере85()
    Состояние = УчебноеОкно85.ПолучитьСвоеСостояниеОкна85(МеткаБазы);
    Если Состояние.Nonce <> Nonce Тогда
        ВызватьИсключение "Own form nonce не совпал с actual saved state";
    КонецЕсли;
    Возврат Состояние;
КонецФункции

&НаСервере
Процедура ПодтвердитьЗаголовкиНаСервере85()
    УчебноеОкно85.ПеревестиСвоюФазуОкна85(МеткаБазы, Nonce, "Показан", "ЗаголовкиВозвращены");
КонецПроцедуры

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

  1. Native readonly globalfactory дает текущий КлиентскоеПриложение; startup guard требует Thin/Taxi и Boolean OS-caption, исключая неподдерживаемые clients/styles.

  2. ПередНачаломРаботыСистемы имеет1параметр Отказ, OnStart0. Ни формы, ни сообщений/окон не создается до готовности главного окна; оба ограниченных setters находятся прямо в BeforeStart.

  3. Первый baseline взят из реальных getters до изменения, ограничен Normal/Boolean OS и сохраняется только в собственном user-scoped ключе, который изначально отсутствует. Противоположный Boolean используется для видимого собственного опыта.

  4. Сервер проверяет exact emptyFileIB/version/oneactualuser и сохраненный actualIBUserUUID реального пользователя ИБ. UUID самой базы не измеряется; ее поле База содержит marker пути. Settings.Load/Save без имени пользователя используют текущего; чужие ключи/пользователи/настройки не затрагиваются.

  5. После реального открытия своего окна mode/OS и заголовки сверяются. Новые caption/short с own nonce устанавливаются и читаются, не заявляются нарисованными только по return setters.

  6. Форма восстанавливает только два своих текста при совпадении текущего собственного оформления. Ее one-shot flag ставится до setters; partialfailure не запускает повтор или автоматический restore.

  7. Второй настоящий запуск разрешен после возвращенных текстов и подтвержденного состояния. Перед стартом допустимы только original/own window mode; новый клиент не выдается за тот же ОС-процесс.

  8. Восстановление Window/OS происходит только в новом native BeforeStart. OnStart отдельно читает весь original baseline и завершает own saved phase; запись сохраняется для ручной проверки.

  9. Font/тип/standalone capability применяются к текущему реальному клиенту. CapabilityBoolean не доказывает actual autonomous connection или готовый запущенный сервер.

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

  1. После первого старта свое приложение показывает РабочееМесто, противоположное собственному baseline отображение ОС-заголовка и два текста750; главный код не управляет чужими процессами.

  2. Форма подтверждает exact own nonce/current appearance и возвращает исходные два текста; window/OS setters из нее отсутствуют.

  3. После второго старта реальные mode/OS/caption/short совпали с сохраненным исходным baseline, а собственная запись отмечена Завершен.

  4. Возврат не выполняется при другом пользователе/пути/фазе/nonce/измененном оформлении. Partial/cancel не объявляются успешным завершением.

  5. Отчет о способности автономного сервера отделен от фактического FileIB connection. Шрифт прочитан как enum, не выдуманный Windows font.

  6. Нужен ручной запуск и визуальная проверка владельца своего стенда. Здесь native/static проверки, а не runtime/UI/DB результат вашей базы.

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

При двух успешных ручных запусках своего подготовленного WindowsThinTaxi/FileIB стенда native startup события меняют и отдельно возвращают оформление текущего собственного клиента. Исходные значения действительно получены getters и сохранены только в своем ключе текущего пользователя. Здесь runtime0; реальное отображение/перезапуск/настройки вашей базы не выполнялись.

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

  1. КлиентскоеПриложение получается из readonly global property, не constructor и не неизвестный переданный объект. Тот же тип доступен на сервере, но конкретные window/OS methods имеют более узкую client availability.

  2. УстановитьРежимОсновногоОкна и УстановитьОтображениеЗаголовкаОС разрешены исключительно в ПередНачаломРаботыСистемы. Нельзя восстановить их в форме/OnStart/обычном общему helper даже в thin-client.

  3. OS setter реально действует только WindowsThin/ThickTaxi; другие clients/interfaces игнорируют вызов. Getter может вернуть Undefined. Нельзя трактовать игнорирование как успешную UI-операцию.

  4. РабочееМесто скрывает меню, панели и горячие клавиши. Собственная заранее созданная общая форма открывается только после появления главного окна, поэтому опыт не зависит от скрытого пункта открытия EPF.

  5. Краткий заголовок автоматически отделяется точкой и участвует в составном системном заголовке. Getter своего значения не является OCR/скриншотом полного заголовка ОС.

  6. Settings storage scope — IB/имя пользователя. Переименование не загружает старые настройки, повторное использование имени может их наследовать; поэтому сохраненный actualIBUserUUID реального пользователя ИБ проверяется и не заменяется marker пути или UUID самой базы.

  7. Save требует СохранениеДанныхПользователя. Thin не вызывает системное settings storage напрямую; отдельный серверный модуль использует только own keys/currentuser, не стороннюю управленческую базу.

  8. Native startup отказ/exception может произойти после saved state или частичного UI изменения. Restore phase не является общей транзакцией. Не повторяйте первый старт поверх baseline и не удаляйте все system settings.

  9. Между двумя стартами новый процесс может уже иметь часть defaults. Это допустимый original snapshot, не гарантия сохранения setters между процессами. Иные modes/тексты отвергаются, а не слепо перезаписываются.

  10. Saved phase является журналом только собственного учебного цикла, не физической backup copy и не доказательством реального UI без manual inspection. No files/archives/backup APIs.

  11. Название ClientUsesStandaloneServer неоднозначно; exact native описание — способность типа клиента. True не означает actual connection, False из регламентного задания не описывает ваше интерактивное окно.

  12. В собственной VM нужны один реальный пользователь, неизмененная CF/Taxi и отсутствие параллельных сеансов. Автор не запускал1С/ОС/process/network/DB/settings/UI/files, а статические тесты не заменяют ваши runtime проверки.

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

Проверить свой серверный JSON-пакет, кэш и временную зону сеанса

Один конкретный пакетOWN-85:3×250=750 проходит два фактических серверных чтения, явную очистку кэша, проверку графа, собственного сообщения и настоящую отложенную проверку. Отдельные команды меняют и возвращают только временную зону собственного сеанса.

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

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

Подготовка

  1. Не вставляйте урок в УТ/КА/УНФ/БП, рабочую базу или расширение. Создайте отдельную новую пустую файловуюИБ на собственной учебнойVM, один собственный сеанс. Имя конфигурации: УчебныйПротоколПакета85.

  2. Предметных объектов, регистров, подписок, заданий, внешних источников и расширений базы/сеанса должно быть0. Никаких подключенных обработок, внешних сервисов или чужих общих модулей.

  3. Платформа строго8.5.1.1343, толстый клиент, управляемое приложение; современный режим совместимости8.5.1. Настройте только свой учебный запуск, не меняйте рабочие ярлыки.

  4. Конфигуратор → Общие → Параметры сеанса: создайте УчебныйUUIDСеанса85, единственный тип УникальныйИдентификатор. Не используйте строковый/составной тип и не обращайтесь к неизвестному динамическому параметру.

  5. Откройте Модуль сеанса собственной конфигурации и вставьте полностью блок Модуль сеанса. Событие вызывает именно платформа, сначала с Неопределено; не вызывайте его вручную и не переинициализируйте UUID при каждом чтении.

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

  7. Повторное использование возвращаемых значений модуля УчебныйКэшПакета85: На время сеанса. Вставьте целиком блок Серверный модуль кэша. Форма реально обращается к серверной функции, которая вызывает данный модуль; JSON возвращается с сервера.

  8. Вставьте целиком блок Модуль управляемого приложения в собственный модуль управляемого приложения. Он содержит реально экспортированную клиентскую процедуру СвойОтложенныйКонтрольПакета85 без параметров; не размещайте ее в модуле формы вместо приложения.

  9. Общие → Общие формы: создайте единственную управляемую УчебнаяФормаПакета85. Не ставьте ее на начальную страницу и не открывайте вспомогательную форму: ОбновитьИнтерфейс может закрывать/пересоздавать другие виды форм.

  10. У формы создайте реквизит ИтогПакета85, Строка неограниченной длины; элемент многострочного текстового поля, ТолькоПросмотр=Да. СостояниеПакета85 — клиентская переменная модуля, НЕ реквизит данныхИБ.

  11. Создайте ровно5команд формы с действиями НачатьСвойПакет85, ОстановитьСвоеОжидание85, ПроверитьПослеОбновленияИнтерфейса85, ПрименитьСвоюЗону85, ВернутьСвоюЗону85. Назначьте их соответствующим5кнопкам.

  12. В свойствах формы подключите событие ПередЗакрытием к одноименной процедуре. Вставьте весь основной модуль формы на верхнем уровне; серверные функции и клиентские процедуры не вкладывайте друг в друга.

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

  14. Для запуска придумайте новый собственный канонический ненулевой UUID. В настройках запуска Предприятия укажите параметр OwnPacket85:<ваш36символьныйUUID>; в командной строке это значение параметра /C. Это ручная подготовка, не операция этого автора. Prefix OwnPacket85: имеет12символов.

  15. UUID запуска — ваша явная метка/разделитель входных данных, не пароль/защита доступа. UUID сеанса независимо создает платформа через собственный параметр; они не обязаны совпадать.

  16. Кэш учебный и единственный. ОбновитьПовторноИспользуемыеЗначения очищает ВСЕ такие значения и делает обращение к серверу; поэтому существующая конфигурация не подходит. Два чтения выполняются сразу, без паузы/таймера; при неподтвержденном повторном использовании урок прекращается.

  17. ОбновитьИнтерфейс отдельно и один раз после callback: он очищает ВСЕ клиентские кэши и вызывает сервер многократно, а не просто перерисовывает поле. Учимся повторно проверять целый свой пакет после тяжелого обновления; не обещаем очистку серверного кэша или новый UUID от этого метода.

  18. Флаги отключения защиты читаются аргументами в каждом текущем вызывающем серверном методе, а не принимаются за глобальный аудит. Ложь/Ложь/D — явная политика допуска собственного маршрута. Защиту и режим ресурсов код не меняет; это не доказательство изоляции сети.

  19. Сообщение создается и читается в одном своем некэшируемом серверном вызове. До него нужен реальный пустой FixedArray; после — ровно одно сообщение своего UUID/расчета. Всегда Ложь, чужие сообщения не удаляем. По возвращении сервера свое сообщение может штатно показаться пользователю.

  20. Временный GMT+03 затрагивает только собственный сеанс, не часовой поясИБ/Windows. Сохраняется фактическая исходная зона. Возврат — отдельная явная команда, только при том же UUID сеанса и неизменившемся фактическом собственном идентификаторе зоны.

  21. Если применение/возврат завершились ошибкой, состояние считается неизвестным; слепого finally/rollback/повтора нет. Диагностируйте только свою новуюИБ или завершите только свой учебный сеанс. Завершение сеанса не объявляется проверенным возвратом getter.

  22. Оперативные отметки упорядочивают собственную проверку; они могут искусственно увеличиваться на секунду и НЕ измеряют длительность/реальное UTC. В проверке зоны используется фиксированная учебная UTC-дата и явно переданный фактический пояс: МестноеВремя без2аргумента использует пояс компьютера, не сеанса.

  23. Actual1C/UI/DB/network/system/filecalls0; подготовка и все команды описаны для будущего ручного теста. Сейчас написан код и выполнены только статические проверки. Новых резервных копий/архивов0.

&НаКлиенте
Перем СостояниеПакета85;

&НаКлиенте
Процедура НачатьСвойПакет85(Команда)
    ПроверитьСвоегоТолстогоКлиента85();
    Если СостояниеПакета85 <> Неопределено Тогда
        ВызватьИсключение "В этой форме уже есть собственный маршрут; новый запуск выполняйте в новом собственном сеансе";
    КонецЕсли;
    Если ТипЗнч(ПараметрЗапуска) <> Тип("Строка") Или СтрДлина(ПараметрЗапуска) <> 48
        Или Лев(ПараметрЗапуска, 12) <> "OwnPacket85:" Тогда
        ВызватьИсключение "Нужен собственный /C OwnPacket85: и ровно36символов UUID";
    КонецЕсли;
    UUIDЗапуска = Прав(ПараметрЗапуска, 36);
    Если Строка(Новый УникальныйИдентификатор(UUIDЗапуска)) <> UUIDЗапуска
        Или UUIDЗапуска = "00000000-0000-0000-0000-000000000000" Тогда
        ВызватьИсключение "Нужен ненулевой канонический UUID собственного запуска";
    КонецЕсли;
    Протокол = НачатьПротоколНаСервере85(UUIDЗапуска);
    СостояниеПакета85 = Новый Структура("UUIDСеанса,UUIDЗапуска,JSON,UUIDРасчета,БазоваяЗона,СвояЗона,ЗонаАктивна,ЗонаНеизвестна,Ожидание,Проверен",
        Протокол.UUIDСеанса, UUIDЗапуска, "", "", Протокол.БазоваяЗона, "", Ложь, Ложь, Ложь, Ложь);
    ПервыйJSON = ЧитатьСвойПакетНаСервере85(СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    Первый = РазобратьСвойПакет85(ПервыйJSON, СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    ВторойJSON = ЧитатьСвойПакетНаСервере85(СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    Второй = РазобратьСвойПакет85(ВторойJSON, СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    Если Первый.UUIDРасчета <> Второй.UUIDРасчета Или ПервыйJSON <> ВторойJSON Тогда
        ВызватьИсключение "Повторное использование конкретного серверного пакета не подтверждено; результаты не принимаются";
    КонецЕсли;
    ОбновитьПовторноИспользуемыеЗначения();
    НовыйJSON = ЧитатьСвойПакетНаСервере85(СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    НовыйПакет = РазобратьСвойПакет85(НовыйJSON, СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    Если НовыйПакет.UUIDРасчета = Первый.UUIDРасчета Тогда
        ВызватьИсключение "Очистка кэша не доказана новым фактическим UUID расчета";
    КонецЕсли;
    СостояниеПакета85.JSON = НовыйJSON;
    СостояниеПакета85.UUIDРасчета = НовыйПакет.UUIDРасчета;
    Контроль = ПроверитьСвойГрафИСообщение85(СостояниеПакета85.UUIDСеанса, UUIDЗапуска, НовыйJSON);
    ЗарегистрироватьСвоюФормуПакета85(ЭтотОбъект, UUIDЗапуска);
    ПодключитьОбработчикОжидания("СвойОтложенныйКонтрольПакета85", 1, Истина);
    СостояниеПакета85.Ожидание = Истина;
    ИтогПакета85 = "Свой пакет OWN-85:3×250=750. Два серверных чтения сохранили UUID расчета;"
        + " после явной очистки получен другой UUID. Цикл обнаружен и разорван: " + Строка(Контроль)
        + ". Теперь оставьте приложение в покое; точное время callback не гарантируется.";
КонецПроцедуры

&НаКлиенте
Функция РазобратьСвойПакет85(JSON, UUIDСеанса, UUIDЗапуска)
    Если ТипЗнч(JSON) <> Тип("Строка") Тогда
        ВызватьИсключение "Свой сервер должен вернуть JSON-строку";
    КонецЕсли;
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(JSON);
    Пакет = ПрочитатьJSON(Чтение, Ложь);
    Чтение.Закрыть();
    Если ТипЗнч(Пакет) <> Тип("Структура") Или Пакет.Количество() <> 7 Тогда
        ВызватьИсключение "Свой JSON имеет ровно7известных полей";
    КонецЕсли;
    Для Каждого Имя Из СтрРазделить("UUIDСеанса,UUIDЗапуска,UUIDРасчета,Артикул,Количество,Цена,Сумма", ",") Цикл
        Если Не Пакет.Свойство(Имя) Тогда
            ВызватьИсключение "Отсутствует собственное поле пакета";
        КонецЕсли;
    КонецЦикла;
    Если ТипЗнч(Пакет.UUIDСеанса) <> Тип("Строка") Или ТипЗнч(Пакет.UUIDЗапуска) <> Тип("Строка")
        Или ТипЗнч(Пакет.UUIDРасчета) <> Тип("Строка") Или ТипЗнч(Пакет.Артикул) <> Тип("Строка")
        Или ТипЗнч(Пакет.Количество) <> Тип("Число") Или ТипЗнч(Пакет.Цена) <> Тип("Число") Или ТипЗнч(Пакет.Сумма) <> Тип("Число") Тогда
        ВызватьИсключение "JSON сохранил неверные типы собственных полей";
    КонецЕсли;
    Если Пакет.UUIDСеанса <> UUIDСеанса Или Пакет.UUIDЗапуска <> UUIDЗапуска Или Пакет.Артикул <> "OWN-85"
        Или Пакет.Количество <> 3 Или Пакет.Цена <> 250 Или Пакет.Сумма <> 750
        Или Пакет.Сумма <> Пакет.Количество * Пакет.Цена Тогда
        ВызватьИсключение "Пакет относится к другому маршруту или неверно вычислен";
    КонецЕсли;
    Если СтрДлина(Пакет.UUIDРасчета) <> 36 Или Строка(Новый УникальныйИдентификатор(Пакет.UUIDРасчета)) <> Пакет.UUIDРасчета Тогда
        ВызватьИсключение "Нужен реальный канонический UUID выполненного расчета";
    КонецЕсли;
    Возврат Пакет;
КонецФункции

&НаКлиенте
Процедура ПроверитьПакетПослеПокоя85(UUIDЗапуска) Экспорт
    Если СостояниеПакета85 = Неопределено Тогда
        Возврат;
    КонецЕсли;
    Если СостояниеПакета85.UUIDЗапуска <> UUIDЗапуска Или Не СостояниеПакета85.Ожидание Тогда
        ВызватьИсключение "Устаревший callback не принимает чужой пакет";
    КонецЕсли;
    ОтключитьОбработчикОжидания("СвойОтложенныйКонтрольПакета85");
    СостояниеПакета85.Ожидание = Ложь;
    ОсвободитьСвоюФормуПакета85(UUIDЗапуска);
    Пакет = РазобратьСвойПакет85(СостояниеПакета85.JSON, СостояниеПакета85.UUIDСеанса, UUIDЗапуска);
    Если Пакет.UUIDРасчета <> СостояниеПакета85.UUIDРасчета Тогда
        ВызватьИсключение "Сохраненная собственная модель изменилась";
    КонецЕсли;
    СостояниеПакета85.Проверен = Истина;
    ИтогПакета85 = "Настоящий однократный обработчик покоя проверил свой сохраненный пакет:3×250=750."
        + " Это не точный таймер и не фоновое задание.";
КонецПроцедуры

&НаКлиенте
Процедура ОстановитьСвоеОжидание85(Команда)
    Если СостояниеПакета85 = Неопределено Тогда
        Возврат;
    КонецЕсли;
    Если СостояниеПакета85.Ожидание Тогда
        ОтключитьОбработчикОжидания("СвойОтложенныйКонтрольПакета85");
        СостояниеПакета85.Ожидание = Ложь;
        ОсвободитьСвоюФормуПакета85(СостояниеПакета85.UUIDЗапуска);
        ИтогПакета85 = "Остановлен только свой обработчик; отложенная проверка не подтверждена.";
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьПослеОбновленияИнтерфейса85(Команда)
    ПроверитьСвоегоТолстогоКлиента85();
    Если СостояниеПакета85 = Неопределено Тогда
        ВызватьИсключение "Сначала получите свой пакет";
    КонецЕсли;
    Если Не СостояниеПакета85.Проверен Или СостояниеПакета85.Ожидание Тогда
        ВызватьИсключение "Сначала дождитесь настоящего однократного callback";
    КонецЕсли;
    ПроверитьСвойСеансНаСервере85(СостояниеПакета85.UUIDСеанса);
    ОбновитьИнтерфейс();
    JSON = ЧитатьСвойПакетНаСервере85(СостояниеПакета85.UUIDСеанса, СостояниеПакета85.UUIDЗапуска);
    Пакет = РазобратьСвойПакет85(JSON, СостояниеПакета85.UUIDСеанса, СостояниеПакета85.UUIDЗапуска);
    ИтогПакета85 = "После однократного тяжелого обновления клиентских кэшей собственный пакет снова проверен:"
        + Строка(Пакет.Сумма) + ". Новый UUID расчета здесь НЕ требуем: серверный кэш этим методом не объявляем очищенным.";
КонецПроцедуры

&НаКлиенте
Процедура ПрименитьСвоюЗону85(Команда)
    Если СостояниеПакета85 = Неопределено Тогда
        ВызватьИсключение "Сначала получите свой пакет и фактическую базовую зону";
    КонецЕсли;
    Если СостояниеПакета85.ЗонаАктивна Или СостояниеПакета85.ЗонаНеизвестна Тогда
        ВызватьИсключение "Повторное изменение при активной или неизвестной собственной зоне запрещено";
    КонецЕсли;
    СостояниеПакета85.ЗонаНеизвестна = Истина;
    Попытка
        Зона = ПрименитьСвоюЗонуНаСервере85(СостояниеПакета85.UUIDСеанса, СостояниеПакета85.БазоваяЗона);
        СостояниеПакета85.СвояЗона = Зона;
        СостояниеПакета85.ЗонаАктивна = Истина;
        СостояниеПакета85.ЗонаНеизвестна = Ложь;
        ИтогПакета85 = "В своем сеансе временно установлен GMT+03. UTC10.10.2026 06:00:00 преобразован в09:00:00."
            + " Теперь отдельно выполните ВернутьСвоюЗону85; зонаИБ не менялась.";
    Исключение
        ИтогПакета85 = "Состояние своей зоны после попытки не подтверждено. Автоматический возврат не выполняется."
            + " Не повторяйте команду; диагностируйте только свой сеанс или завершите именно этот учебный сеанс.";
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ВернутьСвоюЗону85(Команда)
    Если СостояниеПакета85 = Неопределено Тогда
        ВызватьИсключение "Нет собственного сохраненного состояния";
    КонецЕсли;
    Если Не СостояниеПакета85.ЗонаАктивна Или СостояниеПакета85.ЗонаНеизвестна Тогда
        ВызватьИсключение "Возвращать можно только свою подтвержденную временную зону; неизвестное состояние не перезаписываем";
    КонецЕсли;
    СостояниеПакета85.ЗонаНеизвестна = Истина;
    Попытка
        ВернутьСвоюЗонуНаСервере85(СостояниеПакета85.UUIDСеанса, СостояниеПакета85.БазоваяЗона, СостояниеПакета85.СвояЗона);
        СостояниеПакета85.ЗонаАктивна = Ложь;
        СостояниеПакета85.ЗонаНеизвестна = Ложь;
        ИтогПакета85 = "Своя фактическая базовая зона возвращена; отдельное свежее чтение и преобразование времени проверены.";
    Исключение
        ИтогПакета85 = "Возврат зоны не подтвержден. Чужое изменение не перезаписываем; автоматического rollback нет."
            + " Диагностируйте только свой учебный сеанс или завершите именно его.";
    КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ПередЗакрытием(Отказ, СтандартнаяОбработка)
    Если СостояниеПакета85 <> Неопределено Тогда
        Если СостояниеПакета85.ЗонаАктивна Или СостояниеПакета85.ЗонаНеизвестна Тогда
            Отказ = Истина;
            ИтогПакета85 = "Свою подтвержденную зону верните отдельной командой. При неизвестном состоянии остановите именно свой учебный сеанс.";
            Возврат;
        КонецЕсли;
        Если СостояниеПакета85.Ожидание Тогда
            ОтключитьОбработчикОжидания("СвойОтложенныйКонтрольПакета85");
            СостояниеПакета85.Ожидание = Ложь;
            ОсвободитьСвоюФормуПакета85(СостояниеПакета85.UUIDЗапуска);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьСвоегоТолстогоКлиента85()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
#Иначе
    ВызватьИсключение "Этот собственный урок подготовлен для толстого управляемого клиента";
#КонецЕсли
КонецПроцедуры

&НаСервереБезКонтекста
Функция НачатьПротоколНаСервере85(UUIDЗапуска)
    UUIDСеанса = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если Строка(Новый УникальныйИдентификатор(UUIDЗапуска)) <> UUIDЗапуска Тогда
        ВызватьИсключение "Нужен свой UUID запуска";
    КонецЕсли;
    Зона = ЧасовойПоясСеанса();
    Если ТипЗнч(Зона) <> Тип("Строка") Или ПустаяСтрока(Зона) Тогда
        ВызватьИсключение "Нет фактической базовой зоны; не угадываем ее";
    КонецЕсли;
    Возврат Новый Структура("UUIDСеанса,БазоваяЗона", UUIDСеанса, Зона);
КонецФункции

&НаСервереБезКонтекста
Процедура ПроверитьСвойСеансНаСервере85(UUIDСеанса)
    Факт = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если ТипЗнч(UUIDСеанса) <> Тип("Строка") Или Факт <> UUIDСеанса Тогда
        ВызватьИсключение "Другой сеанс не принимает собственный пакет";
    КонецЕсли;
КонецПроцедуры

&НаСервереБезКонтекста
Функция ЧитатьСвойПакетНаСервере85(UUIDСеанса, UUIDЗапуска)
    Факт = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если Факт <> UUIDСеанса Тогда
        ВызватьИсключение "Кэш своего пакета читается только в своем сеансе";
    КонецЕсли;
    Возврат УчебныйКэшПакета85.ПолучитьСвойПакет85(UUIDСеанса, UUIDЗапуска, 3);
КонецФункции

&НаСервереБезКонтекста
Функция ПроверитьСвойГрафИСообщение85(UUIDСеанса, UUIDЗапуска, JSON)
    Факт = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если Факт <> UUIDСеанса Тогда
        ВызватьИсключение "Нужен свой фактический сеанс";
    КонецЕсли;
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(JSON);
    Пакет = ПрочитатьJSON(Чтение, Ложь);
    Чтение.Закрыть();
    Если ТипЗнч(Пакет) <> Тип("Структура") Или Пакет.UUIDСеанса <> UUIDСеанса Или Пакет.UUIDЗапуска <> UUIDЗапуска
        Или Пакет.Количество <> 3 Или Пакет.Цена <> 250 Или Пакет.Сумма <> 750 Тогда
        ВызватьИсключение "Чужую JSON-модель не анализируем";
    КонецЕсли;
    До = ПолучитьОперативнуюОтметкуВремени();
    Чистые = ПроверитьЦиклическиеСсылкиВстроенногоЯзыка(Пакет, "СвойПакет:" + UUIDЗапуска);
    Если ПосчитатьСобственныеЦиклы85(Чистые) <> 0 Тогда
        ВызватьИсключение "JSON-пакет должен быть ациклическим";
    КонецЕсли;
    Граф = Новый Структура("UUIDЗапуска,СсылкаНаСебя", UUIDЗапуска, Неопределено);
    Граф.СсылкаНаСебя = Граф;
    Попытка
        Циклы = ПроверитьЦиклическиеСсылкиВстроенногоЯзыка(Граф, "СвойГраф:" + UUIDЗапуска);
        Найдено = ПосчитатьСобственныеЦиклы85(Циклы);
    Исключение
        Граф.СсылкаНаСебя = Неопределено;
        ВызватьИсключение "Проверка своего цикла не подтверждена; собственная связь разорвана";
    КонецПопытки;
    Граф.СсылкаНаСебя = Неопределено;
    Если Найдено < 1 Тогда
        ВызватьИсключение "Свой действительно созданный цикл должен быть обнаружен";
    КонецЕсли;
    ПослеРазрыва = ПроверитьЦиклическиеСсылкиВстроенногоЯзыка(Граф, "СвойГрафПослеРазрыва:" + UUIDЗапуска);
    Если ПосчитатьСобственныеЦиклы85(ПослеРазрыва) <> 0 Тогда
        ВызватьИсключение "После явного разрыва собственный граф не должен иметь циклов";
    КонецЕсли;
    После = ПолучитьОперативнуюОтметкуВремени();
    Если ТипЗнч(До) <> Тип("Дата") Или ТипЗнч(После) <> Тип("Дата") Или После < До Тогда
        ВызватьИсключение "Оперативные отметки должны быть датами в неубывающем порядке; это не измерение длительности";
    КонецЕсли;
    Ранее = ПолучитьСообщенияПользователю(Ложь);
    Если ТипЗнч(Ранее) <> Тип("ФиксированныйМассив") Или Ранее.Количество() <> 0 Тогда
        ВызватьИсключение "Есть неизвестные ожидающие сообщения; их не удаляем и свое не добавляем";
    КонецЕсли;
    Текст = "СвойПакет:" + UUIDЗапуска + ":" + Пакет.UUIDРасчета + ":3x250=750";
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = Текст;
    Сообщение.Сообщить();
    Сообщения = ПолучитьСообщенияПользователю(Ложь);
    Если ТипЗнч(Сообщения) <> Тип("ФиксированныйМассив") Или Сообщения.Количество() <> 1 Тогда
        ВызватьИсключение "Подтверждено не ровно одно собственное ожидающее сообщение; ничего не удаляем";
    КонецЕсли;
    Единственное = Сообщения[0];
    Если ТипЗнч(Единственное) <> Тип("СообщениеПользователю") Или Единственное.Текст <> Текст Тогда
        ВызватьИсключение "Ожидающее сообщение не относится точно к своему расчету; ничего не удаляем";
    КонецЕсли;
    Возврат Найдено;
КонецФункции

&НаСервереБезКонтекста
Функция ПосчитатьСобственныеЦиклы85(Таблица)
    Если ТипЗнч(Таблица) <> Тип("ТаблицаЗначений") Или Таблица.Колонки.Количество() <> 2 Тогда
        ВызватьИсключение "Нужна настоящая native таблица анализа с2колонками";
    КонецЕсли;
    Если Таблица.Колонки.Найти("ОписаниеЗначения") = Неопределено
        Или Таблица.Колонки.Найти("ЭлементыЦиклическихСсылок") = Неопределено Тогда
        ВызватьИсключение "Неизвестная схема native анализа циклов";
    КонецЕсли;
    Количество = 0;
    Для Каждого СтрокаАнализа Из Таблица Цикл
        Если ТипЗнч(СтрокаАнализа.ОписаниеЗначения) <> Тип("Строка")
            Или ТипЗнч(СтрокаАнализа.ЭлементыЦиклическихСсылок) <> Тип("Массив") Тогда
            ВызватьИсключение "Native анализ возвращает строковое описание и массив строк циклов";
        КонецЕсли;
        Для Каждого ОписаниеЦикла Из СтрокаАнализа.ЭлементыЦиклическихСсылок Цикл
            Если ТипЗнч(ОписаниеЦикла) <> Тип("Строка") Тогда
                ВызватьИсключение "Элемент реального native анализа должен быть строкой";
            КонецЕсли;
            Количество = Количество + 1;
        КонецЦикла;
    КонецЦикла;
    Возврат Количество;
КонецФункции

&НаСервереБезКонтекста
Функция ПрименитьСвоюЗонуНаСервере85(UUIDСеанса, БазоваяЗона)
    Факт = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если Факт <> UUIDСеанса Или ЧасовойПоясСеанса() <> БазоваяЗона Тогда
        ВызватьИсключение "Сеанс или фактическая базовая зона уже изменились; не перезаписываем";
    КонецЕсли;
    УстановитьЧасовойПоясСеанса("GMT+03");
    СвояЗона = ЧасовойПоясСеанса();
    Если ТипЗнч(СвояЗона) <> Тип("Строка") Или ПустаяСтрока(СвояЗона)
        Или МестноеВремя(Дата(2026, 10, 10, 6, 0, 0), СвояЗона) <> Дата(2026, 10, 10, 9, 0, 0) Тогда
        ВызватьИсключение "Фактическое применение собственной зоны не подтверждено; автоматического возврата нет";
    КонецЕсли;
    Возврат СвояЗона;
КонецФункции

&НаСервереБезКонтекста
Процедура ВернутьСвоюЗонуНаСервере85(UUIDСеанса, БазоваяЗона, СвояЗона)
    Факт = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если Факт <> UUIDСеанса Или ТипЗнч(БазоваяЗона) <> Тип("Строка") Или ПустаяСтрока(БазоваяЗона)
        Или ТипЗнч(СвояЗона) <> Тип("Строка") Или ПустаяСтрока(СвояЗона) Или ЧасовойПоясСеанса() <> СвояЗона Тогда
        ВызватьИсключение "Текущая зона уже не является своей подтвержденной временной зоной; чужое изменение не перезаписываем";
    КонецЕсли;
    КонтрольБазы = МестноеВремя(Дата(2026, 10, 10, 6, 0, 0), БазоваяЗона);
    УстановитьЧасовойПоясСеанса(БазоваяЗона);
    Возвращенная = ЧасовойПоясСеанса();
    Если Возвращенная <> БазоваяЗона Или МестноеВремя(Дата(2026, 10, 10, 6, 0, 0), Возвращенная) <> КонтрольБазы Тогда
        ВызватьИсключение "Отдельное свежее чтение возвращенной своей зоны не подтверждено";
    КонецЕсли;
КонецПроцедуры

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

&НаСервереБезКонтекста
Функция ПроверитьКонтекстПакета85(БезопасныйОтключен, ЗащитаОтключена, Ресурсы)
    ПроверитьСвойПустойСтенд();
    Если ТипЗнч(БезопасныйОтключен) <> Тип("Булево") Или ТипЗнч(ЗащитаОтключена) <> Тип("Булево")
        Или ТипЗнч(Ресурсы) <> Тип("Строка") Тогда
        ВызватьИсключение "Неизвестный native результат политики текущего вызывающего метода";
    КонецЕсли;
    Если БезопасныйОтключен Или ЗащитаОтключена Или Ресурсы <> "D" Тогда
        ВызватьИсключение "Свой учебный маршрут не выполняется при отключенной защите или нестандартном режиме ресурсов";
    КонецЕсли;
    Если Метаданные.ПараметрыСеанса.Количество() <> 1 Или Метаданные.ОбщиеМодули.Количество() <> 1
        Или Метаданные.ОбщиеФормы.Количество() <> 1 Тогда
        ВызватьИсключение "Нужны только собственные параметр, модуль кэша и общая форма";
    КонецЕсли;
    Параметр = Метаданные.ПараметрыСеанса.Найти("УчебныйUUIDСеанса85");
    Модуль = Метаданные.ОбщиеМодули.Найти("УчебныйКэшПакета85");
    Форма = Метаданные.ОбщиеФормы.Найти("УчебнаяФормаПакета85");
    Если Параметр = Неопределено Или Модуль = Неопределено Или Форма = Неопределено Тогда
        ВызватьИсключение "Не найдена точная собственная схема";
    КонецЕсли;
    Если Параметр.Тип.Типы().Количество() <> 1 Или Не Параметр.Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда
        ВызватьИсключение "УчебныйUUIDСеанса85 имеет единственный явно заданный тип УникальныйИдентификатор";
    КонецЕсли;
    Если Не Модуль.Сервер Или Модуль.ВызовСервера Или Модуль.КлиентУправляемоеПриложение
        Или Модуль.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НаВремяСеанса Тогда
        ВызватьИсключение "Нужен свой серверный модуль с повторным использованием на время сеанса без прямого клиентского вызова";
    КонецЕсли;
    UUID = ПараметрыСеанса.УчебныйUUIDСеанса85;
    Если ТипЗнч(UUID) <> Тип("УникальныйИдентификатор") Или UUID = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
        ВызватьИсключение "Система должна реально инициализировать свой типизированный UUID сеанса";
    КонецЕсли;
    Возврат Строка(UUID);
КонецФункции
Серверный модуль кэша УчебныйКэшПакета85

Конфигуратор → Общие → Общие модули → УчебныйКэшПакета85 → Модуль.

Серверный неглобальный общий модуль с повторным использованием НаВремяСеанса; прямого клиентского вызова нет.

Функция ПолучитьСвойПакет85(UUIDСеанса, UUIDЗапуска, Количество) Экспорт
    ФактическийUUID = ПроверитьКонтекстПакета85(ПолучитьОтключениеБезопасногоРежима(),
        ПолучитьОтключениеЗащитыОтОпасныхДействий(), ПолучитьРежимВнешнихРесурсов());
    Если ТипЗнч(UUIDСеанса) <> Тип("Строка") Или UUIDСеанса <> ФактическийUUID
        Или ТипЗнч(UUIDЗапуска) <> Тип("Строка") Или ТипЗнч(Количество) <> Тип("Число") Или Количество <> 3 Тогда
        ВызватьИсключение "Свой серверный расчет принимает свой сеанс, конкретный запуск и количество3";
    КонецЕсли;
    Если СтрДлина(UUIDЗапуска) <> 36 Или Строка(Новый УникальныйИдентификатор(UUIDЗапуска)) <> UUIDЗапуска Тогда
        ВызватьИсключение "UUID запуска должен быть канонической строкой";
    КонецЕсли;
    Пакет = Новый Структура("UUIDСеанса,UUIDЗапуска,UUIDРасчета,Артикул,Количество,Цена,Сумма",
        UUIDСеанса, UUIDЗапуска, Строка(Новый УникальныйИдентификатор), "OWN-85", Количество, 250, Количество * 250);
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    ЗаписатьJSON(Запись, Пакет);
    Возврат Запись.Закрыть();
КонецФункции

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

Функция ПроверитьКонтекстПакета85(БезопасныйОтключен, ЗащитаОтключена, Ресурсы)
    ПроверитьСвойПустойСтенд();
    Если ТипЗнч(БезопасныйОтключен) <> Тип("Булево") Или ТипЗнч(ЗащитаОтключена) <> Тип("Булево")
        Или ТипЗнч(Ресурсы) <> Тип("Строка") Тогда
        ВызватьИсключение "Неизвестный native результат политики текущего вызывающего метода";
    КонецЕсли;
    Если БезопасныйОтключен Или ЗащитаОтключена Или Ресурсы <> "D" Тогда
        ВызватьИсключение "Свой учебный маршрут не выполняется при отключенной защите или нестандартном режиме ресурсов";
    КонецЕсли;
    Если Метаданные.ПараметрыСеанса.Количество() <> 1 Или Метаданные.ОбщиеМодули.Количество() <> 1
        Или Метаданные.ОбщиеФормы.Количество() <> 1 Тогда
        ВызватьИсключение "Нужны только собственные параметр, модуль кэша и общая форма";
    КонецЕсли;
    Параметр = Метаданные.ПараметрыСеанса.Найти("УчебныйUUIDСеанса85");
    Модуль = Метаданные.ОбщиеМодули.Найти("УчебныйКэшПакета85");
    Форма = Метаданные.ОбщиеФормы.Найти("УчебнаяФормаПакета85");
    Если Параметр = Неопределено Или Модуль = Неопределено Или Форма = Неопределено Тогда
        ВызватьИсключение "Не найдена точная собственная схема";
    КонецЕсли;
    Если Параметр.Тип.Типы().Количество() <> 1 Или Не Параметр.Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда
        ВызватьИсключение "УчебныйUUIDСеанса85 имеет единственный явно заданный тип УникальныйИдентификатор";
    КонецЕсли;
    Если Не Модуль.Сервер Или Модуль.ВызовСервера Или Модуль.КлиентУправляемоеПриложение
        Или Модуль.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НаВремяСеанса Тогда
        ВызватьИсключение "Нужен свой серверный модуль с повторным использованием на время сеанса без прямого клиентского вызова";
    КонецЕсли;
    UUID = ПараметрыСеанса.УчебныйUUIDСеанса85;
    Если ТипЗнч(UUID) <> Тип("УникальныйИдентификатор") Или UUID = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
        ВызватьИсключение "Система должна реально инициализировать свой типизированный UUID сеанса";
    КонецЕсли;
    Возврат Строка(UUID);
КонецФункции
Модуль сеанса собственной пустой конфигурации

Конфигуратор → Конфигурация → Открыть модуль сеанса.

Серверный модуль сеанса собственной конфигурации; native событие УстановкаПараметровСеанса, один типизированный параметр.

Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
    Если ТребуемыеПараметры = Неопределено Тогда
        ПараметрыСеанса.УчебныйUUIDСеанса85 = Новый УникальныйИдентификатор;
    Иначе
        ВызватьИсключение "Свой единственный параметр должен быть установлен системой при начале сеанса; ленивую переинициализацию не выполняем";
    КонецЕсли;
КонецПроцедуры
Модуль управляемого приложения собственной пустой конфигурации

Конфигуратор → Конфигурация → Открыть модуль управляемого приложения.

Клиентский модуль управляемого приложения собственной конфигурации; экспортированные процедуры доступны из собственной формы.

Перем СобственнаяФормаПакета85;
Перем СобственныйUUIDЗапуска85;

Процедура ЗарегистрироватьСвоюФормуПакета85(Форма, UUID) Экспорт
    Если СобственнаяФормаПакета85 <> Неопределено Тогда
        ВызватьИсключение "Один собственный учебный маршрут уже зарегистрирован";
    КонецЕсли;
    СобственнаяФормаПакета85 = Форма;
    СобственныйUUIDЗапуска85 = UUID;
КонецПроцедуры

Процедура ОсвободитьСвоюФормуПакета85(UUID) Экспорт
    Если СобственныйUUIDЗапуска85 <> UUID Тогда
        ВызватьИсключение "Чужой или устаревший маршрут не освобождаем";
    КонецЕсли;
    СобственнаяФормаПакета85 = Неопределено;
    СобственныйUUIDЗапуска85 = Неопределено;
КонецПроцедуры

Процедура СвойОтложенныйКонтрольПакета85() Экспорт
    Если СобственнаяФормаПакета85 = Неопределено Тогда
        Возврат;
    КонецЕсли;
    СобственнаяФормаПакета85.ПроверитьПакетПослеПокоя85(СобственныйUUIDЗапуска85);
КонецПроцедуры

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

  1. НачатьСвойПакет85 читает настоящий /C, проверяет типизированный UUID сеанса и точную новую схему. Неизвестный контекст не заменяется объектом по умолчанию.

  2. Серверный модуль вычисляет семьJSONполей и новый UUID именно при выполнении функции. При одинаковых трех скалярных аргументах два серверных ответа должны сохранить весьJSON/UUID; после явной native очистки UUID обязан измениться, сумма остаться750.

  3. Перед серверной диагностикой проверяется ациклический пакет. Затем создается собственная реальная ссылка структуры на саму себя, native анализ подсчитывает найденные циклы; связь явно разрывается, свежий анализ должен дать0. Цикл никогда не сериализуетсяJSON.

  4. Две реальные оперативные даты принимаются только в неубывающем порядке. Это не секундомер: искусственное увеличение не превращается в скорость выполнения.

  5. В том же некэшируемом серверном методе читается настоящий пустой FixedArray сообщений, добавляется одно сообщение своего расчета и повторным FixedArray(false) проверяется точный текст. Удаления/очистки чужих сообщений нет.

  6. Форма регистрируется у своего модуля приложения. Native вызывает экспортированную процедуру без аргументов только в покое; она направляет проверку в конкретную собственную форму и снимает только свой точный handler. Циклического ожидания/ручного вызова callback нет.

  7. Команда остановки отменяет только свой отложенный handler без заявления об успешном callback. После успешного callback отдельно можно проверить повторно прочитанный пакет после одного тяжелого ОбновитьИнтерфейс.

  8. Отдельно ПрименитьСвоюЗону85 сверяет текущую фактическую baseline, устанавливает GMT+03, сохраняет freshgetter и проверяет06:00UTC→09:00. МестноеВремя получает явно этот пояс, не defaultпояс компьютера.

  9. ВернутьСвоюЗону85 выполняется только вручную после успешного применения. Server сначала проверяет точный собственный сеанс/временную зону, затем возвращает реальную baseline и отдельно свежим getter/конвертацией проверяет результат. Ошибка означает неизвестное состояние без автоматического rollback.

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

  1. Нормальный тест: два одинаковых UUID расчета до очистки, другой после, во всех трех разборахOWN-85/3/250/750 и оба собственныхUUID. Без правильного /C или при другой схеме остановка до принятия пакета.

  2. В собственной тестовой копии исходного кода подайте в РазобратьСвойПакет85 ту жеJSONстроку с суммой751/чужимUUID/числом-строкой: должна отказать соответствующая проверка, не исправлять вход незаметно.

  3. Реальный ациклический JSONдает0; собственный созданный selfcycle дает≥1; после явного разрыва0. Не ожидайте ровно1строку/цикл или строгого реального интервала между оперативными датами.

  4. Не трогайте приложение после старта: настоящий callback должен отметить подтверждение. Для cancel сначала сразу выполните только свою кнопку остановки; успешный callback в этом маршруте не заявляется.

  5. Флаг политики отключения/ресурсD проверяет именно текущие серверные методы; чужая защитная настройка вызывает отказ, код ее не исправляет. Не отключайте защиту ради прохождения теста.

  6. Временная зона: отдельные apply/readback/restore/readback. При чужом изменении текущей зоны точный guard запрещает возврат поверх него. Не тестируйте это в рабочем сеансе и не ожидайте атомарности изменения/чтения.

  7. После ОбновитьИнтерфейс сумма снова750, собственныеUUID сохранены. Изменение или сохранение UUID расчета не доказывает очистку именно серверного кэша этим тяжелым методом.

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

Получены проверенный собственный пакет750 и фактические признаки cache-hit/cache-invalidation; отложенная проверка подтверждается только native callback. Временная зона возвращена только после отдельной успешной команды и свежей проверки.

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

  1. Один урок не является безопасным инструментом для чужой конфигурации: обе очистки кэшей затрагивают весь соответствующий контекст; нужны только свои пустые метаданные.

  2. UUID/флаги/имя конфигурации не являются криптографической аутентификацией или доказательством физической изоляции. Владелец вручную готовит своюVM/ИБ.

  3. Возможны реальные отказы/изменение состояния между чтениями. Здесь нет promiseатомарности, автоматического rollback, неизвестных готовых объектов или истинного таймера.

  4. Не изменяйте часовой поясИБ/Windows, защиту, регламентные задания или рабочие данные. Код и статические тесты не являются запуском/подтверждением поведения платформы.

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

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

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

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

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