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