Как правильно реализовать проведение одного документа при проведении другого в 1С?

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

При разработке бизнес-логики в 1С часто возникает задача автоматического создания или проведения зависимых документов. Например, при проведении Реализации товаров и услуг требуется начислить бонусы в документе Начисление и списание бонусных баллов. Давайте разберем, почему попытка выполнить проведение напрямую в обработке проведения является рискованным шагом и какие альтернативные подходы предлагает профессиональная разработка.

Почему проведение одного документа внутри другого — это «антипаттерн»?

Рассмотрим ситуацию, когда мы вызываем метод Провести() для второго документа прямо внутри процедуры ОбработкаПроведения первого. Основная проблема кроется в транзакциях:

  1. Растягивание транзакции: В момент выполнения ОбработкиПроведения система уже открыла транзакцию. Запуск проведения второго документа открывает вложенную транзакцию. Это увеличивает время удержания блокировок на регистрах и документах.
  2. Блокировки и взаимоблокировки (Deadlocks): Длительные транзакции — главная причина снижения производительности. Если в системе одновременно работают несколько пользователей, они могут столкнуться с тайм-аутами, так как база данных будет заблокирована до завершения обеих операций.
  3. Риск целостности: Если при проведении второго документа произойдет любая ошибка, вся транзакция (включая основной документ) будет отменена. Это не всегда корректно, так как факт продажи (Реализация) должен быть зафиксирован, даже если начисление бонусов временно не удалось.

Вариант 1: Использование регистров накопления (Рекомендуемый подход)

Часто создание отдельного документа Начисление и списание бонусных баллов является избыточным. Если задача сводится к изменению остатков баллов, лучше использовать РегистрНакопления.

В этом случае вместо создания документа вы напрямую формируете движения по регистру в ОбработкеПроведения реализации:


Процедура ОбработкаПроведения(Отказ, Режим)
    // Формируем движения по регистру накопления "БонусныеБаллы"
    Движения.БонусныеБаллы.Записывать = Истина;
    Движение = Движения.БонусныеБаллы.Добавить();
    Движение.Период = Дата;
    Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
    Движение.СуммаБонусов = СуммаДокумента * 0.05; // 5% от суммы
КонецПроцедуры

Этот метод атомарен, быстр и не требует дополнительных объектов.

Вариант 2: Использование подписки на события и реквизита связи

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

  1. Добавьте в документ Реализация товаров и услуг реквизит ДокументБонусов (тип: ДокументСсылка.НачислениеИСписаниеБонусов).
  2. В модуле объекта Реализация в процедуре ПередЗаписью выполняйте проверку существования связанного документа:

Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если ЗначениеЗаполнено(ДокументБонусов) Тогда
        Если Не ДокументБонусов.Проведен() Тогда
            // Проверка: существует ли документ в базе и не удален ли он
            Если ДокументБонусов.Ссылка.Пустая() Тогда
                ДокументБонусов = Неопределено;
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Вариант 3: Автоматизация через события формы

При интерактивной работе пользователя (через интерфейс) создание зависимого документа можно вынести в событие ПослеЗаписи модуля формы:


&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    // Вызов серверного метода для создания документа
    СоздатьДокументБонусовНаСервере(Объект.Ссылка);
КонецПроцедуры

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

Вариант 4: Очередь заданий (Для массовых операций)

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

Подведем итог: никогда не проводите документ «внутри» другого документа. Либо пишите движения в РегистрНакопления, либо используйте асинхронные механизмы (регламентные задания), либо выносите логику создания зависимых объектов в события формы после завершения транзакции.

← На главную