Александр Мозговой где-то в 2001 Одним из существенных ограничений языка запросов V7 является невозможность использования
своих собственных функций. Для многих задач штатный набор функций (Сумма, НачОст, КонОст,
Приход и Расход) оказывается явно недостаточным.
Но, как оказалось, это ограничение можно обойти, и путём очень простой манипуляции можно
подключить к запросу свою собственную функцию.
Как это делается? Лучше всего показать на конкретном примере.
Дано.
В конфигурации имеется справочник Товары. У справочника
есть реквизит ВалютаУчетаТовара. Тип реквизита:
Справочник.Валюты.
Также в конфигурации имеется регистр Товары. Структура
регистра следующая:
Измерения |
Товар (Справочник.Товары) |
Склад (Справочник.Склады) |
Ресурсы |
Количество (Число, 10.0) |
Себестоимость (Число 15.2) |
При формировании движения регистров, Себестоимость для товара рассчитывается в валюте,
указанной в реквизите ВалютаУчета справочника Товары (реквизит
устанавлиывается один раз, до формирования движений по товару).
Списание делается по средней себестоимости. Теоретически, каждый товар может учитываться в
собственной валюте учета.
Задача.
Требуется отчет, показывающий остатки товаров в выбранной валюте в разрезе наличия на складах.
В отчёте нужны промежуточные итоги по группам и по всем товарам.
Т.е. получаем примерно такую таблицу:
Наименование товара |
Средняя Себестоимость |
Склад 1 |
Склад 2 |
|
Склад N |
Кол-во |
Сумма |
Кол-во |
Сумма |
Кол-во |
Сумма |
Группа |
|
СуммаГр |
СуммаГр |
|
СуммаГр |
Товар |
Себест. |
КолТ |
СуммаТ |
КолТ |
СуммаТ |
|
КолТ |
СуммаТ |
|
Итого |
|
СуммаИт |
СуммаИт |
|
СуммаИт |
Главная проблема состоит в том, чтобы собрать промежуточные итоги в нужной нам валюте отчета.
Можно использовать традиционные методы (т.е. «руками» накапливать итоговые
переменные, перемножая себестоимость на курс валюты отчета), либо использовать таблицы значений.
Текст запроса в традиционном случае будет примерно такой:
"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция СебестоимостьКонОст = КонОст(Себестоимость);
|Группировка Склад без групп;
|Группировка Товар;";
Вот с итогами и возникает потом проблема, поскольку если первую группировку мы проходим вправо
(по складам), то не можем корректно вытащить себестоимость по группам (ноапомню, что в регистрах
себестоимость хранится в разных валютах учета).
В качестве решения предлагается использование стандартных возможностей запроса, а именно
функции Сумма(). В качестве её параметра можно передать
не только числовую переменную запроса, но и вызов некоей внешней функции, в которую в качестве
параметров передаются несколько числовых переменных запроса.
Эта методика, в принципе, является стандартной т.е. описана в документации, хотя и
не очень внятно.
Достоинства методики очевидны все пересчёты себестоимости к требуемой валюте
производятся внутри запроса, что позволяет легко получать перекрёстные итоги стандартными
средствами, без дополнительной работы:
Функция ВВалютеОтчета(Тов,Себ)
//тут пересчитаем валюту
Возврат(глПересчет(Себ,Тов.ВалютаУчетаТовара,ДатаОтчета,ВалютаОтчета,ДатаОтчета));
КонецФункции
//....
"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция ПродВал = Сумма(ВВалютеОтчета(Товар,Себестоимость));
|Группировка Склад без групп;
|Группировка Товар;";
Как легко заметить, показанная методика позволяет значительно упростить и «удешивить»
(в плане затрачиваемого времени) написание сложных отчётов.
Пара замечаний «вдогонку».
Во-первых, в типовых конфигурациях такая методика практически не встречается. Это может ничего не
значить, а может означать нестабильность работы функции запроса
Сумма() в паре со внешней функцией на разных релизах V7.
Во-вторых, если во внешнюю функцию передать в качестве параметров не просто числовые переменные
запроса, а их значения, предварительно обработанные другими функциями запроса:
"Товар = Регистр.Товары.Товар;
|Склад = Регистр.Товары.Склад;
|Количество = Регистр.Товары.Количество;
|Себестоимость = Регистр.Товары.Себестоимость;
|Функция КоличествоКонОст = КонОст(Количество);
|Функция СбсКонОст = КонОст(Себестоимость);
|Функция ПродВал = Сумма(ВВалютеОтчета(Товар,Запрос.СбсКонОст));
|Группировка Склад без групп;
|Группировка Товар;";
То результат, возвращаемый внешней функцией всегда будет целым числом (точность 0).
Почему так происходит не очень понятно, но поделать с этим (как с другими
«фичами» движка V7) ничего нельзя.
|