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