При программной работе с документами в 1С часто возникает задача по формированию бухгалтерских проводок. Стандартный, на первый взгляд, подход с использованием метода Добавить() для коллекции Движения документа может не сработать, и новые записи просто не появляются в регистре. Разберем, почему так происходит и как это исправить.
Проанализируем ситуацию: у нас есть код, который должен создавать новую проводку, но по факту этого не делает. В отладчике видно, что строка кода выполняется, ошибок не возникает, но в движениях документа пусто. Выясним причину такого поведения системы.
Основная причина, по которой метод Добавить() может не работать, — это отсутствие установленной связи между набором записей и документом-регистратором. Коллекция Движения документа является, по сути, набором записей регистра, который привязан к конкретному документу. Если система не знает, какой именно документ формирует эти движения, она не может их корректно создать и записать.
Чтобы запись была успешно создана, перед вызовом метода Добавить() необходимо явно указать регистратор для коллекции движений нужного регистра. Делается это через установку свойства Регистратор.
Этот способ подходит, когда вы работаете с движениями непосредственно в модуле объекта документа. Например, в обработке проведения. Посмотрим на пошаговый алгоритм.
ЭтотОбъект.Движения.Хозрасчетный.Регистратор, присвоив ему ссылку на текущий документ (ЭтотОбъект.Ссылка).Добавить().Посмотрим на пример. Изначально мог быть такой код, который не работает:
// НЕПРАВИЛЬНЫЙ КОД
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Для Каждого ТекСтрокаТЧ Из Товары Цикл
Движение = ЭтотОбъект.Движения.Хозрасчетный.Добавить();
Движение.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
Движение.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками;
Движение.Период = Дата;
Движение.Сумма = ТекСтрокаТЧ.Сумма;
// ... заполнение других полей
КонецЦикла;
КонецПроцедуры
А вот исправленный и корректно работающий вариант. Обратите внимание на одну ключевую строку, добавленную перед циклом.
// ПРАВИЛЬНЫЙ КОД
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Указываем, что все последующие движения будут принадлежать этому документу
ЭтотОбъект.Движения.Хозрасчетный.Регистратор = ЭтотОбъект.Ссылка;
Для Каждого ТекСтрокаТЧ Из Товары Цикл
Движение = ЭтотОбъект.Движения.Хозрасчетный.Добавить();
Движение.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
Движение.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками;
Движение.Период = Дата;
Движение.Сумма = ТекСтрокаТЧ.Сумма;
Движение.Организация = Организация;
// Заполнение субконто
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура] = ТекСтрокаТЧ.Номенклатура;
Движение.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Склады] = Склад;
Движение.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Контрагенты] = Контрагент;
Движение.СубконтоКт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Договоры] = Договор;
КонецЦикла;
КонецПроцедуры
После добавления строки ЭтотОбъект.Движения.Хозрасчетный.Регистратор = ЭтотОбъект.Ссылка; система будет понимать, какой документ является основанием для этих проводок, и метод Добавить() сработает как положено.
Более универсальным и зачастую более производительным способом работы с записями регистров является использование специального объекта РегистрБухгалтерииНаборЗаписей. Этот подход рекомендуется использовать, особенно если вы работаете с движениями не в модуле документа, а, например, во внешней обработке, или если вам нужно выполнить пакетные операции (добавить, изменить или удалить сразу много записей).
Разберем по шагам, как работать с набором записей:
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Регистратор в первом решении. Мы говорим набору, к какому документу он будет относиться.
// Предполагается, что переменная СсылкаНаДокумент уже содержит ссылку
// на нужный документ-регистратор.
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
НаборЗаписей.Прочитать();
Добавить() самого набора записей. Он возвращает объект новой записи, который мы затем заполняем.
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Период = СсылкаНаДокумент.Дата;
НоваяЗапись.СчетДт = ...;
НоваяЗапись.СчетКт = ...;
НоваяЗапись.Сумма = ...;
// и так далее
Записать(). Если нужно перед записью полностью очистить старые движения этого регистратора, можно использовать флаг Записать(Истина).
НаборЗаписей.Записать(); // Записывает набор, замещая старые записи
Посмотрим на полный пример кода с использованием набора записей:
// Получаем ссылку на документ, который будет регистратором
СсылкаНаДокумент = Документы.ПоступлениеТоваровУслуг.НайтиПоНомеру("ПТ-00001", ТекущаяДата());
Если Не СсылкаНаДокумент.Пустая() Тогда
// 1. Создаем набор записей
НаборЗаписей = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
// 2. Устанавливаем отбор по регистратору
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
// Очистим существующие движения, если нужно начать с чистого листа
// НаборЗаписей.Очистить();
// 3. Добавляем новую проводку
НоваяПроводка = НаборЗаписей.Добавить();
НоваяПроводка.Период = СсылкаНаДокумент.Дата;
НоваяПроводка.Организация = СсылкаНаДокумент.Организация;
НоваяПроводка.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах;
НоваяПроводка.СчетКт = ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками;
НоваяПроводка.Сумма = 15000;
// ... заполняем субконто и другие измерения/ресурсы
// 4. Записываем весь набор в базу данных
Попытка
НаборЗаписей.Записать(Истина); // Флаг Истина означает "замещать существующие записи"
Сообщить("Движения успешно сформированы!");
Исключение
Сообщить("Не удалось записать движения: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
Таким образом, для успешного программного добавления проводок в 1С ключевым моментом является явное указание документа-регистратора. Независимо от выбранного способа — через свойство Регистратор коллекции Движения или через отбор в НабореЗаписей — без этой связи система не сможет создать корректные движения в регистре бухгалтерии.