Разработка и Конфигурация · 12 мин
Как прочитать движения документа в 1С
Как прочитать движения документа в 1С: обращение к коллекции Движения, запросы к регистрам, отбор по регистратору, типовые ошибки и проверка результата.
Движения документа — это записи, которые документ формирует в регистрах при проведении: остатки товаров, взаиморасчёты, проводки, кадровые сведения. Прочитать их требуется при отладке проведения, построении отчётов, сверке данных и разборе ошибок учёта. В 1С есть два основных пути: обратиться к коллекции движений объекта документа или выполнить запрос к таблице регистра с отбором по регистратору.
Выбор способа зависит от задачи. Если нужно проанализировать движения конкретного документа в момент проведения или сразу после него — удобнее работать через объект. Если нужно получить записи по одному или нескольким документам из произвольного места кода, например в отчёте или обработке, — правильнее использовать запрос. Оба подхода дают одинаковые данные, но отличаются по производительности и контексту применения.
Ниже разобраны оба метода с примерами кода, типичные ошибки, способы проверить результат и ограничения, о которых стоит помнить, чтобы не получить пустую выборку или лишнюю нагрузку на базу.
Что такое движения документа и где они хранятся
При проведении документ записывает строки в один или несколько регистров: накопления, сведений, расчёта, а также в бухгалтерский регистр. Каждая такая строка содержит ссылку на документ в стандартном реквизите «Регистратор», номер строки, период и заполненные измерения, ресурсы и реквизиты регистра. Физически движения хранятся в таблицах регистров, а не в таблице документа — документ лишь «порождает» их.
Список регистров, по которым документ может делать движения, задаётся в конфигураторе в свойствах документа на закладке «Движения». Если регистр в этом списке не отмечен, обратиться к нему через коллекцию движений объекта не получится — платформа выдаст ошибку. Перед написанием кода полезно открыть конфигуратор и убедиться, какие именно регистры участвуют в проведении нужного вида документа.
Быстро посмотреть движения без программирования можно в пользовательском режиме: откройте проведённый документ и используйте команду перехода к движениям (в типовых конфигурациях это кнопка «Перейти» → список регистров, либо отчёт «Движения документа»). Это удобный способ сверить, что показывает интерфейс, с тем, что возвращает код.
Чтение движений через объект документа
Объект документа (тип ДокументОбъект) содержит коллекцию «Движения», где для каждого регистра из списка движений доступен набор записей. Обращение выглядит так: ДокОбъект.Движения.ТоварыНаСкладах. Полученный набор можно перебрать в цикле, но сначала его нужно прочитать методом Прочитать(), если документ уже записан в базу, — иначе набор может оказаться пустым или содержать только незаписанные изменения.
Пример кода:
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
НаборЗаписей = ДокОбъект.Движения.ТоварыНаСкладах;
НаборЗаписей.Прочитать();
Для Каждого Запись Из НаборЗаписей Цикл
Сообщить("Номенклатура: " + Запись.Номенклатура
+ ", Количество: " + Запись.Количество);
КонецЦикла;
Важно понимать: метод ПолучитьОбъект() загружает весь документ в память и открывает возможность его изменения. Это дорогая операция, если нужно только прочитать данные. Кроме того, пока объект получен, другие процессы могут столкнуться с блокировкой при попытке перепровести тот же документ. Поэтому для «только чтения» вне контекста проведения предпочтителен запрос.
Отдельный случай — обращение к движениям внутри обработчика ОбработкаПроведения. Здесь наборы записей уже существуют в контексте объекта, и после записи движений (например, после Движения.ТоварыНаСкладах.Записать()) их можно перечитать и проанализировать для контроля отрицательных остатков или логирования.
Чтение движений запросом к регистру
Запрос — универсальный способ, не требующий получения объекта документа. Таблица регистра накопления или сведений называется по шаблону РегистрНакопления.ТоварыНаСкладах, бухгалтерского регистра — РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто. Отбор по документу задаётся условием на поле «Регистратор».
Пример запроса к регистру накопления:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Движения.Номенклатура,
| Движения.Склад,
| Движения.ВидДвижения,
| Движения.Количество
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Движения
|ГДЕ
| Движения.Регистратор = &Регистратор";
Запрос.УстановитьПараметр("Регистратор", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Номенклатура);
КонецЦикла;
Для бухгалтерских проводок таблица движений содержит поля счёта дебета и кредита, субконто, суммы и количества. Запрос к РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто с отбором по регистратору вернёт все проводки документа вместе с аналитикой. Учтите, что у виртуальной таблицы «ДвиженияССубконто» отбор по регистратору работает эффективно, а вот сложные соединения с ней без необходимости лучше избегать.
Если нужно получить движения документа сразу по нескольким регистрам, объедините несколько запросов через пакет (разделитель «;») или выполните отдельные запросы в цикле по списку имён регистров. Пакетный запрос удобен тем, что возвращает несколько результатов за одно обращение к серверу.
Запрос = Новый Запрос("ВЫБРАТЬ * ИЗ РегистрНакопления.Взаиморасчеты КАК Д ГДЕ Д.Регистратор = &Ссылка"); Запрос.УстановитьПараметр("Ссылка", ДокументСсылка); Результат = Запрос.Выполнить().Выгрузить();Как узнать, по каким регистрам документ сделал движения
Когда структура конфигурации неизвестна или документ проводится по многим регистрам, полезно сначала определить фактический список регистров с движениями. Для этого перебирают метаданные: у объекта Метаданные документа есть свойство «Движения» — коллекция регистров, отмеченных в конфигураторе.
МетаданныеДокумента = СсылкаНаДокумент.Метаданные();
Для Каждого Регистр Из МетаданныеДокумента.Движения Цикл
Сообщить(Регистр.ПолноеИмя());
КонецЦикла;
Однако отмеченный в конфигураторе регистр не гарантирует наличия записей: документ может быть проведён «вхолостую» по части регистров. Чтобы проверить факт наличия строк, выполните к каждому регистру лёгкий запрос вида ВЫБРАТЬ ПЕРВЫЕ 1 ... ГДЕ Регистратор = &Ссылка и проверьте, пуст ли результат. Это надёжный способ построить реальную карту движений документа.
- 1Откройте документ в режиме предприятия и посмотрите движения через кнопку перехода — зафиксируйте, какие регистры заполнены.
- 2В конфигураторе проверьте список регистров на закладке «Движения» документа.
- 3Напишите запрос к нужному регистру с условием Регистратор = &Ссылка.
- 4Выполните код в отладчике или обработке и сверьте выборку с тем, что видно в интерфейсе.
- 5Если выборка пуста — проверьте, проведён ли документ и верное ли имя регистра используется.
Типичные ошибки и пустые выборки
Самая частая ситуация — запрос возвращает пустой результат, хотя «движения точно есть». Причины обычно такие: документ не проведён (у непроведённого документа движений нет), в параметр передана не та ссылка (например, ссылка другого вида документа), либо имя регистра указано с опечаткой — тогда ошибка возникнет ещё на этапе выполнения запроса.
Вторая группа ошибок связана с объектным подходом: забытый Прочитать() у набора записей, обращение к Движения через ссылку вместо объекта, попытка прочитать набор регистра, не включённого в список движений документа. Каждая из них даёт либо пустой набор, либо исключение платформы с сообщением о недопустимом обращении.
Третья группа — проблемы прав и режимов. Если код выполняется под пользователем без прав на регистр, запрос вернёт пустой результат или ошибку доступа. Также при использовании даты запрета изменения данных и разделителей в сервисных базах поведение может отличаться — проверяйте код под тем пользователем, в контексте которого он будет работать.
Производительность и безопасная работа с данными
Чтение движений — операция безопасная сама по себе: она не меняет данные. Риск появляется, когда объект документа получают через ПолучитьОбъект() и затем случайно записывают, либо когда в цикле по тысячам документов каждый раз создаётся объект. Для массового анализа всегда используйте один запрос с условием Регистратор В (&СписокДокументов) — это на порядки быстрее.
Отдельное предупреждение про модификацию: методы Записать() у наборов записей и документа изменяют учётные данные. Никогда не экспериментируйте с записью движений в рабочей базе без резервной копии — некорректно изменённые записи регистров приводят к расхождениям в отчётах, которые сложно отследить. Для отладки используйте копию базы.
При работе в клиент-серверном варианте помните про контекст: запросы и обращения к регистрам выполняются на сервере. Код чтения движений размещайте в серверных процедурах общих модулей или в серверной части формы, чтобы избежать лишних вызовов и ошибок недоступности контекста.
Проверка результата
Надёжный способ убедиться, что код читает движения правильно, — сверка с интерфейсом. Откройте документ, перейдите к движениям по нужному регистру и сравните количество строк и ключевые суммы с тем, что вернул запрос или выдал перебор набора записей. Совпадение количества строк и контрольных итогов — достаточный признак корректности.
Для автоматической проверки в обработках используйте агрегатный запрос: ВЫБРАТЬ СУММА(Количество), КОЛИЧЕСТВО(*) ... ГДЕ Регистратор = &Ссылка. Если суммы сходятся с данными отчёта по регистру за период документа, чтение выполнено верно.
Как проверить результат
Совпадает с числом записей в движениях документа в интерфейсе
Выборка пуста или строк меньше — проверьте проведённость документа и имя регистра
Итоги запроса совпадают с отчётом по регистру
Расхождения — возможно, отбор срезан периодом или учтены чужие документы
Код выполняется на сервере, параметры запроса заполнены ссылками
Ошибка доступности контекста или пустой параметр
FAQ
Можно ли прочитать движения документа, не получая объект?
Да, и это предпочтительный способ. Запрос к таблице регистра с условием Регистратор = &Ссылка возвращает все движения по ссылке, без загрузки документа в память и без блокировок. Объект нужен только если вы работаете внутри обработчика проведения или собираетесь менять движения.
Почему запрос по регистратору возвращает пустой результат?
Чаще всего документ не проведён — у непроведённого документа записей в регистрах нет. Также проверьте, что в параметр передана ссылка именно того вида документа, что имя регистра указано верно и что у текущего пользователя есть права на чтение регистра.
Как прочитать проводки документа по бухгалтерскому регистру?
Используйте запрос к таблице РегистрБухгалтерии.Хозрасчетный.ДвиженияССубконто с условием Регистратор = &Ссылка. Результат содержит счета дебета и кредита, субконто, суммы и количества — фактически полный набор проводок документа.
Чем отличается чтение через Движения объекта от запроса?
Коллекция Движения объекта требует ПолучитьОбъект(), загружает документ целиком и может содержать незаписанные изменения. Запрос читает только данные из базы, быстрее при массовой обработке и не блокирует документ. Данные при этом одинаковые, если документ записан.
Как получить движения сразу по нескольким документам?
Передайте в запрос массив или список ссылок и используйте условие Регистратор В (&СписокДокументов). Один такой запрос заменяет цикл с обращением к каждому документу и работает значительно быстрее, особенно в клиент-серверном варианте.
Можно ли увидеть движения удалённого документа?
Нет. При удалении документа его записи из регистров удаляются вместе с ним. Если документ только помечен на удаление, он уже отменяет проведение, и движения тоже удаляются. Восстановить картину можно только из резервной копии или по данным журналов и архивных отчётов.
Что важно запомнить
Движения документа хранятся в регистрах и читаются либо через коллекцию Движения объекта документа, либо запросом к регистру с отбором по регистратору. Для анализа и массовой обработки выбирайте запрос, для работы внутри проведения — набор записей объекта. Всегда проверяйте проведённость документа и сверяйте результат с интерфейсом, а любые эксперименты с записью движений выполняйте только на копии базы.