Разработка функционала подписки на товары 1С-Битрикс
Интернет-магазин продаёт расходники: кофе, корм для животных, фильтры, бытовую химию. Клиент покупает одно и то же раз в две-четыре недели. Без подписки он каждый раз проходит полный цикл заказа — или уходит к конкуренту, у которого есть автоповтор. В 1С-Битрикс готового модуля подписки на товары нет. Его нужно строить на базе sale, catalog и собственного модуля, связывающего периодичность с автоматическим созданием заказов.
Архитектура решения
Подписка — это не просто «повторить заказ». Это отдельная сущность со своим жизненным циклом: создание, активная фаза, пауза, отмена, возобновление. Хранить её удобно в отдельной таблице, например b_subscription_order:
| Поле | Тип | Назначение |
|---|---|---|
| ID | int | Первичный ключ |
| USER_ID | int | Привязка к пользователю |
| BASKET_DATA | text | Сериализованный состав корзины |
| PERIOD_DAYS | int | Интервал повтора в днях |
| NEXT_DATE | datetime | Дата следующего заказа |
| STATUS | enum | ACTIVE, PAUSED, CANCELLED |
| PAY_SYSTEM_ID | int | Платёжная система |
| DELIVERY_ID | int | Служба доставки |
| PERSON_TYPE_ID | int | Тип плательщика |
| DISCOUNT_PERCENT | decimal | Скидка подписчика |
Для работы с таблицей создаём ORM-класс, наследуясь от \Bitrix\Main\ORM\Data\DataManager. Это даёт стандартные методы getList(), add(), update(), delete() и возможность использовать фильтры D7.
Автоматическое создание заказов
Ядро функционала — агент или cron-задача, которая запускается раз в сутки (или чаще) и проверяет записи с STATUS = ACTIVE и NEXT_DATE <= NOW().
Алгоритм обработки одной подписки:
- Десериализовать
BASKET_DATA, проверить наличие каждого товара через\Bitrix\Catalog\ProductTable::getList(). - Проверить остатки:
\CCatalogStoreProduct::GetList()или\Bitrix\Catalog\StoreProductTable. Если товара нет на складе — пропустить позицию и уведомить клиента. - Создать корзину:
\Bitrix\Sale\Basket::create(), добавитьBasketItemдля каждой позиции. - Применить скидку подписчика через кастомное правило корзины или прямое изменение цены в
BasketItem::setField('CUSTOM_PRICE', 'Y')+BasketItem::setField('PRICE', $discountedPrice). - Создать заказ:
\Bitrix\Sale\Order::create(), привязать корзину, установитьPERSON_TYPE_ID, заполнить свойства заказа из сохранённого профиля. - Привязать доставку и оплату:
\Bitrix\Sale\Shipment::create(),\Bitrix\Sale\Payment::create(). - Сохранить заказ:
$order->save(). - Обновить
NEXT_DATEнаNEXT_DATE + PERIOD_DAYS.
Критически важно оборачивать каждую подписку в try/catch и логировать ошибки. Один сбой не должен останавливать обработку остальных.
Выбор между агентом и cron. Агенты Битрикс (\CAgent) удобны, но выполняются в контексте хита пользователя (если не настроен cron_events). Для подписки это неприемлемо: создание заказа — тяжёлая операция. Рекомендуется отдельный PHP-скрипт, вызываемый из crontab:
*/30 * * * * /usr/bin/php /home/bitrix/www/local/cron/subscription_process.php
Скрипт подключает пролог (/bitrix/modules/main/include/prolog_before.php), затем обрабатывает подписки пакетами по 50.
Управление подпиской в личном кабинете
Пользователь должен видеть свои активные подписки, менять периодичность, состав, ставить на паузу. Это реализуется через кастомный компонент в разделе /personal/subscriptions/. Компонент использует ORM-класс подписки и рендерит форму с полями:
- Список товаров с возможностью удалить позицию или изменить количество.
- Выбор периода: 7 / 14 / 21 / 30 дней.
- Кнопки «Приостановить» и «Отменить».
- Дата следующей доставки с возможностью сдвига.
При изменении состава корзины пересчитывается BASKET_DATA. При паузе STATUS переключается на PAUSED, агент пропускает запись.
Рекуррентные платежи
Подписка без автоматического списания — полумера. Клиент получает заказ со статусом «Ожидает оплаты» и должен оплатить вручную. Полноценная подписка требует рекуррентных платежей.
Рекуррентные платежи поддерживают не все платёжные системы. Из распространённых: ЮKassa (метод createPayment с параметром payment_method_id сохранённого метода), CloudPayments (recurrent через post-запросы к API). В Битрикс рекуррент реализуется через кастомный обработчик платёжной системы, наследующий \Bitrix\Sale\PaySystem\BaseServiceHandler.
Логика: при первой оплате сохраняем токен платёжного метода в b_subscription_order.PAY_TOKEN. При автосоздании заказа — инициируем списание через API платёжной системы. Если списание не прошло — помечаем заказ как неоплаченный и отправляем письмо клиенту.
Сроки внедрения
| Масштаб | Состав | Срок |
|---|---|---|
| Базовый | Подписка без автоплатежа, управление в ЛК, агент | 5-7 дней |
| Полный | Рекуррентные платежи, уведомления, аналитика подписок | 8-12 дней |
Уведомления
Минимальный набор почтовых событий:
- SUBSCRIPTION_CREATED — подтверждение создания подписки.
- SUBSCRIPTION_ORDER_CREATED — уведомление о новом заказе по подписке.
- SUBSCRIPTION_ITEM_OUT_OF_STOCK — товар из подписки закончился.
- SUBSCRIPTION_PAYMENT_FAILED — ошибка автоматического списания.
- SUBSCRIPTION_REMINDER — напоминание за 1-2 дня до следующего заказа (даёт возможность изменить состав).
Почтовые шаблоны создаются в административном разделе Настройки → Почтовые события с типом события, привязанным к сайту.







