При разработке в среде 1С:Предприятие 8, особенно в крупных конфигурациях вроде УПП 1.3 или ERP, часто возникает задача дополнить стандартные движения документа своими собственными записями. Типичный сценарий: программист создает подписку на событие ПриЗаписи или ОбработкаПроведения, пишет код для добавления записей в регистр, отладчик показывает успешное выполнение метода Записать(), однако в самом регистре после завершения операции данных нет. Рассмотрим подробнее, почему так происходит и как правильно реализовать этот механизм.
Проанализируем ситуацию, с которой столкнулся автор темы. В его коде использовался метод РегистрыНакопления.Затраты.СоздатьНаборЗаписей(). Рассмотрим по шагам, что происходит в системе в этот момент:
ПриЗаписи.РегистрНакопленияНаборЗаписей, устанавливается отбор по регистратору, добавляются строки и вызывается метод Записать(). В этот момент данные физически попадают в базу данных (внутри транзакции).Источник в подписке) существует внутренняя коллекция Движения.Источник.Движения.Затраты и записывает её в базу данных. Поскольку в этой коллекции набора записей по регистру "Затраты" не было (он пуст), платформа записывает пустой набор поверх тех данных, которые вы только что внесли вручную.Таким образом, ваши изменения просто "затираются" стандартным механизмом записи движений документа. Выясним, как этого избежать.
Вместо создания независимого набора записей через менеджер регистра, нам необходимо работать напрямую с коллекцией движений документа, который передается в подписку как параметр Источник. В этом случае мы не вызываем метод Записать() принудительно — платформа сделает это сама автоматически при фиксации транзакции документа.
Рассмотрим правильный пример реализации кода в общем модуле:
Процедура ДобавитьДвиженияПоЗатратам(Источник, Отказ) Экспорт
// Получаем доступ к коллекции движений конкретного документа
ДвиженияЗатрат = Источник.Движения.Затраты;
// Обязательно устанавливаем флаг записи
ДвиженияЗатрат.Записывать = Истина;
// Добавляем новую запись
НовоеДвижение = ДвиженияЗатрат.Добавить();
НовоеДвижение.ВидДвижения = ВидДвиженияНакопления.Приход;
НовоеДвижение.Период = Источник.Дата;
НовоеДвижение.Регистратор = Источник.Ссылка;
// Заполняем измерения и ресурсы
НовоеДвижение.Подразделение = Источник.Подразделение;
НовоеДвижение.Сумма = 1000; // Пример рассчитанной суммы
// Метод Записать() вызывать НЕ НУЖНО.
// Платформа запишет коллекцию автоматически.
КонецПроцедуры
Важный нюанс: Чтобы этот код работал, регистр "Затраты" должен быть указан в списке движений документа в конфигураторе. Если документ не является регистратором для этого регистра "по паспорту", коллекция Источник.Движения.ИмяРегистра будет недоступна.
Разберем, в каком событии лучше всего выполнять расчеты. Автор использовал ПриЗаписи, но для формирования движений накопления в 1С:УПП и других учетных решениях правильнее использовать подписку на ОбработкаПроведения.
Почему это важно? Событие ПриЗаписи срабатывает всегда, когда документ сохраняется (даже без проведения). Если вы будете добавлять движения в этом событии, они могут появиться у непроведенного документа, что нарушит логику учета. Кроме того, в момент ПриЗаписи документ еще не сформировал свои собственные движения, и ваши запросы к регистрам (как в примере автора темы) могут вернуть неактуальные данные.
Проанализируем последовательность действий при проведении:
ПередЗаписью (Проверка условий).ПриЗаписи (Общие действия при сохранении).ОбработкаПроведения (Здесь документ формирует свои основные движения).Движения в БД.Если вам нужно рассчитать сумму на основе данных, которые сам документ только что записал в другие регистры (например, "ДенежныеСредства"), то подписка на ОбработкаПроведения — единственный надежный вариант, так как к этому моменту движения по другим регистрам уже подготовлены в коллекции Движения.
Иногда расчет нужно произвести именно в момент записи, а записать в регистр — только при проведении. В таких случаях удобно использовать структуру ДополнительныеСвойства объекта.
Посмотрим на пример совместной работы двух подписок:
Шаг 1. В подписке "ПриЗаписи":
Источник.ДополнительныеСвойства.Вставить("МояРассчитаннаяСумма", РезультатЗапроса);
Шаг 2. В подписке "ОбработкаПроведения":
Если Источник.ДополнительныеСвойства.Свойство("МояРассчитаннаяСумма") Тогда
СуммаДляЗаписи = Источник.ДополнительныеСвойства.МояРассчитаннаяСумма;
Движение = Источник.Движения.Затраты.Добавить();
Движение.Сумма = СуммаДляЗаписи;
Источник.Движения.Затраты.Записывать = Истина;
КонецЕсли;
Если вы исправили код на работу с Источник.Движения, но данные все равно не появляются, проверьте следующие моменты:
Источник.Движения.ИмяРегистра, но не установили Источник.Движения.ИмяРегистра.Записывать = Истина, платформа проигнорирует этот набор записей при сохранении документа.Записывать = Истина для регистра, по которому документ уже сделал движения в модуле объекта, ваши действия в подписке могут либо дополнить их, либо перезаписать, в зависимости от того, как вы обращаетесь к набору. В подписках рекомендуется использовать метод Добавить(), чтобы не затереть то, что сформировал стандартный код проведения.Подводя итог, можно сказать: никогда не используйте СоздатьНаборЗаписей() для изменения движений того же самого документа, который сейчас находится в процессе записи или проведения. Всегда работайте через коллекцию Источник.Движения, управляя свойством Записывать. Это обеспечит целостность транзакции и гарантирует сохранение данных в базе.