При разработке бизнес-логики в 1С часто возникает задача автоматического создания или проведения зависимых документов. Например, при проведении Реализации товаров и услуг требуется начислить бонусы в документе Начисление и списание бонусных баллов. Давайте разберем, почему попытка выполнить проведение напрямую в обработке проведения является рискованным шагом и какие альтернативные подходы предлагает профессиональная разработка.
Рассмотрим ситуацию, когда мы вызываем метод Провести() для второго документа прямо внутри процедуры ОбработкаПроведения первого. Основная проблема кроется в транзакциях:
ОбработкиПроведения система уже открыла транзакцию. Запуск проведения второго документа открывает вложенную транзакцию. Это увеличивает время удержания блокировок на регистрах и документах.Часто создание отдельного документа Начисление и списание бонусных баллов является избыточным. Если задача сводится к изменению остатков баллов, лучше использовать РегистрНакопления.
В этом случае вместо создания документа вы напрямую формируете движения по регистру в ОбработкеПроведения реализации:
Процедура ОбработкаПроведения(Отказ, Режим)
// Формируем движения по регистру накопления "БонусныеБаллы"
Движения.БонусныеБаллы.Записывать = Истина;
Движение = Движения.БонусныеБаллы.Добавить();
Движение.Период = Дата;
Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
Движение.СуммаБонусов = СуммаДокумента * 0.05; // 5% от суммы
КонецПроцедуры
Этот метод атомарен, быстр и не требует дополнительных объектов.
Если специфика бизнеса требует именно создания отдельного документа (например, для печати или предоставления клиенту), реализуйте жесткую связку между документами.
Реализация товаров и услуг реквизит ДокументБонусов (тип: ДокументСсылка.НачислениеИСписаниеБонусов).Реализация в процедуре ПередЗаписью выполняйте проверку существования связанного документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ЗначениеЗаполнено(ДокументБонусов) Тогда
Если Не ДокументБонусов.Проведен() Тогда
// Проверка: существует ли документ в базе и не удален ли он
Если ДокументБонусов.Ссылка.Пустая() Тогда
ДокументБонусов = Неопределено;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
При интерактивной работе пользователя (через интерфейс) создание зависимого документа можно вынести в событие ПослеЗаписи модуля формы:
&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
// Вызов серверного метода для создания документа
СоздатьДокументБонусовНаСервере(Объект.Ссылка);
КонецПроцедуры
Это исключает влияние на транзакцию записи, так как транзакция основного документа к моменту выполнения этого кода уже успешно завершена.
Если документы создаются в фоновом режиме или массово, лучше использовать механизм очередей. Запишите данные о необходимости начисления в РегистрСведений «Очередь начисления бонусов», а регламентное задание по расписанию будет обрабатывать записи, создавая и проводя документы в фоновом режиме. Это обеспечит стабильность системы и отсутствие влияния на работу пользователей в момент проведения реализации.
Подведем итог: никогда не проводите документ «внутри» другого документа. Либо пишите движения в РегистрНакопления, либо используйте асинхронные механизмы (регламентные задания), либо выносите логику создания зависимых объектов в события формы после завершения транзакции.