Свои накладные и последовательность: реальная регистрация, границы и адресное перепроведение

Учебные задачи

Две настоящие накладные новой собственной конфигурации дают сумму 1500. После изменения цен проверяются прежние движения, затем адресное перепроведение пересчитывает свой оборот до 1600 и 1400. Каждый результат берётся из заново прочитанных данных.

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

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

Подготовка

  1. Урок учит регистрировать собственные накладные в последовательности, читать её границу и адресно перепроводить документы. После ручного запуска в новой учебной базе ожидаются суммы 1500 → 1600 → 1400. Каждый итог берётся из заново прочитанных движений, а не подставляется как ответ. 1С здесь не исполнялась: ниже приведён подробный будущий протокол.

  2. Создайте вручную НОВУЮ пустую файловую базу только C:\1c-labs\OwnSequenceInvoiceRecovery85_4d081684-c9cc-4f77-8e5a-d96b45e34b90\IB. Строка подключения должна точно соответствовать File="этот полный путь";. Используйте Windows, платформу 8.5.1.1343, толстый управляемый клиент и русский встроенный язык. Конфигурация: УчебноеВосстановлениеНакладных85; Версия: 4d081684-c9cc-4f77-8e5a-d96b45e34b90; ОсновнойРежимЗапуска: УправляемоеПриложение; РежимСовместимости: НеИспользовать. Имя и UUID — учебные маркеры, а не доказательство подлинности базы.

  3. В Конфигураторе: Документы → УчебнаяНакладная85. Добавьте ровно три реквизита: Проект85 — Строка длиной 36, переменная; Количество85 и Цена85 — Число 15.2, неотрицательное. У каждого поля должен быть один тип. Номер документа: Строка длиной 8, контроль уникальности включён; код назначит УЧ85-001 и УЧ85-002. Автонумерацию можно выключить. Табличных частей, форм документа и других реквизитов нет. Сумма вычисляется в движении регистра, а не записывается в реквизит документа при проведении.

  4. У документа настройте: Проведение = Разрешить; ОперативноеПроведение = Запретить; УдалениеДвижений = УдалятьАвтоматически; ЗаписьДвиженийПриПроведении = ЗаписыватьВыбранные. В движениях выберите только УчебныеПродажи85. ЗаполнениеПоследовательностей = НеЗаполнятьАвтоматически; документ входит только в УчебныеПродажиОчередь85. Не добавляйте другие обработчики записи, проведения, отмены проведения и подписки.

  5. Регистры накопления → УчебныеПродажи85: ВидРегистра = Обороты; единственный регистратор — собственная УчебнаяНакладная85. Измерение Проект85 — Строка длиной 36, переменная. Ресурсы Количество85 и Сумма85 — Число 15.2, неотрицательное. Реквизитов, агрегатов и индексов нет; модули менеджера и набора записей пусты. В этой новой конфигурации других регистров и справочников не создавайте.

  6. Последовательности → УчебныеПродажиОчередь85: на вкладке Использование выберите только документ УчебнаяНакладная85 и движения УчебныеПродажи85. Измерение Проект85 — Строка длиной 36, переменная; ПеремещениеГраницыПриПроведении = Перемещать. Модуль набора записей пуст. У измерения ЯВНО настройте СоответствиеДокументам на реквизит Проект85 накладной и СоответствиеДвижениям на измерение Проект85 регистра. Совпадающих имён недостаточно. Код проверяет обе доступные только для чтения коллекции: Количество() = 1 и Содержит(фактический объект метаданных поля).

  7. Общие → Общие модули → УчебноеВосстановление85: Сервер = Да; Глобальный, ВызовСервера, оба клиентских флага, ВнешнееСоединение и Привилегированный = Нет; ПовторноеИспользованиеВозвращаемыхЗначений = НеИспользовать. Вставьте основной код целиком на верхнем уровне модуля. Экспортные процедуры вызываются локально серверными процедурами своей формы и модулем объекта документа; прямого вызова общего модуля с клиента нет.

  8. Документы → УчебнаяНакладная85 → Модуль объекта: отдельно вставьте полный поддерживающий модуль документа ниже. ОбработкаПроведения вызывает только платформа при Записать/Восстановить, а не учебная программа вручную. Он передаёт настоящий ЭтотОбъект в общий модуль. Автоматическое удаление текущих движений происходит ДО события. Поэтому внутри обработчика проверяется разрешённое переходное состояние, а полная таблица движений — после успешного возврата внешней операции.

  9. Общие → Общие формы → УчебныйЗапускВосстановления85: управляемая форма. Реквизиты Сумма85 и Количество85 — Число 15.2; Протокол85 — неограниченная многострочная Строка; КлиентФаза85 и СерверФаза85 — Строка длиной 40; КлиентОстановка85 и СерверОстановка85 — Булево. Сумму, количество и протокол показывайте только для просмотра; служебные фазы и остановки не показывайте. Добавьте три отдельные галочки Булево: СогласиеСоздания85, СогласиеОдной85, СогласиеСписка85. Начальное значение — Ложь; надписи должны явно предупреждать об изменении данных своей лаборатории.

  10. Добавьте четыре команды формы и укажите их Действие: СоздатьСвойСтенд85(Команда), ПрочитатьСвойСтенд85(Команда), ВосстановитьОдну85(Команда), ВосстановитьСписок85(Команда). Для каждой создайте отдельную кнопку. Полный поддерживающий модуль формы вставьте в эту форму; подключите ПриСозданииНаСервере через событие формы. При открытии проверяется пустота учебных таблиц, документы не записываются.

  11. Общие → Общие команды → ОткрытьУчебноеВосстановление85: команда без параметра. Полный поддерживающий модуль команды вставьте отдельно в её модуль. Включите команду в собственный учебный раздел. Модуль управляемого приложения оставьте пустым: запись при запуске и автоматический переход к этапам отсутствуют.

  12. Создайте собственную роль Накладные85Администратор с полными учебными правами только этой новой конфигурации, включая Администрирование для ПолучитьПользователей и АктивныеПользователи для ПолучитьСоединенияИнформационнойБазы. Создайте единственного пользователя Накладные85Ученик и назначьте роль. Код не создаёт пользователей и права. Перед запуском закройте Конфигуратор и другие подключения. Проверяются реальный UUID пользователя, единственное соединение, его номер и объект пользователя; у последнего сверяются тип, UUID и имя.

  13. Не добавляйте в новую конфигурацию расширения, общие реквизиты, подписки, регламентные задания, внешние источники данных и сторонние модули. Перед изменениями сервер заново проверяет путь файловой базы, версию, пользователя, схему и фактические документы, регистрации и движения. Не переносите операции в рабочие УТ, КА2, УНФ, БП или их копии.

  14. Обновите вручную только эту новую конфигурацию и сначала скомпилируйте все четыре модуля: основной, документа, формы и команды. Откройте одну свою форму. Отдельно разрешите и выполните Создание, ожидаемый итог 1500; затем Одна, итог 1600; затем Список, итог 1400. Чтение между этапами не изменяет данные. Каждое согласие расходуется до изменяющей операции; при открытии все галочки выключены.

  15. Создание выполняет четыре записи: обычная запись первой накладной, получение её свежего объекта, проведение; затем такие же действия со второй. Плановые ссылки из двух выделенных UUID до записи не считаются существующими документами. Даты: 01.01.2026 и 02.01.2026, 09:00; количества: 4 и 2; начальные цены: 250 и 250. После каждой внешней записи заново читаются полные собственные таблицы документов, регистраций и движений.

  16. Этап Одна обычной записью меняет только цену второй накладной с 250 на 300. Движение в памяти не редактируется. После записи требуется фактически подтвердить прежнюю сумму движений 1500; если она изменилась, выполнение останавливается. Сохранность движений при любой обычной записи не обещается. Затем устанавливается явная граница датой раньше обеих накладных, а восстановление ограничивается своим проектом до настоящего момента второй записи последовательности.

  17. Этап Список меняет только первую цену с 250 на 200 и подтверждает прежнюю сумму движений 1600. Устанавливается такая же явная граница датой. Последовательности.Восстановить получает внешнюю ТаблицуЗначений: две колонки, одна строка с именем своей последовательности и внутренней таблицей проекта. Внутренняя таблица: одна колонка, одна строка. Проверяются оба уровня. Не опускайте ограничения и не заменяйте таблицу структурой.

  18. При исключении или неизвестном результате серверного вызова клиент заранее остаётся в состоянии Остановка/Неизвестно. На сервере фаза тоже Неизвестно во время вызова, но её доставка и сохранение после ошибочного RPC не гарантируется. Нет автоматического повтора, отката, отмены проведения, удаления документов, очистки базы и перехода дальше. Не сбрасывайте флаги в отладчике. Для нового протокола вручную подготовьте другую собственную новую пустую лабораторию.

  19. Статические проверки исходника и установленной справки не подтверждают исполнение. Здесь написаны только учебный исходник и тесты; конфигурация, база, роли и пользователи не создавались, 1С и сеть не запускались. Будущие Записать, УстановитьГраницу и Восстановить действительно меняют свою учебную базу и оставляют в ней два документа, регистрации, движения и границу.

Процедура ПроверитьЛабораторию85()
    Если СтрокаСоединенияИнформационнойБазы() <> "File=""C:\1c-labs\OwnSequenceInvoiceRecovery85_4d081684-c9cc-4f77-8e5a-d96b45e34b90\IB"";" Или Метаданные.РежимСовместимости <> Метаданные.СвойстваОбъектов.РежимСовместимости.НеИспользовать Или Метаданные.ОсновнойРежимЗапуска <> РежимЗапускаКлиентскогоПриложения.УправляемоеПриложение Тогда
        ВызватьИсключение "Нужна только новая собственная файловая лаборатория 8.5.1.1343";
    КонецЕсли;
    Если РасширенияКонфигурации.Получить().Количество() <> 0
        Или Метаданные.Документы.Количество() <> 1 Или Метаданные.Последовательности.Количество() <> 1
        Или Метаданные.РегистрыНакопления.Количество() <> 1 Или Метаданные.ОбщиеМодули.Количество() <> 1
        Или Метаданные.ОбщиеФормы.Количество() <> 1 Или Метаданные.ОбщиеКоманды.Количество() <> 1
        Или Метаданные.Справочники.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0
        Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0
        Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0
        Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Не совпал полный состав собственной схемы";
    КонецЕсли;
    Модуль = Метаданные.ОбщиеМодули.Найти("УчебноеВосстановление85");
    Если Модуль = Неопределено Или ТипЗнч(Модуль.Глобальный) <> Тип("Булево") Или Модуль.Глобальный Тогда
        ВызватьИсключение "Нужен свой неглобальный общий модуль";
    КонецЕсли;
    Если ТипЗнч(Модуль.Сервер) <> Тип("Булево") Или Не Модуль.Сервер
        Или ТипЗнч(Модуль.ВызовСервера) <> Тип("Булево") Или Модуль.ВызовСервера
        Или ТипЗнч(Модуль.КлиентОбычноеПриложение) <> Тип("Булево") Или Модуль.КлиентОбычноеПриложение
        Или ТипЗнч(Модуль.КлиентУправляемоеПриложение) <> Тип("Булево") Или Модуль.КлиентУправляемоеПриложение
        Или ТипЗнч(Модуль.ВнешнееСоединение) <> Тип("Булево") Или Модуль.ВнешнееСоединение
        Или ТипЗнч(Модуль.Привилегированный) <> Тип("Булево") Или Модуль.Привилегированный
        Или Модуль.ПовторноеИспользованиеВозвращаемыхЗначений <> Метаданные.СвойстваОбъектов.ПовторноеИспользованиеВозвращаемыхЗначений.НеИспользовать Тогда
        ВызватьИсключение "Не совпали серверные флаги своего модуля";
    КонецЕсли;
    Если Метаданные.ОбщиеФормы.Найти("УчебныйЗапускВосстановления85") = Неопределено
        Или Метаданные.ОбщиеКоманды.Найти("ОткрытьУчебноеВосстановление85") = Неопределено Тогда
        ВызватьИсключение "Не подготовлены своя форма и команда";
    КонецЕсли;
    Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
    Пользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
    Если ТипЗнч(Пользователь) <> Тип("ПользовательИнформационнойБазы")
        Или Пользователи.Количество() <> 1 Или Пользователь.Имя <> "Накладные85Ученик"
        Или ТипЗнч(Пользователь.УникальныйИдентификатор) <> Тип("УникальныйИдентификатор")
        Или Пользователи[0].УникальныйИдентификатор <> Пользователь.УникальныйИдентификатор Тогда
        ВызватьИсключение "Нужен единственный фактический собственный пользователь";
    КонецЕсли;
    Соединения = ПолучитьСоединенияИнформационнойБазы();
    Если Соединения.Количество() <> 1 Или ТипЗнч(Соединения[0]) <> Тип("СоединениеИнформационнойБазы")
        Или Соединения[0].НомерСоединения <> НомерСоединенияИнформационнойБазы()
        Или ТипЗнч(Соединения[0].Пользователь) <> Тип("ПользовательИнформационнойБазы") Тогда
        ВызватьИсключение "Закройте остальные подключения, в том числе Конфигуратор";
    КонецЕсли;
    Если ТипЗнч(Соединения[0].Пользователь.УникальныйИдентификатор) <> Тип("УникальныйИдентификатор")
        Или Соединения[0].Пользователь.УникальныйИдентификатор <> Пользователь.УникальныйИдентификатор
        Или Соединения[0].Пользователь.Имя <> Пользователь.Имя Тогда
        ВызватьИсключение "Закройте остальные подключения, в том числе Конфигуратор";
    КонецЕсли;
    Док = Метаданные.Документы.Найти("УчебнаяНакладная85");
    Очередь = Метаданные.Последовательности.Найти("УчебныеПродажиОчередь85");
    Регистр = Метаданные.РегистрыНакопления.Найти("УчебныеПродажи85");
    Если Док = Неопределено Или Очередь = Неопределено Или Регистр = Неопределено Тогда
        ВызватьИсключение "Не найдены свои метаданные";
    КонецЕсли;
    Если Док.Реквизиты.Количество() <> 3 Или Док.ТабличныеЧасти.Количество() <> 0
        Или Док.Движения.Количество() <> 1 Или Не Док.Движения.Содержит(Регистр)
        Или Док.Проведение <> Метаданные.СвойстваОбъектов.Проведение.Разрешить
        Или Док.ОперативноеПроведение <> Метаданные.СвойстваОбъектов.ОперативноеПроведение.Запретить
        Или Док.ЗаполнениеПоследовательностей <> Метаданные.СвойстваОбъектов.ЗаполнениеПоследовательностей.НеЗаполнятьАвтоматически
        Или Док.ЗаписьДвиженийПриПроведении <> Метаданные.СвойстваОбъектов.ЗаписьДвиженийПриПроведении.ЗаписыватьВыбранные
        Или Док.УдалениеДвижений <> Метаданные.СвойстваОбъектов.УдалениеДвижений.УдалятьАвтоматически Тогда
        ВызватьИсключение "Не совпали схема и политика проведения накладной";
    КонецЕсли;
    Если Очередь.Документы.Количество() <> 1 Или Не Очередь.Документы.Содержит(Док)
        Или Очередь.Движения.Количество() <> 1 Или Не Очередь.Движения.Содержит(Регистр)
        Или Очередь.Измерения.Количество() <> 1
        Или Очередь.ПеремещениеГраницыПриПроведении <> Метаданные.СвойстваОбъектов.ПеремещениеГраницыПриПроведении.Перемещать
        Или Регистр.Измерения.Количество() <> 1 Или Регистр.Ресурсы.Количество() <> 2
        Или Регистр.Реквизиты.Количество() <> 0
        Или Регистр.ВидРегистра <> Метаданные.СвойстваОбъектов.ВидРегистраНакопления.Обороты Тогда
        ВызватьИсключение "Не совпали собственные последовательность и оборотный регистр";
    КонецЕсли;
    ПроектДок = Док.Реквизиты.Найти("Проект85");
    ПроектРег = Регистр.Измерения.Найти("Проект85");
    ПроектОчереди = Очередь.Измерения.Найти("Проект85");
    ПроверитьТипПоля85(ПроектДок, "Строка");
    ПроверитьТипПоля85(ПроектРег, "Строка");
    ПроверитьТипПоля85(ПроектОчереди, "Строка");
    ПроверитьТипПоля85(Док.Реквизиты.Найти("Количество85"), "Число");
    ПроверитьТипПоля85(Док.Реквизиты.Найти("Цена85"), "Число");
    ПроверитьТипПоля85(Регистр.Ресурсы.Найти("Количество85"), "Число");
    ПроверитьТипПоля85(Регистр.Ресурсы.Найти("Сумма85"), "Число");
    Если ПроектОчереди.СоответствиеДокументам.Количество() <> 1
        Или Не ПроектОчереди.СоответствиеДокументам.Содержит(ПроектДок)
        Или ПроектОчереди.СоответствиеДвижениям.Количество() <> 1
        Или Не ПроектОчереди.СоответствиеДвижениям.Содержит(ПроектРег) Тогда
        ВызватьИсключение "Не заданы явные соответствия своего измерения";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьТипПоля85(Поле, ИмяТипа)
    Если Поле = Неопределено Или ТипЗнч(Поле.Тип) <> Тип("ОписаниеТипов")
        Или Поле.Тип.Типы().Количество() <> 1 Или Не Поле.Тип.СодержитТип(Тип(ИмяТипа)) Тогда
        ВызватьИсключение "Нужен один реальный тип собственного поля";
    КонецЕсли;
    Если ИмяТипа = "Строка" Тогда
        Если Поле.Тип.КвалификаторыСтроки.Длина <> 36
            Или Поле.Тип.КвалификаторыСтроки.ДопустимаяДлина <> ДопустимаяДлина.Переменная Тогда
            ВызватьИсключение "Нужно ограниченное проектное поле Строка36";
        КонецЕсли;
    Иначе
        Если Поле.Тип.КвалификаторыЧисла.Разрядность <> 15
            Или Поле.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти <> 2
            Или Поле.Тип.КвалификаторыЧисла.ДопустимыйЗнак <> ДопустимыйЗнак.Неотрицательный Тогда
            ВызватьИсключение "Нужно собственное числовое поле15.2 неотрицательное";
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Функция СвоиСсылки85()
    Результат = Новый Массив;
    Результат.Добавить(Документы.УчебнаяНакладная85.ПолучитьСсылку(Новый УникальныйИдентификатор("83843f55-238c-4ad1-96ba-e0b2d3ec71a1")));
    Результат.Добавить(Документы.УчебнаяНакладная85.ПолучитьСсылку(Новый УникальныйИдентификатор("cec381df-f376-43d9-a4a7-2f036e8c4c38")));
    Возврат Результат;
КонецФункции

Функция СвояДата85(Индекс)
    Возврат Дата(2026, 1, Индекс + 1, 9, 0, 0);
КонецФункции

Функция СвоеКоличество85(Индекс)
    Если Индекс = 0 Тогда
        Возврат 4;
    КонецЕсли;
    Возврат 2;
КонецФункции

Функция ЧитатьДокументы85()
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Ссылка, Дата, Номер, Проект85, Количество85, Цена85, Проведен, ПометкаУдаления
    |ИЗ Документ.УчебнаяНакладная85 УПОРЯДОЧИТЬ ПО Дата";
    Возврат Запрос.Выполнить().Выгрузить();
КонецФункции

Функция ЧитатьДвижения85()
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Период, Регистратор, Проект85, Количество85, Сумма85, Активность, НомерСтроки
    |ИЗ РегистрНакопления.УчебныеПродажи85 УПОРЯДОЧИТЬ ПО Регистратор.Дата";
    Возврат Запрос.Выполнить().Выгрузить();
КонецФункции

Функция ЧитатьРегистрации85()
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ Период, Регистратор, Проект85
    |ИЗ Последовательность.УчебныеПродажиОчередь85 УПОРЯДОЧИТЬ ПО Период";
    Возврат Запрос.Выполнить().Выгрузить();
КонецФункции

Процедура ПроверитьДокумент85(Объект, Индекс, Цена, Проведен)
    Ссылки = СвоиСсылки85();
    Если ТипЗнч(Объект) <> Тип("ДокументОбъект.УчебнаяНакладная85") Или Объект.ЭтоНовый() Или Объект.Метаданные() <> Метаданные.Документы.Найти("УчебнаяНакладная85") Или ТипЗнч(Объект.Ссылка) <> Тип("ДокументСсылка.УчебнаяНакладная85") Или Объект.Ссылка <> Ссылки[Индекс] Или ТипЗнч(Объект.Дата) <> Тип("Дата") Или Объект.Дата <> СвояДата85(Индекс) Или ТипЗнч(Объект.Номер) <> Тип("Строка") Или Объект.Номер <> "УЧ85-00" + Строка(Индекс + 1) Или ТипЗнч(Объект.Проект85) <> Тип("Строка") Или ТипЗнч(Объект.Количество85) <> Тип("Число") Или Объект.Количество85 <> СвоеКоличество85(Индекс) Или ТипЗнч(Объект.Цена85) <> Тип("Число") Или Объект.Цена85 <> Цена Или ТипЗнч(Объект.ПометкаУдаления) <> Тип("Булево") Или Объект.ПометкаУдаления Или ТипЗнч(Объект.Проведен) <> Тип("Булево") Тогда
        ВызватьИсключение "Не совпал полный фактический собственный документ";
    КонецЕсли;
    Если Проведен <> Неопределено И Объект.Проведен <> Проведен Тогда
        ВызватьИсключение "Не подтвержден результат проведения своего документа";
    КонецЕсли;
КонецПроцедуры

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

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

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

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

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

Процедура СверитьТаблицы85(До, После)
    Если До.Колонки.Количество() <> После.Колонки.Количество() Или До.Количество() <> После.Количество() Тогда
        ВызватьИсключение "Изменился полный размер фактического снимка";
    КонецЕсли;
    Для Индекс = 0 По До.Количество() - 1 Цикл
        Для Колонка = 0 По До.Колонки.Количество() - 1 Цикл
            Если До.Колонки[Колонка].Имя <> После.Колонки[Колонка].Имя
                Или ТипЗнч(До[Индекс][Колонка]) <> ТипЗнч(После[Индекс][Колонка])
                Или До[Индекс][Колонка] <> После[Индекс][Колонка] Тогда
                ВызватьИсключение "Изменилась типизированная ячейка полного снимка";
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

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

Функция СвойОтбор85()
    Возврат Новый Структура("Проект85", Метаданные.Версия);
КонецФункции

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

Процедура ПроверитьКомбинации85(Таблица)
    Если ТипЗнч(Таблица) <> Тип("ТаблицаЗначений") Или Таблица.Колонки.Количество() <> 1 Или Таблица.Количество() <> 1 Или Таблица.Колонки[0].Имя <> "Проект85" Или Не Таблица.Колонки[0].ТипЗначения.СодержитТип(Тип("Строка")) Или Таблица.Колонки[0].ТипЗначения.Типы().Количество() <> 1 Или ТипЗнч(Таблица[0].Проект85) <> Тип("Строка") Тогда
        ВызватьИсключение "Нужна только своя полностью проверенная комбинация проекта";
    КонецЕсли;
КонецПроцедуры

Функция ПроверитьГраницы85(ПослеУстановки)
    Граница = Последовательности.УчебныеПродажиОчередь85.ПолучитьГраницу(СвойОтбор85());
    Границы = Последовательности.УчебныеПродажиОчередь85.ПолучитьГраницы("Проект85", СвоиКомбинации85());
    Если ТипЗнч(Граница) <> Тип("МоментВремени") Или ТипЗнч(Границы) <> Тип("ТаблицаЗначений") Или Границы.Колонки.Количество() <> 2 Или Границы.Количество() <> 1 Или ТипЗнч(Границы[0][0]) <> Тип("МоментВремени") Или ТипЗнч(Границы[0][1]) <> Тип("Строка") Или Границы[0][0].Сравнить(Граница) <> 0 Тогда
        ВызватьИсключение "Не подтверждены реальные границы своего проекта";
    КонецЕсли;
    Если ПослеУстановки И Граница.Дата <> Дата(2026, 1, 1, 0, 0, 0) Тогда
        ВызватьИсключение "Не подтверждена явно установленная дата собственной границы";
    КонецЕсли;
    Возврат Граница;
КонецФункции

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

Процедура ПодготовитьПроведение85(Объект) Экспорт
    ПроверитьЛабораторию85();
    Если ТипЗнч(Объект) <> Тип("ДокументОбъект.УчебнаяНакладная85") Тогда
        ВызватьИсключение "Нужен фактический ЭтотОбъект настоящего собственного Posting";
    КонецЕсли;
    ТаблицаДокументов = ЧитатьДокументы85();
    Ссылки = СвоиСсылки85();
    Индекс = Ссылки.Найти(Объект.Ссылка);
    Если Индекс = Неопределено Или ТаблицаДокументов.Количество() < 1 Или ТаблицаДокументов.Количество() > 2 Тогда
        ВызватьИсключение "Событие принадлежит только реальному собственному документу";
    КонецЕсли;
    ПроверитьДокумент85(Объект, Индекс, Объект.Цена85, Неопределено);
    Для Номер = 0 По ТаблицаДокументов.Количество() - 1 Цикл
        Если ТаблицаДокументов[Номер].Ссылка <> Ссылки[Номер] Тогда
            ВызватьИсключение "Событие не может работать с посторонним документом";
        КонецЕсли;
        Цена = ТаблицаДокументов[Номер].Цена85;
        Если Номер = 0 И Цена <> 250 И Цена <> 200 Или Номер = 1 И Цена <> 250 И Цена <> 300 Тогда
            ВызватьИсключение "Цена вне подготовленных собственных этапов";
        КонецЕсли;
        ТекущийОбъект = ТаблицаДокументов[Номер].Ссылка.ПолучитьОбъект();
        Если Номер = Индекс Тогда
            ПроверитьДокумент85(ТекущийОбъект, Номер, Цена, Неопределено);
        Иначе
            ПроверитьДокумент85(ТекущийОбъект, Номер, Цена, Истина);
        КонецЕсли;
    КонецЦикла;
    Если ТаблицаДокументов.Количество() = 1 И (Индекс <> 0 Или Объект.Цена85 <> 250)
        Или ТаблицаДокументов.Количество() = 2 И ТаблицаДокументов[0].Цена85 = 200 И ТаблицаДокументов[1].Цена85 <> 300
        Или ТаблицаДокументов.Количество() = 2 И ТаблицаДокументов[1].Цена85 = 250 И Индекс <> 1 Тогда
        ВызватьИсключение "Не совпал собственный известный этап проведения";
    КонецЕсли;
    ДвиженияДо = ЧитатьДвижения85();
    Если ДвиженияДо.Количество() <> ТаблицаДокументов.Количество() - 1 Тогда
        ВызватьИсключение "Перед Posting движение текущего документа должно быть удалено платформой";
    КонецЕсли;
    Для Каждого СтрокаДвижения Из ДвиженияДо Цикл
        ДругойИндекс = Ссылки.Найти(СтрокаДвижения.Регистратор);
        Если ДругойИндекс = Неопределено Или ДругойИндекс = Индекс Тогда
            ВызватьИсключение "Недопустимый регистратор в переходном состоянии";
        КонецЕсли;
        Если ДругойИндекс = 0 Тогда
            СуммаДругого = 1000;
            Если ТаблицаДокументов[0].Цена85 = 200 Тогда
                СуммаДругого = 800;
            КонецЕсли;
        Иначе
            СуммаДругого = 500;
            Если ТаблицаДокументов[0].Цена85 = 200 Тогда
                СуммаДругого = 600;
            КонецЕсли;
        КонецЕсли;
        ПроверитьДвижение85(СтрокаДвижения, ДругойИндекс, СуммаДругого);
    КонецЦикла;
    Набор = СвойНабор85(Объект);
    Набор.Прочитать();
    ПроверитьОтбор85(Набор, Объект.Ссылка);
    Если Набор.Количество() > 1 Тогда
        ВызватьИсключение "Недопустимый состав собственного набора перед замещением";
    КонецЕсли;
    Если Набор.Количество() = 1 Тогда
        ПроверитьЗапись85(Набор[0], Объект);
    КонецЕсли;
    Набор.Очистить();
    Запись = Набор.Добавить();
    Запись.Период = Объект.Дата;
    Запись.Регистратор = Объект.Ссылка;
    Запись.Проект85 = Объект.Проект85;
    ПроверитьЗапись85(Запись, Объект);
    ПроверитьЛабораторию85();
    СверитьТаблицы85(ТаблицаДокументов, ЧитатьДокументы85());
    СверитьТаблицы85(ДвиженияДо, ЧитатьДвижения85());
    ПроверитьОтбор85(Набор, Объект.Ссылка);
    Набор.Записать(Истина);
    ПрочитатьСвоюРегистрацию85(Объект, Истина);
    СверитьТаблицы85(ТаблицаДокументов, ЧитатьДокументы85());
    СверитьТаблицы85(ДвиженияДо, ЧитатьДвижения85());
    Движения = Объект.Движения.УчебныеПродажи85;
    Если ТипЗнч(Движения) <> Тип("РегистрНакопленияНаборЗаписей.УчебныеПродажи85")
        Или Движения.Метаданные() <> Метаданные.РегистрыНакопления.Найти("УчебныеПродажи85") Тогда
        ВызватьИсключение "Событие получило набор не своего регистра";
    КонецЕсли;
    Движения.Очистить();
    Движение = Движения.Добавить();
    Движение.Период = Объект.Дата;
    Движение.Регистратор = Объект.Ссылка;
    Движение.Проект85 = Объект.Проект85;
    Движение.Количество85 = Объект.Количество85;
    Движение.Сумма85 = Объект.Количество85 * Объект.Цена85;
    Движение.Активность = Истина;
    Движения.Записывать = Истина;
    Если Движения.Количество() <> 1 Или Не Движения.Записывать Тогда
        ВызватьИсключение "Не подготовлено одно собственное движение";
    КонецЕсли;
    Если Движение.Период <> Объект.Дата Или Движение.Регистратор <> Объект.Ссылка
        Или Движение.Проект85 <> Объект.Проект85 Или Движение.Количество85 <> Объект.Количество85
        Или Движение.Сумма85 <> Объект.Количество85 * Объект.Цена85 Или Не Движение.Активность Тогда
        ВызватьИсключение "Не подтверждены все поля подготовленного движения";
    КонецЕсли;
КонецПроцедуры

Процедура СоздатьДокумент85(Индекс)
    Документ = Документы.УчебнаяНакладная85.СоздатьДокумент();
    Если Не Документ.ЭтоНовый() Тогда
        ВызватьИсключение "Нужен собственный новый черновик";
    КонецЕсли;
    Документ.УстановитьСсылкуНового(СвоиСсылки85()[Индекс]);
    Документ.Дата = СвояДата85(Индекс);
    Документ.Номер = "УЧ85-00" + Строка(Индекс + 1);
    Документ.Проект85 = Метаданные.Версия;
    Документ.Количество85 = СвоеКоличество85(Индекс);
    Документ.Цена85 = 250;
    Если Индекс = 0 Тогда
        ПроверитьСтенд85(0, 250, 250, Ложь, Ложь, 0, 0);
    Иначе
        ПроверитьСтенд85(1, 250, 250, Истина, Ложь, 1000, 0);
    КонецЕсли;
    Документ.Записать(РежимЗаписиДокумента.Запись);
    Если Индекс = 0 Тогда
        ПроверитьСтенд85(1, 250, 250, Ложь, Ложь, 0, 0);
    Иначе
        ПроверитьСтенд85(2, 250, 250, Истина, Ложь, 1000, 0);
    КонецЕсли;
    Сохраненный = СвоиСсылки85()[Индекс].ПолучитьОбъект();
    ПроверитьДокумент85(Сохраненный, Индекс, 250, Ложь);
    ПроверитьЛабораторию85();
    Сохраненный.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный);
    Если Индекс = 0 Тогда
        ПроверитьСтенд85(1, 250, 250, Истина, Ложь, 1000, 0);
    Иначе
        ПроверитьСтенд85(2, 250, 250, Истина, Истина, 1000, 500);
    КонецЕсли;
КонецПроцедуры

Функция ВыполнитьЭтап85(Этап) Экспорт
    ПроверитьЛабораторию85();
    Если ТипЗнч(Этап) <> Тип("Строка") Тогда
        ВызватьИсключение "Неизвестная команда собственного урока";
    КонецЕсли;
    Если Этап = "Создание" Тогда
        ПроверитьСтенд85(0, 250, 250, Ложь, Ложь, 0, 0);
        СоздатьДокумент85(0);
        СоздатьДокумент85(1);
        Данные = ПроверитьСтенд85(2, 250, 250, Истина, Истина, 1000, 500);
    ИначеЕсли Этап = "Одна" Или Этап = "Список" Тогда
        Если Этап = "Одна" Тогда
            Цена1 = 250;
            Цена2 = 250;
            Сумма1 = 1000;
            Сумма2 = 500;
            ИндексИзменения = 1;
            НоваяЦена = 300;
        Иначе
            Цена1 = 250;
            Цена2 = 300;
            Сумма1 = 1000;
            Сумма2 = 600;
            ИндексИзменения = 0;
            НоваяЦена = 200;
        КонецЕсли;
        ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
        Объект = СвоиСсылки85()[ИндексИзменения].ПолучитьОбъект();
        Объект.Цена85 = НоваяЦена;
        ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
        Объект.Записать(РежимЗаписиДокумента.Запись);
        Если ИндексИзменения = 1 Тогда
            Цена2 = НоваяЦена;
        Иначе
            Цена1 = НоваяЦена;
        КонецЕсли;
        ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
        Последовательности.УчебныеПродажиОчередь85.УстановитьГраницу(Дата(2026, 1, 1, 0, 0, 0), СвойОтбор85());
        ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
        Граница = ПроверитьГраницы85(Истина);
        Момент = ПроверитьАктуальность85(Ложь);
        ПервыйМомент = ПрочитатьСвоюРегистрацию85(СвоиСсылки85()[0].ПолучитьОбъект(), Истина);
        Если Граница.Сравнить(ПервыйМомент) <> -1 Или Граница.Сравнить(Момент) <> -1 Тогда
            ВызватьИсключение "Явная собственная граница должна предшествовать обоим документам";
        КонецЕсли;
        Комбинации = СвоиКомбинации85();
        Если Этап = "Одна" Тогда
            ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
            ПроверитьГраницы85(Истина);
            ПроверитьАктуальность85(Ложь);
            ПроверитьКомбинации85(Комбинации);
            Последовательности.УчебныеПродажиОчередь85.Восстановить(Момент, Комбинации);
        Иначе
            Список = Новый ТаблицаЗначений;
            Список.Колонки.Добавить("Последовательность", Новый ОписаниеТипов("Строка"));
            Список.Колонки.Добавить("Комбинации");
            СтрокаСписка = Список.Добавить();
            СтрокаСписка.Последовательность = "УчебныеПродажиОчередь85";
            СтрокаСписка.Комбинации = Комбинации;
            Если Список.Колонки.Количество() <> 2 Или Список.Количество() <> 1
                Или ТипЗнч(Список[0][0]) <> Тип("Строка") Или Список[0][0] <> "УчебныеПродажиОчередь85"
                Или ТипЗнч(Список[0][1]) <> Тип("ТаблицаЗначений") Тогда
                ВызватьИсключение "Нужна явная одна собственная последовательность";
            КонецЕсли;
            ПроверитьКомбинации85(Список[0][1]);
            ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, Сумма1, Сумма2);
            ПроверитьГраницы85(Истина);
            ПроверитьАктуальность85(Ложь);
            Последовательности.Восстановить(Момент, Список);
        КонецЕсли;
        Данные = ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, 4 * Цена1, 2 * Цена2);
        ПроверитьГраницы85(Ложь);
        ПроверитьАктуальность85(Истина);
    ИначеЕсли Этап = "Чтение" Тогда
        ДокументыТаблица = ЧитатьДокументы85();
        Если ДокументыТаблица.Количество() <> 2 Тогда
            ВызватьИсключение "Сначала один раз создайте свой стенд";
        КонецЕсли;
        Цена1 = ДокументыТаблица[0].Цена85;
        Цена2 = ДокументыТаблица[1].Цена85;
        Если Не (Цена1 = 250 И Цена2 = 250 Или Цена1 = 250 И Цена2 = 300 Или Цена1 = 200 И Цена2 = 300) Тогда
            ВызватьИсключение "Источник вне подтвержденных собственных этапов";
        КонецЕсли;
        Данные = ПроверитьСтенд85(2, Цена1, Цена2, Истина, Истина, 4 * Цена1, 2 * Цена2);
    Иначе
        ВызватьИсключение "Такой этап не предусмотрен";
    КонецЕсли;
    Итог = Данные.Итог("Сумма85");
    Количество = Данные.Итог("Количество85");
    Если ТипЗнч(Итог) <> Тип("Число") Или ТипЗнч(Количество) <> Тип("Число") Или Количество <> 6 Тогда
        ВызватьИсключение "Не подтверждены реальные итог и количество";
    КонецЕсли;
    Возврат Новый ФиксированнаяСтруктура("Этап,Сумма,КоличествоЕдиниц", Этап, Итог, Количество);
КонецФункции

Процедура ПроверитьПустуюЛабораторию85() Экспорт
    ПроверитьСтенд85(0, 250, 250, Ложь, Ложь, 0, 0);
КонецПроцедуры
Настоящий обработчик проведения собственного документа

Документы → УчебнаяНакладная85 → Модуль объекта

Серверный модуль объекта собственной накладной; событие вызывается только платформой

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

Общие → Общие формы → УчебныйЗапускВосстановления85 → Модуль

Толстый управляемый клиент и &НаСервере своей формы; через серверный вызов передаются только 3 простых значения отчёта

&НаКлиенте
Процедура СоздатьСвойСтенд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 = "Неизвестно";
    Попытка
        Пакет = ЗапуститьНаСервере85(Этап, Согласие);
        Если ТипЗнч(Пакет) <> Тип("ФиксированнаяСтруктура") Или Пакет.Количество() <> 3
            Или Пакет.Этап <> Этап Или ТипЗнч(Пакет.Сумма) <> Тип("Число")
            Или ТипЗнч(Пакет.КоличествоЕдиниц) <> Тип("Число") Или Пакет.КоличествоЕдиниц <> 6
            Или Этап = "Создание" И Пакет.Сумма <> 1500
            Или Этап = "Одна" И Пакет.Сумма <> 1600
            Или Этап = "Список" И Пакет.Сумма <> 1400
            Или Этап = "Чтение" И Пакет.Сумма <> 1500 И Пакет.Сумма <> 1600 И Пакет.Сумма <> 1400 Тогда
            ВызватьИсключение "Клиент не принимает неполный или неподтвержденный скалярный результат";
        КонецЕсли;
        Сумма85 = Пакет.Сумма;
        Количество85 = Пакет.КоличествоЕдиниц;
        КлиентФаза85 = Строка(Сумма85);
        Протокол85 = "Проверены собственные реальные документы, регистрации и движения. Этап: " + Этап
            + "; количество: " + Строка(Количество85) + "; фактическая сумма: " + Строка(Сумма85);
        КлиентОстановка85 = Ложь;
    Исключение
        КлиентОстановка85 = Истина;
        КлиентФаза85 = "Неизвестно";
        ВызватьИсключение;
    КонецПопытки;
#Иначе
    КлиентОстановка85 = Истина;
    КлиентФаза85 = "Неизвестно";
    ВызватьИсключение "Подготовьте толстый управляемый клиент собственной лаборатории";
#КонецЕсли
КонецПроцедуры

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

Общие → Общие команды → ОткрытьУчебноеВосстановление85 → Модуль

Клиентский модуль собственной общей команды

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

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

  1. Проверить точную свою лабораторию, пользователя, единственное соединение и всю подготовленную схему. Имена и UUID являются маркерами стенда, а не универсальной аутентификацией. Серверный общий модуль неглобален и не вызывается напрямую с клиента.

  2. Обычной записью сохранить первую накладную, получить её свежий объект и провести; повторить для второй. ПринадлежностьПоследовательностям берётся только у существующего документа. Найти → Индекс → Получить дают настоящий связанный набор записей. Перед Записать(Истина) проверяется равенство фильтра Регистратор ссылке именно своей накладной.

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

  4. После каждой внешней записи прочитать свои таблицы и свежие объекты целиком. Движения 1000 и 500 дают реальный Итог("Сумма85") = 1500 и количество 6. Две регистрации содержат свои периоды, регистраторы и проект. МоментВремени записи последовательности сверяется по Дата, Ссылка и Сравнить с настоящим документом.

  5. После отдельного согласия Одна записать вторую цену 300 без проведения. Перечитать документы и движения: прежняя сумма 1500 обязательна, иначе остановка. УстановитьГраницу получает дату раньше первой накладной и структуру своего проекта. ПолучитьГраницу и ПолучитьГраницы сверяются по настоящему моменту; название первой колонки таблицы не предполагается.

  6. Проверить для настоящего второго момента после установки ранней границы должен вернуть Ложь. Восстановить менеджера своей последовательности получает этот момент и явную таблицу комбинаций своего проекта. Внутри нового проведения платформа уже удалила движения текущего документа: проверяются допустимые цены этапа, отсутствие текущего движения и полная неизменность движения другой своей накладной.

  7. После возврата Восстановить полностью перечитать документы, регистрации, движения и границы. Ожидаются движения 1000 и 600, сумма 1600, количество 6; Принадлежит для обоих документов и Проверить для второго момента — Истина. Только после полного контроля серверная и клиентская части формы принимают отчёт из трёх простых значений.

  8. После отдельного согласия Список записать первую цену 200. Подтвердить прежнюю сумму 1600, поставить раннюю границу и получить Проверить = Ложь. Проверить внешнюю таблицу из двух колонок и одной строки и вложенную таблицу проекта из одной колонки и одной строки. Глобальное восстановление ограничено одной своей последовательностью и своим проектом.

  9. Финальное перечитывание должно подтвердить цены 200 и 300, движения 800 и 600, сумму 1400 и количество 6, регистрации и результаты Принадлежит/Проверить. Ошибка не считается успехом; документы не удаляются, а восстановление не повторяется вслепую.

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

  1. Будущий ручной протокол: Создание оставляет 2 документа, 2 регистрации и 2 активных движения; количество 6, сумма 1500. Одна подтверждает прежние 1500 после изменения цены и новые 1600 после адресного восстановления. Список подтверждает прежние 1600 и новые 1400. Это ожидаемые результаты, а не выполненный запуск; runtimeVerified=False.

  2. Все 13 новых методов используются в основном коде через реальные объекты своей схемы; уже покрытые типы не добавляются. Проверки типов, конфигурации, пользователя, соединения, фильтров, всех полей документов и движений, регистраций, моментов и вложенных таблиц охватывают источник целиком, а не только сумму.

  3. Положительные и отрицательные статические тесты проверяют сигнатуры установленного API, доступность на сервере, поля только для чтения, реальные обработчики событий, порядок полного контроля до и после операций и допустимое переходное состояние при проведении. Python не исполняет действия 1С.

  4. Иной путь базы, схема, пользователь, соединение или этап, лишний документ, регистрация или движение, неверный тип, период, ссылка, проект, цена, количество, состав таблицы или неполный отчёт останавливает выполнение. После неизвестного результата серверного вызова нет автоматического повтора и перехода дальше.

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

Ожидаемый будущий ручной протокол своей новой лаборатории: 2 документа, 2 регистрации и 2 активных движения; количество 6, суммы 1500 → 1600 → 1400. После адресного восстановления Принадлежит для обоих документов и Проверить для настоящего второго момента возвращают Истина. Запуск в 1С не проверялся.

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

  1. ФиксированнаяКоллекция создаётся платформой, а не через Новый. ПринадлежностьПоследовательностям доступна только для чтения; её настоящие элементы — ПоследовательностьНаборЗаписей. Новый незаписанный черновик не заменяет существующий документ. Пустая или чужая коллекция приводит к остановке, а не подавляется.

  2. Регистратор набора доступен только для чтения, тогда как Регистратор своей записи можно задать. Сам Отбор только для чтения, но его документированный элемент изменяется методом Установить. Записать(Истина) перед замещением удаляет прежние реальные записи своего фильтра: это изменение базы, а не только памяти.

  3. ОсновнойРежимЗапуска использует глобальный РежимЗапускаКлиентскогоПриложения. Перечисления свойств метаданных берутся через Метаданные.СвойстваОбъектов, а ДопустимыйЗнак и ДопустимаяДлина — отдельные глобальные перечисления. КоллекцияЗначенийОбъектаМетаданных допускает Количество, Содержит и Для каждого, но не Найти, Получить и индексатор. У метаданных регистра накопления нет свойства Регистраторы.

  4. Платформа автоматически удаляет текущие движения до события проведения. Полная таблица движений проверяется после внешней операции. Внутри события не требуется Проведен = Истина и не изменяются сохранённые реквизиты документа. Проверяются текущий свой документ и допустимые движения других своих документов, неизменные до и после записи регистрации.

  5. ПеремещениеГраницыПриПроведении описывает попытку перемещения, а не фиксированный начальный результат. У границы, установленной датой, нельзя придумывать Ссылка = Неопределено. Сверяются настоящая дата и момент. ПолучитьГраницы гарантирует момент в первой колонке, но не её имя.

  6. Восстановить не является чтением: перепроводит реальные документы. Явные ограничения обязательны, иначе можно затронуть все последовательности или комбинации измерений. Транзакция одной записи документа с проведением не доказывает атомарность всех восстановлений, двух документов или нескольких кнопок.

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

  8. Компиляция и запуск в 1С пока не проверены. После частичной записи не разрешайте повтор, не добавляйте слепой откат или очистку и не переносите урок в рабочую конфигурацию. Будущие изменения разрешены только в отдельно подготовленной новой собственной базе.

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

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

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

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

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