Можно ли записать данные документа в процедуре его проведения в 1С?

Программист 1С v8.3 (Управляемые формы) Торговля и дистрибуция
← На главную

В процессе разработки часто возникает задача изменить какие-либо данные в самом документе в момент его проведения. Например, проставить отметку о проверке, зафиксировать текущую дату в строке или изменить статус. Интуитивно кажется, что это можно сделать прямо в процедуре ОбработкаПроведения, получив объект документа и записав его. Однако такой подход не работает и является серьезной ошибкой. Разберем, почему так происходит и как правильно решать эту задачу.

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


// Неправильный код в процедуре ОбработкаПроведения
ФОбъект = Ссылка.ПолучитьОбъект();
Для Каждого СтрокаКодаОбъекта Из ФОбъект.ШтрихкодыУпаковок Цикл
    Если СтрокаКодаОбъекта.ШтрихкодУпаковки = НужныйШтрихкод Тогда
        СтрокаКодаОбъекта.ДатаПроверкиПередачиЧестныйЗнак = ТекущаяДата();
    КонецЕсли;
КонецЦикла;
ФОбъект.ОбменДанными.Загрузка = Истина;
ФОбъект.Записать(РежимЗаписиДокумента.Запись);

Код выполняется без ошибок, но изменения в документе не сохраняются. Выясним причину такого поведения и рассмотрим корректные решения.

Проблема №1: Повторная запись объекта внутри транзакции проведения

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

  1. Начало транзакции: Когда пользователь нажимает "Провести", платформа открывает транзакцию и блокирует объект документа для записи.
  2. Выполнение кода: Внутри ОбработкаПроведения вы пытаетесь выполнить Ссылка.ПолучитьОбъект(). Эта команда считывает из базы данных уже существующую версию документа (ту, что была до начала проведения) и создает в памяти новый, отдельный объект.
  3. Конфликт записи: Далее вы вызываете метод ФОбъект.Записать(). Это попытка инициировать новую запись объекта внутри уже идущей транзакции записи того же самого объекта. Платформа в лучшем случае проигнорирует эту команду, чтобы не вызывать конфликт блокировок или вложенных транзакций.
  4. Завершение транзакции: После завершения процедуры ОбработкаПроведения платформа записывает в базу данных исходный объект документа (тот, с которым транзакция и началась). Все изменения, которые вы пытались внести в "копию" объекта (ФОбъект), просто теряются, так как они были сделаны с другим экземпляром объекта в памяти.

Важно: Получать объект по ссылке (Ссылка.ПолучитьОбъект()) и пытаться его записать внутри его же модулей событий записи (ПередЗаписью, ПриЗаписи, ОбработкаПроведения) — это грубая архитектурная ошибка, которая приводит к непредсказуемому поведению и трудноуловимым багам.

Решение: Используем событие "ПередЗаписью"

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

Это идеальное место для модификации реквизитов, так как:

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Выполняем логику только в том случае, если документ проводится
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        
        // Здесь может быть ваша логика получения НужногоШтрихкода
        // ...

        // Напрямую обращаемся к табличной части объекта
        Для Каждого СтрокаКодаОбъекта Из ЭтотОбъект.ШтрихкодыУпаковок Цикл
            Если СтрокаКодаОбъекта.ШтрихкодУпаковки = НужныйШтрихкод Тогда
                СтрокаКодаОбъекта.ДатаПроверкиПередачиЧестныйЗнак = ТекущаяДата();
                // Прерываем цикл, если штрихкод уникален и уже найден
                Прервать; 
            КонецЕсли;
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Теперь изменения будут корректно сохранены в рамках штатной транзакции записи документа.

Почему изменения все равно могут не сохраняться? Откат транзакции.

Иногда даже после переноса кода в ПередЗаписью изменения не сохраняются. В этом случае наиболее вероятная причина — откат транзакции.

Если после вашего кода, изменяющего данные, где-то дальше по ходу выполнения (в этой же процедуре ПередЗаписью или в ОбработкаПроведения) будет установлена строка:

Отказ = Истина;

...то платформа полностью отменит (откатит) всю транзакцию. Все изменения, сделанные с момента ее начала, включая ваши правки в ПередЗаписью и движения по регистрам, будут отменены. Документ вернется в состояние, в котором он был до начала проведения.

Что делать? Используйте отладчик. Поставьте точку останова на строке, где вы меняете данные, и еще одну в конце процедуры ОбработкаПроведения. Пройдите по шагам и убедитесь, что переменная Отказ нигде не устанавливается в Истина после того, как вы внесли свои изменения.

Архитектурная ошибка: внешние запросы в транзакции проведения

В обсуждаемой теме также была затронута еще одна критически важная тема: выполнение HTTP-запросов к внешним системам (например, "Честный Знак") внутри процедуры проведения. Это категорически запрещенная практика.

Риски и последствия

  1. Длительные блокировки. Транзакция проведения блокирует таблицы в базе данных (сам документ, регистры накопления, сведений и т.д.). Если внешний сервис будет отвечать долго (например, 5-10 секунд из-за нагрузки или проблем с сетью), все это время таблицы в вашей базе будут заблокированы. Другие пользователи не смогут проводить документы, формировать отчеты, что может парализовать работу целого отдела или склада.
  2. Ненадежность системы. Работа вашего предприятия начинает зависеть от стабильности внешнего сервиса, интернет-канала и множества других факторов, которые вы не контролируете. Если сервис "Честного знака" недоступен, отгрузки останавливаются.
  3. Сложность отладки. Ошибки, связанные с тайм-аутами и блокировками, очень сложно воспроизводить и диагностировать. Пользователи будут жаловаться на "зависания" программы, а причина будет крыться в неудачном архитектурном решении.

Рекомендуемые архитектурные решения

Взаимодействие с внешними системами необходимо выносить за рамки транзакции проведения. Рассмотрим правильные подходы.

1. Интерактивная проверка на форме.

Самый простой и надежный способ — выполнять все проверки до начала проведения. Добавьте на форму документа кнопку, например, "Проверить коды маркировки". По ее нажатию будет выполнен запрос к внешнему сервису. Результат проверки (успех или ошибка) можно отобразить пользователю и сохранить во временном хранилище или в реквизите документа (если это не требует записи). Проведение документа разрешается только после получения успешного ответа.

2. Разделение бизнес-операций на разные документы.

Если внешняя операция является самостоятельным хозяйственным событием, ее следует оформить отдельным документом. Например, процесс продажи маркированного товара можно разделить на два этапа:

Такой подход делает систему более устойчивой и правильно отражает бизнес-логику.

3. Асинхронные и фоновые операции.

Если немедленный ответ от внешней системы не требуется, используйте фоновые или регламентные задания. Документ проводится, фиксируя намерение, а фоновое задание в удобное время (например, через несколько секунд) отправляет данные во внешнюю систему и записывает результат в отдельный регистр сведений, связывая его с исходным документом.

← На главную