Разработчики при кастомизации типовых конфигураций (особенно таких сложных, как 1С:Управление производственным предприятием ред. 1.3) часто сталкиваются с неочевидным поведением платформы «1С:Предприятие 8». Одна из классических проблем — попытка получить только что сформированные движения (например, проводки налогового или бухгалтерского учета) в подписке на событие ОбработкаПроведения.
В этой статье мы подробно разберем, почему коллекция движений документа в подписке на событие проведения кажется пустой (хотя в самой базе данных проводки присутствуют), как правильно прочитать эти движения с помощью кода и какие архитектурные нюансы программы УПП 1.3 необходимо учитывать.
Для начала проанализируем ситуацию, с которой столкнулся автор темы. При отладке подписки на событие проведения документа (например, «Реализация товаров и услуг») обращение к коллекции движений напрямую через источник:
// Этот код вернет пустое количество записей, если движения уже записаны в СУБД
КоличествоПроводок = Источник.Движения.Налоговый.Количество();
показывает, что коллекция пуста. Тем не менее, после завершения проведения документа все проводки налогового учета (НУ) успешно отображаются в интерфейсе программы и регистрируются в базе данных.
Дело в особенностях жизненного цикла транзакции проведения документа в платформе 1С:
Движения.Записать() для каждого конкретного набора записей (либо платформа делает это автоматически при завершении транзакции проведения).Записать() локальный буфер набора записей в памяти очищается, а коллекция внутри объекта Источник (передаваемого в подписку) не синхронизируется автоматически с базой данных в обратную сторону. Платформа делает это в целях оптимизации производительности, чтобы повторно не гонять трафик между сервером приложений и СУБД.Таким образом, когда начинает выполняться код вашей подписки на событие ОбработкаПроведения, реальные физические записи уже могут находиться в таблицах СУБД (в рамках еще не зафиксированной транзакции), но объект Источник.Движения.Налоговый в оперативной памяти вашего сеанса будет пуст.
Чтобы обойти эту особенность платформы и гарантированно получить актуальные проводки налогового или бухгалтерского учета, мы должны принудительно прочитать данные из СУБД. Рассмотрим два основных способа решения этой задачи.
Этот способ является наиболее надежным и безопасным. Мы создаем независимый объект набора записей регистра бухгалтерии, устанавливаем отбор по нашему документу-регистратору и считываем данные из базы данных. Посмотрим на пример кода:
// Создаем пустой набор записей регистра бухгалтерии "Налоговый"
ПроводкиНУ = РегистрыБухгалтерии.Налоговый.СоздатьНаборЗаписей();
// Устанавливаем жесткий отбор по регистратору (текущему документу)
ПроводкиНУ.Отбор.Регистратор.Установить(Источник.Ссылка);
// Считываем данные из базы данных в рамках текущей транзакции
ПроводкиНУ.Прочитать();
// Теперь мы можем работать с проводками налогового учета
Для Каждого Проводка Из ПроводкиНУ Цикл
// Выполняем анализ или обработку проводки
Сообщить("Счет Дт: " + Проводка.СчетДт + ", Счет Кт: " + Проводка.СчетКт + ", Сумма НУ: " + Проводка.Сумма);
КонецЦикла;
Поскольку чтение происходит внутри той же транзакции базы данных, в которой проводится документ, метод Прочитать() вернет самые свежие проводки, даже если транзакция проведения еще не зафиксирована окончательно (не выполнен Commit).
Рассмотрим более лаконичный способ, который избавляет нас от необходимости вручную создавать новый объект набора записей. Мы можем заставить саму коллекцию движений внутри источника перечитать данные из базы:
// Принудительно считываем движения из СУБД в существующую коллекцию документа
Источник.Движения.Налоговый.Прочитать();
// Проверяем, появились ли записи
Если Источник.Движения.Налоговый.Количество() > 0 Тогда
Для Каждого Движение Из Источник.Движения.Налоговый Цикл
// Ваши действия с проводками налогового учета
КонецЦикла;
КонецЕсли;
Этот способ удобен тем, что мы продолжаем работать со штатной коллекцией документа Источник.Движения.
При работе с движениями налогового и бухгалтерского учета в конфигурации УПП 1.3 критически важно понимать, в каком режиме учета затрат работает информационная база. От этого напрямую зависит, в какой момент и какими механизмами формируются проводки.
Если в учетной политике организации включен традиционный партионный учет:
ДвиженияПоРегистрам().УправлениеЗапасамиПартионныйУчет).В этом режиме при проведении документа проводки НУ генерируются сразу же, и их можно прочитать методами, описанными выше.
Если в системе используется режим РАУЗ, логика кардинально меняется:
Важное предупреждение: Если у вас включен режим РАУЗ, попытка прочитать проводки по себестоимости в налоговом учете сразу после проведения реализации не принесет никаких результатов, так как этих проводок физически еще не существует в базе данных.
Если перед вами стоит задача не просто проанализировать, а изменить или дописать проводки налогового учета, использовать для этого подписку на событие ОбработкаПроведения крайне не рекомендуется по следующим причинам:
Если вам гарантированно нужно вмешаться в процесс формирования проводок, рассмотрите альтернативное и более надежное решение — перехват записи в модуле набора записей самого регистра бухгалтерии («Налоговый» или «Хозрасчетный») в предопределенном обработчике ПередЗаписью(). Пример такой реализации:
// Данный код размещается в модуле набора записей регистра бухгалтерии "Налоговый"
Процедура ПередЗаписью(Отказ, Замещение)
// Проверяем, что запись производится для конкретного типа документа
Если ЭтотОбъект.Отбор.Регистратор.Использование
И ТипЗнч(ЭтотОбъект.Отбор.Регистратор.Value) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
Для Каждого Запись Из ЭтотОбъект Цикл
// Выполняем точечную корректировку реквизитов проводки НУ непосредственно перед записью в СУБД
Если Запись.СчетДт = ПланыСчетов.Налоговый.НайтиПоКоду("90.01.1") Тогда
// Ваша логика изменения проводки
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры;
Используя этот подход, вы всегда будете работать с финальным и полным набором проводок, который документ подготовил к записи в базу данных, независимо от того, партионный учет используется в системе или РАУЗ.