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

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

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

Анализ типичных ошибок при обращении к регистру бухгалтерии

Проанализируем типовой ошибочный запрос, с которого часто начинаются попытки извлечь остатки:


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

Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.ТоварыНаСкладе);
Запрос.УстановитьПараметр("Номен", Справочники.Номенклатура.НайтиПоКоду("000000109"));

Выясним причину, почему такой запрос может возвращать пустой результат или работать неэффективно:

  1. Неопределенный порядок субконто на счете. Если в параметрах виртуальной таблицы третий параметр ВидыСубконто не задан, поля Субконто1, Субконто2, Субконто3 жестко привязываются к порядку субконто, настроенному в плане счетов для выбранного счета. Если на счете первым субконто идет Склады, а вторым — Номенклатура, обращение к Субконто1 будет возвращать ссылку на склад. Сравнение склада с номенклатурой даст ЛОЖЬ, и выборка окажется пустой.
  2. Фильтрация в секции ГДЕ вместо параметров виртуальной таблицы. Наложение условия в секции ГДЕ заставляет СУБД сначала рассчитать остатки по абсолютно всем позициям счета, и лишь затем отфильтровать результат. Это приводит к избыточной нагрузке на сервер. Условия необходимо накладывать в четвертом параметре виртуальной таблицы.
  3. Использование счетов-групп при проверке на точное равенство. Если в параметр &Счет передается счет-группа (например, счет «28» или «41»), по которому нет прямых проводок, условие Счет = &Счет не вернет записей. Для учета подчиненных субсчетов обязательно использовать условие Счет В ИЕРАРХИИ (&ВыбСчет).

Решение 1. Оптимальный запрос с фиксированным порядком видов субконто

Рассмотрим правильное и надежное решение задачи. Чтобы избежать зависимости от физического порядка субконто на конкретном счете и гарантировать высокую скорость работы СУБД, выполним следующие действия:

  1. Явно передадим массив видов субконто в третий параметр виртуальной таблицы. В этом случае Субконто1 всегда будет соответствовать первому элементу переданного массива (в нашем случае — виду субконто Номенклатура).
  2. Перенесем отбор по конкретному товару в четвертый параметр виртуальной таблицы УсловиеСубконто.
  3. Используем проверку иерархии счета, если требуется собирать остатки со всех подчиненных субсчетов.

Посмотрим на пример готового рабочего кода:


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

// Установка параметров запроса
Запрос.УстановитьПараметр("Период", КонецДня(ТекущаяДата()));
Запрос.УстановитьПараметр("ВыбСчет", ПланыСчетов.Хозрасчетный.ТоварыНаСкладе);
Запрос.УстановитьПараметр("Номен", Справочники.Номенклатура.НайтиПоКоду("000000110"));

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

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

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

Решение 2. Использование предопределенных значений прямо в запросе

Рассмотрим вариант оптимизации кода, при котором отпадает необходимость вручную формировать массив в коде 1С. В платформе 1С:Предприятие 8 можно использовать конструкцию ЗНАЧЕНИЕ() непосредственно внутри текста запроса:


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

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

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
    ТекущийОстаток = Выборка.Количество;
КонецЕсли;

Решение 3. Получение остатка через менеджер регистра бухгалтерии

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


ФильтрСубконто = Новый Структура;
ФильтрСубконто.Вставить(
    ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура, 
    ИскомаяНоменклатура
);

ТаблицаОстатков = РегистрыБухгалтерии.Хозрасчетный.Остатки(
    КонецДня(ТекущаяДата()),
    ПланыСчетов.Хозрасчетный.ТоварыНаСкладе,
    ФильтрСубконто
);

Для Каждого Стр Из ТаблицаОстатков Цикл
    Сообщить("Остаток товара: " + Стр.КоличествоОстаток);
КонецЦикла;

Практические рекомендации

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