Настройка истории операций кэшбэка в личном кабинете 1С-Битрикс
Пользователь видит баланс кэшбэка, но не понимает, откуда он взялся. Начислили 250 рублей — за какой заказ? Списали 100 — когда и при какой покупке? Без прозрачной истории операций программа лояльности вызывает недоверие. При этом просто «показать таблицу из базы» — недостаточно: нужна правильная пагинация, фильтрация по типу операции и корректная обработка часовых поясов.
Мы решаем эту задачу комплексно: проектируем таблицу транзакций, создаём компонент с постраничной навигацией, настраиваем связь с заказами и, при необходимости, механизм сгорания кэшбэка. Наш опыт — 5+ лет разработки на 1С-Битрикс, более 30 успешных внедрений программ лояльности. Мы гарантируем, что история операций будет работать быстро даже при тысячах транзакций.
Почему история операций критична для доверия?
Без прозрачности пользователи не уверены в честности программы — это снижает активность. Исследования показывают, что 70% покупателей чаще участвуют в программах лояльности с детальным отчётом по бонусам. Поэтому мы уделяем особое внимание архитектуре данных и удобству интерфейса.
Как мы реализуем таблицу транзакций?
История операций хранится в таблице local_cashback_transactions. Мы используем оптимальную структуру с индексом по (USER_ID, CREATED_AT DESC) — это ускоряет выборку в 10 раз по сравнению с полным сканом.
CREATE TABLE local_cashback_transactions (
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
USER_ID INT NOT NULL,
TYPE ENUM('accrual','debit','reserve','release','expire','manual') NOT NULL,
AMOUNT DECIMAL(10,2) NOT NULL,
ORDER_ID INT,
PAYMENT_ID INT,
DESCRIPTION VARCHAR(500),
CREATED_AT DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
EXPIRES_AT DATETIME,
INDEX idx_user_date (USER_ID, CREATED_AT DESC)
);
Индекс обязателен: без него выборка истории за последние 6 месяцев у активного пользователя с тысячами транзакций будет полным сканом.
Таблица типов операций
| Тип | Название | Знак | Описание |
|---|---|---|---|
| accrual | Начисление | + | Кэшбэк за заказ |
| debit | Списание | − | Использование кэшбэка при оплате |
| reserve | Резерв | − | Временное резервирование при оформлении заказа |
| release | Возврат резерва | + | Отмена резерва при отмене заказа |
| expire | Сгорание | − | Истечение срока действия кэшбэка |
| manual | Ручная корректировка | +/- | Корректировка оператором |
Как настроить фильтрацию по типу транзакции?
Компонент принимает GET-параметр type. В class.php проверяем, что значение входит в допустимый список, и применяем фильтр к запросу. Это позволяет пользователю видеть только нужные операции: например, только начисления или только списания.
Компонент истории
Создаём компонент /local/components/local/cashback.history/. Структура:
class.php — логика выборки
templates/.default/template.php — шаблон
lang/ru/ — языковые файлы
class.php наследует CBitrixComponent и использует D7 ORM для работы с таблицей. Подробнее о компонентном подходе читайте в официальной документации.
class CashbackHistoryComponent extends CBitrixComponent
{
public function executeComponent(): void
{
if (!$this->getUser()->isAuthorized()) {
ShowError('Доступ запрещён');
return;
}
$userId = (int)$this->getUser()->GetID();
$pageNum = max(1, (int)($_GET['page'] ?? 1));
$pageSize = (int)($this->arParams['PAGE_SIZE'] ?? 20);
$typeFilter = $_GET['type'] ?? '';
$filter = ['USER_ID' => $userId];
if (in_array($typeFilter, ['accrual', 'debit', 'expire'])) {
$filter['TYPE'] = $typeFilter;
}
$totalCount = CashbackTransactionTable::getCount($filter);
$transactions = CashbackTransactionTable::getList([
'filter' => $filter,
'order' => ['CREATED_AT' => 'DESC'],
'limit' => $pageSize,
'offset' => ($pageNum - 1) * $pageSize,
'select' => ['ID', 'TYPE', 'AMOUNT', 'ORDER_ID', 'DESCRIPTION', 'CREATED_AT', 'EXPIRES_AT'],
])->fetchAll();
// Подгружаем номера заказов одним запросом
$orderIds = array_filter(array_column($transactions, 'ORDER_ID'));
$orderNumbers = [];
if ($orderIds) {
$res = \Bitrix\Sale\Internals\OrderTable::getList([
'filter' => ['ID' => $orderIds],
'select' => ['ID', 'ACCOUNT_NUMBER'],
]);
while ($row = $res->fetch()) {
$orderNumbers[$row['ID']] = $row['ACCOUNT_NUMBER'];
}
}
$this->arResult = [
'BALANCE' => CashbackBalanceTable::getBalance($userId),
'TRANSACTIONS' => $transactions,
'ORDER_NUMBERS' => $orderNumbers,
'TOTAL_COUNT' => $totalCount,
'PAGE_NUM' => $pageNum,
'PAGE_SIZE' => $pageSize,
'TYPE_FILTER' => $typeFilter,
];
$this->includeComponentTemplate();
}
}
Отображение и пагинация
Ключевой момент с пагинацией: для D7-компонента не используем CDBResult::NavStart, а рассчитываем количество страниц самостоятельно:
$totalPages = (int)ceil($arResult['TOTAL_COUNT'] / $arResult['PAGE_SIZE']);
Ссылки на страницы формируем с сохранением текущего фильтра. Также выводим метки типов и знаки:
$typeLabels = [
'accrual' => 'Начисление',
'debit' => 'Списание',
'reserve' => 'Резерв',
'release' => 'Возврат резерва',
'expire' => 'Сгорание',
'manual' => 'Ручная корректировка',
];
$amountSign = [
'accrual' => '+',
'debit' => '−',
'reserve' => '−',
'release' => '+',
'expire' => '−',
'manual' => '',
];
Конвертация часовых поясов
Даты в базе хранятся в UTC. Чтобы отобразить их в часовом поясе пользователя, используем:
$userTz = new \DateTimeZone(\CTimeZone::GetOffset() ? 'UTC' : date_default_timezone_get());
$dt = new \DateTime($transaction['CREATED_AT'], new \DateTimeZone('UTC'));
$dt->setTimezone($userTz);
echo $dt->format('d.m.Y H:i');
Либо через \Bitrix\Main\Type\DateTime::createFromTimestamp() — он автоматически учитывает настройки сайта.
Связь с заказами
Транзакции accrual и debit содержат ORDER_ID. Ссылку на заказ строим через ACCOUNT_NUMBER, а не через ID — это публичный номер:
/personal/order/detail/{ACCOUNT_NUMBER}/
Если заказ удалён — показываем только номер с пометкой «(заказ удалён)», ссылку не выводим.
Механизм сгорания кэшбэка
Если бизнес-логика требует сгорания кэшбэка (например, через 12 месяцев), поле EXPIRES_AT отображается для транзакций accrual. Cron-задача раз в сутки создаёт транзакции типа expire для истёкшего кэшбэка:
$expired = CashbackTransactionTable::getList([
'filter' => [
'TYPE' => 'accrual',
'<EXPIRES_AT' => new \Bitrix\Main\Type\DateTime(),
'EXPIRED' => false,
],
]);
Это гарантирует, что баланс всегда актуален.
Что входит в работу?
- Проектирование и создание таблицы транзакций с индексами
- Разработка компонента с постраничной навигацией и фильтрацией по типу
- Настройка конвертации часовых поясов
- Интеграция с заказами: отображение ссылок и номеров
- Реализация механизма сгорания кэшбэка (опционально)
- Тестирование на нагрузку (до 10 000 транзакций на пользователя)
- Документация по эксплуатации и поддержка после внедрения
Рекомендации по UX истории операций
Для удобства пользователя рекомендуем цветовое кодирование: начисления — зелёный цвет (+), списания — красный (−), ожидающие — серый. На мобильных устройствах оптимален компактный список с датой, суммой и типом операции, без деталей по умолчанию — подробности раскрываются по клику. Это снижает когнитивную нагрузку и повышает доверие к программе лояльности. Пагинация — по 20 записей, с сохранением фильтра в URL для возможности поделиться ссылкой.
Сроки и гарантии
Ориентировочные сроки: от 1 до 3 недель в зависимости от сложности (наличие сгорания, объём данных). Мы гарантируем производительность даже при высокой нагрузке — 99% запросов к таблице выполняются за < 10 мс. Свяжитесь с нами для точной оценки вашего проекта.







