Работает ли метод СводныйОстаток со списком значений в 1С 7.7 и как получить остатки по группе складов?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При разработке отчетов или форм списков в 1С:Предприятие 7.7 мы часто сталкиваемся с необходимостью фильтрации данных. Одна из типичных задач — получить остаток товара не по одному конкретному складу, а по списку выбранных складов (например, только по "рабочим" складам, исключая склады брака или транзитные). В более современных версиях платформы (8.х) мы привыкли к возможности передавать списки и массивы в параметры виртуальных таблиц. Однако в версии 7.7 есть свои нюансы.

Давайте подробно разберем, как ведет себя метод СводныйОстаток при передаче в него списка значений, и рассмотрим проверенные практикой способы решения этой задачи.

Анализ синтаксиса и поведения метода СводныйОстаток

Для начала обратимся к синтаксису метода. Согласно документации, метод вызывается следующим образом:

СводныйОстаток(<Измерен1>, <Измерен2>..., <ИмяРесурса>)

Мы должны четко понимать, что платформа 7.7 ожидает в качестве параметров <Измерен...> конкретные скалярные значения, соответствующие типу измерения регистра. Если измерение имеет тип "Справочник.Склады", система ожидает ссылку на конкретный элемент справочника.

Что происходит, если передать список значений?

Если мы попытаемся передать объект типа СписокЗначений вместо элемента справочника, платформа не выдаст ошибку синтаксиса, но логика работы будет нарушена. Метод попытается найти измерение, которое равно самому объекту "СписокЗначений" (что невозможно для справочного типа) или приведет к неверному типу. В результате функция вернет 0 или пустое значение.

Таким образом, мы приходим к однозначному выводу: метод СводныйОстаток (как и метод Остаток) в 1С 7.7 не умеет работать со списками значений напрямую. Он работает только на строгое равенство переданному значению.

Решение 1: Использование фильтра и перебор итогов

Если нам необходимо получить сумму остатков по списку складов штатными средствами (без использования прямых запросов), мы можем воспользоваться объектом Регистр и его методами фильтрации.

Рассмотрим алгоритм, предложенный участниками обсуждения. Он базируется на методе УстановитьЗначениеФильтра. Этот метод позволяет ограничить выборку при переборе итогов.

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

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


// Создаем объект регистра
Рег = СоздатьОбъект("Регистр.ТоварныйКредит"); // Или Регистр.ОстаткиТоваров

// Устанавливаем фильтр. 
// Параметр 2 означает "Отбирать" по вхождению в список
Рег.УстановитьЗначениеФильтра("Клиент", СписокКлиентов, 2); 

// Выбираем итоги с учетом установленного фильтра
Рег.ВыбратьИтоги();

ВсегоОстаток = 0;
Пока Рег.ПолучитьИтог() = 1 Цикл
    // Суммируем ресурсы по отфильтрованным записям
    ВсегоОстаток = ВсегоОстаток + Рег.Сумма; 
КонецЦикла;

Важные нюансы этого метода:

  1. Метод УстановитьЗначениеФильтра влияет на методы выборки (ВыбратьИтоги, ВыбратьДвижения).
  2. Он не влияет на прямой вызов методов получения остатка, таких как СводныйОстаток, если не используется механизм временного расчета регистров. То есть, просто установив фильтр и вызвав СводныйОстаток() без параметров, вы все равно получите полный итог по регистру, если не перебираете выборку.

Решение 2: Вывод остатков в форме списка (Динамические колонки)

Часто задача стоит иначе: нужно в форме списка номенклатуры видеть остатки не по всем складам сразу, а, например, по трем конкретным "магазинам", игнорируя центральный склад. При этом пользователь хочет видеть данные в отдельных колонках или одной суммой.

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

Алгоритм действий:

  1. В форму списка добавляем текстовые колонки (например, "ОстСклад1", "ОстСклад2").
  2. Создаем массив или список складов, которые нас интересуют.
  3. Пишем функцию, которая будет вызываться в формуле колонки.

Пример функции, которую можно разместить в модуле формы списка:


// Функция вызывается из формулы колонки таблицы
// НомерСклада - индекс склада в нашем массиве 'Склады'
Функция ПоказатьОстаток(НомерСклада)
    
    // Защита от ошибок индексации
    Если (НомерСклада <= 0) Или (НомерСклада > Склады.РазмерСписка()) Тогда
        Возврат "";
    КонецЕсли;

    ТекСклад = Склады.ПолучитьЗначение(НомерСклада);
    
    // Получаем остаток конкретного товара на конкретном складе
    // ПромФирма - если есть измерение по фирме
    // ТекущийЭлемент() - ссылка на текущий товар в строке списка
    ЗначениеОстатка = Регистр.ОстаткиТоваров.Остаток(ПромФирма, ТекущийЭлемент(), ТекСклад, "ОстатокТовара");
    
    // Форматируем для красивого вывода
    Возврат СокрЛП(Формат(ЗначениеОстатка, "Ч015.2"));

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

В свойствах колонки в поле "Формула" мы пишем: ПоказатьОстаток(1), для второй колонки ПоказатьОстаток(2) и так далее.

Преимущества и недостатки:

Решение 3: Прямые запросы (Оптимальная производительность)

Если в системе работает много пользователей, а база данных большая, штатные методы перебора или вызова Остаток() в цикле будут работать медленно. В таких случаях профессиональным стандартом для 1С 7.7 является использование прямых запросов к SQL (обычно с помощью внешней компоненты 1C++).

Именно этот способ выбрал автор вопроса как наиболее эффективный. Почему это работает быстрее?

  1. SQL оператор IN: В языке SQL (на котором общается 1С с сервером баз данных) существует оператор IN. Он позволяет одним запросом выбрать записи, где поле (например, ID склада) входит в указанный список.
  2. Отсутствие лишних данных: Мы не перебираем итоги на клиенте, сервер возвращает нам уже готовую таблицу с цифрами.

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

Это позволяет добиться мгновенного отклика интерфейса даже при сложной логике выбора складов (например, "показать остатки по всем магазинам региона, кроме закрытых на ремонт").

Резюме

Подведем итог нашему исследованию:

  1. Метод Регистр.ОстаткиТоваров.СводныйОстаток (и аналогичные) не работает со списком значений в качестве параметра измерения. Он ожидает только конкретное значение.
  2. Для получения сводного остатка по нескольким складам в отчетах используйте УстановитьЗначениеФильтра с последующим ВыбратьИтоги.
  3. Для вывода в списках можно использовать формулы с поэлементным запросом остатка, но это ресурсоемко.
  4. Для высокой производительности и гибких отборов (аналог "В ИЕРАРХИИ" или "В СПИСКЕ" из 8.х) рекомендуется использовать прямые запросы.
← На главную