Как в запросе 1С подставить валюту по умолчанию, если параметр не выбран?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет
← На главную

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

Исходная задача звучала так: если параметр &Валюта не заполнен (равен пустой ссылке), нужно подставить в запрос ссылку на «первый» элемент справочника «Валюты». Однако, как мы выясним, понятие «первый элемент» в 1С очень условно, и такой подход ненадежен. Правильнее использовать конкретное значение, например, основную валюту учета в системе.

Подход 1: Попытка получить "первый" элемент внутри запроса (не рекомендуется)

Первая мысль, которая может возникнуть, — решить все средствами языка запросов (в этом поможет консоль запросов). Например, создать временную таблицу, поместить в нее один элемент из справочника, а затем в основном запросе использовать его.

Проанализируем ситуацию. Понятие "первый элемент справочника" не является строгим. Порядок вывода элементов зависит от текущей сортировки (по коду, наименованию, внутреннему идентификатору) и может меняться. Сегодня первым может быть "руб.", а завтра, после добавления новой валюты, — "USD". Полагаться на такой порядок в бизнес-логике — плохая практика.

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


// Пакет 1: Выбираем первую по наименованию валюту и помещаем во временную таблицу
ВЫБРАТЬ ПЕРВЫЕ 1
    Валюты.Ссылка КАК Ссылка
ПОМЕСТИТЬ ВТ_ВалютаПоУмолчанию
ИЗ
    Справочник.Валюты КАК Валюты
УПОРЯДОЧИТЬ ПО
    Валюты.Наименование
;
//////////////////////////////////////////////////////////////////////////////////
// Пакет 2: Основной запрос, где мы используем данные из временной таблицы
ВЫБРАТЬ
    ВЫБОР
        КОГДА &Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
            ТОГДА ВТ_ВалютаПоУмолчанию.Ссылка
        ИНАЧЕ &Валюта
    КОНЕЦ КАК ИтоговаяВалюта
ИЗ
    ВТ_ВалютаПоУмолчанию КАК ВТ_ВалютаПоУмолчанию

Недостатки этого подхода:

  1. Ненадежность. Результат зависит от сортировки, что может привести к неожиданному поведению отчета.
  2. Производительность. Пакетный запрос с временной таблицей для получения одного значения является избыточным.
  3. Ошибка при пустом справочнике. Если справочник валют окажется пустым, первый запрос ничего не вернет, и второй запрос не выполнится, так как временная таблица будет пуста.
  4. Проблемы с СКД. Система компоновки данных анализирует параметры отчета до выполнения запроса. Если обязательный для других частей запроса параметр &Валюта не заполнен на уровне настроек СКД, система может выдать ошибку, даже не дойдя до выполнения нашей логики с ВЫБОР КОГДА.

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

Подход 2: Передача валюты по умолчанию вторым параметром

Более управляемый вариант — вычислить значение по умолчанию средствами языка 1С до выполнения запроса и передать его в запрос как отдельный параметр. Сам запрос при этом немного упрощается.

Разберем по шагам. Сначала мы на встроенном языке 1С получаем нужную нам валюту (например, валюту регламентированного учета), а затем передаем ее в запрос.

Пример кода на встроенном языке 1С:


// Допустим, у нас есть функция, возвращающая валюту регл. учета
ВалютаРеглУчета = ОбщиеМодули.УправлениеЗапасами.ПолучитьВалютуРегламентированногоУчета();

Запрос = Новый Запрос;
// &Валюта - это параметр, который мог выбрать пользователь в форме отчета
Запрос.УстановитьПараметр("Валюта", ПараметрыОтчета.Валюта); 
Запрос.УстановитьПараметр("ВалютаРеглУчета", ВалютаРеглУчета);

Текст запроса будет выглядеть так:


ВЫБРАТЬ
    ВЫБОР
        КОГДА &Валюта = ЗНАЧЕНИЕ(Справочник.Валюты.ПустаяСсылка)
            ТОГДА &ВалютаРеглУчета
        ИНАЧЕ &Валюта
    КОНЕЦ КАК ИтоговаяВалюта
    // ... прочие поля запроса

Этот способ гораздо лучше, так как он отделяет логику получения значения по умолчанию от основного запроса. Мы явно контролируем, какая именно валюта будет использована. Однако проблема с СКД, которая проверяет параметры до выполнения, может остаться.

Подход 3: Подготовка параметра до выполнения запроса (лучшая практика)

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

Основная идея: не усложнять запрос, а подготовить один-единственный параметр &Валюта так, чтобы он всегда был заполнен к моменту выполнения запроса. Вся логика по определению значения по умолчанию выносится в код 1С.

Рассмотрим, как это реализуется, например, в модуле отчета на СКД (для расширения возможностей подойдет пользовательская СКД).

Шаг 1. Определяем значение параметра.

В процедуре, которая выполняется перед формированием отчета (например, ПриКомпоновкеРезультата для СКД), мы проверяем, заполнено ли значение параметра, пришедшее от пользователя.


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

    // Получаем текущие настройки отчета
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();

    // Находим наш параметр "Валюта"
    ПараметрВалюта = Настройки.ПараметрыДанных.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Валюта"));

    // Проверяем, что параметр найден, доступен и не заполнен
    Если ПараметрВалюта <> Неопределено И ПараметрВалюта.Использование И НЕ ЗначениеЗаполнено(ПараметрВалюта.Значение) Тогда
        
        // Если валюта не выбрана, устанавливаем значение по умолчанию
        ВалютаПоУмолчанию = Константы.ВалютаРегламентированногоУчета.Получить(); // Или другой способ получения
        ПараметрВалюта.Значение = ВалютаПоУмолчанию;
        
    КонецЕсли;

КонецПроцедуры

Шаг 2. Упрощаем запрос.

Поскольку теперь мы гарантируем, что параметр &Валюта всегда будет содержать корректное значение (либо выбранное пользователем, либо установленное нами по умолчанию), запрос становится максимально простым и читаемым. В нем больше не нужны конструкции ВЫБОР КОГДА.


ВЫБРАТЬ
    Продажи.Номенклатура,
    Продажи.СуммаВзаиморасчетов * ВЫРАЗИТЬ(&КурсВалюты КАК ЧИСЛО(10, 4)) КАК СуммаВВалютеОтчета,
    &Валюта КАК ВалютаОтчета
ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Валюта = &Валюта

Преимущества этого подхода:

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

← На главную