Managing Product Returns on 1C-Bitrix
A typical situation: a manager opens an order in /bitrix/admin/sale_order_view.php, manually changes the status, calls the warehouse, then opens 1C to create a "Return of Goods from Buyer" document. One return takes 20-30 minutes. With 15 returns per day, one person is occupied solely with this. We automate the entire cycle: from the "Request a Return" button in the customer's personal account to the posting in 1C and the return receipt under Federal Law 54-FZ.
Where Exactly the Standard Process Breaks Down
Out of the box, Bitrix has no separate "return" entity. There are order statuses in b_sale_status, there's cancellation via CSaleOrder::CancelOrder(), but a full-fledged workflow with partial returns, exchanges, and reverse logistics simply doesn't exist. It has to be built.
-
Partial return — the customer wants to return 2 of 5 items. The standard
CancelOrdercancels the entire order. Custom logic viaCSaleBasketand recalculation withCSaleOrder::Updateis needed -
Inventory discrepancies — the product arrived at the warehouse, but it's not in
b_catalog_store_productbecause the manager forgot to process the receipt. On the site — "Out of Stock," even though the box is sitting on the shelf - Refunds — YooKassa, CloudPayments, Tinkoff — each has its own refund method, its own timeouts, its own error handling. Manual refunds through the payment gateway's dashboard — routine that eats up time
- 54-FZ — a return receipt with the "RETURN OF INCOME" settlement type must be sent to the fiscal data operator (OFD). Without automation, the manager generates it manually in the POS software
What We Build
Customer personal account — self-service returns.
A custom section at /personal/returns/, integrated with sale.personal.order.list. The customer does everything themselves:
- Selects an order from
b_sale_order, sees the list of items fromb_sale_basket - Marks specific products, selects a reason from the reference list (information block property
RETURN_REASONS) or writes free text - Uploads photos via
CFile::SaveFile()— defects, delivery damage - Chooses the return method: courier (CDEK API), pickup point, postal service
- Chooses where to return the money: to the card (refund via payment gateway), to the internal account (
CSaleUserAccount), exchange for another product - Sees the request status in real time — via custom statuses in
b_sale_status_lang
Manager admin panel — no unnecessary clicks.
A dedicated section in the admin panel built on \Bitrix\Main\Engine\Controller:
- Request queue with filters: status, amount, reason, date, manager. Grid on
CAdminListor a custom React component - All information about the request on one screen: order, customer, correspondence history, photos, documents
- One-click actions: approve, reject, request photos, escalate for approval
- Routing: returns above a threshold (configured in
b_option) go to a supervisor via thebizprocmodule business process - Auto-generation of return act and return invoice — PDF via mPDF or TCPDF
Automation — minimal manual operations.
- Returns below a configurable threshold (e.g., 3,000) — auto-approval via the
OnSaleOrderSavedevent handler - 54-FZ return receipt: calling
\Bitrix\Sale\Cashbox\Manager::addChecks()with typeCheck::RETURN_TYPE. Sent to OFD automatically - Notification chain: email via
CEvent::Send(), SMS via SMS gateway, push - After warehouse acceptance — automatic receipt via
CCatalogStoreDocsBarcodeand update ofb_catalog_store_product - Synchronization with 1C: the "Return of Goods from Buyer" document is created automatically during exchange via
\Bitrix\Sale\Exchange - Bonus points earned from the purchase — deduction via
CSaleUserAccount::UpdateAccount()with a negative amount
Payment System Integration — A Separate Headache
Each payment gateway has its own refund API, its own time constraints, its own error codes:
-
YooKassa —
POST /v3/refunds, full and partial refund. Important: refund is only possible within 365 days of payment. Automatic return receipt via receipt API -
CloudPayments —
refundmethod byTransactionId. Refund to the card within 1-5 business days. If it's a 3DS payment — the refund may take up to 30 days on the bank's side -
Tinkoff Acquiring —
CancelbyPaymentId. If paid in installments — the refund recalculates the schedule, and that's separate logic in thesale.paysystem.handler - Apple Pay / Google Pay — the refund goes through the same acquirer, the token is tied to the transaction
- Cash on delivery — refund via payment gateway is impossible, the customer's bank details are needed. A separate form in the personal account
-
Internal account —
CSaleUserAccount::Pay()with the amount credited. Can be incentivized with a multiplier (x1.1) — a 10% bonus for choosing a balance refund instead of a card refund
Legal Compliance — Non-Negotiable
- Consumer Protection Law, Art. 26.1 — distance selling: cancellation at any time before receipt, 7 days after. The system tracks deadlines automatically and warns the manager when the deadline approaches
-
14 days — return of products of proper quality. Check: order
date_insert+ delivery date from tracking + 14 days. If expired — the request is rejected with an explanation -
54-FZ — a return receipt is mandatory.
\Bitrix\Sale\Cashbox\Checkwith typereturnand the correct settlement attribute - Document flow — return act, buyer's application, acceptance act — templates in the system, filled automatically from order data
Return Analytics — Data for Decision-Making
A custom dashboard in the admin panel, data from b_sale_order + a custom returns table:
- Return percentage by category, brand, manager, period
- Top return reasons. If "Does not match description" is in the top 3 — the problem is in the product cards, not the customers
- Financial breakdown: total refund amount, average return value, refund/exchange/balance ratio
- Alerts: if the return rate for a specific SKU exceeds 15% — notification to the category manager
Exchange and Replacement — Preserving the Sale
Not every return is lost revenue. Exchange via CSaleOrder::Update with cart recalculation:
- Replacement with the same product in a different size/color — a new item in
b_sale_basket, the old one goes to return - Exchange for a different product with surcharge — automatic difference calculation, additional payment via the same payment method
- Generation of a shipping invoice for the exchange product via the delivery service API
Reverse Logistics — Integrations
-
CDEK —
POST /v2/orderswithtype: 2(return). Automatic pickup request, tracking via webhook - Boxberry — parcel shop API for selecting a return pickup point
- Russian Post — generating a return invoice via the shipment API
- Tracking the return parcel in the personal account — statuses pulled via a cron task
Implementation Timelines
| Component | Timeline |
|---|---|
| Customer account (form + statuses) | 3-5 days |
| Manager admin panel (grid + actions) | 3-5 days |
| Payment system integration | 2-3 days |
| 1C exchange (return document) | 3-5 days |
| Automation (54-FZ, notifications, inventory) | 2-3 days |
| Reverse logistics (CDEK, Boxberry) | 2-3 days |
| Total | 2-4 weeks |
ROI: return processing time drops from 25 minutes to 3 minutes. With 15 returns per day — that frees up an entire manager. Plus increased repeat purchases: a customer who can easily return a product comes back again.







