Как правильно получить остатки товаров на складе из регистра накопления 'ТоварыНаСкладах' в 1С с помощью запроса?

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

При работе с системой 1С часто возникает необходимость получить актуальные остатки товаров на складах. Это критически важная задача для учета, анализа и планирования деятельности предприятия, особенно если у вас внедрена специализированная конфигурация для организации складского учета. Зачастую стандартные отчеты не покрывают всех потребностей, и разработчикам или продвинутым пользователям приходится обращаться к запросам, чтобы получить данные именно в том формате, который требуется для конкретной задачи (поможет универсальная выгрузка данных из 1С через произвольные запросы) – будь то формирование сложного отчета, заполнение табличной части документа или интеграция с таким инструментом, как расширение для учета ТМЦ. Однако, корректное получение именно остатков из регистров накопления, особенно с учетом различных фильтров (дата, склад, номенклатура), может вызвать затруднения. В этом материале мы подробно разберем, как эффективно решать эту задачу, используя встроенный язык запросов 1С.

Мы выясним, почему прямые запросы к основной таблице регистра накопления могут давать неверные результаты для остатков и как правильно использовать специальные инструменты платформы для корректного сбора этих данных. Мы сосредоточимся на получении остатков из регистра накопления «ТоварыНаСкладах», что является типовой задачей для большинства торговых и производственных предприятий. Мы проанализируем различные подходы и примеры кода, которые помогут вам уверенно работать с остатками в 1С.

Основы работы с остатками в 1С: использование виртуальной таблицы "Остатки"

Для получения актуальных остатков по регистру накопления в 1С, например, по регистру ТоварыНаСкладах, мы не можем просто выбрать все записи из основной таблицы регистра и просуммировать их. Регистры накопления хранят движения (приходы и расходы), и прямой запрос к ним не даст текущего остатка. Для решения этой задачи платформа 1С предоставляет мощный и удобный механизм – виртуальные таблицы. Одной из таких таблиц является виртуальная таблица Остатки, которая доступна для всех регистров накопления с видом регистра "Остатки" или "Обороты и Остатки". Для контроля данных в этих регистрах подойдёт редактор записей регистров накопления для 1С.

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

Виртуальная таблица Остатки позволяет нам указать следующие ключевые параметры:

  1. Момент времени (Дата): На какую дату мы хотим получить остатки. Это может быть как конкретная дата, так и момент времени (например, конец дня или определенная секунда).
  2. Условия: Дополнительные условия отбора, которые будут применены к измерениям регистра (например, отбор по конкретному складу, номенклатуре, характеристике).

Рассмотрим общий синтаксис запроса к виртуальной таблице Остатки (для лучшего понимания синтаксиса вам может пригодиться шпаргалка по языку запросов):


ВЫБРАТЬ
    РегистрНакопления.ИмяРегистра.Остатки.Измерение1,
    РегистрНакопления.ИмяРегистра.Остатки.Измерение2,
    РегистрНакопления.ИмяРегистра.Остатки.РесурсОстаток
ИЗ
    РегистрНакопления.ИмяРегистра.Остатки(&МоментВремени, УсловиеНаИзмерение1 = &ЗначениеИзмерения И УсловиеНаИзмерение2 = &ЗначениеИзмерения) КАК ИмяПсевдонима

Здесь ИмяРегистра – это название вашего регистра накопления (например, ТоварыНаСкладах), Измерение1, Измерение2 – это измерения вашего регистра (например, Номенклатура, Склад), а РесурсОстаток – это ресурс, остаток которого мы хотим получить (например, ВНаличииОстаток, КОтгрузкеОстаток). Параметры &МоментВремени, &ЗначениеИзмерения будут установлены программно перед выполнением запроса.

Решение 1: Получение остатков по одному складу и конкретной номенклатуре

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

Мы будем использовать виртуальную таблицу Остатки регистра накопления ТоварыНаСкладах. Для этого нам потребуется указать дату, по которой мы хотим получить остатки, а также конкретные значения для измерений Номенклатура и Склад.

Давайте посмотрим на пример запроса:


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

Проанализируем этот запрос подробнее:

  1. ВЫБРАТЬ: В этой секции мы указываем, какие поля мы хотим получить. В данном случае это измерения Номенклатура, Склад и ресурсы ВНаличииОстаток, КОтгрузкеОстаток. Эти ресурсы – это именно те значения остатков, которые рассчитывает виртуальная таблица.
  2. ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(...): Это ключевая часть. Мы обращаемся к виртуальной таблице Остатки регистра ТоварыНаСкладах. В скобках мы передаем параметры этой виртуальной таблицы:
    • &Дата: Это первый параметр – момент времени, на который рассчитываются остатки. Критически важно: Если вы хотите получить остатки на конец дня, например, на 31.12.2023, то параметр &Дата должен быть установлен как "конец дня" этого числа. Например, КонецДня(Дата). Если же вы укажете просто дату без времени, то остатки будут рассчитаны на начало этой даты (00:00:00).
    • Номенклатура = &Номенклатура И Склад = &Склад: Это второй параметр – условие отбора для виртуальной таблицы. Здесь мы указываем, что хотим получить остатки только для определенной номенклатуры и склада. Используем параметры &Номенклатура и &Склад, чтобы передать конкретные значения программно.
  3. КАК ТоварыНаСкладахОстатки: Это псевдоним для нашей виртуальной таблицы, который упрощает чтение и написание запроса.

После того как запрос составлен, нам необходимо программно установить его параметры. Это делается с помощью объекта Запрос в 1С:


&НаСервере
Функция ПолучитьОстатокТовара(ДатаЗапроса, НоменклатураОбъект, СкладОбъект)

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

    Запрос.УстановитьПараметр("Дата", КонецДня(ДатаЗапроса)); // Важно: устанавливаем конец дня
    Запрос.УстановитьПараметр("Номенклатура", НоменклатураОбъект);
    Запрос.УстановитьПараметр("Склад", СкладОбъект);

    РезультатЗапроса = Запрос.Выполнить();
    Если РезультатЗапроса.Пустой() Тогда
        Возврат 0; // Или другое значение по умолчанию
    КонецЕсли;

    Выборка = РезультатЗапроса.Выбрать();
    Выборка.Следующий();

    Возврат Выборка.ВНаличииОстаток; // Возвращаем остаток "ВНаличии"

КонецФункции

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

Решение 2: Получение остатков по нескольким складам или нескольким номенклатурам

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

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

Пример запроса с оператором В:


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

Ключевое отличие здесь – это условие Склад В (&СписокСкладов). Теперь вместо одного значения для склада мы ожидаем коллекцию. Если нам нужно получить остатки по нескольким номенклатурам, мы можем аналогично использовать Номенклатура В (&СписокНоменклатур). Можно комбинировать эти условия, например, получать остатки по нескольким номенклатурам на нескольких складах.

Теперь рассмотрим, как программно установить параметр &СписокСкладов:


&НаСервере
Функция ПолучитьОстатокТовараПоНесколькимСкладам(ДатаЗапроса, НоменклатураОбъект, СписокСкладовМассив)

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

    Запрос.УстановитьПараметр("Дата", КонецДня(ДатаЗапроса));
    Запрос.УстановитьПараметр("Номенклатура", НоменклатураОбъект);
    Запрос.УстановитьПараметр("СписокСкладов", СписокСкладовМассив); // Передаем массив объектов "Склад"

    РезультатЗапроса = Запрос.Выполнить();
    Возврат РезультатЗапроса.Выгрузить(); // Возвращаем таблица значений с остатками

КонецФункции

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

Как видим, в данном случае мы передаем в качестве параметра &СписокСкладов объект типа Массив, который содержит ссылки на нужные нам элементы справочника Склады. Платформа 1С автоматически преобразует этот массив в список значений, пригодный для оператора В в запросе. Аналогичным образом можно использовать СписокЗначений. Это очень гибкий механизм, позволяющий динамически формировать условия отбора на основе пользовательских данных или других источников.

Дополнительные нюансы и полезные советы

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

  1. Различие между Остатки и ОстаткиИОбороты:

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

    Пример использования ОстаткиИОбороты:

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

    Обратите внимание на дополнительные параметры: &ДатаНачала, &ДатаОкончания, а также параметры периодичности (Авто), вида движения (ДвиженияИГраницыПериода) и т.д. Эти параметры позволяют очень гибко настраивать получение данных.

  2. Работа с дополнительными измерениями:

    Если в вашем регистре накопления есть такие измерения, как ХарактеристикаНоменклатуры, СерияНоменклатуры, Качество и другие, вы можете включать их в условие отбора виртуальной таблицы так же, как и Номенклатура или Склад. Это позволяет получать остатки с еще большей детализацией.

    Пример:

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

    Для таких запросов вам также потребуется устанавливать дополнительный параметр &Характеристика перед выполнением запроса.

  3. Особенности параметра "Момент времени" в виртуальной таблице:

    Как мы уже упоминали, очень важно правильно указывать параметр даты для виртуальной таблицы Остатки. Если вы хотите получить остатки на конец дня (например, на 23:59:59), всегда используйте функцию КонецДня(). Если вы просто передадите дату, например 01.01.2024, система будет воспринимать ее как 01.01.2024 00:00:00, что даст остатки на начало дня. Для получения остатков на конкретный момент времени (например, до проведения определенного документа), вы можете передавать МоментВремени самого документа, используя ДокументСсылка.МоментВремени().

  4. Оптимизация производительности запросов:

    При работе с большими объемами данных производительность запросов к виртуальным таблицам может стать критичной. Чтобы обеспечить максимальную скорость, всегда старайтесь максимально сузить область выборки, используя условия в параметрах виртуальной таблицы. Чем больше условий вы зададите непосредственно в скобках после названия виртуальной таблицы (например, &Дата, Номенклатура = &Номенклатура И Склад = &Склад), тем быстрее будет выполнен запрос, поскольку система сможет сразу отфильтровать данные на уровне СУБД. Избегайте получения большого объема данных из виртуальной таблицы и последующей фильтрации их в коде 1С, так как это менее эффективно.

  5. Использование конструктора запросов:

    Для начинающих разработчиков и для проверки сложных запросов очень удобно использовать встроенный в конфигуратор 1С Конструктор запросов. Он позволяет визуально строить запросы, выбирать таблицы, поля, задавать условия и параметры. Это отличный инструмент для изучения структуры данных и тестирования запросов перед их внедрением в код.

Итак, мы рассмотрели основные методы получения остатков товаров из регистра накопления ТоварыНаСкладах с помощью языка запросов 1С. Мы научились использовать виртуальную таблицу Остатки как для одиночных, так и для множественных условий фильтрации, а также обсудили важные нюансы, такие как установка параметров и оптимизация запросов. Применяя эти знания, вы сможете эффективно решать большинство задач, связанных с получением актуальных остатков в системе 1С. Помните, что практика — лучший учитель, поэтому не стесняйтесь экспериментировать с запросами и изучать возможности платформы.

← На главную