Отказать в выполнении собственной задачи, затем выполнить другой свой маршрут интерактивно

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

Два независимых собственных опыта на последовательной карте: реальная задача порождается Старт, однопараметровый обработчик проверяет готовность, состояние задачи и процесса читается после метода; каждая транзакция отменяется.

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

Полный модуль обычной формы ЗапускВыполнения85 в толстом клиенте Windows, режим ОбычноеПриложение, новый стенд УчебноеВыполнениеЗадачи85.

Подготовка

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

  2. Основной режим запуска — Обычное приложение; толстый клиент Windows именно в ОбычноеПриложение. Управляемый режим не вызывает ПередИнтерактивнымВыполнением и отклоняется кодом.

  3. Задачи → УчебнаяЗадача85: номер Строка9, автонумерация, Наименование100, реквизит ГотоваКВыполнению85 типа Булево исходно Ложь. Не добавляйте адресацию или обязательные поля.

  4. Бизнес-процессы → УчебныйПроцесс85: номер Строка9, автонумерация, Маркер85 Строка36; Задача=УчебнаяЗадача85.

  5. Карта процесса строго Старт → одна одиночная точка действия Опыт85 → Финиш. Представление действия «Собственный опыт выполнения»; нет условий, групповых точек, подпроцессов и адресации.

  6. В модуль задачи вставьте целиком отдельный ПередИнтерактивнымВыполнением из карточки. Модуль процесса и обработчики точек маршрута пустые; никаких подписок, обмена и внешних действий.

  7. Не копируйте ПередЗаписью с безусловным отказом из урока просмотра: этот новый стенд действительно записывает свои данные внутри отменяемых транзакций.

  8. Обработки → ЗапускВыполнения85 → обычная форма Форма. Весь основной код находится в её модуле без клиент-серверных директив и без общего модуля.

  9. Реквизиты формы: ПодтверждаюПустойСтенд85 и Занято85 типа Булево, Итог85 Строка неограниченной длины; исходные флажки Ложь, занятость и итог только для просмотра.

  10. Обычная кнопка ПроверитьСвоёВыполнение85: Нажатие=ПроверитьСвоёВыполнение85. Это обработчик Кнопка, не команда управляемой формы.

  11. Нажмите F7 и обновите только свой пустой стенд. runtimeVerifiedScenarios=0: 1С, маршрут, запись, интерактивное выполнение и откат здесь не запускались.

  12. Один свой пользователь, один клиент, без фоновых заданий, других писателей, сеансов и сетевых/почтовых/печатных действий. Откат базы не отменяет произвольные внешние эффекты.

  13. Подтвердите пустой стенд и вручную запустите команду. Два опыта используют разные собственные процессы, UUID и маркеры; готовность берётся только из литералов Ложь и Истина основного кода.

  14. Процесс записывается и порождает задачу Старт внутри своей транзакции. Задача находится параметризованным запросом только по этому процессу, а не создаётся вручную для имитации маршрута.

  15. Первый опыт требует штатного отказа и незавершённого процесса. Если метод при отказе возвращает исключение, выполняется откат и сообщается исключение, а не ложный успешный отказ.

  16. Второй опыт разрешает выполнение и требует реально прочитанных Выполнена=Истина и Завершен=Истина. Затем оба созданных объекта исчезают после отмены своей транзакции.

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

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

УчебноеВыполнениеЗадачи85 → Задачи → УчебнаяЗадача85 → Модуль объекта

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

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

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

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

  2. Каждый вызов helper создаёт собственный процесс с новым плановым UUID и маркером. Реальный Старт проходит до единственного действия и порождает одну задачу маршрута.

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

  4. В первом опыте ГотоваКВыполнению85=Ложь, во втором Истина. Собственный контекст задаётся перед методом; обработчик проверяет сохранённый процесс и записывает только доказательство вызова в ДополнительныеСвойства.

  5. ПередИнтерактивнымВыполнением имеет один возвращаемый Отказ и вызывается самим API. Оно отказывает неготовой задаче и разрешает готовую; readonly-флаги выполнения и завершения не присваиваются.

  6. ВыполнитьЗадачуИнтерактивно вызывается на реальной задаче маршрута. При штатном возврате Прочитать получает реальные значения задачи и процесса: оба должны соответствовать готовности.

  7. Если метод завершился исключением, данные не читаются повторно внутри потенциально нарушенной транзакции. Сначала отменяется собственный опыт; даже подтверждённый отказ не скрывает исключение.

  8. Каждая собственная транзакция отменяется при нормальном или ошибочном пути. Вне неё отдельно проверяется отсутствие процесса и порождённой задачи по полученным реальным ссылкам.

  9. Итог содержит штатный отказ первого опыта и штатное выполнение второго только после всех проверок. Занятость снимается до передачи исключения пользователю.

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

  1. ПередИнтерактивнымВыполнением действительно оставляет свой маркер вызова и правильный Отказ, не просто сравнивается флажок готовности в основном модуле.

  2. Первый штатный опыт: задача не выполнена, процесс не завершён. Второй: задача выполнена методом, процесс завершён уведомлением маршрута.

  3. В обоих случаях задача появилась от реального Старт и относится к единственному собственному процессу и точке Опыт85.

  4. После каждого опыта транзакция закрыта, процесс и его задача отсутствуют по собственным ссылкам. Никаких ЗафиксироватьТранзакцию или непосредственного Удалить нет.

  5. Любое неожиданное исключение, отсутствие callback или другое состояние приводит к ошибке после отката, а не к успешному учебному отчёту.

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

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

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

  1. Этот метод доступен в толстом клиенте. ПередИнтерактивнымВыполнением не вызывается в УправляемоеПриложение, поэтому выбран и проверяется обычный режим.

  2. Не применяйте метод к произвольной вручную созданной несвязанной задаче. Здесь принадлежность реальному собственному процессу и точке маршрута проверяется перед выполнением.

  3. Выполнение метода записывает задачу и уведомляет породивший её процесс. Присваивание Выполнена или Завершен не воспроизводит эти действия и здесь не используется.

  4. Готовность — собственный изменяемый реквизит учебного объекта, не readonly-флаг исполнения. Он задаёт бизнес-условие отказа и не заменяет результат метода.

  5. ДополнительныеСвойства хранит доказательство вызова только в текущем экземпляре языка. Оно проверяется до Прочитать; после отката этот экземпляр больше не используется.

  6. Отказ и исключение метода — разные исходы. Если метод завершился исключением, урок не объявляет штатный отказ и не продолжает второй опыт как будто всё прошло нормально.

  7. Два опыта не изменяют один и тот же уже откатившийся экземпляр. Для каждого создаются новые процесс, задача маршрута и собственные ссылки.

  8. Это демонстрация одного действия без адресации и конкурирующих исполнителей. Стандартный выбор всех задач текущего пользователя и контроль производственных прав здесь не реализованы.

  9. Запрос ограничен собственной ссылкой, но отдельная пустая база и единственный писатель всё равно обязательны. Маркер и UUID не делают код production-службой массового выполнения задач.

  10. Своя транзакция завершается только ОтменитьТранзакцию. Откат базы не отменяет внешнюю сеть, почту, печать и файлы из произвольных обработчиков; нельзя отменять чужую транзакцию.

  11. Внешние действия и подписки должны отсутствовать. Этот учебный маршрут не запускает настоящие рабочие роботы, фоновые задания или интеграции.

  12. Откат записи базы не возвращает объекты языка в начальное состояние. Проверка отсутствия идёт по ссылкам после отката, а не по прежним значениям в памяти.

  13. Формы задачи не открываются и пользователь не редактирует записи в середине транзакции. Модальных вопросов, удерживающих транзакцию на время ответа, в приведённом коде нет.

  14. Если авария оборвала работу, штатный результат не гарантируется. Ручные тесты требуют отдельного разрешения; runtimeVerifiedScenarios=0, фактических действий в1С здесь нет.

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

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

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

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

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

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