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