Онлайн-касса - подключение, состав чека, очередь и ошибки
Подключаем онлайн-кассу к магазину: связываем её с платёжной системой, разбираемся, когда пробивается чек и что делать с теми, что не пробились.
Механика
Чек в платформе - это отдельная сущность со своим состоянием. Он создаётся привязанным к оплате или к отгрузке, уходит в очередь, отправляется кассе или её оператору и возвращается с результатом. Между созданием и результатом проходит от секунд до часов, и всё это время чек живёт в промежуточном состоянии.
Касса связана с платёжной системой, а не с заказом. Это и определяет, какой чек чем пробивается: оплата картой через одну систему уходит на одну кассу, наличные при получении - на другую или вообще на кассу курьерской службы. Заказ при этом может собрать два чека и два разных признака расчёта.
Состав чека собирается из позиций заказа, а не пишется вручную. Наименование, количество, цена, ставка налога и признак способа расчёта берутся из товара, из настроек каталога и из настроек кассы. Ошибка в любом из этих мест даёт формально пробитый, но неверный чек, и заметит её проверяющий, а не покупатель.
Печать бывает немедленной и отложенной. Немедленная уходит в момент события, отложенная копится и отправляется заданием по расписанию. Второй способ мягче переживает недоступность оператора, но требует следить за очередью: молча растущая очередь непробитых чеков - самая дорогая из возможных ситуаций.
Отдельно стоит понимать, что сайт в этой цепочке - не последняя инстанция. Фискальный документ создаёт касса или её оператор, и успешный ответ означает только то, что запрос принят. Расхождение между числом оплат на сайте и числом чеков у оператора - обычное дело в первые недели, и сверять их приходится вручную, пока схема не устоится.
Шаги
- Зарегистрировать кассу у оператора и получить её реквизиты доступа.
- Завести кассу в магазине и вписать эти реквизиты в её настройки.
- Связать кассу с платёжными системами, по которым она пробивает чеки.
- Проверить ставки налога у товаров и в настройках самой кассы.
- Провести тестовый заказ и убедиться, что чек ушёл и вернулся успешным.
- Завести проверку очереди чеков, которая замечает непробитые сама.
Код
Смотрим очередь чеков:
use Bitrix\Sale\Cashbox\Internals\CheckTable;
$rows = CheckTable::getList([ 'select' => ['ID', 'ORDER_ID', 'STATUS', 'SUM', 'DATE_CREATE', 'ERROR_MESSAGE'], 'filter' => ['!=STATUS' => 'Y'], // всё, что не пробилось успешно 'order' => ['DATE_CREATE' => 'DESC'],])->fetchAll();Очередь чеков - главный экран этой задачи. Успешно пробитые чеки в разборе не участвуют, а вот всё остальное стоит видеть ежедневно, а не после звонка из бухгалтерии.
Пробиваем чек из кода:
use Bitrix\Sale\Cashbox\CheckManager;
$order = \Bitrix\Sale\Order::load($orderId);$payment = $order->getPaymentCollection()->current();CheckManager::addChecks([$payment]); // чек встаёт в очередь, а не печатается сразу// повторный вызов на той же оплате создаёт второй чек: проверяйте, что первого нетПечать из кода нужна для повторов и для нестандартных сценариев. Штатный путь - настройки кассы, а ручной вызов оставляют на случаи, когда чек не ушёл по чужой вине.
Проверяем состав будущего чека:
foreach ($order->getBasket() as $item) { printf("%s x%s по %s, ставка %s\n", $item->getField('NAME'), $item->getQuantity(), $item->getPrice(), $item->getField('VAT_RATE'));}// ставка приходит из товара, а не из кассы: пустое значение означает «без налога»Состав чека проверяют до боевого запуска, а не после. Ставка налога, приехавшая из обмена пустой, превращается в чек без налога, и разбираться с этим приходится уже с проверяющим.
Регистрируем свой обработчик кассы:
// /local/php_interface/init.php - только если готового обработчика нет\Bitrix\Main\EventManager::getInstance()->addEventHandler('sale', 'onGetCustomCashboxHandlers', function () { return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS, [ '\\Local\\Cashbox\\VendorCashbox' => ['NAME' => 'Касса поставщика'], ]); });Свой обработчик пишут, когда готового для этой кассы нет. Он собирает запрос к оператору, разбирает его ответ и сообщает платформе результат, а всё остальное - очередь, повторы, состояния - остаётся штатным.
Следим за очередью автоматически:
// задание по расписанию: чек висит без результата дольше часа - это повод писать$stuck = CheckTable::getList([ 'filter' => ['!=STATUS' => 'Y', '<DATE_CREATE' => $hourAgo], 'select' => ['ID', 'ORDER_ID', 'ERROR_MESSAGE'],])->fetchAll();if ($stuck) { \Bitrix\Main\Mail\Event::send(['EVENT_NAME' => 'CHECK_STUCK', 'LID' => SITE_ID, 'C_FIELDS' => ['COUNT' => count($stuck)]]); }Очередь обязана жаловаться сама. Ежедневный отчёт о зависших чеках стоит одного задания и снимает главный риск этой задачи: узнать о непробитых чеках через месяц.
Сверяем чеки с оплатами за день:
$paid = \Bitrix\Sale\Internals\OrderTable::getList([ 'select' => ['CNT' => new \Bitrix\Main\Entity\ExpressionField('CNT', 'COUNT(%s)', 'ID')], 'filter' => ['=PAYED' => 'Y', '>=DATE_PAYED' => $dayStart],])->fetch();$checks = CheckTable::getList(['select' => ['CNT' => new \Bitrix\Main\Entity\ExpressionField( 'CNT', 'COUNT(%s)', 'ID')], 'filter' => ['=STATUS' => 'Y', '>=DATE_CREATE' => $dayStart]])->fetch();printf("оплат %s, чеков %s\n", $paid['CNT'], $checks['CNT']);// расхождение этих двух чисел за день и есть повод идти в журнал кассыЧисла обязаны сходиться, и расхождение стоит замечать в тот же день. Один непробитый чек находится за минуту, а сотня за месяц превращается в отдельный проект по восстановлению.
Ограничения
Работа с кассами живёт в модуле интернет-магазина актуальной версии. На старом ядре списка касс нет вовсе, и первый шаг там - обновление продукта, а не настройка. Набор готовых обработчиков тоже привязан к версии: касса, появившаяся у оператора в этом году, на прошлогоднем ядре может отсутствовать.
Признак способа расчёта и признак предмета расчёта - требования закона, а не настройки на вкус. Предоплата, полный расчёт и расчёт при получении оформляются разными чеками, и решать, какой из них уместен, магазин обязан вместе со своим бухгалтером.
Повторная печать чека не всегда безобидна. У оператора он может оказаться вторым фискальным документом на ту же сумму, и отменять его придётся отдельно. Поэтому ручной повтор делают после проверки очереди, а не вместо неё.
Кассу подключают до запуска продаж, а не после первых заказов. Задним числом пробить чеки за прошедшую неделю можно, но объясняться за это придётся с оператором и с бухгалтерией, а иногда и с проверяющим.
Схему расчётов магазина стоит записать словами до всякой настройки. Когда берём деньги, когда отгружаем, что происходит при частичном возврате - на эти вопросы отвечает бизнес, а настройки кассы лишь повторяют его ответ. Разработчик, угадывающий эти ответы самостоятельно, обычно угадывает неверно.
Проверку очереди чеков полезно поставить в тот же день, что и саму кассу. Это единственная часть задачи, которая ловит чужие сбои: недоступность оператора, смену его правил и истёкшие реквизиты доступа.
Типичные проблемы
Заказ оплачен, а чек не пробит.
Чек висит в очереди с ошибкой от оператора кассы. Очередь чеков смотрят ежедневно, а не по жалобе бухгалтерии.
На один заказ пробито два одинаковых чека.
Печать вызвана из кода повторно, без проверки уже существующего чека. Перед ручным вызовом проверяют очередь.
В чеке нулевая ставка налога.
У товара пустое значение ставки, приехавшее обменом. Ставки проверяют в каталоге до боевого запуска.
Чеки не пробиваются по одной платёжной системе.
Касса не связана с этой платёжной системой в настройках. Связь задают для каждой системы отдельно.
При предоплате чек с неверным признаком расчёта.
Признак способа расчёта задан одним значением на все случаи. Предоплата и полный расчёт оформляются разными признаками.
Частые вопросы
Сколько чеков бывает у одного заказа?
Обычно два: при оплате и при выдаче товара. Точное число зависит от схемы расчётов магазина.
Что делать с чеком, зависшим в очереди?
Разобрать текст ошибки оператора и повторить печать после исправления. Молча удалять такой чек нельзя.
Нужен ли свой обработчик кассы?
Только если готового для этой кассы нет. Штатные обработчики обновляются вместе с продуктом.
Как проверить настройку до боевых продаж?
Тестовым режимом оператора и заказом на минимальную сумму. Состав чека при этом смотрят целиком.
Смежное
- Онлайн-касса и чеки - оглавление подтемы
- Чек не уходит в кассу: разбор причин - когда чек так и не пробит
- Оплаты и отгрузки заказа: объекты, признаки, частичные операции - к чему привязан чек
- Свой обработчик оплаты: форма, уведомление, отметка платежа - кто ставит признак оплаты
- НДС в каталоге и заказах: ставки, цена с налогом и доставка - откуда берётся ставка
- Каталог и продажи - устройство магазина целиком
- Возврат покупателю: отмена оплаты, чек возврата, склад - вторая половина расчётов