При написании собственных отчетов в конфигурациях на платформе 1С:Предприятие 7.7 (в частности, в «Торговля и Склад 7.7») разработчики нередко сталкиваются с ситуацией, когда запрос отрабатывает без явных фатальных ошибок, но при обходе результата группировки остаются пустыми либо выводятся только общие итоги. Разберем по шагам, почему возникает эта проблема, какие ошибки допущены в исходном запросе и как правильно организовать выборку данных по складу.
В языке запросов 1С 7.7 встроенные агрегатные функции работы с регистрами (НачОст, КонОст, Приход, Расход) могут применяться только к ресурсам регистра. Посмотрим на строку из запроса:
|Функция СуммаНачОст = НачОст(ЦенаПродажи);
В типовом регистре ОстаткиТМЦ поле ЦенаПрод является измерением, а единственным ресурсом — Количество. Попытка вызвать функцию НачОст или КонОст для измерения или реквизита приводит к ошибке синтаксического анализатора запроса. При этом метод Запрос.Выполнить(ТекстЗапроса) возвращает 0, а объект запроса не содержит данных. Всегда проверяйте результат выполнения перед обработкой:
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Предупреждение("Ошибка выполнения запроса!");
Возврат;
КонецЕсли;
Вызов Запрос.Группировка(2) без предварительного позиционирования на верхнем уровне группировки Запрос.Группировка(1) не позволяет получить данные вложенного уровня. При обходе дерева результатов необходимо использовать один из двух подходов:
Пока Запрос.Группировка("Склад") = 1 Цикл
// Здесь доступны реквизиты склада и общие итоги по складу
Пока Запрос.Группировка("Номенклатура") = 1 Цикл
// Здесь доступны детальные данные по номенклатуре
КонецЦикла;
КонецЦикла;
Пока Запрос.Группировка() = 1 Цикл
Если Запрос.ЭтоГруппа("Склад") = 1 Тогда
// Обработка заголовка склада
Иначе
// Вывод детальных записей
КонецЕсли;
КонецЦикла;
В тексте запроса вместо конкатенации строки проверки на пустое значение можно использовать оператор В. Если переменная ВыбСклад пустая (не выбрана в диалоге), условие Склад В ВыбСклад автоматически трактуется как Истина для всех складов, что избавляет от необходимости динамически формировать секцию Условие:
|Условие(Склад В ВыбСклад);
Если требуется получить остатки номенклатуры по складу и рассчитать розничную сумму, сгруппируем данные по измерению цены, а саму сумму вычислим в коде при выводе строки:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период с ДатаК по ДатаК;
|Склад = Регистр.ОстаткиТМЦ.Склад;
|Номенклатура = Регистр.ОстаткиТМЦ.Номенклатура;
|ЦенаПродажи = Регистр.ОстаткиТМЦ.ЦенаПрод;
|Колво = Регистр.ОстаткиТМЦ.Количество;
|Функция КонОстКолво = КонОст(Колво);
|Функция ПриходКолво = Приход(Колво);
|Функция РасходКолво = Расход(Колво);
|Группировка Склад упорядочить по Склад.Код;
|Группировка Номенклатура;
|Группировка ЦенаПродажи;
|Условие(Склад В ВыбСклад);
|";
Если Запрос.Выполнить(ТекстЗапроса) = 0 Тогда
Возврат;
КонецЕсли;
Пока Запрос.Группировка("Склад") = 1 Цикл
Пока Запрос.Группировка("Номенклатура") = 1 Цикл
Пока Запрос.Группировка("ЦенаПродажи") = 1 Цикл
ОстатокКолво = Запрос.КонОстКолво;
Цена = Запрос.ЦенаПродажи;
СуммаРозн = ОстатокКолво * Цена;
// Вывод данных в таблицу
КонецЦикла;
КонецЦикла;
КонецЦикла;
Если вам необходимы не только розничные цены, но и стоимостная оценка остатков (учетная стоимость, сумма без НДС, себестоимость), следует строить запрос по регистру ПартииНаличие, так как именно в нем содержатся суммовые ресурсы:
Запрос = СоздатьОбъект("Запрос");
ТекстЗапроса = "
|Период по ДатаК;
|Склад = Регистр.ПартииНаличие.Склад;
|Номенклатура = Регистр.ПартииНаличие.Номенклатура;
|Колво = Регистр.ПартииНаличие.Количество;
|СуммаРуб = Регистр.ПартииНаличие.СуммаРуб;
|Функция КонОстКол = КонОст(Колво);
|Функция КонОстСумма = КонОст(СуммаРуб);
|Группировка Склад;
|Группировка Номенклатура;
|Условие(Склад В ВыбСклад);
|";
Если Запрос.Выполнить(ТекстЗапроса) = 1 Тогда
Пока Запрос.Группировка("Склад") = 1 Цикл
Пока Запрос.Группировка("Номенклатура") = 1 Цикл
// Доступны Запрос.КонОстКол и Запрос.КонОстСумма
КонецЦикла;
КонецЦикла;
КонецЕсли;
Если в отчете не нужны обороты за период (приход и расход), а требуется получить только срез остатков на определенную дату, эффективнее и быстрее использовать объект работы с регистром напрямую через метод ВыгрузитьИтоги:
РегОстатки = СоздатьОбъект("Регистр.ОстаткиТМЦ");
ТЗ = СоздатьОбъект("ТаблицаЗначений");
// Устанавливаем фильтр по складу, если он выбран
Если ПустоеЗначение(ВыбСклад) = 0 Тогда
РегОстатки.УстановитьЗначениеФильтра("Склад", ВыбСклад, 1);
КонецЕсли;
// Получаем срез остатков на ДатуК и выгружаем в Таблицу Значений
РегОстатки.ВременныйРасчет(1);
РассчитатьРегистрыНа(ДатаК);
РегОстатки.ВыгрузитьИтоги(ТЗ, 1, 1);
Такой подход работает быстрее выполнения текстового запроса на больших базах и позволяет легко манипулировать полученными строками в объекте ТаблицаЗначений.