Часто возникает ситуация, когда в отчете есть необязательный параметр, например, валюта. Пользователи могут забыть его указать, и в таком случае отчет должен сформироваться с неким значением по умолчанию, например, с валютой регламентированного учета. Рассмотрим, как правильно реализовать такую логику в 1С, особенно при работе с системой компоновки данных (СКД).
Исходная задача звучала так: если параметр &Валюта не заполнен (равен пустой ссылке), нужно подставить в запрос ссылку на «первый» элемент справочника «Валюты». Однако, как мы выясним, понятие «первый элемент» в 1С очень условно, и такой подход ненадежен. Правильнее использовать конкретное значение, например, основную валюту учета в системе.
Первая мысль, которая может возникнуть, — решить все средствами языка запросов (в этом поможет консоль запросов). Например, создать временную таблицу, поместить в нее один элемент из справочника, а затем в основном запросе использовать его.
Проанализируем ситуацию. Понятие "первый элемент справочника" не является строгим. Порядок вывода элементов зависит от текущей сортировки (по коду, наименованию, внутреннему идентификатору) и может меняться. Сегодня первым может быть "руб.", а завтра, после добавления новой валюты, — "USD". Полагаться на такой порядок в бизнес-логике — плохая практика.
Тем не менее, технически такой запрос можно составить. Вот пример работающего, но неоптимального и ненадежного решения:
// Пакет 1: Выбираем первую по наименованию валюту и помещаем во временную таблицу
ВЫБРАТЬ ПЕРВЫЕ 1
Валюты.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ВалютаПоУмолчанию
ИЗ
Справочник.Валюты КАК Валюты
УПОРЯДОЧИТЬ ПО
Валюты.Наименование
;
//////////////////////////////////////////////////////////////////////////////////
// Пакет 2: Основной запрос, где мы используем данные из временной таблицы
ВЫБРАТЬ
ВЫБОР
КОГДА &Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
ТОГДА ВТ_ВалютаПоУмолчанию.Ссылка
ИНАЧЕ &Валюта
КОНЕЦ КАК ИтоговаяВалюта
ИЗ
ВТ_ВалютаПоУмолчанию КАК ВТ_ВалютаПоУмолчанию
Недостатки этого подхода:
&Валюта не заполнен на уровне настроек СКД, система может выдать ошибку, даже не дойдя до выполнения нашей логики с ВЫБОР КОГДА.Этот способ можно рассматривать только как технический пример, но не как руководство к действию в реальных задачах.
Более управляемый вариант — вычислить значение по умолчанию средствами языка 1С до выполнения запроса и передать его в запрос как отдельный параметр. Сам запрос при этом немного упрощается.
Разберем по шагам. Сначала мы на встроенном языке 1С получаем нужную нам валюту (например, валюту регламентированного учета), а затем передаем ее в запрос.
Пример кода на встроенном языке 1С:
// Допустим, у нас есть функция, возвращающая валюту регл. учета
ВалютаРеглУчета = ОбщиеМодули.УправлениеЗапасами.ПолучитьВалютуРегламентированногоУчета();
Запрос = Новый Запрос;
// &Валюта - это параметр, который мог выбрать пользователь в форме отчета
Запрос.УстановитьПараметр("Валюта", ПараметрыОтчета.Валюта);
Запрос.УстановитьПараметр("ВалютаРеглУчета", ВалютаРеглУчета);
Текст запроса будет выглядеть так:
ВЫБРАТЬ
ВЫБОР
КОГДА &Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
ТОГДА &ВалютаРеглУчета
ИНАЧЕ &Валюта
КОНЕЦ КАК ИтоговаяВалюта
// ... прочие поля запроса
Этот способ гораздо лучше, так как он отделяет логику получения значения по умолчанию от основного запроса. Мы явно контролируем, какая именно валюта будет использована. Однако проблема с СКД, которая проверяет параметры до выполнения, может остаться.
Это самый правильный, надежный и универсальный метод, который решает все перечисленные проблемы, включая корректную работу с СКД.
Основная идея: не усложнять запрос, а подготовить один-единственный параметр &Валюта так, чтобы он всегда был заполнен к моменту выполнения запроса. Вся логика по определению значения по умолчанию выносится в код 1С.
Рассмотрим, как это реализуется, например, в модуле отчета на СКД (для расширения возможностей подойдет пользовательская СКД).
Шаг 1. Определяем значение параметра.
В процедуре, которая выполняется перед формированием отчета (например, ПриКомпоновкеРезультата для СКД), мы проверяем, заполнено ли значение параметра, пришедшее от пользователя.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем текущие настройки отчета
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Находим наш параметр "Валюта"
ПараметрВалюта = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Валюта"));
// Проверяем, что параметр найден, доступен и не заполнен
Если ПараметрВалюта <> Неопределено И ПараметрВалюта.Использование И НЕ ЗначениеЗаполнено(ПараметрВалюта.Значение) Тогда
// Если валюта не выбрана, устанавливаем значение по умолчанию
ВалютаПоУмолчанию = Константы.ВалютаРегламентированногоУчета.Получить(); // Или другой способ получения
ПараметрВалюта.Значение = ВалютаПоУмолчанию;
КонецЕсли;
КонецПроцедуры
Шаг 2. Упрощаем запрос.
Поскольку теперь мы гарантируем, что параметр &Валюта всегда будет содержать корректное значение (либо выбранное пользователем, либо установленное нами по умолчанию), запрос становится максимально простым и читаемым. В нем больше не нужны конструкции ВЫБОР КОГДА.
ВЫБРАТЬ
Продажи.Номенклатура,
Продажи.СуммаВзаиморасчетов * ВЫРАЗИТЬ(&КурсВалюты КАК ЧИСЛО(10, 4)) КАК СуммаВВалютеОтчета,
&Валюта КАК ВалютаОтчета
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Валюта = &Валюта
Преимущества этого подхода:
В итоге, несмотря на то что задачу можно попытаться решить "в лоб" средствами языка запросов, правильный инженерный подход заключается в подготовке данных и параметров до выполнения основного запроса. Это делает код более чистым, надежным и простым в сопровождении.