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