Как правильно получить движения документа в 1С:Предприятие 8.3

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке печатных форм или реализации дополнительной логики в системе «1С:Предприятие» часто возникает задача анализа движений, которые документ сделал по регистрам. Начинающие разработчики нередко сталкиваются с тем, что коллекция движений оказывается пустой, хотя в интерфейсе (через кнопку «Дт/Кт») записи видны. В этой статье мы подробно разберем, почему так происходит, и рассмотрим наиболее эффективные способы получения данных регистров.

Разбор типичной ошибки: почему Движения пустые?

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


// Ошибка: движения будут пустыми
ДвиженияДокумента = СсылкаНаДокумент.ПолучитьОбъект().Движения.ПартииТоваровОрганизаций;
Для Каждого Запись Из ДвиженияДокумента Цикл
    // Код не выполнится
КонецЦикла;

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

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

Способ №1: Использование запроса (Query) — Рекомендуемый метод

Проанализируем ситуацию: для печатной формы нам нужно проверить, является ли товар комиссионным или собственным, исходя из движений регистра ПартииТоваровОрганизаций. Самым правильным и производительным способом будет использование механизма запросов. Запрос позволяет получить только нужные поля, наложить фильтры на уровне СУБД и избежать лишнего расхода памяти.

Разберем пример кода для получения движений через запрос:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ПартииТоваров.Номенклатура,
    |   ПартииТоваров.АналитикаУчетаНоменклатуры,
    |   ПартииТоваров.ВидЗапасов
    |ИЗ
    |   РегистрНакопления.ПартииТоваровОрганизаций КАК ПартииТоваров
    |ГДЕ
    |   ПартииТоваров.Регистратор = &Регистратор
    |   И ПартииТоваров.Активность = ИСТИНА";

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

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

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Здесь анализируем ВыборкаДетальныеЗаписи.ВидЗапасов
КонецЦикла;

Обратите внимание на поле Активность. Это критически важный момент: если документ был отменен или помечен на удаление, записи в физической таблице регистра могут остаться, но их флаг Активность станет равным Ложь. Всегда добавляйте это условие, чтобы не получить неактуальные данные.

Способ №2: Использование набора записей (RecordSet)

Если по каким-то причинам использование запроса неудобно (например, требуется программно модифицировать записи), можно воспользоваться объектом НаборЗаписей. Этот способ работает быстрее, чем получение целого объекта документа, но медленнее, чем прямой запрос.

Рассмотрим, как правильно прочитать движения через набор записей:


НаборЗаписей = РегистрыНакопления.ПартииТоваровОрганизаций.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);

// Обязательно вызываем Прочитать(), иначе набор будет пустым
НаборЗаписей.Прочитать();

Для Каждого Запись Из НаборЗаписей Цикл
    // Обработка данных
    Если Запись.ВидЗапасов = ПредопределенноеЗначение("Перечисление.ВидыЗапасов.КомиссионныйТовар") Тогда
        // Логика для комиссионного товара
    КонецЕсли;
КонецЦикла;

Для удобства работы с данными после метода Прочитать() можно использовать метод Выгрузить(). Это преобразует записи в ТаблицаЗначений, в которой удобно искать строки через Найти() или фильтровать данные.

Способ №3: Использование виртуальных таблиц

Если задача стоит не просто «посмотреть движения», а узнать состояние запасов после проведения документа (например, остатки), эффективнее обращаться к виртуальным таблицам регистра, таким как ОстаткиИОбороты. В параметрах виртуальной таблицы можно указать условие по регистратору.

Посмотрим на пример логики: виртуальные таблицы оптимизированы на уровне СУБД и позволяют сразу получить агрегированные данные, что значительно ускоряет формирование отчетов и печатных форм в высоконагруженных системах.

Важные нюансы при работе с движениями

Рассмотрим несколько продвинутых аспектов, которые помогут избежать ошибок в будущем:

  1. Работа в транзакции (ОбработкаПроведения): Если вы пытаетесь получить движения внутри модуля документа в процедуре ОбработкаПроведения, помните: запрос к базе данных может не увидеть текущих движений, так как транзакция еще не завершена. В этом случае нужно обращаться напрямую к свойству ЭтотОбъект.Движения.ИмяРегистра.
  2. Права доступа (RLS): Если у пользователя ограничены права на чтение регистра накопления, запрос вернет пустой результат без ошибок. Для формирования печатных форм в таких случаях часто используют привилегированные модули, где проверки прав доступа отключаются.
  3. Пакетные запросы: Для оптимизации печатной формы лучше всего объединять получение данных из шапки документа и данных из его движений в один пакетный запрос. Это сокращает количество обращений к серверу базы данных (Roundtrips) и повышает общую отзывчивость интерфейса.

Резюмируем: для чтения движений проведенного документа в 1С 8.3 наиболее грамотным подходом является использование Запроса к физической таблице регистра с фильтром по регистратору и активности записей. Использование НаборЗаписей допустимо для простых операций, а обращение через ПолучитьОбъект() следует исключить из практики чтения данных.

← На главную