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

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

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

Попытки реализовать такую логику через события формы (ПередЗаписью, ПослеЗаписи) приводят к серьезным ошибкам: движения могут записаться, даже если документ не провелся из-за ошибки контроля остатков, либо остаться в базе при отмене проведения. Разберем, как устроена транзакционная модель проведения в 1С и как правильно решить эту задачу.

Почему нельзя формировать движения в событиях формы

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

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

Транзакционная модель проведения в 1С

Платформа 1С:Предприятие берет на себя управление жизненным циклом записей регистратора, если разработка ведется по стандартам платформы. Рассмотрим ключевые правила:

  1. Единая транзакция: Процедура ОбработкаПроведения модуля объекта выполняется внутри системной транзакции. Если в процессе проведения переменной Отказ присваивается значение Истина или происходит аварийное завершение, платформа автоматически выполняет откат (Rollback) всей транзакции. Все движения, сформированные документом, бесследно удаляются.
  2. Автоматическая очистка движений: Перед повторным проведением или при отмене проведения платформа или типовые механизмы конфигурации автоматически очищают предыдущие движения документа по всем регистрам, для которых данный документ назначен регистратором.
  3. Флаг записи наборов: Чтобы движения записались в базу данных при успешном завершении процедуры, достаточно добавить записи в коллекцию Движения и выставить свойство Записывать = Истина.

Способ 1. Формирование движений в модуле документа

Разберем по шагам классический вариант добавления движений напрямую в процедуру ОбработкаПроведения модуля документа.

  1. В дереве метаданных открываем свойства нужного регистра накопления (например, Бонусы) и добавляем документ (например, РеализацияТоваровУслуг) в список Регистраторы.
  2. В свойствах самого документа переходим на вкладку Движения и отмечаем флажком регистр Бонусы.
  3. Открываем модуль объекта документа и переходим к процедуре ОбработкаПроведения. В типовых конфигурациях (таких как Управление торговлей 10.3) в конце процедуры расположен блок проверки переменной Отказ. Именно туда помещаем код формирования движений.

Посмотрим на пример реализации кода:


// В конце процедуры ОбработкаПроведения:
Если Не Отказ Тогда

    // Рассчитываем сумму бонусов по документу
    СуммаБонусов = СуммаДокумента * 0.05; // Пример: 5% от суммы

    Если СуммаБонусов > 0 Тогда
        // Получаем набор движений по нашему регистру
        Движение = Движения.Бонусы.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период      = Дата;
        Движение.Контрагент  = Контрагент;
        Движение.СуммаБонуса = СуммаБонусов;
        
        // Взводим флаг необходимости записи набора
        Движения.Бонусы.Записывать = Истина;
    КонецЕсли;

КонецЕсли;

В этом случае при успешном проведении движения запишутся автоматически. Если документ перепроводят с новой суммой, старые движения сначала очистятся, сумма пересчитается, и запишется новый результат. При отмене проведения платформа полностью удалит записи регистратора.

Способ 2. Использование подписки на событие (без изменения типового документа)

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

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

Посмотрим на пример кода в общем модуле:


Процедура НачислитьБонусыПриПроведенииРеализацииОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт

    // Проверяем режим загрузки данных и факт наличия ошибок проведения
    Если Отказ Или Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Рассчитываем сумму бонуса
    СуммаБонусов = Источник.СуммаДокумента * 0.05;

    Если СуммаБонусов > 0 Тогда
        Движение = Источник.Движения.Бонусы.Добавить();
        Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
        Движение.Период      = Источник.Дата;
        Движение.Контрагент  = Источник.Контрагент;
        Движение.СуммаБонуса = СуммаБонусов;

        Источник.Движения.Бонусы.Записывать = Истина;
    КонецЕсли;

КонецПроцедуры

Подписка на событие вызывается после основного кода процедуры ОбработкаПроведения документа. Если типовые алгоритмы проведения выставят Отказ = Истина, подписка корректно прервет выполнение и не сформирует лишних записей.

Настройка свойства «Удаление движений» у документа

Выясним, как свойство документа Удаление движений влияет на очистку записей:

  1. Удалять автоматически: Платформа очищает все существующие движения перед вызовом процедуры ОбработкаПроведения, а также при отмене проведения.
  2. Не удалять автоматически: Очистка выполняется программно. В типовых конфигурациях в начале проведения и при распроведении вызываются специальные сервисные процедуры (например, ОбщегоНазначения.УдалитьДвиженияРегистратора). Они очищают все регистры, привязанные к документу в метаданных.

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

← На главную