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