При работе с механизмами бухгалтерского учета в 1С начинающие разработчики часто сталкиваются с трудностями при получении оборотов по счетам с детальной аналитикой (субконто). Типичная ситуация: требуется получить обороты между дебетом одного счета и кредитом другого (например, Дт 26 - Кт 71.01 или Дт 91.02 - Кт 71.01), ограничив выборку конкретной статьей затрат или прочих расходов. Если написать простой запрос без указания параметров аналитики, система вернет общую сумму по счетам, проигнорировав субконто.
В этой статье мы подробно разберем, как устроена виртуальная таблица ОборотыДтКт, почему важно правильно заполнять параметры субконто и как объединить несколько запросов в один оптимальный пакет для ускорения работы системы.
Проанализируем исходный запрос, который написал автор темы на форуме:
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК Наименование
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(&НачалаПериода, &КонецПериода, , СчетДт = &СчетДт26, , СчетКт = &СчетКт71, , ) КАК ХозрасчетныйОборотыДтКт"
В данном запросе параметры виртуальной таблицы переданы следующим образом:
СчетДт = &СчетДт26).СчетКт = &СчетКт71).При такой структуре запроса база данных вернет общий оборот между счетами 26 и 71 за указанный период, абсолютно игнорируя конкретную аналитику «Командировочные расходы». Нам необходимо переопределить параметры запроса, чтобы наложить жесткий фильтр на субконто дебета.
Для правильного наложения отбора по аналитике в виртуальной таблице ОборотыДтКт необходимо задействовать два взаимосвязанных параметра:
ПланВидовХарактеристикСсылка.ВидыСубконтоХозрасчетные). Например, для счетов затрат это будет СтатьиЗатрат, а для прочих доходов и расходов — ПрочиеДоходыИРасходы.СубконтоДт1, СубконтоДт2 и так далее.Важный нюанс позиционирования субконто: в плане счетов «Хозрасчетный» на разных счетах субконто могут располагаться на разных позициях. Например, на счете 26 («Общехозяйственные расходы») субконто СтатьиЗатрат обычно является первым (Субконто1). А на счете 20.01 («Основное производство») первым субконто идет Номенклатурные группы, а СтатьиЗатрат находятся на второй позиции (Субконто2).
Если мы передадим вид субконто СтатьиЗатрат в 3-й параметр (СубконтоДт), платформа 1С автоматически «поднимет» эту аналитику и сделает ее доступной в поле СубконтоДт1 в рамках этого запроса, независимо от того, на какой физической позиции (первой или второй) она находится на самом счете в плане счетов. Это избавляет разработчика от необходимости выяснять точный индекс субконто для каждого конкретного счета.
Рассмотрим подробнее, как должны выглядеть отборы для каждой из трех задач автора.
Задача 1: Счет Дт 26 Кт 71.01. Аналитика по Дт: Командировочные расходы
Для счета 26 аналитика «Командировочные расходы» хранится в справочнике СтатьиЗатрат. Вид субконто — ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.СтатьиЗатрат.
Запрос должен выглядеть следующим образом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт26,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.СтатьиЗатрат),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &КомандировочныеРасходы
| ) КАК ХозрасчетныйОборотыДтКт";
Запрос.УстановитьПараметр("НачалоПериода", Объект.НачалаПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(Объект.КонецПериода));
Запрос.УстановитьПараметр("СчетДт26", ПланыСчетов.Хозрасчетный.ОбщехозяйственныеРасходы);
// Рекомендуется искать конкретный субсчет 71.01 по коду, если его нет в предопределенных
Запрос.УстановитьПараметр("СчетКт71", ПланыСчетов.Хозрасчетный.НайтиПоКоду("71.01"));
Запрос.УстановитьПараметр("КомандировочныеРасходы", Объект.СтатьяКомандировочныеРасходы);
Задача 2: Счет Дт 91.02 Кт 71.01. Аналитика по Дт: Прочие внереализационные расходы
Для счета 91.02 аналитика ведется по субконто типа ПрочиеДоходыИРасходы. Вид субконто — ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы.
Исправленный вариант запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт91,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &ПрочиеРасходы
| ) КАК ХозрасчетныйОборотыДтКт";
Запрос.УстановитьПараметр("НачалоПериода", Объект.НачалаПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(Объект.КонецПериода));
Запрос.УстановитьПараметр("СчетДт91", ПланыСчетов.Хозрасчетный.ПрочиеРасходы);
Запрос.УстановитьПараметр("СчетКт71", ПланыСчетов.Хозрасчетный.НайтиПоКоду("71.01"));
Запрос.УстановитьПараметр("ПрочиеРасходы", Объект.СтатьяПрочиеРасходы);
Задача 3: Счет Дт 20.01 Кт 71.01. Аналитика по Дт: Командировочные расходы
Счет 20.01, как и счет 26, использует вид субконто СтатьиЗатрат. Несмотря на то, что в структуре счета 20.01 статьи затрат находятся на втором месте, благодаря указанию вида субконто в параметрах таблицы мы можем обращаться к нему через универсальное имя СубконтоДт1.
Код запроса будет выглядеть так:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт20,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.СтатьиЗатрат),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &КомандировочныеРасходы
| ) КАК ХозрасчетныйОборотыДтКт";
Запрос.УстановитьПараметр("НачалоПериода", Объект.НачалаПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(Объект.КонецПериода));
Запрос.УстановитьПараметр("СчетДт20", ПланыСчетов.Хозрасчетный.ОсновноеПроизводство);
Запрос.УстановитьПараметр("СчетКт71", ПланыСчетов.Хозрасчетный.НайтиПоКоду("71.01"));
Запрос.УстановитьПараметр("КомандировочныеРасходы", Объект.СтатьяКомандировочныеРасходы);
Выполнение трех отдельных запросов к базе данных последовательно — неоптимальная практика, которая создает избыточную нагрузку на СУБД. Проанализируем ситуацию: все данные выводятся в один макет. Мы можем объединить наши запросы с помощью конструкции ОБЪЕДИНИТЬ ВСЕ.
Чтобы при обработке результата мы понимали, к какому именно счету относится полученная сумма, добавим в запрос текстовое поле-идентификатор. Посмотрим на итоговый оптимизированный пример кода:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ""Дт 26 Кт 71.01"" КАК ИдентификаторСтроки,
| ХозрасчетныйОборотыДтКт.СуммаОборот КАК Сумма
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт26,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.СтатьиЗатрат),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &КомандировочныеРасходы
| ) КАК ХозрасчетныйОборотыДтКт
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ""Дт 91.02 Кт 71.01"",
| ХозрасчетныйОборотыДтКт.СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт91,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.ПрочиеДоходыИРасходы),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &ПрочиеРасходы
| ) КАК ХозрасчетныйОборотыДтКт
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| ""Дт 20.01 Кт 71.01"",
| ХозрасчетныйОборотыДтКт.СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(
| &НачалоПериода,
| &КонецПериода,
| ,
| СчетДт = &СчетДт20,
| ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.СтатьиЗатрат),
| СчетКт = &СчетКт71,
| ,
| СубконтоДт1 = &КомандировочныеРасходы
| ) КАК ХозрасчетныйОборотыДтКт";
// Установка общих параметров
Запрос.УстановитьПараметр("НачалоПериода", Объект.НачалаПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецДня(Объект.КонецПериода));
// Установка параметров счетов
Запрос.УстановитьПараметр("СчетДт26", ПланыСчетов.Хозрасчетный.ОбщехозяйственныеРасходы);
Запрос.УстановитьПараметр("СчетДт20", ПланыСчетов.Хозрасчетный.ОсновноеПроизводство);
Запрос.УстановитьПараметр("СчетДт91", ПланыСчетов.Хозрасчетный.ПрочиеРасходы);
Запрос.УстановитьПараметр("СчетКт71", ПланыСчетов.Хозрасчетный.НайтиПоКоду("71.01"));
// Установка параметров аналитик (ссылки на элементы справочников)
Запрос.УстановитьПараметр("КомандировочныеРасходы", Объект.СтатьяКомандировочныеРасходы);
Запрос.УстановитьПараметр("ПрочиеРасходы", Объект.СтатьяПрочиеРасходы);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Здесь мы можем выводить данные в макет,
// ориентируясь на поле Выборка.ИдентификаторСтроки
Если Выборка.ИдентификаторСтроки = "Дт 26 Кт 71.01" Тогда
// Код вывода для первого условия
ИначеЕсли Выборка.ИдентификаторСтроки = "Дт 91.02 Кт 71.01" Тогда
// Код вывода для второго условия
ИначеЕсли Выборка.ИдентификаторСтроки = "Дт 20.01 Кт 71.01" Тогда
// Код вывода для третьего условия
КонецЕсли;
КонецЦикла;
Использование единого пакетного запроса позволяет выполнить все расчеты на стороне СУБД за одно обращение. Это значительно повышает производительность отчета, особенно при работе в клиент-серверном варианте базы данных.