Почему не сохраняются движения по регистрам при записи документа из общего модуля или подписки на событие?

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

При разработке в среде 1С:Предприятие 8, особенно в крупных конфигурациях вроде УПП 1.3 или ERP, часто возникает задача дополнить стандартные движения документа своими собственными записями. Типичный сценарий: программист создает подписку на событие ПриЗаписи или ОбработкаПроведения, пишет код для добавления записей в регистр, отладчик показывает успешное выполнение метода Записать(), однако в самом регистре после завершения операции данных нет. Рассмотрим подробнее, почему так происходит и как правильно реализовать этот механизм.

Разбор основной причины: Конфликт независимого набора записей и коллекции Движения

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

  1. Документ начинает транзакцию записи.
  2. Выполняется стандартный код документа.
  3. Вызывается подписка на событие ПриЗаписи.
  4. Внутри подписки программно создается отдельный объект типа РегистрНакопленияНаборЗаписей, устанавливается отбор по регистратору, добавляются строки и вызывается метод Записать(). В этот момент данные физически попадают в базу данных (внутри транзакции).
  5. Подписка завершается, управление возвращается платформе.
  6. Платформа завершает запись документа. При этом у самого объекта документа (параметр Источник в подписке) существует внутренняя коллекция Движения.
  7. Критический момент: Платформа берет содержимое коллекции Источник.Движения.Затраты и записывает её в базу данных. Поскольку в этой коллекции набора записей по регистру "Затраты" не было (он пуст), платформа записывает пустой набор поверх тех данных, которые вы только что внесли вручную.

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

Решение №1: Использование коллекции Движения объекта

Вместо создания независимого набора записей через менеджер регистра, нам необходимо работать напрямую с коллекцией движений документа, который передается в подписку как параметр Источник. В этом случае мы не вызываем метод Записать() принудительно — платформа сделает это сама автоматически при фиксации транзакции документа.

Рассмотрим правильный пример реализации кода в общем модуле:


Процедура ДобавитьДвиженияПоЗатратам(Источник, Отказ) Экспорт
    // Получаем доступ к коллекции движений конкретного документа
    ДвиженияЗатрат = Источник.Движения.Затраты;
    
    // Обязательно устанавливаем флаг записи
    ДвиженияЗатрат.Записывать = Истина;
    
    // Добавляем новую запись
    НовоеДвижение = ДвиженияЗатрат.Добавить();
    НовоеДвижение.ВидДвижения = ВидДвиженияНакопления.Приход;
    НовоеДвижение.Период = Источник.Дата;
    НовоеДвижение.Регистратор = Источник.Ссылка;
    
    // Заполняем измерения и ресурсы
    НовоеДвижение.Подразделение = Источник.Подразделение;
    НовоеДвижение.Сумма = 1000; // Пример рассчитанной суммы
    
    // Метод Записать() вызывать НЕ НУЖНО. 
    // Платформа запишет коллекцию автоматически.
КонецПроцедуры

Важный нюанс: Чтобы этот код работал, регистр "Затраты" должен быть указан в списке движений документа в конфигураторе. Если документ не является регистратором для этого регистра "по паспорту", коллекция Источник.Движения.ИмяРегистра будет недоступна.

Решение №2: Выбор правильного события (ПриЗаписи vs ОбработкаПроведения)

Разберем, в каком событии лучше всего выполнять расчеты. Автор использовал ПриЗаписи, но для формирования движений накопления в 1С:УПП и других учетных решениях правильнее использовать подписку на ОбработкаПроведения.

Почему это важно? Событие ПриЗаписи срабатывает всегда, когда документ сохраняется (даже без проведения). Если вы будете добавлять движения в этом событии, они могут появиться у непроведенного документа, что нарушит логику учета. Кроме того, в момент ПриЗаписи документ еще не сформировал свои собственные движения, и ваши запросы к регистрам (как в примере автора темы) могут вернуть неактуальные данные.

Проанализируем последовательность действий при проведении:

  1. ПередЗаписью (Проверка условий).
  2. Запись объекта в БД.
  3. ПриЗаписи (Общие действия при сохранении).
  4. ОбработкаПроведения (Здесь документ формирует свои основные движения).
  5. Запись коллекции Движения в БД.

Если вам нужно рассчитать сумму на основе данных, которые сам документ только что записал в другие регистры (например, "ДенежныеСредства"), то подписка на ОбработкаПроведения — единственный надежный вариант, так как к этому моменту движения по другим регистрам уже подготовлены в коллекции Движения.

Решение №3: Передача данных через ДополнительныеСвойства

Иногда расчет нужно произвести именно в момент записи, а записать в регистр — только при проведении. В таких случаях удобно использовать структуру ДополнительныеСвойства объекта.

Посмотрим на пример совместной работы двух подписок:

Шаг 1. В подписке "ПриЗаписи":


Источник.ДополнительныеСвойства.Вставить("МояРассчитаннаяСумма", РезультатЗапроса);

Шаг 2. В подписке "ОбработкаПроведения":


Если Источник.ДополнительныеСвойства.Свойство("МояРассчитаннаяСумма") Тогда
    СуммаДляЗаписи = Источник.ДополнительныеСвойства.МояРассчитаннаяСумма;
    
    Движение = Источник.Движения.Затраты.Добавить();
    Движение.Сумма = СуммаДляЗаписи;
    Источник.Движения.Затраты.Записывать = Истина;
КонецЕсли;

Типичные ошибки, которые стоит проверить

Если вы исправили код на работу с Источник.Движения, но данные все равно не появляются, проверьте следующие моменты:

Подводя итог, можно сказать: никогда не используйте СоздатьНаборЗаписей() для изменения движений того же самого документа, который сейчас находится в процессе записи или проведения. Всегда работайте через коллекцию Источник.Движения, управляя свойством Записывать. Это обеспечит целостность транзакции и гарантирует сохранение данных в базе.

← На главную