При работе с регистрами бухгалтерии в 1С разработчики часто сталкиваются с необходимостью построения сложных выборок. Типичная задача — получить обороты между определенными счетами дебета и кредита, когда в качестве условий выступает не один конкретный счет, а целый список (группа) счетов. Например, нам нужно проанализировать дебетовые обороты по счету 08 в корреспонденции со счетами 60 и 76, включая все их субсчета.
В рамках этой статьи мы подробно разберем, как правильно составить такой запрос, как передать массив счетов в параметры виртуальной таблицы с использованием оператора В ИЕРАРХИИ, как избежать типичных ошибок при заполнении массива параметров и как программно получить счета, созданные пользователями в режиме «1С:Предприятие».
Представим ситуацию: нам необходимо получить данные из виртуальной таблицы РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт. Условия отбора следующие:
08.05 или пользовательскому субсчету 08.11.2).60 («Расчеты с поставщиками и подрядчиками») или 76 («Расчеты с разными дебиторами и кредиторами») со всеми их внутренними субсчетами.Рассмотрим по шагам, как реализовать этот алгоритм правильно, производительно и без ошибок.
Когда требуется наложить фильтр на группу счетов и все входящие в нее субсчета, стандартное равенство = не подходит. Нам необходимо использовать оператор В ИЕРАРХИИ. Этот оператор принимает на вход как одиночное значение (родительский счет), так и список значений или массив.
Для передачи нескольких независимых групп счетов (в нашем случае это и 60, и 76) мы должны предварительно собрать их в один массив в коде встроенного языка и передать этот массив в качестве параметра запроса.
Проанализируем типичную ошибку начинающих разработчиков при заполнении массива:
// ОШИБОЧНЫЙ КОД!
мМассив = Новый Массив;
мМассив.Добавить("СчетКт76", ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами);
мМассив.Добавить("СчетКт60", ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками);
Выясним причину ошибки. Метод Добавить() у объекта Массив принимает только один параметр — добавляемое значение. Попытка передать туда два параметра (строковый ключ и саму ссылку на счет) приведет к ошибке компиляции или неправильному поведению кода. Массив в 1С — это индексированная коллекция, а не структура "ключ-значение". Чтобы собрать счета, мы должны добавлять в массив исключительно ссылки на элементы плана счетов:
// ПРАВИЛЬНЫЙ КОД
мСчетаКт = Новый Массив;
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами);
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками);
Обратим внимание на важную деталь. В типовых конфигурациях 1С (например, в «Бухгалтерии предприятия») предопределенный элемент ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками соответствует конкретному субсчету 60.01, а не всей группе счетов 60.
Если мы добавим в массив только субсчет 60.01, то конструкция В ИЕРАРХИИ выберет только его (и его подчиненные субсчета, если бы они были). При этом обороты по субсчетам авансов (60.02), расчетов в валюте (60.21) и другим субсчетам счета 60 не попадут в отчет. Это частая причина, почему запрос возвращает пустой результат или заниженные суммы.
Чтобы получить абсолютно весь счет 60 целиком со всеми его субсчетами, нам нужно обращаться к предопределенному элементу, который является родителем всей группы. В плане счетов «Хозрасчетный» этот предопределенный элемент называется РасчетыСПоставщикамиИПодрядчиками. Посмотрим на правильное сопоставление:
ПланыСчетов.Хозрасчетный.РасчетыСПоставщикамиИПодрядчикамиПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторамиИспользуя эти предопределенные элементы в массиве, мы гарантируем корректный отбор по всей иерархии счетов кредита.
Иногда перед разработчиком встает задача сделать отбор по счету, которого нет в конфигураторе (например, бухгалтер вручную создал в режиме Предприятие субсчет 08.11.2). Мы не можем обратиться к нему напрямую через точку от объекта ПланыСчетов.Хозрасчетный, так как этого свойства физически не существует в метаданных.
Для решения этой проблемы мы должны использовать метод менеджера плана счетов НайтиПоКоду(). Разберем по шагам, как это сделать правильно и безопасно:
// Получаем счет по его коду в информационной базе
СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");
Важное предупреждение о безопасности! Метод НайтиПоКоду() осуществляет поиск по текстовому соответствию. Если пользователь случайно удалит этот счет, переименует его код или база данных будет пустой, метод вернет пустую ссылку (ПланыСчетов.Хозрасчетный.ПустаяСсылка()), не вызывая ошибку выполнения кода.
Если мы передадим пустую ссылку в параметры виртуальной таблицы с оператором В ИЕРАРХИИ, это может привести к двум критическим проблемам:
Поэтому перед установкой параметров запроса всегда необходимо выполнять проверку на заполненность счета:
СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");
Если СчетДт08.Пустая() Тогда
ВызватьИсключение "Внимание! В плане счетов не найден обязательный счет 08.11.2. Выполнение запроса невозможно.";
КонецЕсли;
При написании запросов к бухгалтерским регистрам критически важно накладывать условия фильтрации (по счетам, организациям, субконто) непосредственно в параметрах виртуальной таблицы, а не в секции ГДЕ. Фильтрация в параметрах заставляет СУБД отсекать ненужные записи еще на этапе сборки временных таблиц, что многократно повышает скорость работы системы.
Проанализируем итоговый текст запроса и правильное заполнение его параметров:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.Регистратор КАК Док,
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК Значение
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| Регистратор,
| СчетДт = &СчетДт08,
| ,
| СчетКт В ИЕРАРХИИ (&МассивСчетовКт),
| ,
| Организация = &Организация
| ) КАК ХозрасчетныйОборотыДтКт";
Обратите внимание на синтаксис параметров виртуальной таблицы ОборотыДтКт:
НачалоПериодаКонецПериодаПериодичность (мы выбрали Регистратор для детального анализа по документам)УсловиеДт (передаем конкретный счет дебета &СчетДт08)СубконтоДт (пропускаем, оставляя пустое место между запятыми)УсловиеКт (передаем наш массив счетов кредита через В ИЕРАРХИИ (&МассивСчетовКт))СубконтоКт (пропускаем)Условие (накладываем фильтр по организации Организация = &Организация)Объединим все наши шаги в один готовый и отказоустойчивый блок кода, который можно использовать во внешних отчетах или обработках:
// 1. Инициализируем запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.Регистратор КАК Док,
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК Значение
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| Регистратор,
| СчетДт = &СчетДт08,
| ,
| СчетКт В ИЕРАРХИИ (&МассивСчетовКт),
| ,
| Организация = &Организация
| ) КАК ХозрасчетныйОборотыДтКт";
// 2. Устанавливаем базовые параметры периода и организации
// Важно избегать опечаток в именах переменных (например, "НачалаПериода")
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(КонецПериода));
Запрос.УстановитьПараметр("Организация", Организация);
// 3. Получаем счет дебета (в том числе пользовательский) и проверяем его
СчетДт08 = ПланыСчетов.Хозрасчетный.НайтиПоКоду("08.11.2");
Если СчетДт08.Пустая() Тогда
// Если пользовательский счет не найден, пробуем взять предопределенный по умолчанию
СчетДт08 = ПланыСчетов.Хозрасчетный.ПриобретениеНематериальныхАктивов;
КонецЕсли;
Запрос.УстановитьПараметр("СчетДт08", СчетДт08);
// 4. Формируем массив родительских групп счетов для Кт
мСчетаКт = Новый Массив;
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСПоставщикамиИПодрядчиками); // Группа 60
мСчетаКт.Добавить(ПланыСчетов.Хозрасчетный.РасчетыСРазнымиДебиторамиИКредиторами); // Группа 76
Запрос.УстановитьПараметр("МассивСчетовКт", мСчетаКт);
// 5. Выполняем запрос и выгружаем результат
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();
Если после выполнения правильного кода вы все равно обнаружили, что в результате запроса нет сумм по кредиту (поле Значение пустое), проанализируем возможные бухгалтерские причины этой ситуации:
ОборотыДтКт анализирует исключительно двойную запись (проводки). Если по дебету счета 08 были обороты, это не означает автоматически, что они пришли с кредита 60 или 76. Счет 08 мог дебетоваться в корреспонденции со счетами 10 («Материалы»), 70 («Расчеты с персоналом по оплате труда») или 08.03 («Строительство объектов ОС»). Проверьте корреспонденцию счетов с помощью стандартного бухгалтерского отчета «Отчет по проводкам» или «Анализ счета 08».Неопределено из-за опечаток в коде.Применяя данные правила на практике, вы сможете строить гибкие, быстродействующие и устойчивые к изменениям структуры планов счетов запросы в любых прикладных решениях на платформе 1С:Предприятие. А для контроля корректности данных и поиска ошибок в учете после доработки алгоритмов удобно использовать инструмент для автоматической сверки бухгалтерских и налоговых проводок между информационными базами.