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

Программист 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При работе с регистрами бухгалтерии в 1С разработчики часто сталкиваются с необходимостью построения сложных выборок. Типичная задача — получить обороты между определенными счетами дебета и кредита, когда в качестве условий выступает не один конкретный счет, а целый список (группа) счетов. Например, нам нужно проанализировать дебетовые обороты по счету 08 в корреспонденции со счетами 60 и 76, включая все их субсчета.

В рамках этой статьи мы подробно разберем, как правильно составить такой запрос, как передать массив счетов в параметры виртуальной таблицы с использованием оператора В ИЕРАРХИИ, как избежать типичных ошибок при заполнении массива параметров и как программно получить счета, созданные пользователями в режиме «1С:Предприятие».

Постановка задачи и анализ исходных данных

Представим ситуацию: нам необходимо получить данные из виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт. Условия отбора следующие:

  1. Счет дебета (Дт) должен быть равен конкретному счету учета вложений во внеоборотные активы (например, 08.05 или пользовательскому субсчету 08.11.2).
  2. Счет кредита (Кт) должен принадлежать группам счетов 60 («Расчеты с поставщиками и подрядчиками») или 76 («Расчеты с разными дебиторами и кредиторами») со всеми их внутренними субсчетами.

Рассмотрим по шагам, как реализовать этот алгоритм правильно, производительно и без ошибок.

Шаг 1. Передача списка счетов в параметры запроса с оператором В ИЕРАРХИИ

Когда требуется наложить фильтр на группу счетов и все входящие в нее субсчета, стандартное равенство = не подходит. Нам необходимо использовать оператор В ИЕРАРХИИ. Этот оператор принимает на вход как одиночное значение (родительский счет), так и список значений или массив.

Для передачи нескольких независимых групп счетов (в нашем случае это и 60, и 76) мы должны предварительно собрать их в один массив в коде встроенного языка и передать этот массив в качестве параметра запроса.

Проанализируем типичную ошибку начинающих разработчиков при заполнении массива:


// ОШИБОЧНЫЙ КОД!
мМассив = Новый Массив;
мМассив.Добавить("СчетКт76", ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами);
мМассив.Добавить("СчетКт60", ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками);

Выясним причину ошибки. Метод Добавить() у объекта Массив принимает только один параметр — добавляемое значение. Попытка передать туда два параметра (строковый ключ и саму ссылку на счет) приведет к ошибке компиляции или неправильному поведению кода. Массив в 1С — это индексированная коллекция, а не структура "ключ-значение". Чтобы собрать счета, мы должны добавлять в массив исключительно ссылки на элементы плана счетов:


// ПРАВИЛЬНЫЙ КОД
мСчетаКт = Новый Массив;
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами);
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками);

Шаг 2. Разница между конкретным субсчетом и группой счетов

Обратим внимание на важную деталь. В типовых конфигурациях 1С (например, в «Бухгалтерии предприятия») предопределенный элемент ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками соответствует конкретному субсчету 60.01, а не всей группе счетов 60.

Если мы добавим в массив только субсчет 60.01, то конструкция В ИЕРАРХИИ выберет только его (и его подчиненные субсчета, если бы они были). При этом обороты по субсчетам авансов (60.02), расчетов в валюте (60.21) и другим субсчетам счета 60 не попадут в отчет. Это частая причина, почему запрос возвращает пустой результат или заниженные суммы.

Чтобы получить абсолютно весь счет 60 целиком со всеми его субсчетами, нам нужно обращаться к предопределенному элементу, который является родителем всей группы. В плане счетов «Хозрасчетный» этот предопределенный элемент называется РасчетыСПоставщикамиИПодрядчиками. Посмотрим на правильное сопоставление:

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

Шаг 3. Как получить счет, созданный пользователем (непредопределенный счет)

Иногда перед разработчиком встает задача сделать отбор по счету, которого нет в конфигураторе (например, бухгалтер вручную создал в режиме Предприятие субсчет 08.11.2). Мы не можем обратиться к нему напрямую через точку от объекта ПланыСчетов.Хозрасчетный, так как этого свойства физически не существует в метаданных.

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


// Получаем счет по его коду в информационной базе
СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");

Важное предупреждение о безопасности! Метод НайтиПоКоду() осуществляет поиск по текстовому соответствию. Если пользователь случайно удалит этот счет, переименует его код или база данных будет пустой, метод вернет пустую ссылку (ПланыСчетов.Хозрасчетный.ПустаяСсылка()), не вызывая ошибку выполнения кода.

Если мы передадим пустую ссылку в параметры виртуальной таблицы с оператором В ИЕРАРХИИ, это может привести к двум критическим проблемам:

  1. Запрос вернет пустой результат (так как иерархия для пустой ссылки не определена).
  2. В худшем случае СУБД начнет интерпретировать пустую ссылку как корень всей иерархии плана счетов, что приведет к колоссальной нагрузке на сервер и зависанию системы.

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


СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");

Если СчетДт08.Пустая() Тогда
    ВызватьИсключение "Внимание! В плане счетов не найден обязательный счет 08.11.2. Выполнение запроса невозможно.";
КонецЕсли;

Шаг 4. Оптимальное построение запроса к виртуальной таблице

При написании запросов к бухгалтерским регистрам критически важно накладывать условия фильтрации (по счетам, организациям, субконто) непосредственно в параметрах виртуальной таблицы, а не в секции ГДЕ. Фильтрация в параметрах заставляет СУБД отсекать ненужные записи еще на этапе сборки временных таблиц, что многократно повышает скорость работы системы.

Проанализируем итоговый текст запроса и правильное заполнение его параметров:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ХозрасчетныйОборотыДтКт.Регистратор КАК Док,
    |	ХозрасчетныйОборотыДтКт.СуммаОборот КАК Значение
    |ИЗ
    |	РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
    |		&НачалоПериода, 
    |		&КонецПериода, 
    |		Регистратор, 
    |		СчетДт = &СчетДт08, 
    |		, 
    |		СчетКт В ИЕРАРХИИ (&МассивСчетовКт), 
    |		, 
    |		Организация = &Организация
    |	) КАК ХозрасчетныйОборотыДтКт";

Обратите внимание на синтаксис параметров виртуальной таблицы ОборотыДтКт:

Полный рабочий пример кода

Объединим все наши шаги в один готовый и отказоустойчивый блок кода, который можно использовать во внешних отчетах или обработках:


// 1. Инициализируем запрос
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ХозрасчетныйОборотыДтКт.Регистратор КАК Док,
    |	ХозрасчетныйОборотыДтКт.СуммаОборот КАК Значение
    |ИЗ
    |	РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
    |		&НачалоПериода, 
    |		&КонецПериода, 
    |		Регистратор, 
    |		СчетДт = &СчетДт08, 
    |		, 
    |		СчетКт В ИЕРАРХИИ (&МассивСчетовКт), 
    |		, 
    |		Организация = &Организация
    |	) КАК ХозрасчетныйОборотыДтКт";

// 2. Устанавливаем базовые параметры периода и организации
// Важно избегать опечаток в именах переменных (например, "НачалаПериода")
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Запрос.УстановитьПараметр("Организация", Организация);

// 3. Получаем счет дебета (в том числе пользовательский) и проверяем его
СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");
Если СчетДт08.Пустая() Тогда
    // Если пользовательский счет не найден, пробуем взять предопределенный по умолчанию
    СчетДт08 = ПланыСчетов.Хозрасчетный.ПриобретениеНематериальныхАктивов;
КонецЕсли;
Запрос.УстановитьПараметр("СчетДт08", СчетДт08);

// 4. Формируем массив родительских групп счетов для Кт
мСчетаКт = Новый Массив;
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСПоставщикамиИПодрядчиками); // Группа 60
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами); // Группа 76

Запрос.УстановитьПараметр("МассивСчетовКт", мСчетаКт);

// 5. Выполняем запрос и выгружаем результат
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();

Почему в отчете могут отсутствовать суммы по кредиту?

Если после выполнения правильного кода вы все равно обнаружили, что в результате запроса нет сумм по кредиту (поле Значение пустое), проанализируем возможные бухгалтерские причины этой ситуации:

  1. Отсутствие прямой корреспонденции. Виртуальная таблица ОборотыДтКт анализирует исключительно двойную запись (проводки). Если по дебету счета 08 были обороты, это не означает автоматически, что они пришли с кредита 60 или 76. Счет 08 мог дебетоваться в корреспонденции со счетами 10 («Материалы»), 70 («Расчеты с персоналом по оплате труда») или 08.03 («Строительство объектов ОС»). Проверьте корреспонденцию счетов с помощью стандартного бухгалтерского отчета «Отчет по проводкам» или «Анализ счета 08».
  2. Неверно заполненные параметры периода. Проверьте, чтобы дата начала периода была меньше или равна дате конца периода, а сами переменные не содержали значения Неопределено из-за опечаток в коде.

Применяя данные правила на практике, вы сможете строить гибкие, быстродействующие и устойчивые к изменениям структуры планов счетов запросы в любых прикладных решениях на платформе 1С:Предприятие. А для контроля корректности данных и поиска ошибок в учете после доработки алгоритмов удобно использовать инструмент для автоматической сверки бухгалтерских и налоговых проводок между информационными базами.

← На главную