Как правильно получить остатки продукции в торговом зале с помощью конструктора запроса 1С

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

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

Анализ проблемы: почему возникают отрицательные остатки

Разберем ситуацию: в самописной конфигурации используются два разных регистра — ПриходПродукции и РеализацияПродукции. Это классическая архитектурная ошибка. Когда мы пытаемся получить остаток, система не может сопоставить данные из разных таблиц без сложных вычислений. Если документ «Реализация» делает расход по второму регистру, в котором никогда не было прихода, мы гарантированно получим «минусы».

Рассмотрим типичную ошибку в логике движений:

  1. Поступление: Приход в Регистр №1.
  2. Передача в зал: Расход из Регистра №1.
  3. Реализация: Расход из Регистра №2.

Проанализируем ситуацию: для получения остатка в зале нам пришлось бы вычитать данные одного регистра из другого, что крайне непроизводительно. Правильный подход — использование одного универсального регистра накопления с видом «Остатки».

Шаг 1: Исправление архитектуры регистров

Прежде чем приступать к работе с конструктором запроса, нам необходимо объединить учет в одном регистре, например, ОстаткиТоваров. В этом регистре обязательно должны быть измерения Продукция и МестоХранения (Склад).

Выясним, как должны выглядеть правильные движения документов:

1. Документ «Поступление»: делает движение ВидДвиженияНакопления.Приход по складу «Основной склад».

2. Документ «Передача в торговый зал»: это перемещение. Он должен делать одновременно два движения по одному регистру:


// 1. Списываем с основного склада
Движение = Движения.ОстаткиТоваров.ДобавитьРасход();
Движение.Период = Дата;
Движение.МестоХранения = СкладОтправитель;
Движение.Продукция = ТекСтрока.Продукция;
Движение.Количество = ТекСтрока.Количество;

// 2. Приходуем в торговый зал
Движение = Движения.ОстаткиТоваров.ДобавитьПриход();
Движение.Период = Дата;
Движение.МестоХранения = СкладПолучатель; // Торговый зал
Движение.Продукция = ТекСтрока.Продукция;
Движение.Количество = ТекСтрока.Количество;

3. Документ «Реализация»: делает движение ВидДвиженияНакопления.Расход по складу «Торговый зал».

Шаг 2: Работа с конструктором запроса и виртуальными таблицами

Для получения остатков в 1С никогда не используйте основную таблицу регистра (РегистрНакопления.ИмяРегистра). Платформа предоставляет оптимизированные виртуальные таблицы. Рассмотрим подробнее работу с таблицей Остатки.

Откроем конструктор запроса и выберем таблицу РегистрНакопления.ОстаткиТоваров.Остатки. Обратите внимание на параметры этой таблицы:

  1. Период: момент времени, на который мы хотим получить данные.
  2. Условие: фильтр по складу или номенклатуре.

Важный нюанс: если вы пропишете условие (например, склад) на закладке «Условия» в конструкторе, запрос сначала получит остатки по ВСЕМ складам, а потом отфильтрует их. Чтобы запрос работал быстро, нажимаем кнопку «Параметры виртуальной таблицы» и в поле «Условие» пишем:

МестоХранения = &МестоХранения

Шаг 3: Программное получение остатка для Инвентаризации

Рассмотрим пример кода для кнопки «Заполнить остатки» в документе инвентаризации. Нам нужно получить остатки именно по тому складу, который указан в шапке документа.


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

// Чтобы учесть движения самого документа инвентаризации (если нужно),
// используем МоментВремени() или Границу.
Запрос.УстановитьПараметр("Период", Новый Граница(Объект.Дата, ВидГраницы.Исключая));
Запрос.УстановитьПараметр("МестоХранения", Объект.Склад);

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

Пока Выборка.Следующий() Цикл
    НоваяСтрока = Объект.Товары.Добавить();
    НоваяСтрока.Продукция = Выборка.Продукция;
    НоваяСтрока.КоличествоПоУчету = Выборка.КоличествоУчет;
КонецЦикла;

Проблема «Момента времени» и Границы периода

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

Как избежать «минусов» при реализации

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

Разберем алгоритм по шагам:

  1. В начале проведения создаем запрос к виртуальной таблице Остатки.
  2. Передаем в параметры запроса список номенклатуры из табличной части документа.
  3. Сравниваем количество в документе с количеством в регистре.
  4. Если КоличествоВДокументе > КоличествоОстаток, выводим сообщение и устанавливаем Отказ = Истина.

Посмотрим на пример реализации такого контроля:


Процедура ОбработкаПроведения(Отказ, Режим)
    // Сначала записываем пустые движения, чтобы освободить остатки (если перепроводим)
    Движения.ОстаткиТоваров.Записывать = Истина;
    Движения.ОстаткиТоваров.Записать();
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ... (запрос к остаткам с фильтром по ТЧ документа)";
    
    // ... Выполнение запроса ...
    
    Если Выборка.КоличествоОстаток < Выборка.КоличествоВДокументе Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Недостаточно товара " + Выборка.Продукция + ". Остаток: " + Выборка.КоличествоОстаток;
        Сообщение.Сообщить();
        Отказ = Истина;
    КонецЕсли;
КонецПроцедуры

Дополнительные возможности: Регистры оборотов

Если вам нужно получить не только остаток, но и «количество проданного» за определенный период (как упоминалось в Сообщении 1), рекомендуется создать второй регистр — Регистр накопления «Продажи» с видом «Обороты». В отличие от регистра остатков, он не хранит итоги на каждый момент времени, а суммирует все приходы за период. Это идеальный инструмент для отчетов по выручке и аналитики продаж, который не нагружает систему хранением ненужных итогов.

Подведем итоги:

  1. Используйте один регистр накопления (Остатки) для учета движения товаров между складами и залом.
  2. Перемещение товара — это Расход с одного склада и Приход на другой в рамках одного документа.
  3. Всегда обращайтесь к виртуальным таблицам (.Остатки), настраивая фильтры в параметрах таблицы, а не в тексте запроса.
  4. Используйте объект Граница для управления точностью получения остатков в документах.
← На главную