При автоматизации розничной торговли на базе платформы 1С:Предприятие 7.7 программисты часто сталкиваются с неприятной ситуацией: суммы в печатных чеках ККТ (контрольно-кассовой техники) не совпадают с суммами в документах «Реализация» или «Приходный кассовый ордер» (ПКО). Особенно остро эта проблема проявляется при использовании современных онлайн-касс, таких как АТОЛ 30Ф, работающих под управлением ФФД 1.05 или 1.2.
В этой статье мы подробно разберем, почему возникает данная проблема, проанализируем логику работы драйвера кассового аппарата и предложим проверенное практикой программное решение с примерами кода на языке 1С 7.7.
Давайте проанализируем ситуацию на конкретном примере, который часто встречается в торговой практике. Предположим, в документе 1С у нас есть две позиции номенклатуры после применения скидки или распределения сумм:
Когда эти данные передаются в кассу через стандартную обработку обслуживания ККМ, в драйвер отправляются только два параметра для каждой товарной строки: Price (Цена) и Quantity (Количество). Поскольку кассовый аппарат оперирует только ценами с двумя знаками после запятой (копейками), переданная цена округляется до 20.03 руб.
Внутри математического процессора кассового аппарата жестко заложено правило фискального контроля:
Стоимость позиции = Цена * Количество
В итоге ККТ производит собственный расчет прямо в момент регистрации позиции:
Разработчики ККТ и законодатели (в рамках требований 54-ФЗ) умышленно заблокировали возможность произвольной передачи итоговой суммы позиции, если она математически не бьется с формулой произведения цены на количество. Попытка принудительно передать параметр суммы (например, через свойство Amount) в старых или новых версиях драйвера АТОЛ либо проигнорируется кассой, либо вызовет критическую ошибку «Неверная цена (сумма)», и чек не будет пробит.
Единственный надежный и легальный способ сопоставить копейки в ККТ и 1С — это предварительная подготовка таблицы товаров перед ее отправкой на фискализацию. Если простая математическая проверка показывает, что Окр(Цена * Количество, 2) не совпадает с реальной суммой документа, мы должны применить алгоритм выравнивания копеек за счет разделения строки на две части.
Рассмотрим этот алгоритм по шагам на примере нашего Товара 1 (50 шт. на сумму 1001.64 руб.):
1001.64 / 50 = 20.0328 -> округляем до 2 знаков -> 20.03 руб.(50 - 1) * 20.03 = 49 * 20.03 = 981.47 руб.1001.64 - 981.47 = 20.17 руб.Складываем обе суммы на кассе: 981.47 + 20.17 = 1001.64 руб. Математика сошлась идеально! Касса без проблем примет обе строки, так как внутри каждой из них соблюдено правило Цена * Количество = Сумма.
Рассмотрим подробнее, как изменить код стандартного модуля чека ККМ для реализации этого механизма. Вместо прямой отправки строк из документа мы сначала сформируем временную таблицу значений, скорректируем ее по нашему алгоритму и только потом отправим в ККТ.
// Создаем временную таблицу для подготовки данных
ТабТоваровДляККМ = СоздатьОбъект("ТаблицаЗначений");
ТабТоваровДляККМ.НоваяКолонка("ТовНаим", "Строка");
ТабТоваровДляККМ.НоваяКолонка("Цена", "Число", 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, мы рекомендуем обратить внимание на следующие технические аспекты работы с кассами АТОЛ:
Registration()). Поддержка этой линейки драйверов производителем полностью прекращена. Для долгосрочной и стабильной работы в рамках современных требований ФНС настоятельно рекомендуется использовать драйвер ДТО 10 (Atol.Drv10), подключив его в 1С 7.7 через специальную внешнюю компоненту.Применение предложенного метода разбиения строк гарантирует бесперебойную работу кассового узла и полное отсутствие расхождений в учете между базой 1С и отчетами ФНС.