Integrating Returns with the Online Cash Register in 1C-Bitrix
Under Federal Law No. 54-FZ, when refunding money to a buyer, the cash register must issue a receipt with the settlement attribute "Return of Receipt." If the website processes payments through Bitrix with an online cash register, any return must automatically generate a fiscal document through the same channel. Without this, a violation occurs: money has been refunded but no receipt has been issued.
How Bitrix Interacts with the Cash Register
The sale.cashbox module (bitrix/modules/sale/cashbox/) handles fiscalization. Receipts are sent through handlers inheriting from \Bitrix\Sale\Cashbox\CashboxPaymaster or \Bitrix\Sale\Cashbox\CashboxAtol. Standard handlers include: Atol Online, CloudKassir, OrangeData, YooKassa, and others.
When an order is paid, Bitrix calls \Bitrix\Sale\Cashbox\Manager::sendCheck() with receipt type CHECK_TYPE_SELL (income). On a return — CHECK_TYPE_SELL_RETURN (return of income).
Tables: b_sale_cashbox_check — receipt history; b_sale_cashbox — configured cash registers.
How a Return Receipt Is Generated
Bitrix automatically creates a return receipt when two conditions are met:
- The return transitions to the
COMPLETEDstatus - A cash register is linked to the original payment and a confirmed fiscal income receipt already exists
The code that triggers this — \Bitrix\Sale\Cashbox\Manager::addByReturn():
// Inside the OnSaleReturnComplete event handler
\Bitrix\Sale\Cashbox\Manager::addByReturn($return);
If you have a non-standard scenario (a return is created by an external script), you must call this method manually after saving the return.
What Goes into the Return Receipt
Receipt line items are built from b_sale_order_return_item. Each line item contains:
- Product name (from
b_iblock_element.NAMEvia JOIN onb_sale_basket.PRODUCT_ID) - Quantity
- Price
- VAT rate
- Settlement subject attribute (goods/service/work) — taken from the original order item settings
If VAT is missing or incorrectly specified in the original order, the return receipt will contain an error. This is a common issue when migrating from Bitrix to a new cash register scheme.
Common Issues
Return receipt is not sent. Cause: the return was created directly in the database or via an unofficial mechanism — the OnSaleReturnComplete event does not fire. Solution: always use ORM methods.
Error: "Return amount exceeds income amount." The fiscal operator rejects the receipt if the return amount is greater than in the original income receipt. This happens with partial returns of multiple payments for one order — each return receipt must be linked to a specific income receipt via PARENT_CHECK_ID in b_sale_cashbox_check.
Duplicate receipt on repeated request. If the network fails, Bitrix may send the request twice. Atol Online has an external_id parameter — a unique receipt identifier on your side. Use it so the operator can detect duplicates.
Partial return of multiple items from one order. The receipt must contain only the returned items with the correct quantities. The standard Manager::addByReturn() handles this if b_sale_order_return_item is populated correctly.
Testing Fiscalization of Returns
All fiscal operators provide a test environment. Atol Online — test URL https://testonline.atol.ru/possystem/v5/. OrangeData — test keys and certificates.
Pre-production checklist:
| Scenario | What to verify |
|---|---|
| Full order return | Return receipt amount = income receipt amount |
| Partial return of one item | Receipt contains only the returned item |
| Return of order with multiple payments | Receipt linked to the correct payment |
| Return after price adjustment | VAT recalculated correctly |
| Resend after timeout | No duplicate receipt at the operator |
Configuring Fiscalization Error Notifications
If a return receipt fails, the fiscal operator returns an error. Bitrix stores it in the ERROR field of b_sale_cashbox_check, but by default the manager is not notified. Set up an agent:
// Agent: checks for unhandled errors every 30 minutes
$checks = \Bitrix\Sale\Cashbox\CheckManager::getList([
'filter' => [
'STATUS' => \Bitrix\Sale\Cashbox\Check::CHECK_STATUS_ERROR,
'>=DATE_CREATE' => new \Bitrix\Main\Type\DateTime('-1 hour'),
],
]);
foreach ($checks as $check) {
if ($check['TYPE'] === \Bitrix\Sale\Cashbox\SellReturnCheck::TYPE) {
NotificationService::alertAdmin(
'Return receipt error #' . $check['ID'] . ': ' . $check['ERROR']
);
}
}
Scope of Work
- Check
sale.cashboxmodule version and compatibility with the fiscal operator version - Configure the cash register handler for the return environment (test/production URL)
- Test all return scenarios in the operator's test environment
- Set up a fiscalization error monitoring agent
- Verify VAT correctness in order and return line items
- Documentation for manual receipt issuance in exceptional situations
Timeline: if the cash register is already configured for income receipts — configuring returns takes 1–2 weeks. If the cash register is being set up from scratch — 3–5 weeks, including testing across all scenarios.







