Как программно получить остатки товаров на складах в 1С 8.3?

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

В практике разработки на платформе 1С:Предприятие 8.3 одной из самых частотных задач является получение актуальных остатков товарно-материальных ценностей. Несмотря на кажущуюся простоту, этот процесс имеет множество нюансов.

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

Основы работы с регистрами накопления

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

Рассмотрим подробнее объект РегистрНакопленияМенеджер. Хотя у него есть встроенный метод Остатки(), профессиональным стандартом считается использование языка запросов. Это обеспечивает быстрый анализ данных и дает гибкость: в одном запросе мы можем соединить данные об остатках с ценами, характеристиками номенклатуры или данными из других справочников.

Пошаговое создание запроса к виртуальной таблице остатков

Разберем по шагам процесс написания запроса для получения остатков на конкретную дату по определенному складу. Проанализируем типичный сценарий, когда нам нужно получить список номенклатуры и ее количество. Для эффективной отладки таких конструкций разработчиками часто используется продвинутая консоль запросов, позволяющая видеть результат выполнения в реальном времени.

Для начала нам необходимо инициализировать объект Запрос и задать текст запроса. Важно помнить, что мы обращаемся не к самой таблице регистра, а к ее виртуальному срезу Остатки.


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

В данном примере мы используем псевдонимы Номенклатура и Количество для удобства дальнейшей обработки. Если вы путаетесь в синтаксисе, рекомендуем держать под рукой шпаргалку по языку запросов. Обратите внимание на параметры в скобках после имени таблицы: &Период и &УсловиеСклад — это критически важный момент для производительности.

Настройка параметров и фильтрация данных

Посмотрим на пример установки параметров. Правило хорошего тона в 1С — всегда передавать условия внутрь параметров виртуальной таблицы, а не использовать секцию ГДЕ. Если мы наложим условие в ГДЕ, система сначала получит остатки по всем складам и всей номенклатуре базы, а потом отсечет лишнее. Если же мы передадим условие в параметры таблицы, база данных выберет только нужные записи изначально.

Проанализируем ситуацию с установкой даты. Если параметр &Период не задан, 1С вернет остатки на текущий момент (самые актуальные итоги). Если же нам нужны остатки на начало дня или конкретную секунду, мы должны передать объект Дата или Граница.


// Установка даты остатков
Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДата()));

// Настройка фильтра по складу
// Мы создаем структуру или массив для передачи условий в виртуальную таблицу
Отбор = Новый Структура;
Отбор.Вставить("Склад", Справочники.Склады.НайтиПоНаименованию("Основной склад"));
Запрос.УстановитьПараметр("УсловиеСклад", Отбор);

Работа с объектом Граница

Рассмотрим подробнее важный нюанс: получение остатков "включая" или "исключая" документы конкретного момента времени. Если мы хотим получить остатки после проведения определенного документа, нам поможет объект Граница. Выясним причину: простая передача даты документа в запрос может не учесть движения этого самого документа, так как остатки считаются "на момент".

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


Момент = Новый Граница(Объект.Ссылка.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", Момент);

Это обеспечит корректность данных при формировании отчетов или проведении документов задним числом.

Обработка результатов и вывод данных

После того как запрос подготовлен и параметры установлены, необходимо выполнить его и обойти результат. Мы будем использовать метод Выбрать() для итерации по строкам.


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

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // Здесь мы можем обрабатывать полученные данные
    Сообщить("Товар: " + ВыборкаДетальныеЗаписи.Номенклатура + 
             " Остаток: " + ВыборкаДетальныеЗаписи.Количество);
КонецЦикла;

Использование ВыборкаДетальныеЗаписи.Следующий() является стандартным способом последовательного чтения данных. Внутри цикла Пока мы получаем доступ к полям, которые описали в секции ВЫБРАТЬ нашего запроса.

Оптимизация: получение остатков по списку номенклатуры

Зачастую требуется получить остатки не по всему складу, а только по определенному списку товаров (например, из табличной части документа). В этом случае мы передаем массив ссылок в параметры виртуальной таблицы.

Разберем пример:


СписокТоваров = Объект.Товары.ВыгрузитьКолонку("Номенклатура");

Запрос.Текст = 
    "ВЫБРАТЬ
    |	Остатки.Номенклатура,
    |	Остатки.КоличествоОстаток
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Номенклатура В (&МассивТоваров)) КАК Остатки";

Запрос.УстановитьПараметр("МассивТоваров", СписокТоваров);
Запрос.УстановитьПараметр("Период", ТекущаяДата());

Такой подход минимизирует нагрузку на сервер базы данных, так как индексы регистров накопления оптимизированы для поиска по измерениям (Номенклатура, Склад), переданным в качестве фильтров виртуальной таблицы.

Типичные ошибки при получении остатков

  1. Забытый параметр Период: Если не указать дату, запрос вернет "актуальные" остатки. В отчетах за прошлые периоды это приведет к недостоверным данным.
  2. Фильтрация через ГДЕ: Как уже упоминалось, это замедляет запрос в разы на больших базах. Всегда используйте параметры виртуальной таблицы.
  3. Обращение к основной таблице регистра: Попытка суммировать движения через таблицу РегистрНакопления.ТоварыНаСкладах вместо обращения к Остатки лишает вас преимуществ использования итогов. В ситуациях с некорректными итогами может потребоваться исправление партий с зависшими суммами без количества.
  4. Неучет характеристик: Если в регистре включен учет по характеристикам или сериям, их обязательно нужно включать в запрос, иначе вы получите общую сумму по номенклатуре без детализации.

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

← На главную