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