Перейти к содержимому

Онлайн-касса - подключение, состав чека, очередь и ошибки

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

Механика

Чек в платформе - это отдельная сущность со своим состоянием. Он создаётся привязанным к оплате или к отгрузке, уходит в очередь, отправляется кассе или её оператору и возвращается с результатом. Между созданием и результатом проходит от секунд до часов, и всё это время чек живёт в промежуточном состоянии.

Касса связана с платёжной системой, а не с заказом. Это и определяет, какой чек чем пробивается: оплата картой через одну систему уходит на одну кассу, наличные при получении - на другую или вообще на кассу курьерской службы. Заказ при этом может собрать два чека и два разных признака расчёта.

Состав чека собирается из позиций заказа, а не пишется вручную. Наименование, количество, цена, ставка налога и признак способа расчёта берутся из товара, из настроек каталога и из настроек кассы. Ошибка в любом из этих мест даёт формально пробитый, но неверный чек, и заметит её проверяющий, а не покупатель.

Печать бывает немедленной и отложенной. Немедленная уходит в момент события, отложенная копится и отправляется заданием по расписанию. Второй способ мягче переживает недоступность оператора, но требует следить за очередью: молча растущая очередь непробитых чеков - самая дорогая из возможных ситуаций.

Отдельно стоит понимать, что сайт в этой цепочке - не последняя инстанция. Фискальный документ создаёт касса или её оператор, и успешный ответ означает только то, что запрос принят. Расхождение между числом оплат на сайте и числом чеков у оператора - обычное дело в первые недели, и сверять их приходится вручную, пока схема не устоится.

Шаги

  1. Зарегистрировать кассу у оператора и получить её реквизиты доступа.
  2. Завести кассу в магазине и вписать эти реквизиты в её настройки.
  3. Связать кассу с платёжными системами, по которым она пробивает чеки.
  4. Проверить ставки налога у товаров и в настройках самой кассы.
  5. Провести тестовый заказ и убедиться, что чек ушёл и вернулся успешным.
  6. Завести проверку очереди чеков, которая замечает непробитые сама.

Код

Смотрим очередь чеков:

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']);
// расхождение этих двух чисел за день и есть повод идти в журнал кассы

Числа обязаны сходиться, и расхождение стоит замечать в тот же день. Один непробитый чек находится за минуту, а сотня за месяц превращается в отдельный проект по восстановлению.

Ограничения

Работа с кассами живёт в модуле интернет-магазина актуальной версии. На старом ядре списка касс нет вовсе, и первый шаг там - обновление продукта, а не настройка. Набор готовых обработчиков тоже привязан к версии: касса, появившаяся у оператора в этом году, на прошлогоднем ядре может отсутствовать.

Признак способа расчёта и признак предмета расчёта - требования закона, а не настройки на вкус. Предоплата, полный расчёт и расчёт при получении оформляются разными чеками, и решать, какой из них уместен, магазин обязан вместе со своим бухгалтером.

Повторная печать чека не всегда безобидна. У оператора он может оказаться вторым фискальным документом на ту же сумму, и отменять его придётся отдельно. Поэтому ручной повтор делают после проверки очереди, а не вместо неё.

Кассу подключают до запуска продаж, а не после первых заказов. Задним числом пробить чеки за прошедшую неделю можно, но объясняться за это придётся с оператором и с бухгалтерией, а иногда и с проверяющим.

Схему расчётов магазина стоит записать словами до всякой настройки. Когда берём деньги, когда отгружаем, что происходит при частичном возврате - на эти вопросы отвечает бизнес, а настройки кассы лишь повторяют его ответ. Разработчик, угадывающий эти ответы самостоятельно, обычно угадывает неверно.

Проверку очереди чеков полезно поставить в тот же день, что и саму кассу. Это единственная часть задачи, которая ловит чужие сбои: недоступность оператора, смену его правил и истёкшие реквизиты доступа.

Типичные проблемы

Заказ оплачен, а чек не пробит.

Чек висит в очереди с ошибкой от оператора кассы. Очередь чеков смотрят ежедневно, а не по жалобе бухгалтерии.

На один заказ пробито два одинаковых чека.

Печать вызвана из кода повторно, без проверки уже существующего чека. Перед ручным вызовом проверяют очередь.

В чеке нулевая ставка налога.

У товара пустое значение ставки, приехавшее обменом. Ставки проверяют в каталоге до боевого запуска.

Чеки не пробиваются по одной платёжной системе.

Касса не связана с этой платёжной системой в настройках. Связь задают для каждой системы отдельно.

При предоплате чек с неверным признаком расчёта.

Признак способа расчёта задан одним значением на все случаи. Предоплата и полный расчёт оформляются разными признаками.

Частые вопросы

Сколько чеков бывает у одного заказа?

Обычно два: при оплате и при выдаче товара. Точное число зависит от схемы расчётов магазина.

Что делать с чеком, зависшим в очереди?

Разобрать текст ошибки оператора и повторить печать после исправления. Молча удалять такой чек нельзя.

Нужен ли свой обработчик кассы?

Только если готового для этой кассы нет. Штатные обработчики обновляются вместе с продуктом.

Как проверить настройку до боевых продаж?

Тестовым режимом оператора и заказом на минимальную сумму. Состав чека при этом смотрят целиком.

Смежное

Первоисточник