При разработке в системе 1С:Предприятие 8 часто возникает задача автоматического создания сопутствующих документов. Например, при проведении «Реализации товаров и услуг» может потребоваться создать «Поступление товаров и услуг». Однако разработчики часто сталкиваются с ситуацией: код создания документа отрабатывает без ошибок, метод Записать() вызывается, но после завершения процесса новый документ так и не появляется в списке. Разберем подробно, почему это происходит и как правильно организовать архитектуру взаимодействия объектов.
Главная причина «исчезновения» документа заключается в том, что в 1С запись и проведение документа всегда выполняются в рамках транзакции. Рассмотрим ситуацию: мы пишем код в процедуре ОбработкаПроведения. В этот момент платформа уже открыла транзакцию базы данных. Когда мы вызываем Док.Записать() для нового объекта внутри этой процедуры, 1С не создает отдельную независимую транзакцию, а просто увеличивает счетчик уровня вложенности текущей.
Проанализируем сценарий, описанный в теме:
Док.Записать(). Данные физически записываются в таблицы СУБД, но транзакция еще не зафиксирована (Commit).Отказ = Истина.В результате отката все изменения, сделанные в рамках этой транзакции, аннулируются. С точки зрения базы данных «Поступления» никогда не существовало, так как операция записи не была завершена финальной фиксацией. Именно поэтому использование блока Попытка...Исключение не помогает: программной ошибки нет, метод Записать() отработал штатно, но результат его работы был стерт СУБД из-за ошибки в основном объекте.
Выясним причину странного поведения нумератора, когда при каждой попытке проведения новому документу присваивается один и тот же номер (например, «009»). Это прямое следствие отката транзакции. Механизм автонумерации 1С резервирует номер при записи. Если транзакция откатывается, номер «освобождается» (точнее, запись о его использовании исчезает), и при следующей попытке система снова предлагает тот же самый свободный по её данным номер. Это явный маркер того, что данные не фиксируются в базе.
Многие разработчики пытаются перенести код из ОбработкаПроведения в событие ПриЗаписи. Рассмотрим, решит ли это проблему. Если пользователь просто нажимает кнопку «Записать» в форме документа, то транзакция проведения еще не открыта, и созданный объект может сохраниться успешно. Однако, если пользователь нажимает кнопку «Провести», платформа сначала вызывает ПриЗаписи, а затем ОбработкаПроведения — и все это происходит внутри одной транзакции.
Следовательно, если проведение документа «Реализация» не удастся, то и документ, созданный в ПриЗаписи, также будет удален из базы. Если ваша логика требует, чтобы сопутствующий документ существовал в любом случае, этот метод вам не подходит.
Если нам нужно передать сигнал из формы в модуль объекта о необходимости создания связанных сущностей, рекомендуется использовать структуру ДополнительныеСвойства. Посмотрим на пример кода в модуле формы:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Передаем флаг в модуль объекта
ТекущийОбъект.ДополнительныеСвойства.Вставить("СоздатьПоступление", Истина);
КонецПроцедуры
Затем в модуле объекта мы можем анализировать этот флаг. Это позволяет избежать лишних действий, если запись происходит программно или в фоновых процессах, где создание связанных документов не требуется.
Самый надежный и методически верный способ — инициировать создание связанных документов вне транзакции проведения. Рассмотрим лучшие практики:
ПослеЗаписи (которая выполняется уже после закрытия транзакции) можно инициировать запуск фонового задания, которое создаст нужный документ. Это гарантирует, что основная транзакция завершена успешно.Проанализируем еще один аспект: запись другого документа внутри транзакции первого — это «тяжелая» операция. Она вызывает блокировки таблиц обоих видов документов. В многопользовательской среде это может привести к ошибкам типа Deadlock (взаимная блокировка), когда два пользователя одновременно проводят документы и пытаются записать связанные объекты в разном порядке.
Рекомендация: Всегда стремитесь к тому, чтобы транзакции были максимально короткими и затрагивали только те данные, которые непосредственно относятся к проводимому объекту. Создание других полноценных документов внутри ОбработкаПроведения — это «антипаттерн» разработки на 1С.
Если вы столкнулись с тем, что Док.Записать() не оставляет следов в базе:
ОтменитьТранзакцию().