Почему онлайн-касса АТОЛ разбивает позиции со скидкой и как исправить расхождение сумм

Программист 1С v8.3 (Управляемые формы) Торговля и дистрибуция
← На главную

При интеграции 1С с фискальными регистраторами (онлайн-кассами АТОЛ) разработчики нередко сталкиваются с ситуацией, когда одна товарная позиция в напечатанном чеке делится на две строки с разным количеством и разными ценами. В результате возникает расхождение итога чека с суммой в 1С на одну или несколько копеек, и касса выдает ошибку о несоответствии сумм либо аннулирует чек. Разберем детально, почему это происходит и как устранить данную проблему.

Анализ проблемы: почему касса «расслаивает» товарные позиции

Проанализируем конкретный пример из практики. В документе 1С оформлена продажа товара со скидкой:

Номенклатура продажи: 15 шт. по цене 170,55 руб. Сумма со скидкой 10% составляет 2302,43 руб.

При передаче этих данных в кассу на печать выходит документ следующего вида:

Позиция 1: 7 шт. х 153,50 руб. = 1074,50 руб. (Скидка 17,05 руб.)
Позиция 2: 8 шт. х 153,49 руб. = 1227,92 руб. (Скидка 17,06 руб.)
Итого по чеку: 2302,42 руб.

В учетной системе сумма чека осталась равной 2302,43 руб., а касса зафиксировала 2302,42 руб. Так как оплата передается на сумму 2302,43 руб., кассовый аппарат фиксирует несовпадение итогов строк и суммы оплат, после чего операция прерывается.

Выясним причину такого поведения оборудования. Согласно требованиям форматов фискальных документов (ФФД), касса выполняет жесткий форматно-логический контроль по формуле:

Количество * Цена за единицу с учетом скидки = Стоимость позиции

При этом и цена, и общая стоимость позиции обязаны быть округлены ровно до копеек (2 знака после запятой). Если мы разделим итоговую сумму 2302,43 руб. на количество 15 шт., то получим цену единицы товара 153,495333... руб. Зарегистрировать строку с дробными долями копейки касса физически не может. Чтобы математическое равенство сошлось до копейки, встроенный алгоритм прошивки ККТ принудительно раскладывает 15 единиц товара на две подгруппы (7 штук по 153,50 руб. и 8 штук по 153,49 руб.). Из-за погрешности округления итоговая сумма может измениться на 1 копейку («проблема 1 копейки»).

Вариант 1. Отказ от передачи скидок в ККТ и расчет цен на стороне 1С

Рассмотрим основной способ решения, который устраняет непредсказуемое поведение драйвера. Посмотрим на код прямой работы с драйвером ККТ, в котором используются устаревшие параметры скидок:


// Устаревший способ передачи скидки в кассу
driver.Name = "Номенклатура продажи";
driver.Price = 170.55;
driver.Quantity = 15;
driver.Department = 0;
driver.TaxTypeNumber = 3;
driver.DiscountValue = 10;
driver.DiscountType = 1; // Процентная скидка
driver.Registration();

При таком подходе касса берет на себя пересчет цен по внутреннему алгоритму. Чтобы исключить расхождения, необходимо перенести расчет скидок целиком на сторону 1С:

  1. Не передавать свойства DiscountValue и DiscountType в драйвер ККТ.
  2. Если сумма строки со скидкой не делится на количество без остатка в долях копейки, алгоритм в 1С должен самостоятельно разбить позицию на две строки до момента отправки данных на печать.
  3. В кассу передаются уже готовые строки с конечной ценой и суммой, где количество умноженное на цену дает точную сумму без округлений.

Разберем математику распределения копеек в 1С:

  1. Вычисляем базовую цену за единицу с отсечением лишних знаков: Цел((СуммаСоСкидкой / Количество) * 100) / 100. Для суммы 2302,43 и количества 15 базовая цена составит 153,49 руб.
  2. Считаем остаток нераспределенных копеек: 2302.43 - (153.49 * 15) = 0.08 руб. (то есть 8 копеек).
  3. Формируем две строки: 8 штук по цене 153,50 руб. (1228,00 руб.) и 7 штук по цене 153,49 руб. (1074,43 руб.). Итоговая сумма строк в 1С точно совпадет с 2302,43 руб., и кассе не придется ничего досчитывать самостоятельно.

Вариант 2. Корректное формирование фискального пакета XML

Посмотрим на пример структуры XML-пакета, который передается в кассу через механизмы интеграции:


<CheckPackage>
    <Parameters PaymentType="1" TaxVariant="0" SenderEmail="" CustomerPhone=""/>
    <Positions>
        <FiscalString Name="Номенклатура продажи" Quantity="15" Price="170.55" Amount="2302.43" Tax="18"/>
    </Positions>
    <Payments Cash="2302.43" CashLessType1="0" CashLessType2="0" CashLessType3="0"/>
</CheckPackage>

В теге FiscalString указана исходная цена 170.55, количество 15 и сумма 2302.43. Драйвер видит, что 15 * 170.55 = 2558.25, что не равно значению в Amount, и снова запускает внутренний калькулятор скидок с разбиением позиций. Чтобы этого не происходило, передавайте уже рассчитанные строки, где параметры Price, Quantity и Amount согласованы между собой на уровне математики ФФД.

Вариант 3. Вывод информации о скидке в текстовом виде

Если для покупателя важно видеть размер предоставленной скидки на бумажном чеке, разберем, как вывести эту информацию без вмешательства в фискальный расчет:

  1. Регистрируем товарную позицию сразу по итоговой цене продажи (со скидкой).
  2. После выполнения метода регистрации позиции используем метод печати нефискального текста: driver.PrintString().
  3. Передаем в него поясняющий текст: «В том числе скидка 10% — 255.82 руб.».

В этом случае чек содержит всю необходимую маркетинговую информацию, а фискальные реквизиты остаются строго согласованными, исключая аннулирование чеков из-за разницы в копейку.

Вариант 4. Настройка типовых механизмов БПО и округления чека

Если печать чеков выполняется через типовую Библиотеку подключаемого оборудования (БПО), проанализируем доступные настройки системы:

  1. Включение округления чека в пользу покупателя: в параметрах кассового узла или торговой точки настраивается округление суммы чека до целых рублей или десятков копеек за счет автоматической скидки. Это убирает проблему мелких дробных расхождений при распределении скидок.
  2. Обновление драйвера ККТ: при переходе на драйверы АТОЛ 10-й версии механизмы взаимодействия с ФФД 1.05/1.2 работают без использования устаревших свойств регистрации скидок, что снижает вероятность программных ошибок округления на стороне драйвера.
← На главную