При прямой интеграции торгового оборудования с 1С через драйвер ККТ часто возникает вопрос: как правильно пробить чек, если клиент вносит только часть суммы? Если с полной оплатой все достаточно просто — касса сама автоматически подсчитывает итог по позициям и закрывает чек, — то при частичной оплате стандартный алгоритм вызывает ошибку ККТ. Драйвер не позволяет закрыть чек, если сумма переданных оплат меньше суммарной стоимости товаров.
В этой статье мы подробно разберем, как устроена логика частичной оплаты в ККТ АТОЛ (на примере драйвера версии 8), какие реквизиты необходимо передавать для ФФД 1.05 и как правильно использовать методы драйвера для успешного закрытия чека. При необходимости можно воспользоваться готовым рабочим местом кассира с поддержкой онлайн-касс АТОЛ.
Проанализируем ситуацию: в чеке содержатся товарные позиции на общую сумму 5000 рублей. Покупатель вносит наличными только 2000 рублей, а оставшиеся 3000 рублей обязуется доплатить позже. Если мы просто укажем в чеке позиции на 5000 рублей, передадим признак способа расчета «Частичный расчет» и попытаемся закрыть чек передав оплату в 2000 рублей, ККТ выдаст ошибку несоответствия сумм. Касса «ожидает», что вся сумма чека будет полностью распределена по типам оплаты.
Выясним причину этой логики. Согласно требованиям Федерального закона № 54-ФЗ и форматам фискальных документов (ФФД), общая сумма всех видов плат в чеке должна до копейки совпадать с суммой всех зарегистрированных товарных позиций. Чтобы решить эту задачу, нам необходимо использовать не только фактическую оплату (наличные или безналичные), но и неденежные типы оплат, такие как Кредит (Постоплата).
Для каждой позиции в чеке мы должны правильно указать признак способа расчета. В драйвере АТОЛ 8 за это отвечает свойство PaymentMode. Рассмотрим основные значения этого свойства:
В нашем случае для каждой строки номенклатуры перед завершением регистрации позиции необходимо установить значение 5:
ECR.PaymentMode = 5; // Частичный расчет и кредит
ECR.EndItem();
После того как все товарные позиции зарегистрированы в чеке, нам нужно передать информацию о том, как именно распределяется оплата. Для этого используется метод драйвера Payment().
Каждый вызов метода Payment() регистрирует оплату определенного типа на указанную сумму. За тип оплаты отвечает свойство TypeClose:
Важное правило: Сумма всех вызванных методов Payment() должна в точности равняться сумме всех позиций в чеке!
Рассмотрим по шагам, как должен выглядеть финальный блок кода закрытия чека при частичной оплате. Допустим, общая сумма товаров составляет 1333 рубля, а клиент вносит наличными только 1000 рублей. Оставшиеся 333 рубля мы обязаны закрыть видом оплаты «Кредит» (тип закрытия 3).
Проанализируем пример кода на языке 1С:
// Переменные для расчетов
СуммаЧека = 1333;
ФактическиОплачено = 1000;
СуммаКредита = СуммаЧека - ФактическиОплачено;
// 1. Регистрируем оплату наличными (1000 рублей)
ECR.TypeClose = 0; // Наличные
ECR.PointPosition = 2; // Количество знаков после запятой
ECR.Summ = ФактическиОплачено;
ECR.Payment();
// 2. Регистрируем оставшуюся сумму как Кредит/Постоплату (333 рубля)
ECR.TypeClose = 3; // Кредит / Последующая оплата
ECR.PointPosition = 2;
ECR.Summ = СуммаКредита;
ECR.Payment();
// 3. Закрываем чек на кассе
ECR.CloseCheck();
Если бы клиент оплачивал часть картой, мы бы изменили ECR.TypeClose для первой оплаты на 1 (Электронные). Такой подход позволяет кассовому аппарату корректно сопоставить суммы и закрыть чек без зависаний драйвера.
Теперь объединим все элементы в одну работающую процедуру для 1С. Мы добавим расчет суммы позиций, установку признака способа расчета для каждой строки и последующее закрытие чека по двум типам оплаты.
Процедура ПробитьЧекЧастичнойОплаты(ДокументРеализация, ФактическаяОплатаКлиента)
ECR.DeviceEnabled = 1;
Если ECR.ResultCode <> 0 Тогда
Предупреждение("ККМ не подключена!");
Возврат;
КонецЕсли;
ECR.Password = "1";
// Входим в режим регистрации
ECR.Mode = 1;
Если ECR.SetMode() <> 0 Тогда
Предупреждение("Касса не смогла войти в режим регистрации чеков!");
Возврат;
КонецЕсли;
// Кассир (Тег 1021)
ECR.AttrNumber = 1021;
ECR.AttrValue = "Иванов И.И.";
ECR.WriteAttribute();
ECR.CheckType = 1; // Приход денег
ECR.CheckMode = 1; // Печатать на ленте
ECR.OpenCheck();
ОбщаяСуммаЧека = 0;
// Цикл по товарным позициям
Для Каждого Стр Из ДокументРеализация.Товары Цикл
ECR.BeginItem();
ECR.StreamFormat = 5;
ECR.Name = Стр.Номенклатура.Наименование + " шт";
ECR.Price = Стр.Цена;
ECR.Quantity = Стр.Количество;
СтоимостьПозиции = Стр.Цена * Стр.Количество;
ECR.Summ = СтоимостьПозиции;
ОбщаяСуммаЧека = ОбщаяСуммаЧека + СтоимостьПозиции;
// Указываем тип налога
ECR.TaxTypeNumber = 4; // Без НДС
ECR.Tax = 4;
// Указываем признак способа расчета - Частичная оплата и кредит
ECR.PaymentMode = 5;
ECR.EndItem();
КонецЦикла;
// Расчет сумм оплат
Если ФактическаяОплатаКлиента > ОбщаяСуммаЧека Тогда
ФактическаяОплатаКлиента = ОбщаяСуммаЧека; // Исключаем переплату
КонецЕсли;
СуммаПостоплаты = ОбщаяСуммаЧека - ФактическаяОплатаКлиента;
// Пробиваем фактическую оплату (например, Наличными)
Если ФактическаяОплатаКлиента > 0 Тогда
ECR.TypeClose = 0; // 0 - Наличные, 1 - Безналичные
ECR.PointPosition = 2;
ECR.Summ = ФактическаяОплатаКлиента;
ECR.Payment();
КонецЕсли;
// Пробиваем сумму, уходящую в долг (Кредит)
Если СуммаПостоплаты > 0 Тогда
ECR.TypeClose = 3; // Последующая оплата (Кредит)
ECR.PointPosition = 2;
ECR.Summ = СуммаПостоплаты;
ECR.Payment();
КонецЕсли;
// Окончательное закрытие чека
ECR.CloseCheck();
КонецПроцедуры
Рассмотрим несколько критически важных моментов, с которыми вы можете столкнуться при практическом внедрении этого механизма:
Payment() по отдельности в цикле — достаточно будет передать массив оплат в едином структурированном запросе, что сводит к минимуму вероятность зависания ККТ в полузакрытом состоянии.