При разработке произвольных отчетов в 1С:Бухгалтерия 8.3 часто возникает необходимость отфильтровать данные по конкретным счетам или их группам. Одной из типичных задач является исключение определенного субсчета (например, 50.04 "Касса по деятельности платежного агента") так, чтобы он не попадал в общие обороты. В этой статье мы подробно рассмотрим, как правильно реализовать такое исключение на уровне программного кода и запроса, чтобы отчет работал корректно и быстро.
Рассмотрим ситуацию, когда отчет собирает данные по кассе (счет 50), но специфика учета требует скрыть обороты по валютным операциям или деятельности агентов, закрепленных за счетом 50.04. Мы разберем несколько подходов: от простых проверок в цикле до оптимизированных запросов к виртуальным таблицам регистра бухгалтерии.
Проанализируем самый распространенный подход: когда перед выполнением запроса программист программно формирует массив или список значений со счетами. Если мы используем выборку из плана счетов, мы можем поставить условие пропуска ненужных элементов непосредственно в цикле.
Часто разработчики совершают ошибку, пытаясь просто сравнить код счета со строкой "50.04". Однако это не учитывает иерархию (если у счета 50.04 появятся свои субсчета). Рассмотрим правильный алгоритм с проверкой вложенности:
// Подготовим список исключений
СписокИсключений = Новый СписокЗначений;
СписокИсключений.Добавить(ПланыСчетов.Хозрасчетный.НайтиПоКоду("50.04"));
// Получаем выборку по всему 50 счету
СчетаВыборка = ПланыСчетов.Хозрасчетный.ВыбратьИерархически(ПланыСчетов.Хозрасчетный.НайтиПоКоду("50"));
КорСчетаДляЗапроса = Новый СписокЗначений;
Пока СчетаВыборка.Следующий() Цикл
// Проверим, не является ли текущий счет нашим исключением 50.04
// или его подчиненным субсчетом
Если СчетаВыборка.Ссылка = ПланыСчетов.Хозрасчетный.НайтиПоКоду("50.04") Тогда
Продолжить; // Пропускаем сам счет
КонецЕсли;
// Более надежный метод - использование функции Принадлежит()
Если СчетаВыборка.Ссылка.Принадлежит(ПланыСчетов.Хозрасчетный.НайтиПоКоду("50.04")) Тогда
Продолжить; // Пропускаем все субсчета 50.04.1, 50.04.2 и т.д.
КонецЕсли;
КорСчетаДляЗапроса.Добавить(СчетаВыборка.Ссылка);
КонецЦикла;
Выясним причину, почему метод Принадлежит() предпочтительнее простого сравнения кодов. Строковое сравнение Код = "50.04" крайне хрупкое: если пользователь изменит код в режиме "Предприятие" или добавит субсчета, логика сломается. Метод Принадлежит() работает с объектными ссылками и учитывает всю иерархию плана счетов, что делает код устойчивым к изменениям данных.
Теперь рассмотрим более профессиональный и производительный метод — фильтрацию данных непосредственно внутри запроса. В 1С:Предприятие 8 работа с бухгалтерскими итогами ведется через виртуальные таблицы (например, Хозрасчетный.Обороты). Самая частая ошибка — накладывать фильтр в секции ГДЕ. Это заставляет систему сначала прочитать все данные, а потом отсеивать их.
Проанализируем, как правильно передать условия в параметры виртуальной таблицы. Это позволит СУБД выполнить фильтрацию на самом раннем этапе. Посмотрим на пример кода запроса:
ТекстЗапроса =
"ВЫБРАТЬ
| ХозрасчетныйОбороты.КорСчет КАК КорСчет,
| ХозрасчетныйОбороты.СуммаОборотДт КАК СуммаОборотДт,
| ХозрасчетныйОбороты.СуммаОборотКт КАК СуммаОборотКт
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(
| &НачПериода,
| &КонПериода,
| ,
| Счет В ИЕРАРХИИ (&Счет),
| ,
| ,
| КорСчет В (&КорСчета) И НЕ КорСчет В ИЕРАРХИИ (&ИсключаемыйСчет),
| ) КАК ХозрасчетныйОбороты";
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("НачПериода", ДатаНачала);
Запрос.УстановитьПараметр("КонПериода", ДатаКонца);
Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.НайтиПоКоду("62")); // Пример
Запрос.УстановитьПараметр("КорСчета", КорСчетаДляЗапроса);
Запрос.УстановитьПараметр("ИсключаемыйСчет", ПланыСчетов.Хозрасчетный.НайтиПоКоду("50.04"));
Обратите внимание на конструкцию НЕ КорСчет В ИЕРАРХИИ (&ИсключаемыйСчет). Оператор В ИЕРАРХИИ — это мощный инструмент, который автоматически включает в проверку не только указанный счет, но и все его вложенные субсчета любой глубины. Если мы просто напишем <> &ИсключаемыйСчет, то субсчета вида 50.04.1 все равно попадут в отчет.
Разберем несколько критически важных моментов, которые помогут избежать ошибок при разработке:
НайтиПоКоду("50.04") в коде допустимо, но лучше использовать предопределенные счета, если они созданы в конфигураторе. Например: ПланыСчетов.Хозрасчетный.Касса. Если счет 50.04 не является предопределенным, лучше вынести его выбор в настройки отчета или на форму, чтобы пользователь сам мог указать, что именно исключать.НайтиПоКоду вернет ПустаяСсылка, запрос может отработать непредсказуемо или выдать ошибку.Счет Кор. Не в иерархии 50.04. Это самый гибкий метод, который позволяет конечному пользователю управлять видимостью данных без помощи программиста.Рассмотрим ситуацию из практики: разработчик пишет ГДЕ НЕ ХозрасчетныйОбороты.Счет В (&СписокИскл), но счет 50.04 всё равно выводится. Почему так происходит?
Проанализируем структуру данных: в регистрах бухгалтерии есть Счет (основной счет проводки) и КорСчет (корреспондирующий). Если вы строите отчёт по Дт 62 - Кт 50, то счет 50 будет являться КорСчетом. Следовательно, фильтр нужно накладывать именно на поле КорСчет. В сообщениях форума часто путают эти поля, что приводит к отсутствию результата при фильтрации.
Посмотрим на пример правильного комбинированного фильтра в параметрах виртуальной таблицы:
// В параметрах Обороты:
// 4-й параметр: Условие на Счет
// 7-й параметр: Условие на КорСчет
// Пример исключения из КорСчета:
(КорСчет В (&Весь50Счет) И НЕ КорСчет В ИЕРАРХИИ (&Счет50_04))
Таким образом, мы гарантируем, что система сначала выберет все движения по кассе, а затем "вычтет" из них те, что относятся к специфическому субсчету 50.04. Сочетание программной подготовки списка счетов и грамотного использования параметров виртуальных таблиц запроса обеспечивает максимальную надежность и скорость работы вашего отчета в 1С:Бухгалтерии.