Как настроить отбор по контрагенту в произвольном отчете 1С и устранить ошибку неверных параметров в запросе

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

При доработке нетиповых отчетов, созданных без использования Системы компоновки данных (СКД), часто возникает задача предоставить пользователю возможность гибкой фильтрации данных (например, исключить определенный список контрагентов). В процессе реализации разработчики нередко сталкиваются с двумя распространенными проблемами: пользовательский отбор в объекте ПостроительОтчета не влияет на результат выборки, а при попытке переписать запрос возникает ошибка вида «Неверные параметры "-"». Разберем по шагам причины такого поведения платформы 1С и рассмотрим надежные варианты решения.

Причины некорректной работы отбора в объекте ПостроительОтчета

Проанализируем типичную ситуацию: на форму выведено табличное поле с типом данных Отбор, связанное с реквизитом Построитель (тип ПостроительОтчета). Пользователь интерактивно указывает условие (например, Контрагент Не в списке), однако отчет все равно формируется по всем записям без учета фильтра.

Выясним причину такого поведения:

  1. Сброс настроек при повторной установке текста запроса: Если в обработчике формирования отчета выполняется присвоение свойства Построитель.Текст = Запрос.Текст, коллекция Построитель.Отбор полностью сбрасывается и переинициализируется исходными значениями. Все параметры, флаги использования и значения, которые пользователь установил на форме до нажатия кнопки формирования, при этом стираются.
  2. Несоответствие описания полей в секции расширения языка запросов: Для того чтобы построитель мог автоматически наложить фильтр на нужную таблицу, в тексте запроса должны быть корректно описаны поля в фигурных скобках {ГДЕ ...}. Например, синтаксис {(Контрагент).* КАК Контрагент} в параметрах виртуальной таблицы или {ГДЕ Контрагент.*} в основном запросе.
  3. Выполнение запроса в обход построителя: Если в коде сначала вызывается Запрос.Выполнить(), а затем данные выводятся вручную, построитель никак не участвует в фильтрации. Для применения условий построителя необходимо либо использовать метод Построитель.Выполнить() с последующей выборкой Построитель.Результат.Выбрать(), либо применять специализированный объект ПостроительЗапроса.

Вариант 1. Корректная инициализация и применение Построителя отчета

Рассмотрим, как правильно организовать работу с объектом ПостроительОтчета, чтобы пользовательские отборы не затирались при формировании данных.

Текст запроса с секциями отбора должен задаваться построителю один раз при инициализации формы. В обработчике открытия вызывается метод ЗаполнитьНастройки(), который формирует доступный список полей на форме:


Процедура ПриОткрытии()
    
    // Задаем основной текст запроса с секцией расширения построителя {ГДЕ ...}
    Построитель.Текст日益 = 
    "ВЫБРАТЬ
    |    Взаиморасчеты.Контрагент КАК Контрагент,
    |    Взаиморасчеты.ДоговорКонтрагента КАК ДоговорКонтрагента,
    |    Взаиморасчеты.СуммаВзаиморасчетовОстаток КАК ОстатокДолга
    |ИЗ
    |    РегистрНакопления.ВзаиморасчетыСКонтрагентами.Остатки(&Период, ) КАК Взаиморасчеты
    |{ГДЕ
    |    Взаиморасчеты.Контрагент.* КАК Контрагент,
    |    Взаиморасчеты.ДоговорКонтрагента.* КАК ДоговорКонтрагента}";
    
    // Заполняем состав доступных настроек
    Построитель.ЗаполнитьНастройки();
    
КонецПроцедуры

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


Процедура СформироватьОтчет()
    
    // Заполняем параметры построителя
    Построитель.Параметры.Вставить("Период", КонецДня(ДатаОтчета));
    
    // Выполняем построитель с учетом наложенных пользователем отборов
    Построитель.Выполнить();
    Выборка = Построитель.Результат.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        // Обработка и вывод данных в отчет
    КонецЦикла;
    
КонецПроцедуры

Вариант 2. Фильтрация через параметр запроса и список исключений

Если задача заключается исключительно в том, чтобы исключить список контрагентов-взаимозачетчиков, можно отказаться от механизма построителя и реализовать отбор напрямую через параметры обычного объекта Запрос.

Разберем реализацию: разместим на форме отчета реквизит СписокИсключений с типом данных СписокЗначений. В тексте запроса добавим проверку условия вхождения:


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

Запрос.УстановитьПараметр("ДатаОтчета", КонецДня(ДатаДолга));
Запрос.УстановитьПараметр("СписокИсключений", СписокИсключений);
Запрос.УстановитьПараметр("ИспользоватьИсключения", СписокИсключений.Количество() > 0);

РезультатЗапроса = Запрос.Выполнить();

Такой подход упрощает программный код, делает поведение формы предсказуемым и избавляет от необходимости синхронизировать свойства табличного поля с коллекцией отборов построителя.

Устранение ошибки «Неверные параметры "-"» при вычислениях в запросе

Рассмотрим вторую проблему, возникающую при выполнении запросов с временными таблицами: сообщение об ошибке {(..., ...)}: Неверные параметры "-" в строке с вычислением разности дат и числовых полей.

Посмотрим на пример выражения, вызывающего ошибку:


ГДЕ
    РАЗНОСТЬДАТ(КОНЕЦПЕРИОДА(ВтДолги.Период, ДЕНЬ), КОНЕЦПЕРИОДА(&ДатаОтчета, ДЕНЬ), ДЕНЬ) - ВтДолги.ДопустимоеЧислоДнейЗадолженности >= -3

Выясним причину: во временной таблице поле ДопустимоеЧислоДнейЗадолженности формировалось с помощью конструкции ВЫБОР КОГДА ... ТОГДА ... ИНАЧЕ ... КОНЕЦ. В платформе 1С результирующее поле условной конструкции во временной таблице может получить составной или неопределенный тип данных, если значение одного из реквизитов не заполнено, возвращает NULL или параметр &ЧислоДнейПоУмолчанию не имеет строго зафиксированного типа.

СУБД не может применить арифметическую операцию вычитания (-) к нетипизированной колонке. Для устранения ошибки применим явное приведение типов с помощью функции ВЫРАЗИТЬ и обработаем возможные пустые значения через ЕСТЬNULL.

Разберем по шагам правильное формирование поля во временной таблице:


ВЫБРАТЬ
    ВтВзаиморасчеты.Период КАК Период,
    ВтВзаиморасчеты.Контрагент КАК Контрагент,
    ВЫРАЗИТЬ(
        ВЫБОР
            КОГДА ЕСТЬNULL(ВтВзаиморасчеты.ДоговорКонтрагента.Дней, 0) > 0
                ТОГДА ВтВзаиморасчеты.ДоговорКонтрагента.Дней
            ИНАЧЕ &ЧислоДнейПоУмолчанию
        КОНЕЦ КАК ЧИСЛО(10, 0)
    ) КАК ДопустимоеЧислоДнейЗадолженности
ПОМЕСТИТЬ ВтДолгиПоДокументам
ИЗ
    ВтВзаиморасчеты КАК ВтВзаиморасчеты
;

После явного указания типа ЧИСЛО(10, 0) в секции формирования временной таблицы арифметические операции в последующих пакетах запроса и условиях ГДЕ будут выполняться без ошибок.

← На главную