Почему программно созданный документ не сохраняется при записи из модуля другого объекта?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При разработке в системе 1С:Предприятие 8 часто возникает задача автоматического создания сопутствующих документов. Например, при проведении «Реализации товаров и услуг» может потребоваться создать «Поступление товаров и услуг». Однако разработчики часто сталкиваются с ситуацией: код создания документа отрабатывает без ошибок, метод Записать() вызывается, но после завершения процесса новый документ так и не появляется в списке. Разберем подробно, почему это происходит и как правильно организовать архитектуру взаимодействия объектов.

Анализируем причину: механизмы транзакций

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

Проанализируем сценарий, описанный в теме:

  1. Начинается проведение документа «Реализация». Система открывает транзакцию.
  2. Выполняется наш код, создается новый документ «Поступление».
  3. Вызывается Док.Записать(). Данные физически записываются в таблицы СУБД, но транзакция еще не зафиксирована (Commit).
  4. Система продолжает проведение «Реализации» и обнаруживает, например, нехватку товара на складе.
  5. Процедура проведения прерывается, устанавливается флаг Отказ = Истина.
  6. Платформа выполняет откат транзакции (Rollback).

В результате отката все изменения, сделанные в рамках этой транзакции, аннулируются. С точки зрения базы данных «Поступления» никогда не существовало, так как операция записи не была завершена финальной фиксацией. Именно поэтому использование блока Попытка...Исключение не помогает: программной ошибки нет, метод Записать() отработал штатно, но результат его работы был стерт СУБД из-за ошибки в основном объекте.

Проблема бесконечного назначения номера

Выясним причину странного поведения нумератора, когда при каждой попытке проведения новому документу присваивается один и тот же номер (например, «009»). Это прямое следствие отката транзакции. Механизм автонумерации 1С резервирует номер при записи. Если транзакция откатывается, номер «освобождается» (точнее, запись о его использовании исчезает), и при следующей попытке система снова предлагает тот же самый свободный по её данным номер. Это явный маркер того, что данные не фиксируются в базе.

Решение 1: Смена события на «ПриЗаписи»

Многие разработчики пытаются перенести код из ОбработкаПроведения в событие ПриЗаписи. Рассмотрим, решит ли это проблему. Если пользователь просто нажимает кнопку «Записать» в форме документа, то транзакция проведения еще не открыта, и созданный объект может сохраниться успешно. Однако, если пользователь нажимает кнопку «Провести», платформа сначала вызывает ПриЗаписи, а затем ОбработкаПроведения — и все это происходит внутри одной транзакции.

Следовательно, если проведение документа «Реализация» не удастся, то и документ, созданный в ПриЗаписи, также будет удален из базы. Если ваша логика требует, чтобы сопутствующий документ существовал в любом случае, этот метод вам не подходит.

Решение 2: Использование дополнительных свойств для управления записью

Если нам нужно передать сигнал из формы в модуль объекта о необходимости создания связанных сущностей, рекомендуется использовать структуру ДополнительныеСвойства. Посмотрим на пример кода в модуле формы:


&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Передаем флаг в модуль объекта
    ТекущийОбъект.ДополнительныеСвойства.Вставить("СоздатьПоступление", Истина);
КонецПроцедуры

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

Решение 3: Правильная архитектура через «Создать на основании»

Самый надежный и методически верный способ — инициировать создание связанных документов вне транзакции проведения. Рассмотрим лучшие практики:

  1. Ввод на основании: Пользователь явно нажимает кнопку создания документа. Это происходит в интерактивном режиме, документы записываются независимо.
  2. Фоновые задания: В процедуре ПослеЗаписи (которая выполняется уже после закрытия транзакции) можно инициировать запуск фонового задания, которое создаст нужный документ. Это гарантирует, что основная транзакция завершена успешно.
  3. Использование БСП: Если конфигурация построена на базе БСП, можно использовать механизм «Подписки на события». Это позволяет отделить логику типовой конфигурации от кастомных доработок и более гибко управлять порядком выполнения процедур.

Важные замечания по блокировкам

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

Рекомендация: Всегда стремитесь к тому, чтобы транзакции были максимально короткими и затрагивали только те данные, которые непосредственно относятся к проводимому объекту. Создание других полноценных документов внутри ОбработкаПроведения — это «антипаттерн» разработки на 1С.

Резюме для разработчика

Если вы столкнулись с тем, что Док.Записать() не оставляет следов в базе:

← На главную