Получает номер текущего соединения с информационной базой.
Синтаксис
НомерСоединенияИнформационнойБазы()Полное описание, параметры и ограничения
Глобальный контекст.НомерСоединенияИнформационнойБазы (Global context.InfoBaseConnectionNumber)
Глобальный контекст (Global context)
НомерСоединенияИнформационнойБазы (InfoBaseConnectionNumber)
Доступен, начиная с версии 8.0.
Синтаксис:
НомерСоединенияИнформационнойБазы()
Возвращаемое значение:
Тип: Число.
Описание:
Получает номер текущего соединения с информационной базой.
Доступность:
Сервер, толстый клиент, внешнее соединение.
См. также:
СоединениеИнформационнойБазы, свойство НомерСоединения
Использование в версии:
Доступен, начиная с версии 8.0.
Методическая информация
Практические примеры
Три оплачиваемых дня, вытеснение среднего дня и премия: собственная явная очередь, не автоматический расчет денег
Полный учебный маршрут нового пустого стенда: реальный график и регистраторы, действительный и предварительный ФПД, база премии и отдельно подтвержденная собственная задача перерасчета. Все денежные ресурсы вычисляет показанный код; автоматическая запись очереди в native Calc.Write выключена.
Где и как запускать
Толстый клиент, обычное приложение собственной новой CF; полный общий модуль УчебныеПериодыМаршрут85, только Клиент(обычное приложение).
Подготовка
Рабочие УТ, УНФ, КА, БП и их копии с реальными данными запрещены. На своей новой отдельной учебной VM вручную создайте совершенно новую пустую файловую ИБ 8.5.1.1343 только в новом каталоге C:\1C85_OwnPeriodsLab\8c9b7372-b30e-47f1-88fb-00f6b7d7a26b\Base. Если этот каталог/база уже существуют, упражнение не начинайте и данные не переиспользуйте. В регистрации ИБ используйте ровно File="C:\1C85_OwnPeriodsLab\8c9b7372-b30e-47f1-88fb-00f6b7d7a26b\Base";. GUID в имени каталога — только метка отдельного учебного пути, НЕ UUID информационной базы. Packet UUID/маркеры документов не заменяют identity ИБ. Имя конфигурации УчебныеПериодыНачисления85. В Конфигураторе Сервис → Параметры → Общие выберите вид редактирования конфигурации для режима запуска «Управляемое приложение и обычное приложение»; свойство конфигурации ОсновнойРежимЗапуска = ОбычноеПриложение. Только толстый обычный клиент. Агент не создавал здесь каталог/VM/ИБ и не запускал1С.
Создавайте именно перечисленные ниже метаданные: один документ, один план видов расчета, один регистр расчета, один регистр сведений, одну обработку, один общий модуль и одну роль. Справочники, отчеты, перечисления, остальные регистры/планы, константы, общие реквизиты, параметры сеанса, подписки, задания, внешние источники, общие формы и хранилища настроек отсутствуют. Не устанавливайте расширения в ИБ, сеанс или файловую систему.
Роль УчебныйАдминистраторПериодов85 должна иметь Администрирование и АктивныеПользователи, а также Чтение/Добавление/Изменение своих документа и видов расчета, Чтение/Изменение собственных двух регистров, право Использование своей обработки. Это только учебная роль новой пустой ИБ, не модель минимальных производственных прав. Создайте единственного пользователя УченикПериоды85, назначьте ему эту роль и войдите им.
Закройте конфигуратор и все другие соединения только своего нового стенда перед упражнением. Не открывайте второе окно 1С, консоль запросов или фоновый сеанс во время этапов. Код читает массив соединений, требует ровно текущее соединение с собственным реальным пользователем; это снимок, а не блокировка будущих подключений и не атомарная защита.
План видов расчета УчебныеВидыНачисления85: код Строка длиной12, наименование длиной80; Использует период действия=Да; Зависимость от базы=По периоду действия; в список базовых планов включите только этот же собственный план. Предопределенных видов, собственных реквизитов и табличных частей не создавайте. Код этапа Подготовка85 сам создаст ровно WORK85, ABS85 и BON85, проверяя каждую полученную настоящую ссылку.
WORK85 — оплачиваемые дни, ABS85 — неоплачиваемый день, BON85 — десятипроцентная премия. Полный код запишет WORK85.ВытесняющиеВидыРасчета=[ABS85] и BON85.БазовыеВидыРасчета=[WORK85]. Ведущие списки всех трех видов пустые, остальные базовые/вытесняющие списки пустые, ПериодДействияБазовый=false у всех. Зависимость получения базы и ЯВНАЯ учебная очередь не означают автоматического расчета денег.
Регистр сведений УчебныеДниГрафика85: независимый, НЕПЕРИОДИЧЕСКИЙ, измерения График85 Строка12 переменной длины и Дата85 Дата без времени, ресурс Дни85 Число(2,0), собственных реквизитов нет. Для обоих измерений выставьте Проверка заполнения=Показывать ошибку. Не делайте его периодическим: по native график регистра расчета — непериодический регистр с Date-измерением и Number-ресурсом.
Регистр расчета УчебныеНачисленияПериодов85: периодичность Месяц, план УчебныеВидыНачисления85, Период действия=Да, Базовый период=Да. Измерение Сотрудник85 Строка12 переменной длины, ресурс Сумма85 Число(9,2), знак Любой; реквизит График85 Строка12 переменной длины. Для сотрудника и графика проверка заполнения Показывать ошибку. Иных измерений/ресурсов/реквизитов нет.
В свойствах собственного регистра расчета назначьте График=УчебныеДниГрафика85, Дата графика=его измерение Дата85, Значение графика=его ресурс Дни85. У собственного реквизита График85 настройте Связь с графиком на УчебныеДниГрафика85.График85. Это реальное конфигураторное соответствие, в XML ScheduleLink; урок не присваивает readonly метаданные и не выдумывает runtime setter. Native график проверяется фактическими возвращенными значениями3 и2.
Внутри этого регистра создайте единственный перерасчет ОчередьПремии85 и единственное измерение Сотрудник85. Его Измерение регистра укажите ровно собственное Сотрудник85; Данные ведущих регистров оставьте пустыми. Тип выводится из родительского измерения Строка12. Проверку заполнения оставьте Показывать ошибку. Автоматическую регистрацию перерасчетов сам код всех первых записей явно отключает четвертым аргументом Ложь; очередь создается вручную как отдельная собственная учебная задача.
Документ УчебныйРегистраторПериодов85: реквизиты Маркер85 Строка36 и Назначение85 Строка12, табличных частей нет. Номер Строка длиной12, автонумерация выключена, контроль уникальности включен. Проведение Разрешить; в Движениях отметьте только УчебныеНачисленияПериодов85. Модуль документа оставьте пустым: код не проводит документ и не имитирует ОбработкаПроведения. Обычная запись создает собственные настоящие регистраторы с номерами WORK, BON, ABS.
Общий модуль УчебныеПериодыМаршрут85: только Клиент(обычное приложение)=Да, Сервер=Нет, Глобальный=Нет, Привилегированный=Нет. Полный основной BSL ниже целиком поместите в этот модуль. Сервер и внешнее соединение указаны в native доступности API, но для этого самостоятельного маршрута не смешивайте контексты и не используйте тонкий/веб-клиент.
В модуль набора записей перерасчета ОчередьПремии85 целиком поместите второй полный BSL. ОбработкаПроверкиЗаполнения имеет ровно два native параметра. ЭтотОбъект там — настоящий набор, который передает сама платформа. Обработчик вызывается только native методом ПроверитьЗаполнение; напрямую его не вызывают и список ПроверяемыеРеквизиты не очищают. У самого модуля набора есть также серверный и внешний контексты: весь разбор с обращением к нашему клиентскому общему модулю заключен в #Если ТолстыйКлиентОбычноеПриложение Тогда. Согласно установленному shlang_ru.hbk Instructions, в файловом варианте толстого обычного приложения этот символ определен на обеих частях — клиентской и серверной; это не универсальная проверка «не сервер». Урок ограничен точным собственным File-адресом независимо от символа. В отдельном сервере клиент-серверного варианта, внешнем соединении и сервисном контексте без этого символа #Иначе оставляет исключительно Отказ=Истина без вызова клиентского общего модуля. Эти варианты для маршрута намеренно не поддерживаются.
Обработка УчебныеЭтапыПериодов85: одна обычная форма Этапы85, основная форма этой обработки; собственных реквизитов и табличных частей обработки нет. На форме создайте локальный реквизит ПодтверждаюИзменениеСвоегоСтенда85 типа Булево с начальным Ложь и соответствующий флажок. Это только явное разрешение следующего учебного этапа, не разрешение действий в рабочей ИБ.
На обычной форме создайте5 настоящих кнопок с именами Подготовка85, Начисление85, Исключение85, Перерасчет85, Очистка85. В Нажатие каждой привяжите одноименный обработчик; у ПриОткрытии формы выберите ПриОткрытии. Целиком поместите третий полный BSL в модуль этой формы. Не вызывайте обработчики кнопок вручную, не передавайте Неопределено вместо source-control.
Сохраните/обновите только свою новую конфигурацию вручную, запустите толстый обычный клиент и откройте собственную обработку УчебныеЭтапыПериодов85 обычной стандартной командой. Открытие только создает пакет в памяти и проверяет точную полную File-строку и пустоту всех пяти собственных таблиц; данных оно не пишет. Native СтрокаСоединенияИнформационнойБазы возвращает вид регистрации, не канонизирует путь/слеши/разделители. Если строка отличается даже оформлением, остановитесь и вручную проверьте регистрацию именно своего пути; не расширяйте gate под рабочую или Srvr/Ref-базу. Ошибка означает стоп, не обход условий.
Этап1 Подготовка85: вручную поставьте флажок и нажмите эту кнопку. Код после полного empty guard создаст3 своих вида,3 своих документа с новым действительным UUID-маркером и3 строки DAY85/11,12,13 января2026/1. Ожидайте сообщение о подготовке и0 движений/0 задач. Настоящие ссылки не заменяются плановыми неизвестными UUID-ссылками.
Этап2 Начисление85: заново поставьте флажок. WORK пытается получить11..13 января, BON имеет тот же базовый период, регистрация01.01.2026. Результат3×250=750, настоящая база750 и премия75. Этап3 Исключение85 после нового подтверждения пишет ABS только за12 января: действительный ФПД WORK становится11 и13 января, деньги ПОКА остаются750/75, затем создается одна ЯВНАЯ собственная задача BON/EMP85. Встроенная очередь здесь выключена, встроенный движок деньги не считает.
Этап4 Перерасчет85 после нового подтверждения: предварительный и записанный ФПД2 дня, ресурс WORK500, база BON500, премия50, итог550. Изменяются только ресурсы уже записанных, заново полностью прочитанных наборов. OnlyWrite=true запрещено применять к новому набору или измененным ключам/датам/видам. Этап5 Очистка85 требует отдельного нового подтверждения и полного свежего whitelist всей очереди; удаляется только своя задача по exact BON-документу, начисления/график сохраняются.
При любой неожиданной ошибке форма блокирует дальнейшие этапы и повторы. Код не делает blind rollback, не создает архивы, не восстанавливает старые снимки и не обещает атомарность нескольких записей. Нужна ручная сверка исключительно своего учебного стенда; reopening тоже не обходит full-empty guard. Для нового прохождения создайте вручную новый отдельный стенд, не удаляйте данные рабочих ИБ. Внешние файлы, сеть, печать, OS, службы и рабочие настройки не используются.
Функция Таблица85(Имена)
Результат = Новый ТаблицаЗначений;
Для Каждого Имя Из СтрРазделить(Имена, ",") Цикл
Результат.Колонки.Добавить(Имя);
КонецЦикла;
Возврат Результат;
КонецФункции
Процедура ПроверитьТаблицы85(Факт, Ожидание)
Если ТипЗнч(Факт) <> Тип("ТаблицаЗначений") Или ТипЗнч(Ожидание) <> Тип("ТаблицаЗначений") Тогда
ВызватьИсключение "OWN-PERIOD-TABLE: нужны полные таблицы";
КонецЕсли;
Если Факт.Количество() <> Ожидание.Количество() Или Факт.Колонки.Количество() <> Ожидание.Колонки.Количество() Тогда
ВызватьИсключение "OWN-PERIOD-TABLE: изменился полный состав";
КонецЕсли;
Для Каждого Колонка Из Ожидание.Колонки Цикл
Если Факт.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-TABLE: отсутствует собственное поле";
КонецЕсли;
КонецЦикла;
Использованные = Новый Массив;
Для Каждого СвояСтрока Из Ожидание Цикл
НайденныйИндекс = -1;
Для Индекс = 0 По Факт.Количество() - 1 Цикл
Если Использованные.Найти(Индекс) <> Неопределено Тогда
Продолжить;
КонецЕсли;
Совпало = Истина;
Для Каждого Колонка Из Ожидание.Колонки Цикл
ЗначениеФакта = Факт[Индекс][Колонка.Имя];
ЗначениеОжидания = СвояСтрока[Колонка.Имя];
Если ТипЗнч(ЗначениеФакта) <> ТипЗнч(ЗначениеОжидания) Или ЗначениеФакта <> ЗначениеОжидания Тогда
Совпало = Ложь;
КонецЕсли;
КонецЦикла;
Если Совпало Тогда
НайденныйИндекс = Индекс;
Прервать;
КонецЕсли;
КонецЦикла;
Если НайденныйИндекс = -1 Тогда
ВызватьИсключение "OWN-PERIOD-TABLE: неизвестная строка, тип или значение";
КонецЕсли;
Использованные.Добавить(НайденныйИндекс);
КонецЦикла;
КонецПроцедуры
Функция Читать85(Текст)
Запрос = Новый Запрос;
Запрос.Текст = Текст;
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Процедура ПроверитьТипПоля85(Поле, ИмяТипа, Длина, ДробнаяЧасть)
Если Поле = Неопределено Или Поле.Тип.Типы().Количество() <> 1 Или Не Поле.Тип.СодержитТип(Тип(ИмяТипа)) Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверный тип собственного поля";
КонецЕсли;
Если ИмяТипа = "Строка" Тогда
Если Поле.Тип.КвалификаторыСтроки.Длина <> Длина Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверная длина строки";
КонецЕсли;
ИначеЕсли ИмяТипа = "Число" Тогда
Если Поле.Тип.КвалификаторыЧисла.Разрядность <> Длина
Или Поле.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> ДробнаяЧасть Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверные квалификаторы числа";
КонецЕсли;
ИначеЕсли ИмяТипа = "Дата" Тогда
Если Поле.Тип.КвалификаторыДаты.ЧастиДаты <> ЧастиДаты.Дата Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: дата графика должна быть без времени";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция СвойПользователь85()
Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
Если ТипЗнч(Пользователи) <> Тип("Массив") Или Пользователи.Количество() <> 1 Или Текущий = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-USER: нужен единственный свой пользователь";
КонецЕсли;
Если Пользователи[0].Имя <> "УченикПериоды85" Или Текущий.УникальныйИдентификатор <> Пользователи[0].УникальныйИдентификатор Тогда
ВызватьИсключение "OWN-PERIOD-USER: неизвестный пользователь";
КонецЕсли;
Если Не РольДоступна("УчебныйАдминистраторПериодов85") Тогда
ВызватьИсключение "OWN-PERIOD-USER: отсутствует собственная учебная роль";
КонецЕсли;
Соединения = ПолучитьСоединенияИнформационнойБазы();
Если ТипЗнч(Соединения) <> Тип("Массив") Или Соединения.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-USER: закройте все остальные соединения только своего стенда";
КонецЕсли;
Если ТипЗнч(Соединения[0]) <> Тип("СоединениеИнформационнойБазы") Или Соединения[0].НомерСоединения <> НомерСоединенияИнформационнойБазы()
Или Соединения[0].Пользователь.УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "OWN-PERIOD-USER: единственное соединение должно быть текущим и собственным";
КонецЕсли;
Возврат Текущий.УникальныйИдентификатор;
КонецФункции
Процедура ПроверитьСхему85()
Если СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1C85_OwnPeriodsLab\8c9b7372-b30e-47f1-88fb-00f6b7d7a26b\Base"";" Тогда
ВызватьИсключение "OWN-PERIOD-PATH: разрешена только точная собственная новая файловая ИБ этого урока";
КонецЕсли;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: нужен новый собственный стенд 8.5.1.1343 без транзакции";
КонецЕсли;
Если Метаданные.Документы.Количество() <> 1 Или Метаданные.ПланыВидовРасчета.Количество() <> 1
Или Метаданные.РегистрыРасчета.Количество() <> 1 Или Метаданные.РегистрыСведений.Количество() <> 1
Или Метаданные.Обработки.Количество() <> 1 Или Метаданные.ОбщиеМодули.Количество() <> 1 Или Метаданные.Роли.Количество() <> 1
Или Метаданные.Справочники.Количество() <> 0 Или Метаданные.Отчеты.Количество() <> 0
Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.Константы.Количество() <> 0
Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0
Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0
Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0
Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПараметрыСеанса.Количество() <> 0
Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0
Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Или Метаданные.ОбщиеФормы.Количество() <> 0
Или Метаданные.ХранилищаНастроек.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: найдены посторонние метаданные";
КонецЕсли;
Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: расширения запрещены";
КонецЕсли;
ДокументМД = Метаданные.Документы.Найти("УчебныйРегистраторПериодов85");
ПланМД = Метаданные.ПланыВидовРасчета.Найти("УчебныеВидыНачисления85");
РегистрМД = Метаданные.РегистрыРасчета.Найти("УчебныеНачисленияПериодов85");
ГрафикМД = Метаданные.РегистрыСведений.Найти("УчебныеДниГрафика85");
Если ДокументМД = Неопределено Или ПланМД = Неопределено Или РегистрМД = Неопределено Или ГрафикМД = Неопределено
Или Метаданные.Обработки.Найти("УчебныеЭтапыПериодов85") = Неопределено
Или Метаданные.ОбщиеМодули.Найти("УчебныеПериодыМаршрут85") = Неопределено
Или Метаданные.Роли.Найти("УчебныйАдминистраторПериодов85") = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: отсутствуют собственные объекты";
КонецЕсли;
Свойства = Метаданные.СвойстваОбъектов;
Если ДокументМД.Реквизиты.Количество() <> 2 Или ДокументМД.ТабличныеЧасти.Количество() <> 0
Или ДокументМД.Движения.Количество() <> 1 Или Не ДокументМД.Движения.Содержит(РегистрМД)
Или ДокументМД.Проведение <> Свойства.Проведение.Разрешить Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверная схема собственного регистратора";
КонецЕсли;
ПроверитьТипПоля85(ДокументМД.Реквизиты.Найти("Маркер85"), "Строка", 36, 0);
ПроверитьТипПоля85(ДокументМД.Реквизиты.Найти("Назначение85"), "Строка", 12, 0);
Если Не ПланМД.ИспользованиеПериодаДействия
Или ПланМД.ЗависимостьОтВидовРасчета <> Свойства.ИспользованиеБазыПланаВидовРасчета.ПоПериодуДействия
Или ПланМД.БазовыеВидыРасчета.Количество() <> 1 Или Не ПланМД.БазовыеВидыРасчета.Содержит(ПланМД)
Или ПланМД.Реквизиты.Количество() <> 0 Или ПланМД.ТабличныеЧасти.Количество() <> 0
Или ПланМД.ДлинаКода <> 12 Или ПланМД.ДлинаНаименования <> 80 Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверный собственный план с зависимостью по периоду действия";
КонецЕсли;
Если РегистрМД.Периодичность <> Свойства.ПериодичностьРегистраРасчета.Месяц
Или Не РегистрМД.ПериодДействия Или Не РегистрМД.БазовыйПериод Или РегистрМД.ПланВидовРасчета <> ПланМД
Или РегистрМД.Измерения.Количество() <> 1 Или РегистрМД.Ресурсы.Количество() <> 1
Или РегистрМД.Реквизиты.Количество() <> 1 Или РегистрМД.Перерасчеты.Количество() <> 1
Или РегистрМД.График <> ГрафикМД Или РегистрМД.ДатаГрафика <> ГрафикМД.Измерения.Найти("Дата85")
Или РегистрМД.ЗначениеГрафика <> ГрафикМД.Ресурсы.Найти("Дни85") Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверные периоды или собственный график";
КонецЕсли;
ПроверитьТипПоля85(РегистрМД.Измерения.Найти("Сотрудник85"), "Строка", 12, 0);
ПроверитьТипПоля85(РегистрМД.Реквизиты.Найти("График85"), "Строка", 12, 0);
ПроверитьТипПоля85(РегистрМД.Ресурсы.Найти("Сумма85"), "Число", 9, 2);
Если ГрафикМД.Измерения.Количество() <> 2 Или ГрафикМД.Ресурсы.Количество() <> 1
Или ГрафикМД.Реквизиты.Количество() <> 0 Или ГрафикМД.ПериодичностьРегистраСведений <> Метаданные.СвойстваОбъектов.ПериодичностьРегистраСведений.Непериодический Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: нужен собственный непериодический график";
КонецЕсли;
ПроверитьТипПоля85(ГрафикМД.Измерения.Найти("График85"), "Строка", 12, 0);
ПроверитьТипПоля85(ГрафикМД.Измерения.Найти("Дата85"), "Дата", 0, 0);
ПроверитьТипПоля85(ГрафикМД.Ресурсы.Найти("Дни85"), "Число", 2, 0);
ПерерасчетМД = РегистрМД.Перерасчеты.Найти("ОчередьПремии85");
Если ПерерасчетМД = Неопределено Или ПерерасчетМД.Измерения.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: нужен собственный перерасчет с одним измерением";
КонецЕсли;
ИзмерениеОчереди = ПерерасчетМД.Измерения.Найти("Сотрудник85");
Если ИзмерениеОчереди = Неопределено Или ИзмерениеОчереди.ИзмерениеРегистра <> РегистрМД.Измерения.Найти("Сотрудник85")
Или ИзмерениеОчереди.ДанныеВедущихРегистров.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-SCHEMA: неверное собственное измерение очереди";
КонецЕсли;
КонецПроцедуры
Функция НовыйПакет85() Экспорт
ПроверитьСхему85();
Пакет = Новый Структура;
Пакет.Вставить("UUID", Новый УникальныйИдентификатор);
Пакет.Вставить("Пользователь", СвойПользователь85());
Пакет.Вставить("Этап", 0);
Пакет.Вставить("Виды", Таблица85("Ссылка,Код,Наименование,ПериодДействияБазовый,ПометкаУдаления,Предопределенный"));
Пакет.Вставить("Документы", Таблица85("Ссылка,Маркер85,Назначение85,Дата,Номер,ПометкаУдаления,Проведен"));
Пакет.Вставить("График", Таблица85("График85,Дата85,Дни85"));
Пакет.Вставить("Записи", Таблица85("Регистратор,НомерСтроки,ПериодРегистрации,ВидРасчета,Активность,Сторно,БазовыйПериодНачало,БазовыйПериодКонец,ПериодДействияНачало,ПериодДействияКонец,Сотрудник85,График85,Сумма85"));
Пакет.Вставить("Очередь", Таблица85("ОбъектПерерасчета,ВидРасчета,Сотрудник85"));
Пакет.Вставить("Вытесняющий", Неопределено);
Пакет.Вставить("Базовый", Неопределено);
ПроверитьПолноеСостояние85(Пакет);
Возврат Пакет;
КонецФункции
Процедура ПроверитьПакет85(Пакет) Экспорт
ПроверитьСхему85();
Если ТипЗнч(Пакет) <> Тип("Структура") Или Пакет.Количество() <> 10 Тогда
ВызватьИсключение "OWN-PERIOD-PACKET: неизвестная структура";
КонецЕсли;
Если ТипЗнч(Пакет.UUID) <> Тип("УникальныйИдентификатор") Или ТипЗнч(Пакет.Пользователь) <> Тип("УникальныйИдентификатор")
Или Пакет.Пользователь <> СвойПользователь85() Или ТипЗнч(Пакет.Этап) <> Тип("Число")
Или Пакет.Этап < 0 Или Пакет.Этап > 5 Или Пакет.Этап <> Цел(Пакет.Этап) Тогда
ВызватьИсключение "OWN-PERIOD-PACKET: чужой пользователь или неверный этап";
КонецЕсли;
Для Каждого Документ Из Пакет.Документы Цикл
Если ТипЗнч(Документ.Маркер85) <> Тип("Строка") Или Документ.Маркер85 <> Строка(Пакет.UUID) Тогда
ВызватьИсключение "OWN-PERIOD-PACKET: UUID собственного документа не совпал";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Процедура ПроверитьПолноеСостояние85(Пакет) Экспорт
ПроверитьПакет85(Пакет);
ПроверитьТаблицы85(Читать85("ВЫБРАТЬ Ссылка,Код,Наименование,ПериодДействияБазовый,ПометкаУдаления,Предопределенный ИЗ ПланВидовРасчета.УчебныеВидыНачисления85"), Пакет.Виды);
ПроверитьТаблицы85(Читать85("ВЫБРАТЬ Ссылка,Маркер85,Назначение85,Дата,Номер,ПометкаУдаления,Проведен ИЗ Документ.УчебныйРегистраторПериодов85"), Пакет.Документы);
ПроверитьТаблицы85(Читать85("ВЫБРАТЬ График85,Дата85,Дни85 ИЗ РегистрСведений.УчебныеДниГрафика85"), Пакет.График);
ПроверитьТаблицы85(Читать85("ВЫБРАТЬ Регистратор,НомерСтроки,ПериодРегистрации,ВидРасчета,Активность,Сторно,БазовыйПериодНачало,БазовыйПериодКонец,ПериодДействияНачало,ПериодДействияКонец,Сотрудник85,График85,Сумма85 ИЗ РегистрРасчета.УчебныеНачисленияПериодов85"), Пакет.Записи);
ПроверитьТаблицы85(Читать85("ВЫБРАТЬ ОбъектПерерасчета,ВидРасчета,Сотрудник85 ИЗ РегистрРасчета.УчебныеНачисленияПериодов85.ОчередьПремии85"), Пакет.Очередь);
Для Каждого Вид Из Пакет.Виды Цикл
ОбъектВида = Вид.Ссылка.ПолучитьОбъект();
Если ОбъектВида = Неопределено Или ОбъектВида.ВедущиеВидыРасчета.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-KIND: неизвестные ведущие зависимости";
КонецЕсли;
ОжидаемыйВытесняющий = ?(Вид.Код = "WORK85", Пакет.Вытесняющий, Неопределено);
ОжидаемыйБазовый = ?(Вид.Код = "BON85", Пакет.Базовый, Неопределено);
ПроверитьЗависимость85(ОбъектВида.ВытесняющиеВидыРасчета, ОжидаемыйВытесняющий);
ПроверитьЗависимость85(ОбъектВида.БазовыеВидыРасчета, ОжидаемыйБазовый);
КонецЦикла;
КонецПроцедуры
Процедура ПроверитьЗависимость85(ТабличнаяЧасть, СвойВид)
ОжидаемоеКоличество = ?(СвойВид = Неопределено, 0, 1);
Если ТабличнаяЧасть.Количество() <> ОжидаемоеКоличество Тогда
ВызватьИсключение "OWN-PERIOD-KIND: неизвестный полный состав зависимости";
КонецЕсли;
Для Каждого СтрокаЗависимости Из ТабличнаяЧасть Цикл
Если ТипЗнч(СтрокаЗависимости.ВидРасчета) <> Тип("ПланВидовРасчетаСсылка.УчебныеВидыНачисления85")
Или СтрокаЗависимости.ВидРасчета <> СвойВид Тогда
ВызватьИсключение "OWN-PERIOD-KIND: неизвестная ссылка зависимости";
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция СвойВид85(Пакет, Код)
Строки = Пакет.Виды.НайтиСтроки(Новый Структура("Код", Код));
Если Строки.Количество() <> 1 Или ТипЗнч(Строки[0].Ссылка) <> Тип("ПланВидовРасчетаСсылка.УчебныеВидыНачисления85") Или Строки[0].Ссылка.Пустая() Тогда
ВызватьИсключение "OWN-PERIOD-KIND: нужен единственный собственный записанный вид";
КонецЕсли;
Возврат Строки[0].Ссылка;
КонецФункции
Функция СвойДокумент85(Пакет, Назначение)
Строки = Пакет.Документы.НайтиСтроки(Новый Структура("Назначение85", Назначение));
Если Строки.Количество() <> 1 Или ТипЗнч(Строки[0].Ссылка) <> Тип("ДокументСсылка.УчебныйРегистраторПериодов85") Или Строки[0].Ссылка.Пустая()
Или Строки[0].Маркер85 <> Строка(Пакет.UUID) Тогда
ВызватьИсключение "OWN-PERIOD-DOCUMENT: нужен единственный собственный записанный документ своего UUID";
КонецЕсли;
Возврат Строки[0].Ссылка;
КонецФункции
Процедура Подготовить85(Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если Пакет.Этап <> 0 Или Пакет.Виды.Количество() <> 0 Или Пакет.Документы.Количество() <> 0
Или Пакет.График.Количество() <> 0 Или Пакет.Записи.Количество() <> 0 Или Пакет.Очередь.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-STATE: подготовка допускается только на полностью пустом стенде";
КонецЕсли;
Для Каждого Код Из СтрРазделить("WORK85,ABS85,BON85", ",") Цикл
ПроверитьПолноеСостояние85(Пакет);
Вид = ПланыВидовРасчета.УчебныеВидыНачисления85.СоздатьВидРасчета();
Вид.Код = Код;
Вид.Наименование = Код;
Вид.ПериодДействияБазовый = Ложь;
Если Не Вид.ЭтоНовый() Или Вид.БазовыеВидыРасчета.Количество() <> 0 Или Вид.ВытесняющиеВидыРасчета.Количество() <> 0 Или Вид.ВедущиеВидыРасчета.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-KIND: требуется собственный новый вид без зависимостей";
КонецЕсли;
Вид.Записать();
Если ТипЗнч(Вид.Ссылка) <> Тип("ПланВидовРасчетаСсылка.УчебныеВидыНачисления85") Или Вид.Ссылка.Пустая() Тогда
ВызватьИсключение "OWN-PERIOD-KIND: новая ссылка не получена после записи";
КонецЕсли;
Ожидание = Пакет.Виды.Добавить();
Ожидание.Ссылка = Вид.Ссылка;
Ожидание.Код = Код;
Ожидание.Наименование = Код;
Ожидание.ПериодДействияБазовый = Ложь;
Ожидание.ПометкаУдаления = Ложь;
Ожидание.Предопределенный = Ложь;
ПроверитьПолноеСостояние85(Пакет);
КонецЦикла;
ПроверитьПолноеСостояние85(Пакет);
ВидWORK = СвойВид85(Пакет, "WORK85").ПолучитьОбъект();
ВидWORK.ВытесняющиеВидыРасчета.Добавить().ВидРасчета = СвойВид85(Пакет, "ABS85");
ВидWORK.Записать();
Пакет.Вытесняющий = СвойВид85(Пакет, "ABS85");
ПроверитьПолноеСостояние85(Пакет);
ВидBON = СвойВид85(Пакет, "BON85").ПолучитьОбъект();
ВидBON.БазовыеВидыРасчета.Добавить().ВидРасчета = СвойВид85(Пакет, "WORK85");
ВидBON.Записать();
Пакет.Базовый = СвойВид85(Пакет, "WORK85");
ПроверитьПолноеСостояние85(Пакет);
Для Каждого Назначение Из СтрРазделить("WORK,BON,ABS", ",") Цикл
ПроверитьПолноеСостояние85(Пакет);
Документ = Документы.УчебныйРегистраторПериодов85.СоздатьДокумент();
Документ.Номер = Назначение;
Документ.Дата = Дата(2026, 1, 1);
Документ.Маркер85 = Строка(Пакет.UUID);
Документ.Назначение85 = Назначение;
Если Не Документ.ЭтоНовый() Тогда
ВызватьИсключение "OWN-PERIOD-DOCUMENT: требуется собственный новый документ";
КонецЕсли;
Документ.Записать(РежимЗаписиДокумента.Запись);
Ожидание = Пакет.Документы.Добавить();
Ожидание.Ссылка = Документ.Ссылка;
Ожидание.Маркер85 = Строка(Пакет.UUID);
Ожидание.Назначение85 = Назначение;
Ожидание.Дата = Дата(2026, 1, 1);
Ожидание.Номер = Назначение;
Ожидание.ПометкаУдаления = Ложь;
Ожидание.Проведен = Ложь;
СвойДокумент85(Пакет, Назначение);
ПроверитьПолноеСостояние85(Пакет);
КонецЦикла;
ПроверитьПолноеСостояние85(Пакет);
НаборГрафика = РегистрыСведений.УчебныеДниГрафика85.СоздатьНаборЗаписей();
НаборГрафика.Отбор.График85.Установить("DAY85");
Для День = 11 По 13 Цикл
ЗаписьГрафика = НаборГрафика.Добавить();
ЗаписьГрафика.График85 = "DAY85";
ЗаписьГрафика.Дата85 = Дата(2026, 1, День);
ЗаписьГрафика.Дни85 = 1;
КонецЦикла;
НаборГрафика.Записать(Истина);
Для День = 11 По 13 Цикл
Ожидание = Пакет.График.Добавить();
Ожидание.График85 = "DAY85";
Ожидание.Дата85 = Дата(2026, 1, День);
Ожидание.Дни85 = 1;
КонецЦикла;
ПроверитьПолноеСостояние85(Пакет);
Пакет.Этап = 1;
Сообщить("Своя подготовка подтверждена. В ИБ еще нет начислений. UUID: " + Строка(Пакет.UUID));
КонецПроцедуры
Процедура ПроверитьОтбор85(ОтборНабора, ИмяКлюча, СвояСсылка)
Если ТипЗнч(ОтборНабора) <> Тип("Отбор") Или СвояСсылка = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-FILTER: неизвестный отбор";
КонецЕсли;
Используемых = 0;
Для Индекс = 0 По ОтборНабора.Количество() - 1 Цикл
Элемент = ОтборНабора.Получить(Индекс);
Если ТипЗнч(Элемент.Использование) <> Тип("Булево") Тогда
ВызватьИсключение "OWN-PERIOD-FILTER: неверный флаг фильтра";
КонецЕсли;
Если Элемент.Имя <> ИмяКлюча И Элемент.Имя <> "Сотрудник85" Тогда
ВызватьИсключение "OWN-PERIOD-FILTER: посторонний ключ фильтра";
КонецЕсли;
Если Элемент.Использование Тогда
Используемых = Используемых + 1;
Если Элемент.Имя <> ИмяКлюча Или Элемент.ВидСравнения <> ВидСравнения.Равно
Или ТипЗнч(Элемент.Значение) <> ТипЗнч(СвояСсылка) Или Элемент.Значение <> СвояСсылка Тогда
ВызватьИсключение "OWN-PERIOD-FILTER: используется не единственный собственный регистратор";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если Используемых <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-FILTER: должен использоваться ровно один свой ключ";
КонецЕсли;
КонецПроцедуры
Функция НовыйНабор85(Пакет, Назначение)
СвояСсылка = СвойДокумент85(Пакет, Назначение);
Набор = РегистрыРасчета.УчебныеНачисленияПериодов85.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СвояСсылка);
ПроверитьОтбор85(Набор.Отбор, "Регистратор", СвояСсылка);
Если Набор.Количество() <> 0 Или Набор.ОбменДанными.Загрузка Тогда
ВызватьИсключение "OWN-PERIOD-SET: фабрика должна дать собственный пустой набор без загрузки обмена";
КонецЕсли;
Возврат Набор;
КонецФункции
Функция СвояСтрока85(Пакет, Назначение, Сумма)
Начало = Дата(2026, 1, ?(Назначение = "ABS", 12, 11));
Конец = КонецДня(Дата(2026, 1, ?(Назначение = "ABS", 12, 13)));
Если ТипЗнч(Сумма) <> Тип("Число") Или Сумма < 0 Или Сумма <> Окр(Сумма, 2) Или Начало > Конец Тогда
ВызватьИсключение "OWN-PERIOD-ROW: неверная сумма или период";
КонецЕсли;
Результат = Новый Структура;
Результат.Вставить("Регистратор", СвойДокумент85(Пакет, Назначение));
Результат.Вставить("НомерСтроки", 1);
Результат.Вставить("ПериодРегистрации", Дата(2026, 1, 1));
Результат.Вставить("ВидРасчета", СвойВид85(Пакет, Назначение + "85"));
Результат.Вставить("Активность", Истина);
Результат.Вставить("Сторно", Ложь);
Результат.Вставить("БазовыйПериодНачало", Дата(2026, 1, 11));
Результат.Вставить("БазовыйПериодКонец", КонецДня(Дата(2026, 1, 13)));
Результат.Вставить("ПериодДействияНачало", Начало);
Результат.Вставить("ПериодДействияКонец", Конец);
Результат.Вставить("Сотрудник85", "EMP85");
Результат.Вставить("График85", "DAY85");
Результат.Вставить("Сумма85", Сумма);
Возврат Результат;
КонецФункции
Функция ДобавитьНачисление85(Набор, Значения)
Запись = Набор.Добавить();
Запись.Регистратор = Значения.Регистратор;
Запись.ПериодРегистрации = Значения.ПериодРегистрации;
Запись.ВидРасчета = Значения.ВидРасчета;
Запись.Активность = Значения.Активность;
Запись.Сторно = Значения.Сторно;
Запись.БазовыйПериодНачало = Значения.БазовыйПериодНачало;
Запись.БазовыйПериодКонец = Значения.БазовыйПериодКонец;
Запись.ПериодДействияНачало = Значения.ПериодДействияНачало;
Запись.ПериодДействияКонец = Значения.ПериодДействияКонец;
Запись.Сотрудник85 = Значения.Сотрудник85;
Запись.График85 = Значения.График85;
Запись.Сумма85 = Значения.Сумма85;
Если Запись.ПериодДействия <> Дата(2026, 1, 1) Тогда
ВызватьИсключение "OWN-PERIOD-ROW: производный период действия должен быть началом января";
КонецЕсли;
Возврат Запись;
КонецФункции
Функция ПроверитьИнтервалы85(Интервалы, Дни)
Если ТипЗнч(Интервалы) <> Тип("ФиксированныйМассив") Или Интервалы.Количество() <> ?(Дни = 3, 1, 2) Тогда
ВызватьИсключение "OWN-PERIOD-FPD: неверный полный состав фактических интервалов";
КонецЕсли;
Длительность = 0;
Использованные = Новый Массив;
Для Каждого Интервал Из Интервалы Цикл
Если ТипЗнч(Интервал) <> Тип("ЭлементФактическогоПериодаДействия") Или ТипЗнч(Интервал.ДатаНачала) <> Тип("Дата") Или ТипЗнч(Интервал.ДатаОкончания) <> Тип("Дата") Тогда
ВызватьИсключение "OWN-PERIOD-FPD: неверный нативный тип интервала";
КонецЕсли;
НачальныйДень = День(Интервал.ДатаНачала);
Если Дни = 3 Тогда
Если Интервал.ДатаНачала <> Дата(2026, 1, 11) Или Интервал.ДатаОкончания <> КонецДня(Дата(2026, 1, 13)) Тогда
ВызватьИсключение "OWN-PERIOD-FPD: ожидался целый собственный период 11..13 января";
КонецЕсли;
Иначе
Если (НачальныйДень <> 11 И НачальныйДень <> 13) Или Интервал.ДатаНачала <> Дата(2026, 1, НачальныйДень)
Или Интервал.ДатаОкончания <> КонецДня(Дата(2026, 1, НачальныйДень)) Тогда
ВызватьИсключение "OWN-PERIOD-FPD: должен отсутствовать ровно средний день";
КонецЕсли;
КонецЕсли;
Если Использованные.Найти(НачальныйДень) <> Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-FPD: обнаружен дублированный интервал";
КонецЕсли;
Использованные.Добавить(НачальныйДень);
Длительность = Длительность + (НачалоДня(Интервал.ДатаОкончания) - Интервал.ДатаНачала) / 86400 + 1;
КонецЦикла;
Если Длительность <> Дни Тогда
ВызватьИсключение "OWN-PERIOD-FPD: неверное количество собственных дней";
КонецЕсли;
Возврат Длительность;
КонецФункции
Функция ПроверитьПредварительныйФПД85(Набор, Дни)
Если Набор.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: нужен единственный собственный кандидат";
КонецЕсли;
ИсходныеДанные = Набор.Выгрузить();
ФПД = Набор.ПолучитьФактическийПериодДействия();
Если ТипЗнч(ФПД) <> Тип("ТаблицаЗначений") Или ФПД.Количество() <> ?(Дни = 3, 1, 2)
Или ФПД.Колонки.Количество() <> ИсходныеДанные.Колонки.Количество() Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: неверная полная структура native предварительного ФПД";
КонецЕсли;
Для Каждого Колонка Из ИсходныеДанные.Колонки Цикл
Если ФПД.Колонки.Найти(Колонка.Имя) = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: потеряна колонка собственного регистра";
КонецЕсли;
КонецЦикла;
Длительность = 0;
НачальныеДни = Новый Массив;
Для Каждого СтрокаФПД Из ФПД Цикл
Для Каждого Колонка Из ИсходныеДанные.Колонки Цикл
Если Колонка.Имя <> "ПериодДействияНачало" И Колонка.Имя <> "ПериодДействияКонец" Тогда
Если ТипЗнч(СтрокаФПД[Колонка.Имя]) <> ТипЗнч(ИсходныеДанные[0][Колонка.Имя]) Или СтрокаФПД[Колонка.Имя] <> ИсходныеДанные[0][Колонка.Имя] Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: изменилось поле собственного кандидата";
КонецЕсли;
КонецЕсли;
КонецЦикла;
Если ТипЗнч(СтрокаФПД.ПериодДействияНачало) <> Тип("Дата") Или ТипЗнч(СтрокаФПД.ПериодДействияКонец) <> Тип("Дата") Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: границы должны быть датами";
КонецЕсли;
ДеньНачала = День(СтрокаФПД.ПериодДействияНачало);
Если Дни = 3 Тогда
Если СтрокаФПД.ПериодДействияНачало <> Дата(2026, 1, 11) Или СтрокаФПД.ПериодДействияКонец <> КонецДня(Дата(2026, 1, 13)) Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: ожидался полный период 11..13 января";
КонецЕсли;
Иначе
Если (ДеньНачала <> 11 И ДеньНачала <> 13) Или СтрокаФПД.ПериодДействияНачало <> Дата(2026, 1, ДеньНачала)
Или СтрокаФПД.ПериодДействияКонец <> КонецДня(Дата(2026, 1, ДеньНачала)) Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: ожидались два отдельных дня без 12 января";
КонецЕсли;
КонецЕсли;
Если НачальныеДни.Найти(ДеньНачала) <> Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: дублированный интервал";
КонецЕсли;
НачальныеДни.Добавить(ДеньНачала);
Длительность = Длительность + (НачалоДня(СтрокаФПД.ПериодДействияКонец) - СтрокаФПД.ПериодДействияНачало) / 86400 + 1;
КонецЦикла;
Если Длительность <> Дни Тогда
ВызватьИсключение "OWN-PERIOD-PREVIEW: неверная независимая длительность";
КонецЕсли;
Возврат Длительность;
КонецФункции
Процедура ПроверитьЗапись85(Запись, Ожидание)
Если ТипЗнч(Запись) <> Тип("РегистрРасчетаЗапись.УчебныеНачисленияПериодов85") Тогда
ВызватьИсключение "OWN-PERIOD-ROW: требуется настоящая запись собственного набора";
КонецЕсли;
Для Каждого Колонка Из Ожидание Цикл
Если ТипЗнч(Запись[Колонка.Ключ]) <> ТипЗнч(Колонка.Значение) Или Запись[Колонка.Ключ] <> Колонка.Значение Тогда
ВызватьИсключение "OWN-PERIOD-ROW: неизвестное поле, тип или значение своего движения";
КонецЕсли;
КонецЦикла;
Если Запись.ПериодДействия <> Дата(2026, 1, 1) Тогда
ВызватьИсключение "OWN-PERIOD-ROW: изменился производный месячный период";
КонецЕсли;
КонецПроцедуры
Функция СвойПрочитанныйНабор85(Пакет, Назначение, Сумма)
ПроверитьПолноеСостояние85(Пакет);
Набор = НовыйНабор85(Пакет, Назначение);
Набор.Прочитать();
Если Набор.Количество() <> 1 Или Не Набор.Выбран() Или Набор.Модифицированность() Тогда
ВызватьИсключение "OWN-PERIOD-READ: должна быть единственная свежая неизмененная запись";
КонецЕсли;
ПроверитьЗапись85(Набор.Получить(0), СвояСтрока85(Пакет, Назначение, Сумма));
Возврат Набор;
КонецФункции
Функция ЕдинственныйСкаляр85(Данные)
Если ТипЗнч(Данные) <> Тип("ТаблицаЗначений") Или Данные.Количество() <> 1 Или Данные.Колонки.Количество() <> 1 Или ТипЗнч(Данные[0][0]) <> Тип("Число") Тогда
ВызватьИсключение "OWN-PERIOD-GRAPH: нужен единственный настоящий числовой результат графика записи";
КонецЕсли;
Возврат Данные[0][0];
КонецФункции
Процедура ПроверитьДваСтолбца85(Данные, НомерСтроки, Значение)
Если ТипЗнч(Данные) <> Тип("ТаблицаЗначений") Или Данные.Количество() <> 1 Или Данные.Колонки.Количество() <> 2
Или Данные.Колонки.Найти("НомерСтроки") = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-RESULT: неподдерживаемая полная native структура двух колонок";
КонецЕсли;
Если ТипЗнч(Данные[0].НомерСтроки) <> Тип("Число") Или Данные[0].НомерСтроки <> НомерСтроки Тогда
ВызватьИсключение "OWN-PERIOD-RESULT: результат относится не к своей записи";
КонецЕсли;
Для Каждого Колонка Из Данные.Колонки Цикл
Если Колонка.Имя <> "НомерСтроки" Тогда
Если ТипЗнч(Данные[0][Колонка.Имя]) <> Тип("Число") Или Данные[0][Колонка.Имя] <> Значение Тогда
ВызватьИсключение "OWN-PERIOD-RESULT: неверное настоящее числовое значение";
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Функция ДниПоГрафику85(Пакет, Набор, Дни)
Запись = Набор.Получить(0);
Если Запись.Регистратор <> СвойДокумент85(Пакет, "WORK") Тогда
ВызватьИсключение "OWN-PERIOD-GRAPH: ожидалась только своя запись WORK";
КонецЕсли;
Факт = ЕдинственныйСкаляр85(Запись.ПолучитьДанныеГрафика(ВидПериодаРегистраРасчета.ФактическийПериодДействия));
Если Факт <> Дни Или ПроверитьИнтервалы85(Запись.ФактическийПериодДействия, Дни) <> Факт Тогда
ВызватьИсключение "OWN-PERIOD-GRAPH: график и реальные интервалы расходятся";
КонецЕсли;
ДанныеМенеджера = РегистрыРасчета.УчебныеНачисленияПериодов85.ПолучитьДанныеГрафика(Новый Структура("Регистратор", Запись.Регистратор), ВидПериодаРегистраРасчета.ФактическийПериодДействия);
ПроверитьДваСтолбца85(ДанныеМенеджера, Запись.НомерСтроки, Факт);
Возврат Факт;
КонецФункции
Функция БазаПремии85(Пакет, НаборПремии, ОжидаемаяБаза)
Запись = НаборПремии.Получить(0);
Если Запись.Регистратор <> СвойДокумент85(Пакет, "BON") Или Запись.ВидРасчета <> СвойВид85(Пакет, "BON85")
Или Запись.БазовыйПериодНачало <> Дата(2026, 1, 11) Или Запись.БазовыйПериодКонец <> КонецДня(Дата(2026, 1, 13)) Тогда
ВызватьИсключение "OWN-PERIOD-BASE: неизвестная запись или базовый период премии";
КонецЕсли;
Ресурсы = Новый Массив;
Ресурсы.Добавить("УчебныеНачисленияПериодов85.Сумма85");
Измерения = Новый Структура("Сотрудник85", "УчебныеНачисленияПериодов85.Сотрудник85");
ДанныеЗаписи = Запись.ПолучитьБазу(Ресурсы, Измерения);
ДанныеМенеджера = РегистрыРасчета.УчебныеНачисленияПериодов85.ПолучитьБазу(Новый Структура("Регистратор", Запись.Регистратор), Ресурсы, Измерения);
ПроверитьДваСтолбца85(ДанныеЗаписи, Запись.НомерСтроки, ОжидаемаяБаза);
ПроверитьДваСтолбца85(ДанныеМенеджера, Запись.НомерСтроки, ОжидаемаяБаза);
Для Каждого Колонка Из ДанныеЗаписи.Колонки Цикл
Если Колонка.Имя <> "НомерСтроки" Тогда
Возврат ДанныеЗаписи[0][Колонка.Имя];
КонецЕсли;
КонецЦикла;
ВызватьИсключение "OWN-PERIOD-BASE: числовая колонка не найдена";
КонецФункции
Процедура ЗаписатьНовоеНачисление85(Пакет, Назначение, Сумма, ДниПредварительно)
ПроверитьПолноеСостояние85(Пакет);
СвояСсылка = СвойДокумент85(Пакет, Назначение);
Если Пакет.Записи.НайтиСтроки(Новый Структура("Регистратор", СвояСсылка)).Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-REPLACE: регистратор должен еще не иметь собственных движений";
КонецЕсли;
Набор = НовыйНабор85(Пакет, Назначение);
Значения = СвояСтрока85(Пакет, Назначение, Сумма);
Запись = ДобавитьНачисление85(Набор, Значения);
ПроверитьЗапись85(Запись, Значения);
Если ДниПредварительно > 0 Тогда
РассчитаннаяСумма = ПроверитьПредварительныйФПД85(Набор, ДниПредварительно) * 250;
Если РассчитаннаяСумма <> Сумма Тогда
ВызватьИсключение "OWN-PERIOD-MATH: сумма не совпала с реальным предварительным ФПД";
КонецЕсли;
Запись.Сумма85 = РассчитаннаяСумма;
КонецЕсли;
ПроверитьПолноеСостояние85(Пакет);
ПроверитьОтбор85(Набор.Отбор, "Регистратор", СвояСсылка);
Набор.Записать(Истина, Ложь, Истина, Ложь);
Ожидание = Пакет.Записи.Добавить();
ЗаполнитьЗначенияСвойств(Ожидание, Значения);
ПроверитьПолноеСостояние85(Пакет);
КонецПроцедуры
Процедура ИзменитьТолькоРесурс85(Пакет, Назначение, Было, Стало)
Набор = СвойПрочитанныйНабор85(Пакет, Назначение, Было);
Запись = Набор.Получить(0);
До = СвояСтрока85(Пакет, Назначение, Было);
Запись.Сумма85 = Стало;
После = СвояСтрока85(Пакет, Назначение, Стало);
ПроверитьЗапись85(Запись, После);
Для Каждого Поле Из До Цикл
Если Поле.Ключ <> "Сумма85" И До[Поле.Ключ] <> После[Поле.Ключ] Тогда
ВызватьИсключение "OWN-PERIOD-ONLYWRITE: изменены не только ресурсы";
КонецЕсли;
КонецЦикла;
ПроверитьПолноеСостояние85(Пакет);
ПроверитьОтбор85(Набор.Отбор, "Регистратор", СвойДокумент85(Пакет, Назначение));
Набор.Записать(Истина, Истина, Истина, Ложь);
Строки = Пакет.Записи.НайтиСтроки(Новый Структура("Регистратор", СвойДокумент85(Пакет, Назначение)));
Если Строки.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-ONLYWRITE: полный собственный набор должен содержать одну строку";
КонецЕсли;
Строки[0].Сумма85 = Стало;
ПроверитьПолноеСостояние85(Пакет);
СвойПрочитанныйНабор85(Пакет, Назначение, Стало);
КонецПроцедуры
Функция НоваяОчередь85(Пакет)
Менеджеры = РегистрыРасчета.УчебныеНачисленияПериодов85.Перерасчеты;
Если ТипЗнч(Менеджеры) <> Тип("ПерерасчетыМенеджер.УчебныеНачисленияПериодов85") Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: требуется настоящий современный менеджер перерасчетов";
КонецЕсли;
Очередь = Менеджеры.ОчередьПремии85.СоздатьНаборЗаписей();
Если ТипЗнч(Очередь) <> Тип("ПерерасчетНаборЗаписей.ОчередьПремии85") Или Очередь.Количество() <> 0 Или Очередь.Выбран() Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: требуется настоящий новый пустой несчитанный набор";
КонецЕсли;
Очередь.Отбор.ОбъектПерерасчета.Установить(СвойДокумент85(Пакет, "BON"));
ПроверитьОтбор85(Очередь.Отбор, "ОбъектПерерасчета", СвойДокумент85(Пакет, "BON"));
Если Очередь.ОбменДанными.Загрузка Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: режим Загрузка запрещен";
КонецЕсли;
Очередь.ДополнительныеСвойства.Вставить("Пакет85", Пакет);
Схема = Очередь.ВыгрузитьКолонки("ОбъектПерерасчета,ВидРасчета,Сотрудник85");
Если ТипЗнч(Схема) <> Тип("ТаблицаЗначений") Или Схема.Количество() <> 0 Или Схема.Колонки.Количество() <> 3
Или Схема.Колонки.Найти("ОбъектПерерасчета") = Неопределено Или Схема.Колонки.Найти("ВидРасчета") = Неопределено
Или Схема.Колонки.Найти("Сотрудник85") = Неопределено Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: выгружается только полная собственная схема без данных";
КонецЕсли;
Для Каждого Колонка Из Схема.Колонки Цикл
ИмяТипа = ?(Колонка.Имя = "ОбъектПерерасчета", "ДокументСсылка.УчебныйРегистраторПериодов85", ?(Колонка.Имя = "ВидРасчета", "ПланВидовРасчетаСсылка.УчебныеВидыНачисления85", "Строка"));
Если Колонка.ТипЗначения.Типы().Количество() <> 1 Или Не Колонка.ТипЗначения.СодержитТип(Тип(ИмяТипа)) Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: неизвестный тип полной выгруженной схемы";
КонецЕсли;
Если Колонка.Имя = "Сотрудник85" И Колонка.ТипЗначения.КвалификаторыСтроки.Длина <> 12 Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: неверный тип собственного измерения";
КонецЕсли;
КонецЦикла;
Возврат Очередь;
КонецФункции
Процедура ПроверитьКандидатОчереди85(Очередь, Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если ТипЗнч(Очередь) <> Тип("ПерерасчетНаборЗаписей.ОчередьПремии85") Или Очередь.Количество() <> 1 Или Очередь.ОбменДанными.Загрузка Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: нужна единственная собственная задача без режима Загрузка";
КонецЕсли;
ПроверитьОтбор85(Очередь.Отбор, "ОбъектПерерасчета", СвойДокумент85(Пакет, "BON"));
Строка = Очередь.Получить(0);
Если ТипЗнч(Строка.ОбъектПерерасчета) <> Тип("ДокументСсылка.УчебныйРегистраторПериодов85")
Или ТипЗнч(Строка.ВидРасчета) <> Тип("ПланВидовРасчетаСсылка.УчебныеВидыНачисления85") Или ТипЗнч(Строка.Сотрудник85) <> Тип("Строка")
Или Строка.ОбъектПерерасчета <> СвойДокумент85(Пакет, "BON") Или Строка.ВидРасчета <> СвойВид85(Пакет, "BON85") Или Строка.Сотрудник85 <> "EMP85" Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: чужой объект, вид или измерение";
КонецЕсли;
КонецПроцедуры
Процедура Начислить85(Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если Пакет.Этап <> 1 Или Пакет.Записи.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-STATE: начисление только после собственной подготовки";
КонецЕсли;
ЗаписатьНовоеНачисление85(Пакет, "WORK", 750, 3);
НаборWORK = СвойПрочитанныйНабор85(Пакет, "WORK", 750);
Дни = ДниПоГрафику85(Пакет, НаборWORK, 3);
Если Дни * 250 <> 750 Тогда
ВызватьИсключение "OWN-PERIOD-MATH: три дня должны дать 750";
КонецЕсли;
ЗаписатьНовоеНачисление85(Пакет, "BON", 0, 0);
НаборBON = СвойПрочитанныйНабор85(Пакет, "BON", 0);
База = БазаПремии85(Пакет, НаборBON, 750);
Премия = Окр(База * 0.1, 2);
Если Премия <> 75 Тогда
ВызватьИсключение "OWN-PERIOD-MATH: первая собственная премия должна быть 75";
КонецЕсли;
ИзменитьТолькоРесурс85(Пакет, "BON", 0, Премия);
Пакет.Этап = 2;
ПроверитьПолноеСостояние85(Пакет);
Сообщить("Свои начальные суммы: WORK 750, BON 75, итог 825. Автоматическая очередь отключена.");
КонецПроцедуры
Процедура ИсключитьСреднийДень85(Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если Пакет.Этап <> 2 Или Пакет.Очередь.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-STATE: вытеснение только после собственного первого начисления";
КонецЕсли;
ЗаписатьНовоеНачисление85(Пакет, "ABS", 0, 0);
НаборWORK = СвойПрочитанныйНабор85(Пакет, "WORK", 750);
Дни = ДниПоГрафику85(Пакет, НаборWORK, 2);
Если Дни <> 2 Или НаборWORK.Получить(0).Сумма85 <> 750 Тогда
ВызватьИсключение "OWN-PERIOD-MATH: движок должен изменить ФПД, но не вычислять деньги";
КонецЕсли;
ПроверитьПолноеСостояние85(Пакет);
Очередь = НоваяОчередь85(Пакет);
Задача = Очередь.Добавить();
Задача.ОбъектПерерасчета = СвойДокумент85(Пакет, "BON");
Задача.ВидРасчета = СвойВид85(Пакет, "BON85");
Задача.Сотрудник85 = "EMP85";
ПроверитьКандидатОчереди85(Очередь, Пакет);
ПроверитьНеверныеКандидаты85(Пакет);
Если Не Очередь.Модифицированность() Или Не Очередь.ПроверитьЗаполнение() Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: новая задача должна быть измененной и заполненной";
КонецЕсли;
ПроверитьПолноеСостояние85(Пакет);
ПроверитьОтбор85(Очередь.Отбор, "ОбъектПерерасчета", СвойДокумент85(Пакет, "BON"));
Очередь.Записать(Истина);
Ожидание = Пакет.Очередь.Добавить();
Ожидание.ОбъектПерерасчета = СвойДокумент85(Пакет, "BON");
Ожидание.ВидРасчета = СвойВид85(Пакет, "BON85");
Ожидание.Сотрудник85 = "EMP85";
ПроверитьПолноеСостояние85(Пакет);
СвежаяОчередь = НоваяОчередь85(Пакет);
СвежаяОчередь.Прочитать();
ПроверитьКандидатОчереди85(СвежаяОчередь, Пакет);
ПроверитьТаблицы85(СвежаяОчередь.Выгрузить(), Пакет.Очередь);
Если Не СвежаяОчередь.Выбран() Или СвежаяОчередь.Модифицированность() Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: нужен новый полностью считанный неизмененный набор";
КонецЕсли;
Пакет.Этап = 3;
Сообщить("Средний день вытеснен. ФПД: 11 и 13 января. Деньги пока старые. Создана одна ЯВНАЯ своя задача премии; это не автоматический перерасчет.");
КонецПроцедуры
Процедура Пересчитать85(Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если Пакет.Этап <> 3 Или Пакет.Очередь.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-STATE: необходима собственная ожидающая задача";
КонецЕсли;
НаборWORK = СвойПрочитанныйНабор85(Пакет, "WORK", 750);
Кандидат = НовыйНабор85(Пакет, "WORK");
ДобавитьНачисление85(Кандидат, СвояСтрока85(Пакет, "WORK", 750));
ДниКандидата = ПроверитьПредварительныйФПД85(Кандидат, 2);
Дни = ДниПоГрафику85(Пакет, НаборWORK, 2);
Если Дни <> ДниКандидата Или Дни * 250 <> 500 Тогда
ВызватьИсключение "OWN-PERIOD-MATH: фактический и предварительный ФПД должны дать 500";
КонецЕсли;
ИзменитьТолькоРесурс85(Пакет, "WORK", 750, Дни * 250);
НаборBON = СвойПрочитанныйНабор85(Пакет, "BON", 75);
База = БазаПремии85(Пакет, НаборBON, 500);
Премия = Окр(База * 0.1, 2);
Если Премия <> 50 Тогда
ВызватьИсключение "OWN-PERIOD-MATH: обновленная собственная премия должна быть 50";
КонецЕсли;
ИзменитьТолькоРесурс85(Пакет, "BON", 75, Премия);
Пакет.Этап = 4;
ПроверитьПолноеСостояние85(Пакет);
Сообщить("Свой расчет подтвержден: 2 дня x 250 = 500, премия 10% = 50, итог 550. Очередь еще не удалена.");
КонецПроцедуры
Процедура ОчиститьСвоюЗадачу85(Пакет) Экспорт
ПроверитьПолноеСостояние85(Пакет);
Если Пакет.Этап <> 4 Или Пакет.Очередь.Количество() <> 1 Тогда
ВызватьИсключение "OWN-PERIOD-STATE: очистка допустима только после собственной успешной сверки 550";
КонецЕсли;
Очередь = НоваяОчередь85(Пакет);
Очередь.Прочитать();
ПроверитьКандидатОчереди85(Очередь, Пакет);
ПроверитьТаблицы85(Очередь.Выгрузить(), Пакет.Очередь);
Если Не Очередь.Выбран() Или Очередь.Модифицированность() Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: задача изменилась до очистки";
КонецЕсли;
Очередь.Очистить();
ПроверитьПолноеСостояние85(Пакет);
ПроверитьОтбор85(Очередь.Отбор, "ОбъектПерерасчета", СвойДокумент85(Пакет, "BON"));
Если Очередь.Количество() <> 0 Тогда
ВызватьИсключение "OWN-PERIOD-QUEUE: свой пустой кандидат не подготовлен";
КонецЕсли;
Очередь.Записать(Истина);
Пакет.Очередь.Очистить();
ПроверитьПолноеСостояние85(Пакет);
СвежаяОчередь = НоваяОчередь85(Пакет);
СвежаяОчередь.Прочитать();
ПроверитьТаблицы85(СвежаяОчередь.Выгрузить(), Пакет.Очередь);
Пакет.Этап = 5;
Сообщить("Удалена только одна собственная задача BON/EMP85. Начисления 500 + 50 + 0 и график сохранены. Не повторяйте учебные этапы.");
КонецПроцедуры
Процедура ПроверитьНеверныеКандидаты85(Пакет)
НезаполненнаяОчередь = НоваяОчередь85(Пакет);
Задача = НезаполненнаяОчередь.Добавить();
Задача.ОбъектПерерасчета = СвойДокумент85(Пакет, "BON");
Задача.ВидРасчета = СвойВид85(Пакет, "BON85");
Задача.Сотрудник85 = "";
Если НезаполненнаяОчередь.ПроверитьЗаполнение() Тогда
ВызватьИсключение "OWN-PERIOD-NEGATIVE: незаполненная собственная задача ошибочно принята";
КонецЕсли;
Поймано = Ложь;
Попытка
СвояСтрока85(Пакет, "WORK", "750");
Исключение
Если СтрНайти(ОписаниеОшибки(), "OWN-PERIOD-ROW: неверная сумма или период") = 0 Тогда
ВызватьИсключение;
КонецЕсли;
Поймано = Истина;
КонецПопытки;
Если Не Поймано Тогда
ВызватьИсключение "OWN-PERIOD-NEGATIVE: строковая сумма не отклонена";
КонецЕсли;
ДругойПакет = Новый Структура;
Для Каждого Поле Из Пакет Цикл
ДругойПакет.Вставить(Поле.Ключ, Поле.Значение);
КонецЦикла;
ДругойПакет.UUID = Новый УникальныйИдентификатор;
Поймано = Ложь;
Попытка
ПроверитьПолноеСостояние85(ДругойПакет);
Исключение
Если СтрНайти(ОписаниеОшибки(), "OWN-PERIOD-PACKET: UUID собственного документа не совпал") = 0 Тогда
ВызватьИсключение;
КонецЕсли;
Поймано = Истина;
КонецПопытки;
Если Не Поймано Тогда
ВызватьИсключение "OWN-PERIOD-NEGATIVE: чужой UUID не отклонен";
КонецЕсли;
ПроверитьПолноеСостояние85(Пакет);
КонецПроцедурыПолный native модуль собственного набора перерасчета
Регистры расчета → УчебныеНачисленияПериодов85 → Перерасчеты → ОчередьПремии85 → Модуль набора записей
Native CheckFilling callback по #Если ТолстыйКлиентОбычноеПриложение: в собственном File/thickordinary символ есть на обеих частях, клиентской и серверной, и не означает «не сервер». Отдельный сервер клиент-серверного варианта, внешнее соединение и сервисный контекст без символа отказывают без вызова клиентского общего модуля.
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
#Если ТолстыйКлиентОбычноеПриложение Тогда
Если ТипЗнч(ПроверяемыеРеквизиты) <> Тип("Массив") Или ЭтотОбъект.Метаданные().Имя <> "ОчередьПремии85" Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Пакет = Неопределено;
Если Не ЭтотОбъект.ДополнительныеСвойства.Свойство("Пакет85", Пакет) Или ЭтотОбъект.Количество() <> 1 Или ЭтотОбъект.ОбменДанными.Загрузка Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Задача = ЭтотОбъект.Получить(0);
Если Задача.Сотрудник85 = "" Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
УчебныеПериодыМаршрут85.ПроверитьКандидатОчереди85(ЭтотОбъект, Пакет);
#Иначе
Отказ = Истина;
#КонецЕсли
КонецПроцедурыПолная собственная обычная форма пяти явных этапов
Обработки → УчебныеЭтапыПериодов85 → Формы → Этапы85 → Модуль
Толстый клиент, только ordinary форма и ее фактические source-control callbacks.
Перем СвойПакет85;
Перем ОшибкаЭтапа85;
Процедура ПриОткрытии()
ОшибкаЭтапа85 = Ложь;
ПодтверждаюИзменениеСвоегоСтенда85 = Ложь;
СвойПакет85 = УчебныеПериодыМаршрут85.НовыйПакет85();
Сообщить("Данные еще не записывались. Ставьте свое подтверждение заново перед каждым из пяти этапов. Автоматическая очередь выключена; деньги считает учебный код.");
КонецПроцедуры
Процедура ВыполнитьСвойЭтап85(Кнопка, Имя, Этап)
Если Кнопка = Неопределено Или ТипЗнч(Кнопка) <> Тип("Кнопка") Или Кнопка <> ЭлементыФормы[Имя] Или Кнопка.Имя <> Имя Тогда
ВызватьИсключение "OWN-PERIOD-BUTTON: нужна настоящая собственная кнопка";
КонецЕсли;
Если ОшибкаЭтапа85 Или СвойПакет85 = Неопределено Или СвойПакет85.Этап <> Этап Тогда
ВызватьИсключение "OWN-PERIOD-STATE: неверная последовательность или предыдущая ошибка, повтор запрещен";
КонецЕсли;
Если ТипЗнч(ПодтверждаюИзменениеСвоегоСтенда85) <> Тип("Булево") Или Не ПодтверждаюИзменениеСвоегоСтенда85 Тогда
ВызватьИсключение "OWN-PERIOD-CONFIRM: подтвердите изменение только своего нового стенда";
КонецЕсли;
ПодтверждаюИзменениеСвоегоСтенда85 = Ложь;
Попытка
УчебныеПериодыМаршрут85.ПроверитьПолноеСостояние85(СвойПакет85);
Если Этап = 0 Тогда
УчебныеПериодыМаршрут85.Подготовить85(СвойПакет85);
ИначеЕсли Этап = 1 Тогда
УчебныеПериодыМаршрут85.Начислить85(СвойПакет85);
ИначеЕсли Этап = 2 Тогда
УчебныеПериодыМаршрут85.ИсключитьСреднийДень85(СвойПакет85);
ИначеЕсли Этап = 3 Тогда
УчебныеПериодыМаршрут85.Пересчитать85(СвойПакет85);
ИначеЕсли Этап = 4 Тогда
УчебныеПериодыМаршрут85.ОчиститьСвоюЗадачу85(СвойПакет85);
Иначе
ВызватьИсключение "OWN-PERIOD-STATE: неизвестная команда";
КонецЕсли;
Исключение
ОшибкаЭтапа85 = Истина;
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
Процедура Подготовка85(Кнопка)
ВыполнитьСвойЭтап85(Кнопка, "Подготовка85", 0);
КонецПроцедуры
Процедура Начисление85(Кнопка)
ВыполнитьСвойЭтап85(Кнопка, "Начисление85", 1);
КонецПроцедуры
Процедура Исключение85(Кнопка)
ВыполнитьСвойЭтап85(Кнопка, "Исключение85", 2);
КонецПроцедуры
Процедура Перерасчет85(Кнопка)
ВыполнитьСвойЭтап85(Кнопка, "Перерасчет85", 3);
КонецПроцедуры
Процедура Очистка85(Кнопка)
ВыполнитьСвойЭтап85(Кнопка, "Очистка85", 4);
КонецПроцедурыРазбор по шагам
Начните с точной схемы и единственного реального собственного пользователя/соединения. Полная сверка не отбирает лишь первую строку: она читает все строки своих видов, документов, графика, регистра расчета и native таблицы перерасчета и сравнивает каждый ключ, тип и скаляр независимо от порядка строк.
Создайте actual виды и документы через собственные менеджеры, запишите и подтвердите полученные ссылки. Задайте единственную вытесняющую зависимость WORK←ABS и единственную базовую BON←WORK. Каждый следующий write снова требует полный ранее подтвержденный состав, без чужих видов, ссылок или строк.
Первый собственный WORK-кандидат имеет nominal11..13 января. Native ПолучитьФактическийПериодДействия возвращает actual ТаблицаЗначений, не FixedArray. Сравните всю схему с настоящей Выгрузить своего кандидата и все остальные колонки, а не лишь начало/конец. Записанный ФактическийПериодДействия, наоборот, RO FixedArray настоящих ЭлементФактическогоПериодаДействия.
Начальный Write(Истина,Ложь,Истина,Ложь) замещает только whitelist собственного регистратора, считает фактический период, но НЕ ставит автоматические перерасчеты. ПолучитьДанныеГрафика вызывается у actual manager и actual record с native ФактическийПериодДействия. Факт3 дня подтверждается независимыми тремя строками графика; сумма750.
ПолучитьБазу у manager требует own recorder filter, список полностью квалифицированных ресурсов и явное сопоставление измерений. У record первым параметром уже идут ресурсы, recorder filter не передают. Без Разрезы ожидается один result для одной своей строки; обе настоящие таблицы проверяются целиком и дают750/500, а код потребляет фактическую числовую колонку, не печатает golden вместо результата.
ABS12 января вытесняет только средний день WORK. Сверьте оба actual интервала без обещания порядка, их native типы и точные даты. Nominal bounds остаются11..13, RO ПериодДействия остается01.01.2026. Движок изменяет ФПД, но сумма750 сама не превращается в500. Явная задача собственной премии показывает обязанность прикладного кода выполнить расчет.
Настоящий modern manager получается через Перерасчеты→ОчередьПремии85→СоздатьНаборЗаписей. ВыгрузитьКолонки создает только схему трех собственных колонок и0 данных. Native Выбран/Модифицированность различают новый кандидат и свежий прочитанный набор, но не подтверждают отсутствие конкуренции. Native ПроверитьЗаполнение действительно доставляет scoped ЭтотОбъект обработчику.
Проверьте незаполненную собственную задачу native CheckFilling=false, строковую денежную сумму и чужой новый UUID только в памяти. Неожиданное исключение не скрывается. У pending-задачи полный persisted состав отдельно читается новым набором и нефильтрованным запросом; AdditionalProperties.UUID-маркер не является persisted полем очереди.
OnlyWrite=true только для уже записанного fresh-read набора и только ресурсных изменений. Сначала500 из фактических2 дней, затем реальная база500 и премия50. После readback550 отдельная ручная команда проверяет полную очередь и exact equality фильтр по своему BON-документу, пишет свой пустой набор с replace=true и подтверждает0 задач, остальные данные неизменны.
Как проверить результат
Подготовка: виды3, документы3, график3, начислений0 и задач0. Типы ссылок только собственного документа/плана; один UUID-маркер и один actual текущий пользователь.
Начисление: две raw записи WORK750/BON75, nominal WORK3 дня, actual ФПД1 интервал11..13, graph3, base750, итог825; автоматических задач0.
Вытеснение: raw записи WORK750/BON75/ABS0, WORK actual2 интервала11/13, graph2, явная задача строго BON-reference/BON-kind/EMP85, все ее поля проверены.
Пересчет: тот же полный состав ключей/дат, ресурсы WORK500/BON50/ABS0, actual base500, независимый итог550; очередь пока1. Очистка: очередь0, остальные строки полностью неизменны.
Три отрицательных in-memory проверки: empty employee→native CheckFilling=false; string money→точное own исключение; новый чужой nonce→точное own исключение. Неподдерживаемая TV/FixedArray схема, лишняя строка или измененный scalar дают fail-stop до следующей записи.
Ожидаемый результат
Ожидаемый при будущем ручном запуске результат: собственные начисления825→после явного прикладного перерасчета550, действительный ФПД3→2 дня и собственная явная задача0→1→0. Агент не создавал ИБ, не выполнял1С/график/записи/перерасчет/формы; только полный авторский текст и статические проверки.
На что обратить внимание
Production запрещено. Замещение затрагивает все записи соответствующего собственного recorder/object; филтр, полный глобальный состав и каждая строка сверяются до действия. Это не разрешение чистить чужую очередь.
Автоматическая запись перерасчетов во всех первичных Calc.Write=false, leading списки пустые. Здесь queue1 ставит авторский код явно. Не выдавайте такой маршрут за автоперерасчет механизма или за готовую зарплатную/налоговую схему.
Первый аргумент Calc.Write — Замещать; второй ТолькоЗапись; третий запись ФПД; четвертый автоматическая очередь. ТолькоЗапись=true означает только уже записанный набор с изменением ресурсов/реквизитов; здесь только Сумма85. В этом режиме пересчет ФПД/очереди не проводится. Замещать=Ложь (добавление) не используется: при таком режиме набор после записи дополнительно очищается по native контракту.
Имена/порядок недокументированной календарной числовой колонки не угадываются. Record ScheduleData строго1×1 Number; manager/base строго1×2 с ожидаемым line identity и единственной оставшейся actual numeric колонкой. Если native структура в конкретном ручном стенде иная — стоп, не исправляйте result фиктивными значениями.
Колонки предварительного ФПД берутся из полной фактической схемы собственного native кандидата; их совпадение и скаляры проверяются, а неизменность непроизнесенных в справке qualifiers результата не обещается. Порядок строк/интервалов не является предпосылкой.
RO контейнеры Отбор, ОбменДанными, ДополнительныеСвойства не переназначают. Изменяется единственный собственный фильтр и свой memory-marker; Загрузка не включается. Маркер в AdditionalProperties не сохраняется как задача в ИБ.
Scoped ЭтотОбъект принадлежит только настоящему модулю набора ОчередьПремии85. По native во время FillCheckProcessing платформа временно отключает SafeMode; сам урок защиту не отключает и запускается только в собственной доверенной пустой CF.
Снимки, пользователь/соединение, Selected/Modified и fresh readback — диагностические проверки, не транзакция/блокировка/гарантия конкуренции. Никакого rollback/retry или сохранения прошлых снимков после вмешательства. Частичная ошибка стопорит форму и требует ручной сверки только своего стенда.
Старый РегистрРасчетаПерерасчетыМенеджер deprecated с8.3.3 исключен. ПолучитьДополнение для сторнирования прошлых регистрационных периодов не используется. Runtime форма/конфигурация, база и вывод не проверены; UI и запись только описаны как будущие ручные шаги.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
План отказов в доступе в памяти: включить, изменить состав и восстановить свой предпросмотр
Настоящие native descriptor и режим события используются нашим отдельным потребителем: сумма счета 1050, выключенный план 0, альтернативные цены 400. Реальное журналирование и права доступа не меняются.
Где и как запускать
Серверный общий модуль собственной новой File CF 8.5.1.1343; толстая управляемая форма получает только проверенные скаляры. Runtime не выполнялся.
Подготовка
Что изучаем. Сначала создаём в памяти два настоящих описания отказа в доступе и объект использования события. Затем наш отдельный предпросмотр меняет режим и выбранное описание: 1050 → 0 → 1050 → 400 → 1050. Так видны роль Булево, содержимое свойства ОписаниеИспользования и порядок альтернатив. Это подготовка собственного плана, а не включение журналирования и не проверка реального отказа в доступе.
Создайте вручную НОВУЮ пустую файловую учебную базу только C:\1c-labs\OwnAccessDeniedPolicy85_c5771276-93dc-42d9-8f52-23ba39a74485\IB. Имя конфигурации УчебныйПланОтказа85; ОсновнойРежимЗапуска = УправляемоеПриложение; РежимСовместимости = НеИспользовать. Платформа Windows 8.5.1.1343, толстый управляемый клиент. Регистрируйте именно File="этот полный путь";: другой каталог, суффикс или формат строки отвергается. UUID в имени папки — только маркер лаборатории, не UUID базы.
Документы → Добавить → УчебнаяНакладная85. Создайте ровно три реквизита: Количество85, Цена85, Сумма85; каждый Число, длина 15, точность 2, не составной тип. Не добавляйте табличные части, формы документа, движения, подписки и модуль документа. Не создавайте и не записывайте ни одного документа: нам нужны только реальные метаданные, их полное имя и описание числовых типов.
Другие документы, справочники, регистры и расширения не добавляйте. В своей новой CF создайте собственную роль ПланОтказа85Администратор с полными учебными правами, включая Администрирование для ПолучитьПользователей и АктивныеПользователи для ПолучитьСоединенияИнформационнойБазы. Создайте единственного реального пользователя ПланОтказа85Ученик и назначьте роль. Код не создаёт пользователей и не меняет права. Проверяются настоящий UUID пользователя и текущее единственное соединение; Конфигуратор перед ручным тестом закройте.
Общие → Общие модули → ПланОтказаПамять85. Сервер = Да; Глобальный, ВызовСервера, Привилегированный, КлиентУправляемоеПриложение, КлиентОбычноеПриложение, ВнешнееСоединение = Нет. ПовторноеИспользованиеВозвращаемыхЗначений = НеИспользовать. Вставьте весь основной модуль CODE. Он проверяет эти настройки и не кеширует повторные проверки. Только ВыполнитьПредпросмотр85 экспортируется, без аргументов; все остальные функции работают с объектами, созданными здесь.
Общие → Общие формы → ПредпросмотрОтказа85, управляемая форма. Добавьте восемь реквизитов Число 15.2: Количество85, Сумма85, СуммаЦен85, Включен85, Отключен85, СноваВключен85, ДругойСостав85, Восстановлен85. Добавьте Протокол85 — Строка неограниченной длины, Остановка85 и Завершено85 — Булево с начальным значением Ложь. Покажите восемь чисел и многострочный протокол только для просмотра; служебные Булево пользователю не выводите.
Создайте собственную команду формы Предпросмотр85. В свойстве Действие назначьте обработчик Предпросмотр85(Команда); кнопку на командной панели привяжите к этой команде. Вставьте полный поддерживающий модуль формы. Его &НаСервере процедура вызывает серверный общий модуль, а клиент получает только восемь скаляров. Массивы, ТаблицаЗначений и native descriptor через RPC не передаются.
Конфигурация → Открыть модуль управляемого приложения: вставьте полный поддерживающий модуль УправляемоеПриложение. Штатное ПриНачалеРаботыСистемы() без аргументов откроет свою общую форму только в толстом управляемом клиенте. Сами обработчики событий не вызывайте. Константы перечислимых свойств метаданных в коде квалифицированы через Метаданные.СвойстваОбъектов.
ПоляРегистрации у описания отказа — readonly свойство. Поэтому ему ничего не присваиваем. У нового descriptor читаем настоящий Массив, требуем пустое состояние, вызываем документированный Массив.Добавить на нём и затем заново читаем свойство через полный ПроверитьОписание85. Если изменения не видны, тип неожиданен или начальный массив непустой, урок останавливается. Справка не превращается в обещание удержания изменений; это проверяет будущий ручной протокол.
A получает вложенный массив [Сумма85, Цена85] и отдельное Количество85; B — [Цена85, Сумма85] и Количество85. Это два собственных native описания одного настоящего документа. В обеих проекциях доступны обе альтернативы: наш потребитель выбирает первую имеющуюся и вычисляет реальные native Итог по собственной копии. Поэтому A даёт сумму счёта 1050, B — сумму цен 400. Отдельный режим Использование = Ложь означает нулевой предпросмотр по явно заданному правилу именно нашего потребителя.
Обновите вручную только эту новую учебную CF и запустите единственного своего пользователя в толстом управляемом клиенте. Нажмите Предпросмотр85 один раз. После успеха и после ошибки повтор запрещён. Для нового ручного протокола закройте клиент и начните новый собственный сеанс; не сбрасывайте служебные флаги в отладчике. В случае ошибки изучите первый отказ: нет автоматического повторения, catch-восстановления или продолжения после частичного memory изменения.
Здесь написаны и статически проверяются только source и тесты. CF, ИБ, роль, пользователь, 1С и GUI не создавались и не запускались. Нет запросов, записи прикладных данных, смены использования событий, записи журнала, сети, печати и файлового сохранения результата. Все числа далее — ожидаемый будущий ручной протокол, а не выполненный runtime.
Функция ПроверитьСтенд85()
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnAccessDeniedPolicy85_c5771276-93dc-42d9-8f52-23ba39a74485\IB"";" Тогда
ВызватьИсключение "Нужен свой точно подготовленный файловый стенд 8.5.1.1343";
КонецЕсли;
Если Метаданные.Документы.Количество() <> 1 Или Метаданные.Документы.Найти("УчебнаяНакладная85") = Неопределено
Или Метаданные.ОбщиеМодули.Количество() <> 1 Или Метаданные.ОбщиеМодули.Найти("ПланОтказаПамять85") = Неопределено
Или Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеФормы.Найти("ПредпросмотрОтказа85") = Неопределено
Или Метаданные.Справочники.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0
Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0
Или Метаданные.РегистрыРасчета.Количество() <> 0 Тогда
ВызватьИсключение "Допускаются только свои описание документа, общий модуль и общая форма";
КонецЕсли;
МодульМД = Метаданные.ОбщиеМодули.Найти("ПланОтказаПамять85");
Если Не МодульМД.Сервер Или МодульМД.Глобальный Или МодульМД.ВызовСервера Или МодульМД.Привилегированный
Или МодульМД.КлиентУправляемоеПриложение Или МодульМД.КлиентОбычноеПриложение Или МодульМД.ВнешнееСоединение Тогда
ВызватьИсключение "Общий модуль должен быть только серверным, неглобальным и без кеширования результатов";
КонецЕсли;
Если МодульМД.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НеИспользовать Тогда
ВызватьИсключение "Повторные чтения не должны возвращать кешированный результат";
КонецЕсли;
Если РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.БазаДанных).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансАктивные).Количество() <> 0
Или РасширенияКонфигурации.Получить(, ИсточникРасширенийКонфигурации.СеансОтключенные).Количество() <> 0 Тогда
ВызватьИсключение "В собственном стенде не должно быть расширений";
КонецЕсли;
Текущий = ПользователиИнформационнойБазы.ТекущийПользователь();
Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
Если Текущий = Неопределено Или Пользователи.Количество() <> 1 Тогда
ВызватьИсключение "Нужен единственный реальный собственный пользователь";
КонецЕсли;
Если Текущий.Имя <> "ПланОтказа85Ученик" Или Пользователи[0].УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "Не совпала настоящая идентичность своего пользователя ИБ";
КонецЕсли;
Соединения = ПолучитьСоединенияИнформационнойБазы();
Если Соединения.Количество() <> 1 Тогда
ВызватьИсключение "Закройте Конфигуратор и другие сеансы своей лаборатории";
КонецЕсли;
Соединение = Соединения[0];
Если Соединение.НомерСоединения <> НомерСоединенияИнформационнойБазы()
Или Соединение.Пользователь.УникальныйИдентификатор <> Текущий.УникальныйИдентификатор Тогда
ВызватьИсключение "Единственное соединение должно принадлежать текущему учебному пользователю";
КонецЕсли;
МетаДокумент = Метаданные.Документы.Найти("УчебнаяНакладная85");
Если МетаДокумент.ПолноеИмя() <> "Документ.УчебнаяНакладная85" Или МетаДокумент.Реквизиты.Количество() <> 3 Тогда
ВызватьИсключение "Проверьте точное имя и три реквизита собственного документа";
КонецЕсли;
Для Каждого ИмяПоля Из ИменаПолей85() Цикл
ПолеМД = МетаДокумент.Реквизиты.Найти(ИмяПоля);
Если ПолеМД = Неопределено Тогда
ВызватьИсключение "Отсутствует собственный числовой реквизит";
КонецЕсли;
Если ПолеМД.Тип.Типы().Количество() <> 1 Или Не ПолеМД.Тип.СодержитТип(Тип("Число")) Тогда
ВызватьИсключение "Собственный реквизит должен иметь единственный тип Число";
КонецЕсли;
КонецЦикла;
Возврат МетаДокумент;
КонецФункции
Функция ИменаПолей85()
Имена = Новый Массив;
Имена.Добавить("Количество85");
Имена.Добавить("Цена85");
Имена.Добавить("Сумма85");
Возврат Имена;
КонецФункции
Функция СоздатьДанные85(МетаДокумент)
Данные = Новый ТаблицаЗначений;
Для Каждого ИмяПоля Из ИменаПолей85() Цикл
ПолеМД = МетаДокумент.Реквизиты.Найти(ИмяПоля);
Данные.Колонки.Добавить(ИмяПоля, ПолеМД.Тип);
КонецЦикла;
Первая = Данные.Добавить();
Первая.Количество85 = 3;
Первая.Цена85 = 250;
Первая.Сумма85 = Первая.Количество85 * Первая.Цена85;
Вторая = Данные.Добавить();
Вторая.Количество85 = 2;
Вторая.Цена85 = 150;
Вторая.Сумма85 = Вторая.Количество85 * Вторая.Цена85;
Возврат Данные;
КонецФункции
Функция ПрочитатьДанные85(Данные)
Если ТипЗнч(Данные) <> Тип("ТаблицаЗначений") Или Данные.Количество() <> 2 Или Данные.Колонки.Количество() <> 3 Тогда
ВызватьИсключение "Исходник должен содержать две собственные строки и три колонки";
КонецЕсли;
Для Каждого ИмяПоля Из ИменаПолей85() Цикл
Колонка = Данные.Колонки.Найти(ИмяПоля);
Если Колонка = Неопределено Тогда
ВызватьИсключение "Пропала колонка собственной таблицы";
КонецЕсли;
Если Колонка.ТипЗначения.Типы().Количество() <> 1 Или Не Колонка.ТипЗначения.СодержитТип(Тип("Число")) Тогда
ВызватьИсключение "Тип каждой колонки должен оставаться единственным Число";
КонецЕсли;
КонецЦикла;
Первая = Данные.Получить(0);
Вторая = Данные.Получить(1);
Если ТипЗнч(Первая.Количество85) <> Тип("Число") Или ТипЗнч(Первая.Цена85) <> Тип("Число") Или ТипЗнч(Первая.Сумма85) <> Тип("Число")
Или ТипЗнч(Вторая.Количество85) <> Тип("Число") Или ТипЗнч(Вторая.Цена85) <> Тип("Число") Или ТипЗнч(Вторая.Сумма85) <> Тип("Число") Тогда
ВызватьИсключение "Все шесть ячеек должны содержать числа";
КонецЕсли;
Если Первая.Количество85 <> 3 Или Первая.Цена85 <> 250 Или Первая.Сумма85 <> 750
Или Вторая.Количество85 <> 2 Или Вторая.Цена85 <> 150 Или Вторая.Сумма85 <> 300
Или Первая.Сумма85 <> Первая.Количество85 * Первая.Цена85 Или Вторая.Сумма85 <> Вторая.Количество85 * Вторая.Цена85 Тогда
ВызватьИсключение "Изменилось хотя бы одно значение собственного исходного счета";
КонецЕсли;
Количество = Данные.Итог("Количество85");
Сумма = Данные.Итог("Сумма85");
СуммаЦен = Данные.Итог("Цена85");
Если Количество <> 5 Или Сумма <> 1050 Или СуммаЦен <> 400 Тогда
ВызватьИсключение "Native итоги исходника должны быть 5, 1050 и 400";
КонецЕсли;
Возврат Новый ФиксированнаяСтруктура("Количество,Сумма,СуммаЦен", Количество, Сумма, СуммаЦен);
КонецФункции
Процедура ПроверитьОписание85(Описание, МетаДокумент, ПервоеПоле, Пустое)
Если ТипЗнч(Описание) <> Тип("ОписаниеИспользованияСобытияОтказВДоступеЖурналаРегистрации") Тогда
ВызватьИсключение "Нужен реальный собственный native descriptor отказа в доступе";
КонецЕсли;
Если ТипЗнч(Описание.Объект) <> Тип("Строка") Или Описание.Объект <> МетаДокумент.ПолноеИмя()
Или Метаданные.НайтиПоПолномуИмени(Описание.Объект) <> МетаДокумент Тогда
ВызватьИсключение "Объект должен быть полным именем своих настоящих метаданных";
КонецЕсли;
Регистрация = Описание.ПоляРегистрации;
Если ТипЗнч(Регистрация) <> Тип("Массив") Тогда
ВызватьИсключение "Readonly свойство должно вернуть настоящий Массив";
КонецЕсли;
Если Пустое Тогда
Если Регистрация.Количество() <> 0 Тогда
ВызватьИсключение "Новый массив должен быть пустым; чужое или неожиданное состояние не изменяем";
КонецЕсли;
Возврат;
КонецЕсли;
Если ПервоеПоле <> "Сумма85" И ПервоеПоле <> "Цена85" Тогда
ВызватьИсключение "Допускаются только две собственные альтернативы";
КонецЕсли;
ВтороеПоле = ?(ПервоеПоле = "Сумма85", "Цена85", "Сумма85");
Если Регистрация.Количество() <> 2 Тогда
ВызватьИсключение "Нужны ровно две группы регистрации своего плана";
КонецЕсли;
Если ТипЗнч(Регистрация[0]) <> Тип("Массив") Или ТипЗнч(Регистрация[1]) <> Тип("Строка")
Или Регистрация[1] <> "Количество85" Тогда
ВызватьИсключение "Проверьте вложенные альтернативы и отдельное поле количества";
КонецЕсли;
Альтернативы = Регистрация[0];
Если Альтернативы.Количество() <> 2 Тогда
ВызватьИсключение "Вложенный массив должен содержать ровно две альтернативы";
КонецЕсли;
Если ТипЗнч(Альтернативы[0]) <> Тип("Строка") Или ТипЗнч(Альтернативы[1]) <> Тип("Строка")
Или Альтернативы[0] <> ПервоеПоле Или Альтернативы[1] <> ВтороеПоле Тогда
ВызватьИсключение "Нужно полностью подтвердить типы и порядок обеих альтернатив";
КонецЕсли;
КонецПроцедуры
Функция СоздатьОписание85(МетаДокумент, ПервоеПоле)
Если ПервоеПоле <> "Сумма85" И ПервоеПоле <> "Цена85" Тогда
ВызватьИсключение "Неизвестное поле нового собственного плана";
КонецЕсли;
ИмяОбъекта = МетаДокумент.ПолноеИмя();
Описание = Новый ОписаниеИспользованияСобытияОтказВДоступеЖурналаРегистрации(ИмяОбъекта);
ПроверитьОписание85(Описание, МетаДокумент, ПервоеПоле, Истина);
Регистрация = Описание.ПоляРегистрации;
Альтернативы = Новый Массив;
Альтернативы.Добавить(ПервоеПоле);
Альтернативы.Добавить(?(ПервоеПоле = "Сумма85", "Цена85", "Сумма85"));
Регистрация.Добавить(Альтернативы);
Регистрация.Добавить("Количество85");
ПроверитьОписание85(Описание, МетаДокумент, ПервоеПоле, Ложь);
Возврат Описание;
КонецФункции
Процедура ПроверитьСостав85(Состав, МетаДокумент, ПервоеПоле)
Если ТипЗнч(Состав) <> Тип("Массив") Или Состав.Количество() <> 1 Тогда
ВызватьИсключение "Состав должен быть своим массивом с одним описанием отказа";
КонецЕсли;
Описание = Состав[0];
ПроверитьОписание85(Описание, МетаДокумент, ПервоеПоле, Ложь);
КонецПроцедуры
Процедура ПроверитьПлан85(План, МетаДокумент, Использовать, ПервоеПоле)
Если ТипЗнч(План) <> Тип("ИспользованиеСобытияЖурналаРегистрации") Тогда
ВызватьИсключение "Нужен настоящий native объект использования события";
КонецЕсли;
Если ТипЗнч(План.Использование) <> Тип("Булево") Или План.Использование <> Использовать Тогда
ВызватьИсключение "Режим должен точно совпадать с ожидаемым собственным этапом";
КонецЕсли;
Состав = План.ОписаниеИспользования;
ПроверитьСостав85(Состав, МетаДокумент, ПервоеПоле);
КонецПроцедуры
Функция Предпросмотр85(План, МетаДокумент, Данные, Использовать, ПервоеПоле)
ПроверитьПлан85(План, МетаДокумент, Использовать, ПервоеПоле);
ПрочитатьДанные85(Данные);
Если Не План.Использование Тогда
ПроверитьПлан85(План, МетаДокумент, Ложь, ПервоеПоле);
Возврат Новый ФиксированнаяСтруктура("Количество,Итог,Поле", 0, 0, "");
КонецЕсли;
Состав = План.ОписаниеИспользования;
Описание = Состав[0];
Регистрация = Описание.ПоляРегистрации;
Альтернативы = Регистрация[0];
ВыбранноеПоле = "";
Для Индекс = 0 По Альтернативы.Количество() - 1 Цикл
ИмяПоля = Альтернативы[Индекс];
Если Данные.Колонки.Найти(ИмяПоля) <> Неопределено Тогда
ВыбранноеПоле = ИмяПоля;
Прервать;
КонецЕсли;
КонецЦикла;
ПолеКоличества = Регистрация[1];
Если ВыбранноеПоле = "" Или Данные.Колонки.Найти(ПолеКоличества) = Неопределено Тогда
ВызватьИсключение "Собственная проекция не обеспечивает обе группы вывода";
КонецЕсли;
Проекция = Данные.Скопировать(, ПолеКоличества + "," + ВыбранноеПоле);
Если Проекция.Количество() <> 2 Или Проекция.Колонки.Количество() <> 2
Или Проекция.Колонки.Найти(ПолеКоличества) = Неопределено Или Проекция.Колонки.Найти(ВыбранноеПоле) = Неопределено Тогда
ВызватьИсключение "Native копия должна содержать ровно две свои строки и две выбранные колонки";
КонецЕсли;
Количество = Проекция.Итог(ПолеКоличества);
Итог = Проекция.Итог(ВыбранноеПоле);
Если ТипЗнч(Количество) <> Тип("Число") Или ТипЗнч(Итог) <> Тип("Число") Тогда
ВызватьИсключение "Предпросмотр должен вычислить реальные числовые native итоги";
КонецЕсли;
ПрочитатьДанные85(Данные);
ПроверитьПлан85(План, МетаДокумент, Истина, ПервоеПоле);
Возврат Новый ФиксированнаяСтруктура("Количество,Итог,Поле", Количество, Итог, ВыбранноеПоле);
КонецФункции
Процедура ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Использовать, ПервоеПоле)
ПроверитьСтенд85();
ПрочитатьДанные85(Данные);
ПроверитьСостав85(СоставA, МетаДокумент, "Сумма85");
ПроверитьСостав85(СоставB, МетаДокумент, "Цена85");
ПроверитьПлан85(План, МетаДокумент, Использовать, ПервоеПоле);
КонецПроцедуры
Функция ВыполнитьПредпросмотр85() Экспорт
МетаДокумент = ПроверитьСтенд85();
ОписаниеA = СоздатьОписание85(МетаДокумент, "Сумма85");
ОписаниеB = СоздатьОписание85(МетаДокумент, "Цена85");
СоставA = Новый Массив;
СоставA.Добавить(ОписаниеA);
СоставB = Новый Массив;
СоставB.Добавить(ОписаниеB);
План = Новый ИспользованиеСобытияЖурналаРегистрации(Истина, СоставA);
Данные = СоздатьДанные85(МетаДокумент);
До = ПрочитатьДанные85(Данные);
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
Включен = Предпросмотр85(План, МетаДокумент, Данные, Истина, "Сумма85");
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
План.Использование = Ложь;
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Ложь, "Сумма85");
Отключен = Предпросмотр85(План, МетаДокумент, Данные, Ложь, "Сумма85");
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Ложь, "Сумма85");
План.Использование = Истина;
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
СноваВключен = Предпросмотр85(План, МетаДокумент, Данные, Истина, "Сумма85");
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
План.ОписаниеИспользования = СоставB;
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Цена85");
ДругойСостав = Предпросмотр85(План, МетаДокумент, Данные, Истина, "Цена85");
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Цена85");
План.ОписаниеИспользования = СоставA;
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
Восстановлен = Предпросмотр85(План, МетаДокумент, Данные, Истина, "Сумма85");
ПроверитьЭтап85(План, МетаДокумент, Данные, СоставA, СоставB, Истина, "Сумма85");
После = ПрочитатьДанные85(Данные);
Если Включен.Количество <> 5 Или Включен.Итог <> 1050 Или Включен.Поле <> "Сумма85"
Или Отключен.Количество <> 0 Или Отключен.Итог <> 0 Или Отключен.Поле <> ""
Или СноваВключен.Количество <> 5 Или СноваВключен.Итог <> 1050 Или СноваВключен.Поле <> "Сумма85"
Или ДругойСостав.Количество <> 5 Или ДругойСостав.Итог <> 400 Или ДругойСостав.Поле <> "Цена85"
Или Восстановлен.Количество <> 5 Или Восстановлен.Итог <> 1050 Или Восстановлен.Поле <> "Сумма85"
Или После.Количество <> До.Количество Или После.Сумма <> До.Сумма Или После.СуммаЦен <> До.СуммаЦен Тогда
ВызватьИсключение "Не подтвердился полный результат пяти этапов собственного предпросмотра";
КонецЕсли;
Возврат Новый ФиксированнаяСтруктура("Количество,Сумма,СуммаЦен,Включен,Отключен,СноваВключен,ДругойСостав,Восстановлен",
После.Количество, После.Сумма, После.СуммаЦен, Включен.Итог, Отключен.Итог, СноваВключен.Итог, ДругойСостав.Итог, Восстановлен.Итог);
КонецФункцииСвоя управляемая форма: восемь скаляров, реальные команды и две границы остановки
Общие → Общие формы → ПредпросмотрОтказа85 → Модуль
Толстый управляемый клиент и &НаСервере процедуры собственной формы
&НаКлиенте
Процедура Предпросмотр85(Команда)
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если Остановка85 Или Завершено85 Или ТипЗнч(Команда) <> Тип("КомандаФормы") Или Команда <> Команды.Предпросмотр85 Тогда
Остановка85 = Истина;
ВызватьИсключение "Только своя команда и один запуск; после ошибки или успеха повтор запрещен";
КонецЕсли;
Попытка
ПредпросмотрНаСервере85();
Если Не Завершено85 Или Количество85 <> 5 Или Сумма85 <> 1050 Или СуммаЦен85 <> 400
Или Включен85 <> 1050 Или Отключен85 <> 0 Или СноваВключен85 <> 1050
Или ДругойСостав85 <> 400 Или Восстановлен85 <> 1050 Тогда
ВызватьИсключение "Не совпал весь скалярный пакет своего предпросмотра";
КонецЕсли;
Исключение
Остановка85 = Истина;
Протокол85 = "Отказ. Настройки журнала не менялись. Возможно частичное состояние только собственного memory плана; повтор и слепое восстановление запрещены.";
ВызватьИсключение;
КонецПопытки;
#Иначе
Остановка85 = Истина;
ВызватьИсключение "Подготовьте именно свой толстый управляемый клиент";
#КонецЕсли
КонецПроцедуры
&НаСервере
Процедура ПредпросмотрНаСервере85()
Если Остановка85 Или Завершено85 Тогда
Остановка85 = Истина;
ВызватьИсключение "Серверная граница также запрещает повтор";
КонецЕсли;
Попытка
Пакет = ПланОтказаПамять85.ВыполнитьПредпросмотр85();
Если Пакет.Количество <> 5 Или Пакет.Сумма <> 1050 Или Пакет.СуммаЦен <> 400
Или Пакет.Включен <> 1050 Или Пакет.Отключен <> 0 Или Пакет.СноваВключен <> 1050
Или Пакет.ДругойСостав <> 400 Или Пакет.Восстановлен <> 1050 Тогда
ВызватьИсключение "Сервер не принимает неполный или неподтвержденный результат";
КонецЕсли;
Количество85 = Пакет.Количество;
Сумма85 = Пакет.Сумма;
СуммаЦен85 = Пакет.СуммаЦен;
Включен85 = Пакет.Включен;
Отключен85 = Пакет.Отключен;
СноваВключен85 = Пакет.СноваВключен;
ДругойСостав85 = Пакет.ДругойСостав;
Восстановлен85 = Пакет.Восстановлен;
Протокол85 = "Свой счет: количество 5, сумма 1050, сумма цен 400. НАШ предпросмотр: 1050 → 0 → 1050 → 400 → 1050. Реальное журналирование, RLS и запросы не проверялись и не изменялись.";
Завершено85 = Истина;
Исключение
Остановка85 = Истина;
ВызватьИсключение;
КонецПопытки;
КонецПроцедурыНастоящее startup событие открывает только собственную форму
Конфигурация → Открыть модуль управляемого приложения
Толстый клиент, управляемое приложение
Процедура ПриНачалеРаботыСистемы()
#Если ТолстыйКлиентУправляемоеПриложение Тогда
Если Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnAccessDeniedPolicy85_c5771276-93dc-42d9-8f52-23ba39a74485\IB"";" Тогда
ВызватьИсключение "Открывается только собственная новая файловая лаборатория этого урока";
КонецЕсли;
ОткрытьФорму("ОбщаяФорма.ПредпросмотрОтказа85", , , Истина);
#Иначе
ВызватьИсключение "Нужен толстый управляемый клиент 8.5.1.1343";
#КонецЕсли
КонецПроцедурыРазбор по шагам
Проверяем точный File/version/NoUse, серверные настройки своего модуля, отсутствие расширений, настоящего единственного пользователя и соединение. Из реальных метаданных единственного документа получаем ПолноеИмя и три числовых типа. Документ не создаётся и не читается из базы.
Передаём ровно один настоящий String в ctor150. Проверяем native класс, actual ObjectString и metadata lookup, затем пустой массив из readonly свойства. Создаём два разных собственных порядка альтернатив A/B через Array.Add и свежий полный getter readback. Если удержание содержимого не подтверждено, немедленно отказываем; setter readonly свойства отсутствует.
Создаём две реальные строки ТаблицыЗначений: 3×250=750 и 2×150=300. Полностью перечитываем все шесть типизированных ячеек и вычисляем количество 5, сумму 1050, сумму цен 400. Native ctor151 получает явно Истина и новый массив с одним своим descriptor A; его фактическое содержимое заново проверяется.
Наш отдельный consumer читает actual режим и вложенные имена полей из native плана. Для включённого A он создаёт настоящую проекцию через Скопировать с пустым первым слотом и явными колонками, затем вычисляет Итог 1050/5. Не подменяем actual результат готовыми числами и не называем проекцию данными реального журнала.
Перед каждым из четырёх RW назначений выполняется полный свежий ПроверитьЭтап85: свой стенд, весь исходник, оба массива описаний и ожидаемый текущий native план. Использование=False даёт собственный пустой предпросмотр 0/0; True возвращает 1050/5; смена ОписаниеИспользования на свой B даёт 400/5; возврат своего A разрешён только после подтверждённого состояния B и возвращает 1050/5. Ни одно восстановление не выполняется из catch.
В конце проверяем поля, количество и итог каждого из пяти результатов, полностью неизменные входные ячейки и оба native описания. Сервер формы принимает восемь скаляров только целиком; клиент отдельно подтверждает их. Ошибки на любой границе устанавливают Остановка85, успех — Завершено85; ни один флаг не сбрасывается.
Как проверить результат
Ожидаемый будущий протокол: исходные 5/1050/400; пять собственных предпросмотров 1050 → 0 → 1050 → 400 → 1050. У включённых этапов количество 5, у отключённого 0; выбор A=Сумма85, B=Цена85; отключённый выбор пустой. Все шесть исходных ячеек и оба порядка вложенных альтернатив полностью проверяются, не только суммы или Count.
Все четыре setter имеют fresh whole-state guard непосредственно перед изменением и после него. Неизвестное состояние, неверная CF/пользователь/другое соединение, непустой новый массив, wrong type, потерянный порядок или частичный scalar пакет приводят к отказу; повтор, blind rollback и catch-успех запрещены.
MAIN реально использует все восемь PRIMARY. ПоляРегистрации не присваивается; generic ОписаниеИспользования допускается только после проверки фактического Array[ownDeniedDescriptor]. Нет нулевого ctor193/194, native event installation, запроса, RLS-теста или записи журнала.
Ожидаемый результат
Ожидаемый будущий ручной результат формы: 5, 1050, 400, 1050, 0, 1050, 400, 1050. Это реальный расчёт нашего memory consumer при указанной подготовке, не выполненный здесь запуск 1С и не доказательство регистрации отказов в журнале.
На что обратить внимание
У ctor150 String необязателен, но мы явно передаём один собственный FullName. Нулевой ctor150 пересекается с ctor193; аналогичную неоднозначность имеет access ctor149/194. Нулевые перегрузки не выбираются и не кредитуются.
Object8836 объявлен String. Не копируйте противоречивую фразу ctor150 про пустые массивы в Object: код требует реальный String своего документа и останавливается при другом результате. ПоляРегистрации8837 readonly; native setter-пример в большой странице SetEvent4041 не отменяет этот контракт.
Readonly свойство и тип Массив не являются гарантией, что изменения getter-результата удержатся в descriptor. Поэтому только собственный новый пустой массив, нативный Add и свежий полный readback; если подготовленная платформа не удержит изменения, будущий ручной протокол честно остановится, а не будет считаться успешным.
UseDescription имеет тип Произвольный. Для события _$Access$_.AccessDenied методическая область SetEvent4041 описывает Array[DeniedDescriptor]; здесь мы сами строим только такой массив и проверяем весь граф. Большая страница читалась только в относящемся к этому событию фрагменте, не целиком.
План никуда не устанавливается. Наше правило нулевого предпросмотра и суммы проекций не доказывают live RLS, query trigger, native Data.Data или порядок приоритетов реального регистратора. Не переносите код в рабочую базу: все входные данные и метаданные должны быть только своими.
Назначения и изменение массивов не атомарны. Возврат состава A допустим только после успешного этапа B и его полного fresh snapshot; при исключении не восстанавливаем вслепую. Sticky флаги защищают наш протокол формы, но не являются универсальным механизмом безопасности 1С.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.