При организации обмена с кассовым программным обеспечением в режиме ККМ-Offline (например, Frontol или АТОЛ РМК) обработка загрузки смены считывает отчет о продажах во временную таблицу значений, после чего выполняет агрегацию данных. Довольно часто разработчики сталкиваются с ситуацией, когда в течение смены произошел возврат товара, проданного ранее со скидкой (количество -1), а затем был продан такой же товар, но уже по полной цене (количество +1).
Если в алгоритме обработки предусмотрена свертка только по номенклатуре и базовой цене из справочника, итоговое количество по позиции превращается в ноль (-1 + 1 = 0). В результате строка удаляется или отсекается условием проверки количества, а разница в сумме (размер скидки) бесследно исчезает из учета. Разберем детально, почему это происходит и как правильно модернизировать алгоритм загрузки чеков в конфигурации «1С:Торговля и Склад 7.7».
Проанализируем механику работы метода Свернуть() в 1С 7.7. Типовая группировка по колонкам "Товар, Цена" предполагает, что цена позиции всегда однозначна. Однако при продаже со скидкой касса фиксирует:
Если возврат оформляется по чеку со скидкой, а повторная продажа идет по базовой цене, то при одинаковой базовой цене строки попадают в одну группу группировки. Количество суммируется и дает 0, а в колонке Сумма остается суммовая разница. Документ Отчет ККМ не может содержать строки с нулевым количеством и ненулевой суммой, поэтому данные теряются, вызывая расхождение между Z-отчетом кассы и учетной базой.
Рассмотрим первый вариант решения проблемы — отказ от группировки по базовой цене из прайса и переход к расчету фактической цены единицы товара с учетом всех предоставленных скидок.
Перед вызовом метода свертки добавим в таблицу значений расчетную колонку ФактическаяЦена, в которую поместим результат деления абсолютной суммы строки на абсолютное количество. Разберем по шагам, как это реализовать в программном коде:
// Добавляем расчетную колонку в Таблицу Значений чеков
ТЗЧеков.НоваяКолонка("ФактическаяЦена", "Число", 15, 2);
ТЗЧеков.ВыбратьСтроки();
Пока ТЗЧеков.ПолучитьСтроку() = 1 Цикл
Если ТЗЧеков.Количество <> 0 Тогда
// Рассчитываем фактическую цену с учетом знака операции
ТЗЧеков.ФактическаяЦена = Окр(Абс(ТЗЧеков.Сумма) / Абс(ТЗЧеков.Количество), 2);
Иначе
ТЗЧеков.ФактическаяЦена = 0;
КонецЕсли;
КонецЦикла;
// Выполняем свертку по номенклатуре и фактической цене
ТЗЧеков.Свернуть("Номенклатура, ФактическаяЦена", "Количество, Сумма");
Посмотрим на результат выполнения этого алгоритма:
ФактическаяЦена, не будут объединены и попадут в документ отдельными записями.Выясним причину, почему смешивать продажи и возвраты в одной таблице не всегда правильно с точки зрения методологии учета 1С 7.7. Документ Отчет ККМ в конфигурации «Торговля и Склад 7.7» предназначен для списания проданного товара (движение расхода по регистру ПартииНаличие). Появление отрицательных строк в документе приводит к сторнированию расхода, что при партионном учете (FIFO/LIFO) может исказить себестоимость, если товар был продан в прошлые смены.
Наиболее надежным архитектурным решением является предварительное разделение всех загружаемых строк на две независимые таблицы значений:
Количество > 0).Количество < 0 или транзакции возврата).Рассмотрим пример кода для раздельной обработки чеков:
// Создаем отдельные таблицы для продаж и возвратов
ТЗПродажи = СоздатьОбъект("ТаблицаЗначений");
ТЗВозвраты = СоздатьОбъект("ТаблицаЗначений");
ТЗЧеков.Выгрузить(ТЗПродажи);
ТЗЧеков.Выгрузить(ТЗВозвраты);
// Фильтруем продажи
ТЗПродажи.ВыбратьСтроки();
НомСтр = 1;
Пока НомСтр <= ТЗПродажи.КоличествоСтрок() Цикл
ТЗПродажи.ПолучитьСтрокуПоНомеру(НомСтр);
Если ТЗПродажи.Количество <= 0 Тогда
ТЗПродажи.УдалитьСтроку(НомСтр);
Иначе
НомСтр = НомСтр + 1;
КонецЕсли;
КонецЦикла;
// Фильтруем возвраты
ТЗВозвраты.ВыбратьСтроки();
НомСтр = 1;
Пока НомСтр <= ТЗВозвраты.КоличествоСтрок() Цикл
ТЗВозвраты.ПолучитьСтрокуПоНомеру(НомСтр);
Если ТЗВозвраты.Количество >= 0 Тогда
ТЗВозвраты.УдалитьСтроку(НомСтр);
Иначе
// Делаем количество и сумму положительными для оформления документа возврата
ТЗВозвраты.Количество = -ТЗВозвраты.Количество;
ТЗВозвраты.Сумма = -ТЗВозвраты.Сумма;
НомСтр = НомСтр + 1;
КонецЕсли;
КонецЦикла;
// Выполняем раздельную свертку
ТЗПродажи.Свернуть("Номенклатура, Цена", "Количество, Сумма");
ТЗВозвраты.Свернуть("Номенклатура, Цена", "Количество, Сумма");
После разделения данных:
ТЗПродажи загружается в документ Отчет ККМ (или документ Чек ККМ).ТЗВозвраты формирует документ Возврат ТМЦ от покупателя с признаком розничного возврата, что гарантирует правильное восстановление партий на складе и точность кассовой выручки.При доработке модуля загрузки обратим внимание на нюансы протоколов обмена АТОЛ:
11 обозначает продажу, транзакция 12 — сторно, а транзакция 14 — возврат. Корректнее анализировать не только знак числа в поле количества, но и сам код транзакции кассового аппарата.