При разработке отчетов по основным средствам (ОС) программисты часто сталкиваются с задачей вывода балансовой стоимости и накопленной амортизации на конец каждого месяца за определенный период. Казалось бы, для этого идеально подходит виртуальная таблица РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты с периодичностью Месяц. Однако при построении такого запроса за большой интервал времени обнаруживается неприятная особенность: за те месяцы, в которых по основному средству не было никаких движений (оборотов), данные в отчет вообще не попадают или выводятся некорректно.
В рамках этой статьи мы подробно разберем, почему виртуальная таблица остатков и оборотов ведет себя подобным образом, проанализируем причины возникновения проблемы и рассмотрим три надежных способа ее решения: с помощью построения сетки периодов в чистом запросе, через связи наборов данных в СКД и с использованием механизма дополнения периодов компоновки данных.
Для начала проанализируем, почему простой запрос к виртуальной таблице ОстаткиИОбороты с периодичностью Месяц дает сбой. Платформа 1С:Предприятие оптимизирует запросы к базе данных. Виртуальная таблица не хранит остатки на каждую секунду или на каждый день для каждого аналитического разреза (в нашем случае — субконто ОсновныеСредства). Остатки рассчитываются динамически на основе реальных движений (записей регистра).
Если по конкретному основному средству в мае и июне не было никаких бухгалтерских проводок (например, не начислялась амортизация, не было модернизации или списания), то платформа считает эти периоды "пустыми" для данного субконто. В результате в выборке за май и июнь по этому ОС не будет ни одной строки. Настройка параметра виртуальной таблицы МетодДополнения в значение ДвиженияИГраницыПериода решает проблему лишь частично — она принудительно выведет остатки только на начало и на конец всего выбранного периода отчета, но проигнорирует промежуточные "тихие" месяцы.
Кроме того, при левом соединении двух таблиц (например, стоимости со счета 01 и амортизации со счета 02) по полям Субконто1 и Период возникает ситуация, когда периоды в двух таблицах не совпадают. Если по счету 02 обороты были (начислялась амортизация), а по счету 01 оборотов не было, левое соединение по равенству периодов отсечет или исказит конечные данные.
Если мы разрабатываем отчет на базе универсального отчета или выгружаем данные программно в таблицу значений без использования СКД, нам необходимо решить задачу генерации непрерывной временной шкалы (календаря) непосредственно в теле запроса.
Разберем этот алгоритм по шагам:
NULL, которое затем программно заполним остатком из предыдущего периода.Рассмотрим пример реализации такого запроса:
// Шаг 1: Получаем сетку месяцев из производственного календаря (или другого источника дат)
ВЫБРАТЬ РАЗЛИЧНЫЕ
НАЧАЛОПЕРИОДА(Календарь.Дата, МЕСЯЦ) КАК МесяцПериода
ПОМЕСТИТЬ ВТ_Периоды
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаря КАК Календарь
ГДЕ
Календарь.Дата МЕЖДУ &НачПериода И &КонПериода
;
// Шаг 2: Получаем список всех ОС, у которых были остатки на счетах учета
ВЫБРАТЬ РАЗЛИЧНЫЕ
ХозрасчетныйОстатки.Субконто1 КАК ОсновноеСредство
ПОМЕСТИТЬ ВТ_ОсновныеСредства
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(&НачПериода, Счет В (&Счет01, &Счет02), &ВидыСубконтоОС, Организация = &Организация) КАК ХозрасчетныйОстатки
;
// Шаг 3: Строим декартово произведение (ОС * Месяц)
ВЫБРАТЬ
ВТ_Периоды.МесяцПериода КАК Период,
ВТ_ОсновныеСредства.ОсновноеСредство КАК ОсновноеСредство
ПОМЕСТИТЬ ВТ_Матрица
ИЗ
ВТ_Периоды КАК ВТ_Периоды
СОЕДИНЕНИЕ ВТ_ОсновныеСредства КАК ВТ_ОсновныеСредства
ПО ИСТИНА
;
// Шаг 4: Соединяем матрицу с остатками на конец каждого месяца
ВЫБРАТЬ
Матрица.Период КАК Период,
Матрица.ОсновноеСредство КАК ОсновноеСредство,
ЕСТЬNULL(Остатки01.СуммаКонечныйОстатокДт, 0) КАК Стоимость,
ЕСТЬNULL(Остатки02.СуммаКонечныйОстатокКт, 0) КАК Амортизация,
ЕСТЬNULL(Остатки01.СуммаКонечныйОстатокДт, 0) - ЕСТЬNULL(Остатки02.СуммаКонечныйОстатокКт, 0) КАК ОстаточнаяСтоимость
ИЗ
ВТ_Матрица КАК Матрица
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачПериода, &КонПериода, Месяц, , Счет = &Счет01, &ВидыСубконтоОС, Организация = &Организация) КАК Остатки01
ПО Матрица.ОсновноеСредство = Остатки01.Субконто1
И КОНЕЦПЕРИОДА(Матрица.Период, МЕСЯЦ) = КОНЕЦПЕРИОДА(Остатки01.Период, МЕСЯЦ)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&НачПериода, &КонПериода, Месяц, , Счет = &Счет02, &ВидыСубконтоОС, Организация = &Организация) КАК Остатки02
ПО Матрица.ОсновноеСредство = Остатки02.Субконто1
И КОНЕЦПЕРИОДА(Матрица.Период, МЕСЯЦ) = КОНЕЦПЕРИОДА(Остатки02.Период, МЕСЯЦ)
УПОРЯДОЧИТЬ ПО
Период,
ОсновноеСредство
Обратите внимание на конструкцию КОНЕЦПЕРИОДА(..., МЕСЯЦ) в условиях связи. Как справедливо заметили участники обсуждения, даты периодов в разных виртуальных таблицах могут незначительно отличаться по времени (из-за секунд проведения регламентных операций), поэтому приведение всех сопоставляемых дат к концу месяца гарантирует корректность соединения таблиц.
Если отчет разрабатывается в Системе компоновки данных (СКД), то проблема пустых периодов и отсутствующих оборотов решается гораздо проще и элегантнее. Наиболее надежный способ — разделение запроса на два отдельных набора данных с последующей настройкой связи между ними.
Рассмотрим этот алгоритм настройки в СКД по шагам:
Шаг 1. Создание первого набора данных (НаборДанных1 - Источник):
В этом наборе данных мы получаем только "скелет" нашего отчета — список основных средств и периодов, за которые нам нужно вывести информацию. Запрос может выглядеть следующим образом:
ВЫБРАТЬ
ВТ_Периоды.МесяцПериода КАК Период,
ВТ_ОсновныеСредства.ОсновноеСредство КАК ОсновноеСредство
ИЗ
ВТ_Периоды КАК ВТ_Периоды
СОЕДИНЕНИЕ ВТ_ОсновныеСредства КАК ВТ_ОсновныеСредства
ПО ИСТИНА
Шаг 2. Создание второго набора данных (НаборДанных2 - Приемник):
Второй набор данных будет извлекать актуальные остатки по счетам 01 и 02 на конкретную дату. Обратите внимание, что мы используем таблицу Остатки, а не ОстаткиИОбороты, так как нам нужен срез на определенный момент времени:
ВЫБРАТЬ
ХозрасчетныйОстатки.Субконто1 КАК ОсновноеСредство,
ЕСТЬNULL(ХозрасчетныйОстатки.СуммаОстатокДт, 0) КАК Стоимость,
ЕСТЬNULL(АмортизацияОстатки.СуммаОстатокКт, 0) КАК Амортизация
ИЗ
РегистрБухгалтерии.Хозрасчетный.Остатки(&ПериодГраница, Счет = &Счет01, &ВидыСубконтоОС, Организация = &Организация) КАК ХозрасчетныйОстатки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Остатки(&ПериодГраница, Счет = &Счет02, &ВидыСубконтоОС, Организация = &Организация) КАК АмортизацияОстатки
ПО ХозрасчетныйОстатки.Субконто1 = АмортизацияОстатки.Субконто1
Шаг 3. Настройка связей наборов данных:
Переходим на вкладку Связи наборов данных в схеме компоновки и добавляем новую строку со следующими параметрами:
НаборДанных1НаборДанных2ОсновноеСредство = ОсновноеСредствоПериодГраница, Выражение источника — КОНЕЦПЕРИОДА(Период, "ДЕНЬ")При таком подходе СКД сама выполнит запрос из второго набора данных для каждой строки первого набора, передавая дату конца текущего месяца в качестве параметра получения остатков. Это полностью исключит проблему "пропавших" месяцев.
Существует еще один штатный механизм СКД, позволяющий заполнять временные пропуски в данных без создания дополнительных наборов данных. Это функция дополнения периодов роли поля компоновки.
Чтобы воспользоваться этим функционалом, выполним следующие шаги:
ОстаткиИОбороты выберем поле Период (или ПериодМесяц).Период, откроем его свойства в колонке Роль.Месяц.&НачалоПериода и &КонецПериода.После этой настройки, когда СКД будет формировать группировку по полю Период в структуре отчета, она автоматически сгенерирует строки для всех недостающих месяцев и спроецирует (продублирует) на них последние известные остатки из предыдущих периодов.
При работе с остатками основных средств необходимо всегда помнить о специфике проведения регламентных операций в закрытии периода:
23:59:59.КОНЕЦПЕРИОДА(..., МЕСЯЦ) или КОНЕЦПЕРИОДА(..., ДЕНЬ).Хозрасчетный.ОстаткиИОбороты на крупных базах данных могут выполняться медленно. Если в вашей конфигурации (например, ERP 2.5 или Комплексная автоматизация) ведется учет по регистрам накопления, для получения стоимости и амортизации ОС рекомендуется использовать специализированные регистры накопления (например, СтоимостьОС, АмортизацияОС), так как они работают значительно быстрее универсального бухгалтерского регистра.Мы подробно разобрали причины возникновения проблемы с выводом остатков по неактивным периодам и изучили три надежных метода борьбы с этой особенностью платформы. Выбор конкретного метода зависит от архитектуры вашего решения и требований к производительности системы.