Налаштування підтвердження замовлення через SMS-код 1С-Бітрікс
На великих магазинах із високим середнім чеком зустрічається завдання: перед фінальним оформленням замовлення підтвердити намір покупця по SMS. Це знижує кількість «випадкових» замовлень і верифікує номер телефону, який потім використовується в програмі лояльності. Стандартний чекаут 1С-Бітрікс такого механізму не має — потрібно втручатися в процес оформлення.
Архітектура підтвердження
Процес: покупець заповнив форму замовлення → натиснув «Оформити» → система надсилає SMS із кодом на вказаний телефон → покупець вводить код → замовлення створюється. Замовлення в 1С-Бітрікс створюється лише після успішної верифікації коду, не раніше.
Зберігання кодів — у таблиці local_order_confirmations:
CREATE TABLE local_order_confirmations (
ID INT AUTO_INCREMENT PRIMARY KEY,
PHONE VARCHAR(20) NOT NULL,
CODE VARCHAR(6) NOT NULL,
SESSION_ID VARCHAR(128),
ATTEMPTS TINYINT DEFAULT 0,
CONFIRMED CHAR(1) DEFAULT 'N',
CREATED_AT DATETIME NOT NULL,
EXPIRES_AT DATETIME NOT NULL,
INDEX idx_phone_code (PHONE, CODE),
INDEX idx_session (SESSION_ID)
);
Термін дії коду — 5 хвилин. Максимум спроб — 3. Після вичерпання — новий запит коду із затримкою (rate limit).
Інтеграція в чекаут
Якщо використовується sale.order.ajax — втручаємося в його JavaScript. Перехоплюємо подію відправки форми:
// В result_modifier.php компонента або підключеному JS
BX.addCustomEvent('onSaleComponentOrderSuccess', function(order) {
// Стандартна обробка — вимикаємо
});
document.querySelector('.order-confirm-btn').addEventListener('click', async (e) => {
e.preventDefault();
const phone = document.querySelector('[name="ORDER_PROP_PHONE"]').value;
// Запитуємо SMS
const res = await fetch('/local/api/order-confirm/send', {
method: 'POST',
headers: {'Content-Type': 'application/json', 'X-Bitrix-Csrf-Token': BX.bitrix_sessid()},
body: JSON.stringify({phone})
});
if (res.ok) {
showCodeInputModal(phone);
}
});
Після успішного підтвердження коду фронтенд надсилає токен підтвердження разом із даними замовлення, сервер перевіряє токен до створення замовлення.
Серверна частина
class OrderConfirmController
{
public function sendCode(): void
{
$phone = $this->normalizePhone($_POST['phone'] ?? '');
if (!$phone) { $this->error('Невірний номер телефону'); }
// Rate limit: не більше 3 відправок за 15 хвилин
if ($this->isRateLimited($phone)) {
$this->error('Забагато запитів. Зачекайте 15 хвилин.');
}
$code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
$expiresAt = (new \DateTime())->modify('+5 minutes');
OrderConfirmationTable::add([
'PHONE' => $phone,
'CODE' => password_hash($code, PASSWORD_DEFAULT), // не зберігаємо відкритий код
'SESSION_ID' => session_id(),
'EXPIRES_AT' => \Bitrix\Main\Type\DateTime::createFromTimestamp($expiresAt->getTimestamp()),
]);
SmsService::send($phone, "Код підтвердження замовлення: {$code}. Діє 5 хвилин.");
$this->success(['expires_in' => 300]);
}
public function verifyCode(): void
{
$phone = $this->normalizePhone($_POST['phone'] ?? '');
$code = $_POST['code'] ?? '';
$record = OrderConfirmationTable::getActiveRecord($phone, session_id());
if (!$record) {
$this->error('Код не знайдено або термін дії вичерпано');
}
// Increment attempts
OrderConfirmationTable::incrementAttempts($record['ID']);
if ($record['ATTEMPTS'] >= 3) {
$this->error('Перевищено кількість спроб. Запросіть новий код.');
}
if (!password_verify($code, $record['CODE'])) {
$this->error('Невірний код');
}
// Код вірний — видаємо одноразовий токен для створення замовлення
$token = bin2hex(random_bytes(32));
OrderConfirmationTable::markConfirmed($record['ID'], $token);
$this->success(['token' => $token]);
}
}
Код зберігається в базі в хешованому вигляді — password_hash(). Навіть при витоку бази коди не скомпрометовані.
Перевірка токена при створенні замовлення
Перед стандартним створенням замовлення через OnBeforeSaleOrderSaved або перевизначення контролера:
AddEventHandler('sale', 'OnBeforeSaleOrderSaved', function(\Bitrix\Sale\Order $order, array $data) {
if (!ConfirmConfig::isRequiredForOrder($order)) {
return; // не всі замовлення потребують підтвердження
}
$token = $_POST['confirm_token'] ?? '';
if (!OrderConfirmationTable::isValidToken($token, session_id())) {
throw new \Exception('Замовлення не підтверджено по SMS');
}
});
SMS-провайдер
Інтеграція з провайдером через абстракцію:
interface SmsProviderInterface {
public function send(string $phone, string $message): bool;
}
Реалізації: SMS.ru, SMSC.ru, МТС Комунікатор, інтеграція через Bitrix24 SMS. Перемикання провайдера без зміни бізнес-логіки.
Склад робіт
- Таблиця підтверджень, логіка rate limit і спроб
- API-контролер: відправка коду, верифікація, видача токена
- Інтеграція з чекаутом (перехоплення JS, передача токена)
- Перевірка токена перед створенням замовлення
- Підключення SMS-провайдера
Терміни: 5–7 днів з одним провайдером SMS. 1.5–2 тижні при кастомному чекауті.







