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