Hare.ru @ Коллективный разум / Hare.ru @ Дикое место

Архив hare.ru 
Мысли, конвертированные в текст

Собственные руки TM


Все статьи раздела

Сложные отчёты – это просто! Своя функция в запросе.

Александр Мозговой (где-то в 2001)

Одним из существенных ограничений языка запросов V7 является невозможность использования своих собственных функций. Для многих задач штатный набор функций (Сумма, НачОст, КонОст, Приход и Расход) оказывается явно недостаточным.

Но, как оказалось, это ограничение можно обойти, и путём очень простой манипуляции можно подключить к запросу свою собственную функцию.

Как это делается? Лучше всего показать на конкретном примере.

Дано.

В конфигурации имеется справочник Товары. У справочника есть реквизит ВалютаУчетаТовара. Тип реквизита: Справочник.Валюты.

Также в конфигурации имеется регистр Товары. Структура регистра следующая:

Измерения Товар (Справочник.Товары)
Склад (Справочник.Склады)
Ресурсы Количество (Число, 10.0)
Себестоимость (Число 15.2)

При формировании движения регистров, Себестоимость для товара рассчитывается в валюте, указанной в реквизите ВалютаУчета справочника Товары (реквизит устанавлиывается один раз, до формирования движений по товару).

Списание делается по средней себестоимости. Теоретически, каждый товар может учитываться в собственной валюте учета.

Задача.

Требуется отчет, показывающий остатки товаров в выбранной валюте в разрезе наличия на складах. В отчёте нужны промежуточные итоги по группам и по всем товарам.

Т.е. получаем примерно такую таблицу:

Наименование
товара
Средняя
Себестоимость
Склад 1 Склад 2 Склад N
Кол-во Сумма Кол-во Сумма Кол-во Сумма
Группа   СуммаГр СуммаГр СуммаГр
Товар Себест. КолТ СуммаТ КолТ СуммаТ КолТ СуммаТ
Итого   СуммаИт СуммаИт СуммаИт

Главная проблема состоит в том, чтобы собрать промежуточные итоги в нужной нам валюте отчета. Можно использовать традиционные методы (т.е. «руками» накапливать итоговые переменные, перемножая себестоимость на курс валюты отчета), либо использовать таблицы значений.

Текст запроса в традиционном случае будет примерно такой:

"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция СебестоимостьКонОст = КонОст(Себестоимость);
|Группировка Склад без групп;
|Группировка Товар;";

Вот с итогами и возникает потом проблема, поскольку если первую группировку мы проходим вправо (по складам), то не можем корректно вытащить себестоимость по группам (ноапомню, что в регистрах себестоимость хранится в разных валютах учета).

В качестве решения предлагается использование стандартных возможностей запроса, а именно функции Сумма(). В качестве её параметра можно передать не только числовую переменную запроса, но и вызов некоей внешней функции, в которую в качестве параметров передаются несколько числовых переменных запроса.

Эта методика, в принципе, является стандартной – т.е. описана в документации, хотя и не очень внятно. Достоинства методики очевидны – все пересчёты себестоимости к требуемой валюте производятся внутри запроса, что позволяет легко получать перекрёстные итоги стандартными средствами, без дополнительной работы:

Функция ВВалютеОтчета(Тов,Себ)
//тут пересчитаем валюту
   Возврат(глПересчет(Себ,Тов.ВалютаУчетаТовара,ДатаОтчета,ВалютаОтчета,ДатаОтчета));
КонецФункции

//....

"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция ПродВал = Сумма(ВВалютеОтчета(Товар,Себестоимость));
|Группировка Склад без групп;
|Группировка Товар;";

Как легко заметить, показанная методика позволяет значительно упростить и «удешивить» (в плане затрачиваемого времени) написание сложных отчётов.

Пара замечаний «вдогонку».

Во-первых, в типовых конфигурациях такая методика практически не встречается. Это может ничего не значить, а может означать нестабильность работы функции запроса Сумма() в паре со внешней функцией на разных релизах V7.

Во-вторых, если во внешнюю функцию передать в качестве параметров не просто числовые переменные запроса, а их значения, предварительно обработанные другими функциями запроса:

"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция СбсКонОст = КонОст(Себестоимость);
|Функция ПродВал = Сумма(ВВалютеОтчета(Товар,Запрос.СбсКонОст));
|Группировка Склад без групп;
|Группировка Товар;";

То результат, возвращаемый внешней функцией всегда будет целым числом (точность 0). Почему так происходит – не очень понятно, но поделать с этим (как с другими «фичами» движка V7) ничего нельзя.

Партнеры:


Также может быть интересно:

Канал Россия 1 на http://spbtvonline.ru/
   
 Сайт поддерживается за счет партнеров:
:::... Сайт содержит архив двух версий hare.ru Карта сайта