Development of Product Subscription Functionality for 1C-Bitrix
Online store sells consumables: coffee, pet food, filters, household chemicals. Customer buys the same thing every two to four weeks. Without subscription, he goes through full order cycle every time — or switches to competitor with auto-repeat. 1C-Bitrix has no built-in subscription module. Build it on base of sale, catalog and custom module linking periodicity to automatic order creation.
Solution Architecture
Subscription is not just "repeat order". It's separate entity with own lifecycle: creation, active phase, pause, cancellation, resumption. Store it conveniently in separate table, e.g. b_subscription_order:
| Field | Type | Purpose |
|---|---|---|
| ID | int | Primary key |
| USER_ID | int | User binding |
| BASKET_DATA | text | Serialized cart composition |
| PERIOD_DAYS | int | Repetition interval in days |
| NEXT_DATE | datetime | Next order date |
| STATUS | enum | ACTIVE, PAUSED, CANCELLED |
| PAY_SYSTEM_ID | int | Payment system |
| DELIVERY_ID | int | Delivery service |
| PERSON_TYPE_ID | int | Payer type |
| DISCOUNT_PERCENT | decimal | Subscriber discount |
For table interaction, create ORM-class, inheriting from \Bitrix\Main\ORM\Data\DataManager. Gives standard methods getList(), add(), update(), delete() and D7 filter capability.
Automatic Order Creation
Core of functionality — agent or cron task running daily (or more) and checking records with STATUS = ACTIVE and NEXT_DATE <= NOW().
Processing algorithm for one subscription:
- Deserialize
BASKET_DATA, verify each product exists via\Bitrix\Catalog\ProductTable::getList(). - Check stock:
\CCatalogStoreProduct::GetList()or\Bitrix\Catalog\StoreProductTable. If out of stock — skip item and notify customer. - Create basket:
\Bitrix\Sale\Basket::create(), addBasketItemfor each position. - Apply subscriber discount via custom cart rule or direct price change in
BasketItem::setField('CUSTOM_PRICE', 'Y')+BasketItem::setField('PRICE', $discountedPrice). - Create order:
\Bitrix\Sale\Order::create(), bind basket, setPERSON_TYPE_ID, fill order properties from saved profile. - Bind delivery and payment:
\Bitrix\Sale\Shipment::create(),\Bitrix\Sale\Payment::create(). - Save order:
$order->save(). - Update
NEXT_DATEtoNEXT_DATE + PERIOD_DAYS.
Critically important to wrap each subscription in try/catch and log errors. One failure shouldn't stop processing of rest.
Agent vs Cron choice. Bitrix agents (\CAgent) convenient but execute in user hit context (unless cron_events configured). For subscription unacceptable: order creation is heavy operation. Recommend separate PHP script called from crontab:
*/30 * * * * /usr/bin/php /home/bitrix/www/local/cron/subscription_process.php
Script includes prologue (/bitrix/modules/main/include/prolog_before.php), then processes subscriptions in batches of 50.
Subscription Management in Personal Account
User must see active subscriptions, change frequency, composition, pause. Implemented via custom component in /personal/subscriptions/. Component uses ORM subscription class and renders form with fields:
- Product list with ability to remove item or change quantity.
- Period selection: 7 / 14 / 21 / 30 days.
- "Pause" and "Cancel" buttons.
- Next delivery date with shift option.
On composition change, BASKET_DATA recalculated. On pause, STATUS switches to PAUSED, agent skips record.
Recurring Payments
Subscription without automatic charging — half-measure. Customer gets order with "Awaiting payment" status and must pay manually. Full subscription requires recurring payments.
Recurring payments not all payment systems support. From common: YooKassa (method createPayment with saved method payment_method_id parameter), CloudPayments (recurrent via API post-requests). In Bitrix, recurrent implemented via custom payment system handler, inheriting \Bitrix\Sale\PaySystem\BaseServiceHandler.
Logic: on first payment, save payment method token in b_subscription_order.PAY_TOKEN. On auto order creation — initiate charge via payment system API. If charge fails — mark order as unpaid and send customer email.
Implementation Timelines
| Scale | Contents | Timeline |
|---|---|---|
| Basic | Subscription without autopay, personal account management, agent | 5-7 days |
| Full | Recurring payments, notifications, subscription analytics | 8-12 days |
Notifications
Minimal email event set:
- SUBSCRIPTION_CREATED — subscription creation confirmation.
- SUBSCRIPTION_ORDER_CREATED — notification of new subscription order.
- SUBSCRIPTION_ITEM_OUT_OF_STOCK — product from subscription out of stock.
- SUBSCRIPTION_PAYMENT_FAILED — automatic charge error.
- SUBSCRIPTION_REMINDER — reminder 1-2 days before next order (allows composition change).
Email templates created in Settings → Email Events with event type bound to site.







