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