Как решить проблему расхождения копеек при печати чеков на ККТ АТОЛ 30Ф из 1С 7.7?

Программист 1С v7.7 Управленческий учет Торговля и дистрибуция
← На главную

При автоматизации розничной торговли на базе платформы 1С:Предприятие 7.7 программисты часто сталкиваются с неприятной ситуацией: суммы в печатных чеках ККТ (контрольно-кассовой техники) не совпадают с суммами в документах «Реализация» или «Приходный кассовый ордер» (ПКО). Особенно остро эта проблема проявляется при использовании современных онлайн-касс, таких как АТОЛ 30Ф, работающих под управлением ФФД 1.05 или 1.2.

В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем логику работы драйвера кассового аппарата и предложим проверенное практикой программное решение с примерами кода на языке 1С 7.7.

Выясняем причину: почему касса пересчитывает суммы?

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

Когда эти данные передаются в кассу через стандартную обработку обслуживания ККМ, в драйвер отправляются только два параметра для каждой товарной строки: Price (Цена) и Quantity (Количество). Поскольку кассовый аппарат оперирует только ценами с двумя знаками после запятой (копейками), переданная цена округляется до 20.03 руб.

Внутри математического процессора кассового аппарата жестко заложено правило фискального контроля:

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

В итоге ККТ производит собственный расчет прямо в момент регистрации позиции:

Разработчики ККТ и законодатели (в рамках требований 54-ФЗ) умышленно заблокировали возможность произвольной передачи итоговой суммы позиции, если она математически не бьется с формулой произведения цены на количество. Попытка принудительно передать параметр суммы (например, через свойство Amount) в старых или новых версиях драйвера АТОЛ либо проигнорируется кассой, либо вызовет критическую ошибку «Неверная цена (сумма)», и чек не будет пробит.

Решение проблемы: алгоритм разбиения строк на стороне 1С

Единственный надежный и легальный способ сопоставить копейки в ККТ и 1С — это предварительная подготовка таблицы товаров перед ее отправкой на фискализацию. Если простая математическая проверка показывает, что Окр(Цена * Количество, 2) не совпадает с реальной суммой документа, мы должны применить алгоритм выравнивания копеек за счет разделения строки на две части.

Рассмотрим этот алгоритм по шагам на примере нашего Товара 1 (50 шт. на сумму 1001.64 руб.):

  1. Определяем базовую округленную цену одной единицы товара: 1001.64 / 50 = 20.0328 -> округляем до 2 знаков -> 20.03 руб.
  2. Рассчитываем стоимость основной партии товара без одной штуки: (50 - 1) * 20.03 = 49 * 20.03 = 981.47 руб.
  3. Вычисляем скорректированную стоимость для последней (1-й) штуки товара, которая заберет на себя всю погрешность округления копеек: 1001.64 - 981.47 = 20.17 руб.
  4. Формируем для кассы две отдельные строки вместо одной:
    • Строка 1.1: Количество = 49 шт., Цена = 20.03 руб. (Сумма позиции: 981.47 руб.)
    • Строка 1.2: Количество = 1 шт., Цена = 20.17 руб. (Сумма позиции: 20.17 руб.)

Складываем обе суммы на кассе: 981.47 + 20.17 = 1001.64 руб. Математика сошлась идеально! Касса без проблем примет обе строки, так как внутри каждой из них соблюдено правило Цена * Количество = Сумма.

Реализация алгоритма в коде 1С:Предприятие 7.7

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


// Создаем временную таблицу для подготовки данных
ТабТоваровДляККМ = СоздатьОбъект("ТаблицаЗначений");
ТабТоваровДляККМ.НоваяКолонка("ТовНаим", "Строка");
ТабТоваровДляККМ.НоваяКолонка("Цена", "Число", 15, 2);
ТабТоваровДляККМ.НоваяКолонка("Количество", "Число", 15, 3);
ТабТоваровДляККМ.НоваяКолонка("Сумма", "Число", 15, 2);
ТабТоваровДляККМ.НоваяКолонка("СтавкаНДС", "Строка");

// Заполняем таблицу исходными данными из документа
СписокТоваров.ВыбратьСтроки();
Пока СписокТоваров.ПолучитьСтроку() = 1 Цикл
    ИскомаяСумма = СписокТоваров.Сумма;
    ИскомоеКол   = СписокТоваров.Количество;
    
    // Вычисляем базовую округленную цену
    БазоваяЦена = Окр(ИскомаяСумма / ИскомоеКол, 2, 1);
    РасчетнаяСумма = Окр(БазоваяЦена * ИскомоеКол, 2, 1);
    
    Если (РасчетнаяСумма = ИскомаяСумма) Или (ИскомоеКол <= 1) Тогда
        // Округление не требуется или товар штучный в количестве 1 шт.
        ТабТоваровДляККМ.НоваяСтрока();
        ТабТоваровДляККМ.ТовНаим     = СписокТоваров.ТовНаим;
        ТабТоваровДляККМ.Цена        = БазоваяЦена;
        ТабТоваровДляККМ.Количество  = ИскомоеКол;
        ТабТоваровДляККМ.Сумма       = ИскомаяСумма;
        ТабТоваровДляККМ.СтавкаНДС   = СписокТоваров.СтавкаНДС;
    Иначе
        // Есть расхождение в копейках. Разбиваем позицию на две строки!
        // Строка 1: Основное количество без одной единицы
        ТабТоваровДляККМ.НоваяСтрока();
        ТабТоваровДляККМ.ТовНаим     = СписокТоваров.ТовНаим;
        ТабТоваровДляККМ.Цена        = БазоваяЦена;
        ТабТоваровДляККМ.Количество  = ИскомоеКол - 1;
        ТабТоваровДляККМ.Сумма       = Окр(БазоваяЦена * (ИскомоеКол - 1), 2, 1);
        ТабТоваровДляККМ.СтавкаНДС   = СписокТоваров.СтавкаНДС;
        
        // Строка 2: Последняя единица товара со скорректированной ценой
        ТабТоваровДляККМ.НоваяСтрока();
        ТабТоваровДляККМ.ТовНаим     = СписокТоваров.ТовНаим + " (доп)";
        ТабТоваровДляККМ.Цена        = ИскомаяСумма - ТабТоваровДляККМ.ПолучитьЗначение(ТабТоваровДляККМ.КоличествоСтрок(), "Сумма");
        ТабТоваровДляККМ.Количество  = 1;
        ТабТоваровДляККМ.Сумма       = ТабТоваровДляККМ.Цена;
        ТабТоваровДляККМ.СтавкаНДС   = СписокТоваров.СтавкаНДС;
    КонецЕсли;
КонецЦикла;

Теперь наша временная таблица ТабТоваровДляККМ содержит абсолютно корректные строки. Мы можем отправить их непосредственно на печать в объект драйвера ККТ АТОЛ:


// Отправка подготовленных данных в ККМ
ТабТоваровДляККМ.ВыбратьСтроки();
Пока ТабТоваровДляККМ.ПолучитьСтроку() = 1 Цикл
    
    Объект.Name     = ТабТоваровДляККМ.ТовНаим;
    Объект.Price    = ТабТоваровДляККМ.Цена;
    Объект.Quantity = ТабТоваровДляККМ.Количество;
    
    // Настройка ставок НДС (соответствие кодов ДТО АТОЛ)
    Если ТабТоваровДляККМ.СтавкаНДС = "none" Тогда
        Объект.TaxTypeNumber = 4; // Без НДС
    ИначеЕсли ТабТоваровДляККМ.СтавкаНДС = "20" Тогда
        Объект.TaxTypeNumber = 3; // НДС 20%
    ИначеЕсли ТабТоваровДляККМ.СтавкаНДС = "10" Тогда
        Объект.TaxTypeNumber = 2; // НДС 10%
    ИначеЕсли ТабТоваровДляККМ.СтавкаНДС = "0" Тогда
        Объект.TaxTypeNumber = 1; // НДС 0%
    КонецЕсли;
    
    // Выполняем фискальную регистрацию строки чека
    Если ПризнВозврата = 0 Тогда
        Если Объект.Registration() <> 0 Тогда
            Предупреждение("Ошибка регистрации продажи: " + Объект.ResultDescription);
            Возврат;
        КонецЕсли;
    Иначе    
        Если Объект.Return() <> 0 Тогда
            Предупреждение("Ошибка регистрации возврата: " + Объект.ResultDescription);
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
КонецЦикла;

Важные рекомендации по настройке оборудования

Помимо доработки программного кода 1С 7.7, мы рекомендуем обратить внимание на следующие технические аспекты работы с кассами АТОЛ:

  1. Обновление драйверов (Переход на ДТО 10): В рассмотренном выше коде используются методы старого драйвера ДТО 8 (объект Registration()). Поддержка этой линейки драйверов производителем полностью прекращена. Для долгосрочной и стабильной работы в рамках современных требований ФНС настоятельно рекомендуется использовать драйвер ДТО 10 (Atol.Drv10), подключив его в 1С 7.7 через специальную внешнюю компоненту.
  2. Передача НДС: Обратите внимание на соответствие кодов НДС в вашей конфигурации 1С и настройках кассы. При переходе с НДС 18% на НДС 20% убедитесь, что таблицы налогов в кассовом аппарате сопоставлены корректно, а прошивка ККТ обновлена.
  3. Скидки на уровне ККТ: Постарайтесь полностью отказаться от механизмов начисления скидок средствами самого драйвера кассы. Рассчитывайте все скидки, акции и округления непосредственно в коде 1С, передавая на ККТ исключительно конечную цену и сумму, как это было продемонстрировано в нашем примере.

Применение предложенного метода разбиения строк гарантирует бесперебойную работу кассового узла и полное отсутствие расхождений в учете между базой 1С и отчетами ФНС.

← На главную