При разработке нетиповых отчетов в 1С, которые строятся на прямых запросах к регистрам (без использования Системы компоновки данных), часто возникает задача исключить конкретную операцию или сумму из итогового результата. Например, когда необходимо убрать из отчета конкретное поступление на расчетный счет. Разберем по шагам, почему простые фильтры в запросе могут не работать и какими способами можно гарантированно скрыть ненужные данные.
Первое, что мы обычно пробуем — это добавить условие непосредственно в текст запроса. Рассмотрим пример кода, где мы пытаемся исключить сумму из оборотов по хозрасчетному регистру:
ИсклСумма = Новый Массив;
ИсклСумма.Добавить(10537829.89);
ТекстЗапроса = "ВЫБРАТЬ
| ХозрасчетныйОбороты.КорСчет,
| СУММА(ХозрасчетныйОбороты.СуммаОборотДт) КАК СуммаОборотДт,
| СУММА(ХозрасчетныйОбороты.СуммаОборотКт) КАК СуммаОборотКт,
| ХозрасчетныйОбороты.Субконто1 КАК Контрагент
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, , , , , , ) КАК ХозрасчетныйОбороты
|ГДЕ
| НЕ ХозрасчетныйОбороты.СуммаОборотДт В (&ИсклСумма)
|СГРУППИРОВАТЬ ПО
| ХозрасчетныйОбороты.КорСчет,
| ХозрасчетныйОбороты.Субконто1";
Проанализируем ситуацию: почему такой фильтр может не сработать? Виртуальная таблица Обороты возвращает уже сгруппированные данные. Если за один период было два разных документа с одинаковой суммой, они «схлопнутся», и условие ГДЕ может отработать некорректно по отношению к итоговой сумме группы.
Если данные в запросе агрегируются (используется СУММА), то фильтр нужно накладывать не в секции ГДЕ, а в секции ИМЕЮЩИЕ. Это позволит проверить уже рассчитанный результат суммы. Посмотрим на пример изменения запроса:
|ИМЕЮЩИЕ
| НЕ СУММА(ХозрасчетныйОбороты.СуммаОборотДт) В (&ИсклСумма)
Важно помнить, что прямое сравнение дробных чисел в запросах — это «тонкий» момент. Из-за особенностей хранения чисел с плавающей точкой в SQL-базах, число 10.00 может храниться как 10.000000001. Чтобы избежать проблем с точностью, рекомендуется использовать округление или проверку нахождения в очень узком диапазоне.
Фильтрация по сумме — крайне хрупкое решение. Если завтра придет другой платеж на ту же сумму, он тоже исчезнет из отчета, что приведет к ошибке в учете. Выясним причину, по которой опытные программисты предпочитают фильтровать по объекту: сумма может измениться, а ссылка на документ — нет.
Вместо того чтобы искать сумму, добавим в исключения конкретный документ (Регистратор). Для этого выполним следующие действия:
Регистратор в выборку запроса (если отчет детальный).ГДЕ.Рассмотрим пример реализации:
Запрос.Текст = "ВЫБРАТЬ
| ХозрасчетныйОбороты.Регистратор,
| ХозрасчетныйОбороты.СуммаОборотДт КАК Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(&НачПериода, &КонПериода, Регистратор, , , , , ) КАК ХозрасчетныйОбороты
|ГДЕ
| НЕ ХозрасчетныйОбороты.Регистратор В (&ИсклДокументы)";
Запрос.УстановитьПараметр("ИсклДокументы", МассивНужныхДокументов);
Этот метод гарантирует, что мы уберем именно ту операцию, которую планировали, даже если ее сумма в будущем будет отредактирована бухгалтером.
Если запрос слишком сложный или является частью типового механизма, который не хочется менять, можно «поймать» ненужную строку прямо в момент формирования печатной формы. Поскольку мы рассматриваем отчет «не на СКД», вывод данных обычно происходит в цикле Пока Выборка.Следующий().
Рассмотрим подробнее, как это реализовать в коде обработки:
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Проверяем условие исключения
Если Выборка.СуммаОборотДт = 10537829.89 Тогда
Продолжить; // Просто пропускаем итерацию и не выводим строку в табличный документ
КонецЕсли;
// Дальше идет стандартный код заполнения области макета
ОбластьСтрока.Параметры.Заполнить(Выборка);
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
Преимущество метода: вы полностью контролируете процесс вывода и можете добавить любую сложную логику проверки (например, проверку по комментарию, по дате или по специфическому реквизиту контрагента), которую тяжело описать в одном запросе.
Если вы применили условие, но сумма все равно остается в отчете, проанализируем ситуацию с помощью инструментов разработчика. Часто проблема кроется в том, что разработчик правит один запрос, а в отчет выводятся данные из другого (например, из временной таблицы или вложенного запроса).
Запрос.Выполнить(). Проверьте содержимое параметра ИсклСумма. Убедитесь, что тип данных в массиве совпадает с типом данных в базе (Число, а не Строка).ИТОГИ ПО ОБЩИЕ, помните, что фильтрация строк в ГДЕ влияет на итоги, а фильтрация в ИМЕЮЩИЕ — только на отображение групп. Если вы просто скрыли строку при выводе в ТабличныйДокумент, общая сумма итогов в подвале отчета сама не уменьшится — ее придется пересчитывать вручную.Резюмируем: наиболее правильным и архитектурно верным способом является исключение документа по ссылке (Регистратор) в самом запросе. Если же требуется быстрое решение «здесь и сейчас» для разовой задачи, условие Продолжить в цикле вывода выборки будет самым простым и наглядным вариантом.