К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как в 1С прочитать проводки документа

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

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

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

Ниже разобраны оба подхода с готовыми примерами кода, особенности чтения субконто и сумм, типичные ошибки и способы проверить, что данные прочитаны корректно. Примеры ориентированы на типовые конфигурации с планом счетов «Хозрасчетный», но подход применим к любому регистру бухгалтерии.

Где физически хранятся проводки документа

Проводка — это запись регистра бухгалтерии. Документ при проведении формирует набор таких записей и сохраняет его в регистре, а поле «Регистратор» связывает каждую запись с документом-источником. Сам документ проводки не содержит: он только их порождает.

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

Способ 1: чтение проводок через коллекцию «Движения»

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

ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();

НаборПроводок = ДокОбъект.Движения.Хозрасчетный;

НаборПроводок.Прочитать(); // обязательно, если объект получен не при проведении

Для Каждого Проводка Из НаборПроводок Цикл

Сообщить("Счёт Дт: " + Проводка.СчетДт

+ " | Счёт Кт: " + Проводка.СчетКт

+ " | Сумма: " + Проводка.Сумма

+ " | Содержание: " + Проводка.Содержание);

КонецЦикла;

Вызов Прочитать() обязателен, когда объект получен из базы напрямую, а не находится в процессе проведения: без него набор будет пустым. Внутри обработчика «ОбработкаПроведения» набор заполняется программно, и читать его из базы не нужно — наоборот, Прочитать() затрёт сформированные движения.

Обращение к субконто в этом варианте идёт через коллекцию СубконтоДт и СубконтоКт с указанием вида субконто:

Номенклатура = Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура];

Способ 2: чтение проводок запросом к регистру

Запрос — основной инструмент, когда нужно прочитать проводки без получения объекта документа, обработать много документов сразу или сгруппировать данные. Запрос обращается к таблице регистра бухгалтерии напрямую.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Хозрасчетный.СчетДт КАК СчетДт,

| Хозрасчетный.СчетКт КАК СчетКт,

| Хозрасчетный.Сумма КАК Сумма,

| Хозрасчетный.Содержание КАК Содержание,

| Хозрасчетный.СубконтоДт1 КАК СубконтоДт1,

| Хозрасчетный.СубконтоДт2 КАК СубконтоДт2

|ИЗ

| РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный

|ГДЕ

| Хозрасчетный.Регистратор = &Регистратор";

Запрос.УстановитьПараметр("Регистратор", СсылкаНаДокумент);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

Сообщить("Дт " + Выборка.СчетДт + " Кт " + Выборка.СчетКт

+ " Сумма " + Выборка.Сумма);

КонецЦикла;

Здесь ссылка передаётся параметром — это исключает ошибки с представлением ссылки в тексте запроса и ускоряет выполнение. Поля СубконтоДт1, СубконтоДт2 и так далее нумеруются по порядку видов субконто счёта; их состав зависит от конкретного счёта в каждой строке, поэтому для анализа субконто часто удобнее виртуальная таблица «ДвиженияССубконто».

Запрос через виртуальную таблицу «ДвиженияССубконто»

Запрос.Текст =

"ВЫБРАТЬ

| Движения.СчетДт,

| Движения.СчетКт,

| Движения.СубконтоДт1,

| Движения.СубконтоКт1,

| Движения.Сумма

|ИЗ

| РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто(

| , , Регистратор = &Регистратор, , ) КАК Движения";

Таблица «ДвиженияССубконто» разворачивает субконто в именованные поля и удобна для отчётов, но работает медленнее основной таблицы. Для простого перебора сумм и счетов достаточно обычной таблицы регистра.

Сравнение способов

Коллекция «Движения»

Подходит внутри модуля документа и при обработке одного объекта. Требует ПолучитьОбъект() — затратно при массовой обработке.

Запрос к регистру

Подходит для отчётов, выгрузок и массового анализа. Не поднимает объекты документов, работает быстрее, легко группирует итоги.

ДвиженияССубконто

Подходит, когда нужен анализ субконто по видам. Медленнее основной таблицы, не используйте без необходимости.

Как прочитать проводки нескольких документов сразу

Для пакетной обработки передайте в запрос список ссылок и добавьте группировку или итоги. Получать объекты документов в цикле и читать их «Движения» — антипаттерн: на каждой итерации выполняется чтение объекта из базы, и обработка тысячи документов растягивается надолго.

Запрос.Текст =

"ВЫБРАТЬ

| Хозрасчетный.Регистратор КАК Документ,

| Хозрасчетный.СчетДт,

| Хозрасчетный.СчетКт,

| СУММА(Хозрасчетный.Сумма) КАК Сумма

|ИЗ

| РегистрБухгалтерии.Хозрасчетный КАК Хозрасчетный

|ГДЕ

| Хозрасчетный.Регистратор В (&СписокДокументов)

|СГРУППИРОВАТЬ ПО

| Хозрасчетный.Регистратор,

| Хозрасчетный.СчетДт,

| Хозрасчетный.СчетКт

|ИТОГИ ПО

| Хозрасчетный.Регистратор";

Запрос.УстановитьПараметр("СписокДокументов", СписокСсылок);

Результат = Запрос.Выполнить();

ВыборкаДокументы = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаДокументы.Следующий() Цикл

ВыборкаПроводки = ВыборкаДокументы.Выбрать();

Пока ВыборкаПроводки.Следующий() Цикл

// обработка строки проводки

КонецЦикла;

КонецЦикла;

Такой подход выполняет один запрос вместо тысячи обращений к базе. При больших объёмах дополнительно ограничивайте выборку периодом через параметры виртуальной таблицы или условие по полю «Период».

Чтение движений по регистрам накопления и сведений

Тот же принцип работает для любых движений документа, а не только бухгалтерских проводок. Меняется только имя таблицы и набор полей: у регистров накопления есть вид движения (Приход/Расход), измерения и ресурсы вместо счетов и субконто.

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Номенклатура,

| Товары.Склад,

| Товары.Количество,

| Товары.ВидДвижения

|ИЗ

| РегистрНакопления.ТоварыНаСкладах КАК Товары

|ГДЕ

| Товары.Регистратор = &Регистратор";

Какие регистры двигает конкретный вид документа, видно в конфигураторе: свойства документа, закладка «Движения». В пользовательском режиме список движений показывает кнопка «Ещё — Движения документа» в форме проведённого документа.

Порядок действий при чтении проводок
  1. 1
    Определите, какой регистр двигает документ (свойства документа в конфигураторе или «Движения документа» в форме)
  2. 2
    Выберите способ: объект с коллекцией «Движения» для одиночной обработки или запрос для массовой
  3. 3
    Напишите запрос с отбором Регистратор = &Регистратор и передайте ссылку параметром
  4. 4
    Обойдите выборку и извлеките счета, субконто, суммы и содержание
  5. 5
    Проверьте результат: количество строк и итоговая сумма должны совпадать с данными формы документа

Проверка результата и типичные ошибки

Самый надёжный способ проверить правильность чтения — сверить полученные данные с формой документа: кнопка «Дт/Кт» или отчёт «Проводки» показывают те же записи, что и запрос по регистратору. Совпадение количества строк и итоговой суммы — признак корректной выборки.

Типичные ошибки
01
Обращение к Движения у ссылки, а не у объекта — ошибка выполнения. Сначала вызовите ПолучитьОбъект()
02
Пропуск Прочитать() у набора записей — набор оказывается пустым, и цикл молча ничего не выводит
03
Вызов Прочитать() внутри ОбработкиПроведения — сформированные движения затираются данными из базы
04
Отбор по периоду вместо регистратора — в выборку попадают проводки чужих документов за тот же день
05
Чтение объектов в цикле вместо одного запроса — критичная потеря производительности на больших объёмах
06
Игнорирование признака активности: неактивные записи (Активность = Ложь) искажают анализ, если их не отфильтровать

Отдельного внимания заслуживает поле «Активность». У непроведённого документа записей в регистре нет вовсе, а у документа, проведённого вручную с отключённой активностью, записи есть, но в отчёты не попадают. Если вы строите аналитику, добавьте условие «Хозрасчетный.Активность» или учитывайте этот флаг при обходе.

Проверка без программирования: что доступно пользователю

Если задача разовая и писать код не требуется, проводки документа видны штатными средствами. В форме проведённого документа кнопка «Дт/Кт» (или «Показать проводки») открывает сформированные бухгалтерские записи, а меню «Ещё — Движения документа» показывает движения по всем регистрам.

Для анализа без кода подходят стандартные отчёты: «Оборотно-сальдовая ведомость по счёту», «Анализ счёта», «Карточка счёта» — в них можно установить отбор по конкретному документу и детализировать до проводки. Внешний отчёт или консоль запросов (доступна в инструментах разработчика) позволяет выполнить произвольный запрос к регистру без изменения конфигурации.

Контрольные точки

Как проверить результат

Количество строк в выборке
Норма

Совпадает с числом проводок в форме «Дт/Кт»

Тревожный признак

Строк меньше или ноль — проверьте ссылку, Прочитать() и проведённость документа

Итоговая сумма по выборке
Норма

Равна сумме проводок документа

Тревожный признак

Расхождение — возможно, попали неактивные записи или чужой период

Субконто в строках
Норма

Значения соответствуют аналитике документа

Тревожный признак

Пустые субконто — неверный номер поля СубконтоДтN для данного счёта

Итог

Что важно запомнить

Проводки читаются из регистра по отбору «Регистратор = ссылка»: через коллекцию Движения объекта (с обязательным Прочитать() вне проведения) или запросом к регистру. Для массовой обработки используйте только запрос, для анализа субконто — ДвиженияССубконто. Результат сверяйте с формой «Дт/Кт» документа.

Частые вопросы

Почему запрос возвращает пустой результат, хотя документ проведён?

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

Как прочитать проводки документа, не получая объект?

Используйте запрос к таблице регистра бухгалтерии с условием Регистратор = &Ссылка. Это единственный корректный способ без ПолучитьОбъект(): запрос работает напрямую с таблицей регистра и не требует загрузки объекта документа в память.

Чем отличается поле СубконтоДт1 в запросе от коллекции СубконтоДт у записи?

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

Можно ли прочитать проводки удалённого или непроведённого документа?

Непроведённый документ не имеет записей в регистрах — читать нечего. При удалении документа его движения удаляются вместе с ним. Исключение — помеченный на удаление, но ещё проведённый документ: его записи остаются в регистре до отмены проведения.

Как выгрузить проводки документа в таблицу значений?

Метод Запрос.Выполнить().Выгрузить() возвращает таблицу значений с результатом запроса. Дальше её можно обойти, выгрузить в табличный документ, передать в СКД или сериализовать для обмена.

Почему в цикле по документам всё работает медленно?

Причина почти всегда в вызове ПолучитьОбъект() и чтении Движений для каждого документа отдельно — это запрос к базе на каждой итерации. Замените цикл одним запросом с условием «Регистратор В (&Список)» и итогами по регистратору — ускорение будет кратным.