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