Как правильно пробить чек со скидкой через драйвер АТОЛ 10 (COM-объект) в 1С

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

При работе с торговым оборудованием АТОЛ через 10-ю версию драйвера программисты часто сталкиваются с трудностями при оформлении скидок на отдельные позиции. Основная проблема заключается в том, что логика работы драйвера версии 10 существенно отличается от предыдущих версий и жестко привязана к требованиям Формата фискальных данных (ФФД) 1.05 и выше. В этой статье мы подробно разберем, как реализовать пробитие чека со скидкой, избежать распространенной «ошибки -1» и добиться корректного отображения информации для покупателя. Для альтернативной организации взаимодействия с ККТ через JSON-задания можно использовать внешнюю компоненту для работы с драйвером АТОЛ v.10.

Анализ проблемы: почему возникает ошибка -1

Рассмотрим ситуацию, с которой сталкивается автор темы. При попытке передать параметр LIBFPTR_PARAM_POSITION_SUM (полная сумма позиции), отличный от произведения цены на количество, кассовый аппарат возвращает ошибку и требует аннулирования чека. Проанализируем причину такого поведения оборудования.

Согласно ФФД 1.05, в фискальном чеке значение реквизита «цена за единицу предмета расчета» (тег 1079) должно указываться уже с учетом всех скидок и наценок. Драйвер АТОЛ 10 осуществляет строгий математический контроль. Если вы передаете цену, количество и итоговую сумму, то формула Цена * Количество = Сумма должна соблюдаться с точностью до копейки. Если вы передаете исходную цену (без скидки) и итоговую сумму (со скидкой), драйвер видит математическое расхождение и блокирует операцию.

Вариант 1. Использование расчетной цены (рекомендуемый способ)

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

Выясним, какие параметры нам необходимы:

  1. LIBFPTR_PARAM_COMMODITY_NAME — наименование товара.
  2. LIBFPTR_PARAM_PRICE — цена за единицу товара (уже с учетом скидки).
  3. LIBFPTR_PARAM_QUANTITY — количество.
  4. LIBFPTR_PARAM_TAX_ID — налоговая ставка (важно всегда указывать явно).
  5. LIBFPTR_PARAM_INFO_DISCOUNT_SUM — информационное поле, которое напечатает на чеке сумму скидки для покупателя, но не будет участвовать в фискальных расчетах.

Рассмотрим пример кода:


// Очистка параметров перед регистрацией позиции
Объект.setParam(Объект.LIBFPTR_PARAM_COMMODITY_NAME, СтрокаЧека.Номенклатура.ПолноеНаименование);
Объект.setParam(Объект.LIBFPTR_PARAM_QUANTITY, СтрокаЧека.Количество);

// Вычисляем цену со скидкой на стороне 1С
ЦенаСоСкидкой = СтрокаЧека.Сумма / СтрокаЧека.Количество;
Объект.setParam(Объект.LIBFPTR_PARAM_PRICE, ЦенаСоСкидкой);

// Устанавливаем итоговую сумму позиции для контроля округлений
Объект.setParam(Объект.LIBFPTR_PARAM_POSITION_SUM, СтрокаЧека.Сумма);

// Налоговая ставка (например, без НДС или 20%)
Объект.setParam(Объект.LIBFPTR_PARAM_TAX_ID, Объект.LIBFPTR_TAX_NO);

// Выводим информацию о скидке для красоты чека
Если СтрокаЧека.СуммаСкидки <> 0 Тогда
    Объект.setParam(Объект.LIBFPTR_PARAM_INFO_DISCOUNT_SUM, СтрокаЧека.СуммаСкидки);
КонецЕсли;

Объект.registration();

Вариант 2. Автоматическое распределение скидки драйвером

Иногда возникают ситуации, когда сумма скидки на позицию не делится ровно на количество (например, скидка 1 рубль на 3 единицы товара). В этом случае возникают «лишние» копейки. Драйвер АТОЛ 10 умеет решать эту задачу самостоятельно через механизм распределения скидки. Посмотрим, как это работает.

Если мы передадим исходную цену (без скидки) и итоговую сумму позиции (со скидкой), драйвер сам рассчитает разницу и, если необходимо, разобьет позицию на две строки в чеке с разницей в одну копейку, чтобы итоговая сумма сошлась. Для этого нужно передать параметр LIBFPTR_PARAM_POSITION_SUM, который будет меньше, чем результат PRICE * QUANTITY.

Важный нюанс: Этот метод работает корректно только в том случае, если разница между Цена * Количество и Сумма не превышает разумных пределов (обычно это сумма скидки). Если передать некорректные данные, ККТ вернет ошибку.

Вариант 3. Визуальное отображение «Старой цены»

Пользователи часто хотят видеть в чеке классическую структуру: «Цена без скидки — Скидка — Итого». Как мы выяснили, ФФД требует указывать в фискальной строке только цену со скидкой. Чтобы обойти это ограничение, проанализируем возможность использования нефискальных строк.

Мы можем использовать метод printText() перед регистрацией позиции или специальные текстовые параметры внутри позиции. Рассмотрим, как дополнить чек информационным текстом:


// Печать текстовой строки перед позицией (нефискальная информация)
Объект.setParam(Объект.LIBFPTR_PARAM_TEXT, "Цена без скидки: " + СтрокаЧека.СтараяЦена);
Объект.setParam(Объект.LIBFPTR_PARAM_ALIGNMENT, Объект.LIBFPTR_ALIGN_LEFT);
Объект.printText();

// Далее стандартная регистрация позиции по цене со скидкой
Объект.setParam(Объект.LIBFPTR_PARAM_COMMODITY_NAME, СтрокаЧека.Номенклатура.ПолноеНаименование);
Объект.setParam(Объект.LIBFPTR_PARAM_PRICE, СтрокаЧека.ЦенаСоСкидкой);
Объект.setParam(Объект.LIBFPTR_PARAM_QUANTITY, СтрокаЧека.Количество);
Объект.registration();

Работа с оплатами и закрытие чека

После того как все позиции зарегистрированы методом registration(), нам необходимо корректно закрыть чек, распределив оплаты по типам (наличные, безналичные). Обратите внимание, что общая сумма оплат по методам payment() должна в точности совпадать с итоговой суммой всех зарегистрированных позиций.

Разберем завершающий этап оформления чека:


// Оплата наличными
Если ПолученоНал > 0 Тогда
    Объект.setParam(Объект.LIBFPTR_PARAM_PAYMENT_TYPE, Объект.LIBFPTR_PT_CASH);
    Объект.setParam(Объект.LIBFPTR_PARAM_PAYMENT_SUM, ПолученоНал);
    Объект.payment();
КонецЕсли;

// Оплата картой (электронными)
Если ПолученоБезНал > 0 Тогда
    Объект.setParam(Объект.LIBFPTR_PARAM_PAYMENT_TYPE, Объект.LIBFPTR_PT_ELECTRONICALLY);
    Объект.setParam(Объект.LIBFPTR_PARAM_PAYMENT_SUM, ПолученоБезНал);
    Объект.payment();
КонецЕсли;

// Закрытие чека
Если Объект.closeReceipt() <> 0 Тогда
    // Обработка ошибки закрытия
    ОписаниеОшибки = Объект.errorDescription();
    Сообщить("Не удалось закрыть чек: " + ОписаниеОшибки);
КонецЕсли;

Рекомендации по отладке

Если чек все равно не пробивается и драйвер возвращает ошибку -1, рекомендуем выполнить следующие действия:

  1. Включите лог драйвера. В настройках через «Тест драйвера ККТ» установите ведение лога. В файле fptr10.log будет детально расписано, какой именно параметр вызвал сбой. Часто там можно увидеть сообщения вида «Sum check failed», что прямо указывает на математическую ошибку в копейках.
  2. Проверьте налоговые ставки. В драйвере 10-й версии LIBFPTR_PARAM_TAX_ID является критически важным параметром. Если он не передан, ККТ может использовать значение по умолчанию, которое несовместимо с настройками вашей организации.
  3. Округляйте суммы. При вычислении ЦенаСоСкидкой = Сумма / Количество в 1С всегда используйте функцию Окр(Значение, 2). Передача в драйвер чисел с более чем двумя знаками после запятой (например, 33.333333) часто становится причиной отказа в регистрации позиции.

Подводя итог, отметим, что ключ к успеху при работе с АТОЛ 10 — это соблюдение жесткой математической точности и понимание того, что LIBFPTR_PARAM_INFO_DISCOUNT_SUM носит лишь справочный характер, а реальная цена продажи должна передаваться в LIBFPTR_PARAM_PRICE уже с учетом скидки.

← На главную