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