На сайте товары и услуги доступны по подписке, пользователи пополняют внутренний счёт,
после чего происходит автоматическое дублирование заказа с заданной периодичностью и
списание средств с баланса. Примеры использования:
- Предоставление услуг хостинга;
- Доставка воды в офис;
- Подписка на журнал;
- Так же приходилось реализовывать магазин по еженедельной доставке новых носков;
- и.т.д.
Пополнение баланса внутреннего счета
Здесь всё просто: в 1С-Битрикс уже существует компонент для этих целей – sale.account.pay (Добавление средств на счёт). Необходимо вывести его в кабинете пользователя и настроить под нужные суммы. Шаблон компонента достаточно простой и легко адаптируется под любой дизайн.

Скрипт для повтора заказа и автоматической оплаты со списанием с баланса
Ниже представлен скрипт, который можно запускать по cron с нужной периодичностью (например в 00:00 каждого дня).
Также его можно выполнять через агенты в системе (подробнее – Создание агента в
1С-Битрикс).
$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/../..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS",true);
define('BX_NO_ACCELERATOR_RESET', true);
define('CHK_EVENT', true);
define('BX_WITH_ON_AFTER_EPILOG', true);
require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
@set_time_limit(0);
@ignore_user_abort(true);
use Bitrix\Main\Loader,
Bitrix\Sale\Basket,
Bitrix\Sale\Order,
Bitrix\Currency\CurrencyManager;
Loader::includeModule('sale');
// Получаем дату неделю назад от текущей
$initialDate = new \Bitrix\Main\Type\Date();
$weekAgo = $initialDate->add('-1w');
// Получаем заказы, созданные неделю назад
$orderList = Order::getList([
'filter' => [
'DATE_INSERT' => $weekAgo,
'STATUS' => 'F'
],
'select' => [
'ID',
'USER_ID',
'PRICE',
'CURRENCY'
]
]);
while ($order = $orderList->fetch()) {
// Получаем ID пользователя из заказа
$userId = $order['USER_ID'];
// Получаем сумму заказа
$orderTotal = $order['PRICE'];
// Получаем внутренний счет пользователя
if (
$bill = CSaleUserAccount::GetByUserID(
$userId,
$order['CURRENCY']
)
) {
$userBalance = $bill['CURRENT_BUDGET'];
// Проверяем, достаточно ли средств на внутреннем счете
// для оплаты заказа
if ($userBalance >= $orderTotal) {
// Повторяем заказ функция repeatOrder (сама она ниже)
repeatOrder($order['ID']);
} else {
/*
Денег на балансе не достаточно
Можно отправить пользователю письмо
с оповещением
*/
}
} else {
/*
У пользователя в принципе нет счета
Лучше всего при регистрации в фоне счет создавать
с нулем на балансе или с привественным бонусом
CSaleUserAccount::Add
*/
}
}
function repeatOrder($orderId)
{
// Загружаем заказ по ID
$loadOrder = Order::load($order);
// Получаем данные о пользователе
$userId = $loadOrder->getUserId();
$userEmail = $loadOrder->getPropertyCollection()->getUserEmail(); // Получаем email пользователя
$siteId = $loadOrder->getSiteId();
$currencyCode = CurrencyManager::getBaseCurrency();
// Очищаем корзину пользователя
$basket = Sale\Basket::loadItemsForFUser(
$userId,
$siteId
);
foreach ($basket as $basketItem) {
// Отложенные не трогаем
if ($basketItem->getField('DELAY') === 'N') {
// Удаляем запись
$basket->getItemById($basketItem->getId())->delete();
// Сохраняем корзину
$basket->save();
}
}
// Получаем корзину из заказа
$orderBasket = $loadOrder->getBasket();
// Тут можно добавить проверку на существование корзины
// И если ее нет создать пустую
// $basket = Basket::create($siteId);
// Переносим товары из корзины старого заказа в новую корзину
foreach ($orderBasket as $orderItem) {
$productID = $orderItem->getProductId();
$quantity = $orderItem->getQuantity();
// Добавляем товар в новую корзину
$basketItem = $basket->createItem('catalog', $productID);
$basketItem->setFields(array(
'QUANTITY' => $quantity,
'CURRENCY' => $currencyCode,
'PRODUCT_PROVIDER_CLASS' => '\Bitrix\Catalog\Product\CatalogProvider',
));
}
// Создаем новый заказ на основе новой корзины
$newOrder = Order::create($siteId, $userId);
$newOrder->setPersonTypeId(1); // Установите ID типа плательщика
$newOrder->setBasket($basket);
// Устанавливаем доставку с ID 1
$shipmentCollection = $loadOrder->getShipmentCollection();
$shipment = $shipmentCollection->createItem(
Bitrix\Sale\Delivery\Services\Manager::getObjectById(1) // 1 - ID службы доставки
);
$shipmentItemCollection = $shipment->getShipmentItemCollection();
foreach ($basket as $basketItem) {
$item = $shipmentItemCollection->createItem($basketItem);
$item->setQuantity($basketItem->getQuantity());
}
// Устанавливаем платежную систему с ID 4
$paymentCollection = $newOrder->getPaymentCollection();
$payment = $paymentCollection->createItem(
Bitrix\Sale\PaySystem\Manager::getObjectById(1) // ID платежной системы
);
$payment->setField("SUM", $newOrder->getPrice());
$payment->setField("CURRENCY", $newOrder->getCurrency());
$paymentCollection[0]->setPaid('Y');
// Сохраняем новый заказ
$result = $newOrder->save();
if (!$result->isSuccess()) {
throw new \Exception("Не удалось создать новый заказ: " . implode(", ", $result->getErrorMessages()));
}
$orderId = $newOrder->getId();
return $orderId; // Возвращаем ID нового заказа
}
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php');
Данный скрипт получает список выполненных заказов (со статусом «F»), совершённых неделю назад и собирает данные о заказе (ID, ID пользователя, цену, валюту).
Определяется внутренний счёт пользователя. Если средств достаточно для списания суммы заказа, происходит вызов функции повтора заказа. Если средств недостаточно — заказ остается без изменений, можно вывести соответствующее сообщение или оптравить письмо пользователю.
Функция repeatOrder().
- По переданному ID загружается исходный заказ.
- Из заказа извлекаются данные о пользователе, его email, сайт и базовая валюта.
- Очищается текущая корзина пользователя что бы не было накладок и спорных ситуаций.
- Получаем корзину исходного заказа и создаём новую корзину, в которую копируются все товары с сохранением количества.
- Создаём новый заказ, которому присваиваем тип плательщика.
- Затем устанавливаем доставку: выбирается служба доставки по ID 1 - это системная доставка "Без доставки". Подходит для услуг, но можете скопировать из предыдущего заказа или явно указать ID нужной доставки
- Выполняем настройку платежной системы: выбирается система по ID 1, это всегда "Внутренний счет пользователя".
- Оплата помечается как переключенная в "Оплачен", средства с внутреннего счета спишутся автоматически в пользу этого заказа
- Новый заказ сохраняется. При отсутствии ошибок возвращается ID созданного заказа, что свидетельствует об успешном повторении заказа.