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