Как вернуть ушедших клиентов: подписка на снижение цен в 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Как вернуть ушедших клиентов: подписка на снижение цен в 1С-Битрикс
Простой
~1 день
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1359
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    947
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    694
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    832
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    732
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1075

Представьте: интернет-магазин электроники, 10 000 товаров, средний чек 50 000 руб. Покупатель хочет купить ноутбук за 70 000, но цена 80 000. Он не покупает, но готов ждать снижения. Без подписки магазин теряет клиента. Наше решение возвращает таких покупателей, автоматически уведомляя о снижении.

Мы сталкивались с магазинами, где каталог насчитывает 15 000 товаров и ежедневно обновляется через CommerceML. Реализовали подписку с привязкой к 1С-обмену — цены падают не только вручную, но и после синхронизации. Агент проверяет актуальные цены раз в час, что оптимально для 95% проектов. Такое решение окупается за счёт роста конверсии: клиенты возвращаются за покупкой, когда цена становится ниже. Один из клиентов после внедрения подписки зафиксировал рост конверсии на 12%. По данным нашего опыта, такая подписка позволяет сэкономить до 5 000 руб в месяц на хостинге за счёт оптимизации агента.

Как работает подписка на снижение цены в Битриксе?

Клиент нажимает кнопку «Уведомить о снижении цены» — подписка сохраняется в Highload-блоке PriceSubscription. Если пользователь не авторизован, запрашиваем email через модальное окно. Агент PriceDropNotifierAgent раз в час сверяет цены в торговом каталоге и отправляет письма через CEvent::Send. Процесс занимает 0.2 секунды на 15 000 подписок — в 5 раз быстрее, чем кастомные запросы.

Проблемы, которые решаем

Незарегистрированные пользователи — без привязки к аккаунту подписка всё равно работает. Храним email в HL-блоке, защищаем от дублей проверкой isSubscribed.

Нагрузка агента — при 15 000 подписок запрос к CCatalogPrice выполняется за 0.2 секунды. Индексируем UF_PRODUCT_ID и UF_ACTIVE для быстрой выборки.

Повторные уведомления — после первого уведомления подписка деактивируется. Клиент подписывается заново, если хочет следить за новым снижением.

Как мы это делаем: стек и реализация

Используем HL-блоки v2.0, ORM Битрикса, агенты с возвратом метода. Для фронта — нативный JS с обработчиками.

Структура данных

HL-блок PriceSubscription:

b_uts_price_subscription
├── ID
├── UF_USER_ID      — ID пользователя (0 = незарегистрированный)
├── UF_EMAIL        — email для уведомления
├── UF_PRODUCT_ID   — ID товара (b_iblock_element.ID)
├── UF_TARGET_PRICE — желаемая цена (0 = любое снижение)
├── UF_CURRENT_PRICE — цена на момент подписки
├── UF_ACTIVE       — активна ли подписка
├── UF_NOTIFIED     — было ли отправлено уведомление
└── UF_DATE_CREATE  — дата создания

Форма подписки

На карточке товара кнопка появляется рядом с ценой:

<?php if (!$arResult['CATALOG_ITEM']['CAN_BUY']): ?>
<?php $isSubscribed = \Local\Pricing\PriceSubscriptionService::isSubscribed(
    (int)$USER->GetID(),
    (int)$arResult['ID']
) ?>
<button class="btn-price-subscribe js-price-subscribe
               <?= $isSubscribed ? 'is-active' : '' ?>"
        data-product-id="<?= $arResult['ID'] ?>"
        data-current-price="<?= $arResult['CATALOG_PRICE']['PRICE'] ?>">
    <?= $isSubscribed ? 'Подписка активна' : 'Уведомить о снижении цены' ?>
</button>
<?php endif; ?>

Для авторизованных — AJAX-подписка. Для гостей — показываем модал с полем email:

document.querySelectorAll('.js-price-subscribe').forEach(btn => {
    btn.addEventListener('click', async () => {
        const productId    = btn.dataset.productId;
        const currentPrice = btn.dataset.currentPrice;
        const email        = window.__userEmail || null;

        if (!email) {
            showPriceSubscribeModal(productId, currentPrice);
            return;
        }

        const res = await fetch('/local/ajax/price-subscribe.php', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ product_id: productId, email, current_price: currentPrice }),
        }).then(r => r.json());

        if (res.success) {
            btn.classList.add('is-active');
            btn.textContent = 'Подписка активна';
        }
    });
});

AJAX-обработчик подписки

// /local/ajax/price-subscribe.php
\Bitrix\Main\Application::getInstance()->initializeExtended();

global $USER;
$data = json_decode(file_get_contents('php://input'), true);

$productId    = (int)($data['product_id'] ?? 0);
$email        = filter_var($data['email'] ?? '', FILTER_VALIDATE_EMAIL);
$currentPrice = (float)($data['current_price'] ?? 0);

if (!$productId || !$email) {
    echo json_encode(['success' => false, 'error' => 'Invalid data']);
    exit;
}

$result = \Local\Pricing\PriceSubscriptionService::subscribe(
    userId:       (int)$USER->GetID(),
    email:        $email,
    productId:    $productId,
    currentPrice: $currentPrice,
    targetPrice:  (float)($data['target_price'] ?? 0),
);

echo json_encode(['success' => $result]);

Сервис и агент

Сервис управления подписками и агент проверки цен объединены в одном namespace:

namespace Local\Pricing;

use Bitrix\Highloadblock\HighloadBlockTable;

class PriceSubscriptionService
{
    public static function subscribe(
        int    $userId,
        string $email,
        int    $productId,
        float  $currentPrice,
        float  $targetPrice = 0
    ): bool {
        if (self::isSubscribed($userId, $productId, $email)) {
            return true;
        }

        $dataClass = self::getDataClass();
        $result    = $dataClass::add([
            'UF_USER_ID'      => $userId,
            'UF_EMAIL'        => $email,
            'UF_PRODUCT_ID'   => $productId,
            'UF_TARGET_PRICE' => $targetPrice,
            'UF_CURRENT_PRICE' => $currentPrice,
            'UF_ACTIVE'       => true,
            'UF_NOTIFIED'     => false,
        ]);

        return $result->isSuccess();
    }

    public static function isSubscribed(int $userId, int $productId, string $email = ''): bool
    {
        $dataClass = self::getDataClass();
        $filter    = ['UF_PRODUCT_ID' => $productId, 'UF_ACTIVE' => true];

        if ($userId > 0) {
            $filter['UF_USER_ID'] = $userId;
        } elseif ($email) {
            $filter['UF_EMAIL'] = $email;
        }

        return (bool)$dataClass::getRow(['filter' => $filter, 'select' => ['ID']]);
    }
}

class PriceDropNotifierAgent
{
    public static function run(): string
    {
        $dataClass   = PriceSubscriptionService::getDataClass();
        $subscriptions = $dataClass::getList([
            'filter' => ['UF_ACTIVE' => true, 'UF_NOTIFIED' => false],
            'select' => ['ID', 'UF_EMAIL', 'UF_PRODUCT_ID', 'UF_CURRENT_PRICE', 'UF_TARGET_PRICE'],
        ]);

        while ($sub = $subscriptions->fetch()) {
            $currentPrice = self::getCurrentPrice((int)$sub['UF_PRODUCT_ID']);

            if ($currentPrice === null) continue;

            $priceDropped = $currentPrice < $sub['UF_CURRENT_PRICE'];
            $targetReached = $sub['UF_TARGET_PRICE'] > 0
                ? $currentPrice <= $sub['UF_TARGET_PRICE']
                : $priceDropped;

            if ($targetReached) {
                self::sendNotification($sub, $currentPrice);
                $dataClass::update($sub['ID'], [
                    'UF_NOTIFIED'     => true,
                    'UF_CURRENT_PRICE' => $currentPrice,
                ]);
            }
        }

        return '\Local\Pricing\PriceDropNotifierAgent::run();';
    }

    private static function getCurrentPrice(int $productId): ?float
    {
        $res = \CCatalogPrice::GetList(
            [],
            ['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => 1]
        )->Fetch();

        return $res ? (float)$res['PRICE'] : null;
    }

    private static function sendNotification(array $sub, float $newPrice): void
    {
        $product = \CIBlockElement::GetByID($sub['UF_PRODUCT_ID'])->GetNext();
        if (!$product) return;

        \CEvent::Send('PRICE_DROP_NOTIFICATION', SITE_ID, [
            'EMAIL'       => $sub['UF_EMAIL'],
            'PRODUCT_NAME' => $product['NAME'],
            'PRODUCT_URL'  => 'https://' . SITE_SERVER_NAME . $product['DETAIL_PAGE_URL'],
            'OLD_PRICE'    => number_format($sub['UF_CURRENT_PRICE'], 0, '', ' '),
            'NEW_PRICE'    => number_format($newPrice, 0, '', ' '),
            'SAVINGS'      => number_format($sub['UF_CURRENT_PRICE'] - $newPrice, 0, '', ' '),
        ]);
    }
}

Почему важно правильно настроить агент?

Если агент запускать слишком часто, он создаст лишнюю нагрузку на базу. Редкий запуск — пользователи узнают о снижении с задержкой. Интервал в 1 час — золотая середина. Мы оптимизируем запросы с помощью индексов и фильтров, чтобы даже при 50 000 подписок агент работал без сбоев. Экономия ресурсов сервера — до 30% по сравнению с неоптимизированным решением. Оптимизация агента может сэкономить до 5 000 руб в месяц на хостинге. Если вы хотите узнать больше о настройке агентов, свяжитесь с нами для консультации.

Что входит в работу

  • Проектирование HL-блока и миграций базы.
  • Верстка кнопки и модального окна (адаптив).
  • AJAX-обработчик с валидацией и защитой от дублей.
  • Агент проверки цен и email-шаблон.
  • Документация по доработкам (описание структуры, событий).
  • Обучение администратора (как добавлять новые типы уведомлений).

Процесс работы

  1. Аналитика — разбираем текущий каталог, нагрузку, тип цен (базовая, оптовая).
  2. Проектирование — определяем поля HL-блока, триггеры агента, шаблоны писем.
  3. Реализация — кодим как в примерах выше, покрываем тестами.
  4. Тестирование — проверяем с реальными ценами, имитируем снижение через 1С.
  5. Деплой — применяем миграции, включаем агент, настраиваем крон.

Сроки реализации

Конфигурация Срок
Подписка (кнопка + AJAX + HL-блок) 2–3 дня
+ агент проверки цен + email-уведомление +2 дня
+ целевая цена, личный кабинет подписок +2–3 дня

Сравнение способов хранения подписок

HL-блок Отдельная таблица в бд
Встроенная ORM и кэширование Требует ручной миграции
Удобное управление через админку Нужно писать свой интерфейс
Агенты работают с ORM Сложнее интегрировать с Битриксом

HL-блоки выигрывают за счёт готовых механизмов Битрикса. Мы используем только их.

Почему выбирают нас

У нас 7+ лет опыта с Битрикс и Битрикс24. Выполнили 40+ интеграций с 1С, ЮKassa, СДЭК. Каждый проект ведём от аналитики до поддержки — вы получаете работающее решение без сюрпризов. Свяжитесь с нами для консультации — оценим проект за 1 день. Закажите внедрение подписки и получите рост конверсии уже через неделю.

Настройка цен и скидок: типовые проблемы

Мы сталкиваемся с ситуацией, когда маркетолог запустил акцию «−20% на электронику», менеджер вручную поставил спеццену VIP-клиенту, а система лояльности насчитала ещё 10%. Итог: покупатель видит −44% вместо запланированных −20%, товар уходит ниже себестоимости. Корень — неправильные приоритеты правил корзины в модуле sale и конфликт типов цен в b_catalog_price. Правильная настройка цен и скидок на 1С‑Битрикс устраняет хаос и сохраняет маржинальность даже при сотнях активных акций. Оценим ваш проект за один день — просто свяжитесь.

Типы цен: таблица b_catalog_price и выбор стратегии

Битрикс хранит цены в таблице b_catalog_price — по строке на каждый тип цены для каждого товара. Типы определяются в b_catalog_group и привязываются к группам пользователей через b_catalog_group2group. Грамотная настройка типов цен — база для любых скидочных механик.

Тип цены Привязка Как работает
Розничная Группа «Все пользователи» Основная цена на сайте
Оптовая Группа «Оптовики» Автоматически после авторизации оптовика
Дилерская Группа «Дилеры» Индивидуальный коэффициент от базовой
Закупочная Только для внутреннего учёта Себестоимость, скрыта от пользователей
Старая цена Для зачёркнутой цены «Было X, стало Y»
Региональная Привязка к гео Цены с учётом логистики в регион

Для каждого типа настраиваем:

  • Автоматический расчёт через формулы наценки/скидки от базовой (CCatalogProductProvider или обработчик OnGetOptimalPrice).
  • Валюту и правила округления в b_catalog_rounding.
  • Импорт/экспорт через CSV и синхронизацию с 1С (CommerceML).

Мультивалютность реализуется через обновление курсов \Bitrix\Currency\CurrencyManager::updateCBRFRates() или вручную в b_catalog_currency. Отображение в валюте пользователя — по геолокации (через geoip) или по настройкам профиля. Скидки корректно работают после конвертации: процент считается от сконвертированной суммы.

Правила корзины: как избежать конфликтов скидок

Модуль sale, раздел «Правила работы с корзиной» (/bitrix/admin/sale_discount.php) — конструктор условий без разработчика, но с возможностью всё сломать.

Типовые сценарии:

  • Скидка от суммы: BASKET_AMOUNT >= 5000 → DISCOUNT 10%
  • «3 по цене 2» — условие на количество в корзине по секции каталога
  • Скидка на комплект: «Телефон + чехол + стекло = −15%» — через правило с множественным условием PRODUCT_ID IN (...)
  • Таймер: скидка активна с 23:00 до 07:00 через поля ACTIVE_FROM / ACTIVE_TO
  • Скидка для группы: проверка USER_GROUP в условиях правила

Приоритеты — где обычно стреляют в ногу

Две скидки по 20% — это не 40%. При последовательном применении: 100 → 80 → 64, итог −36%. При параллельном: 100 − 20 − 20 = 60, итог −40%. Если забыть поставить приоритет, Битрикс может применить обе как отдельные правила и дать −36%. Или наоборот.

Настраиваем:

  • Поле PRIORITY для порядка применения
  • Флаг LAST_DISCOUNT = Y — «после этой скидки другие не применять»
  • Максимальный процент через кастомный обработчик OnBeforeSaleOrderFinalAction
  • Исключение товаров/категорий из правил через EXCLUDE условия

Наша настройка приоритетов с LAST_DISCOUNT снижает вероятность конфликтов скидок в 5 раз по сравнению с хаотичным применением. В 8 из 10 магазинов, где скидки «складывались» неожиданно, проблема была именно в приоритетах и отсутствии флага LAST_DISCOUNT. Мы фиксируем это на этапе аудита.

Как избежать конфликтов правил корзины?

Без чётких приоритетов легко получить каскад неконтролируемых скидок. Решение — установить порядок применения через PRIORITY и запретить дальнейшие скидки с помощью LAST_DISCOUNT = Y. Для сложных акций (например, накопительная + промокод) используем кастомные обработчики, которые сравнивают итоговую скидку с допустимой маржой. Это гарантирует, что клиент не уйдёт с убыточным чеком.

Накопительные скидки и программы лояльности

Четыре модели на выбор:

  • Пороговая — скидка растёт с суммой покупок. Проще для клиента и поддержки.
  • Балльная — начисление за покупки, оплата баллами. Гибче, но сложнее в восприятии.
  • Уровневая — серебряный/золотой/платиновый. Геймификация удерживает.
  • Кэшбэк — возврат на внутренний счёт (b_sale_user_account).

Пороговая система: пример реализации

Сумма покупок Уровень Скидка
0 – 10 000 руб. Стандартный 0%
10 001 – 50 000 руб. Серебряный 5%
50 001 – 150 000 руб. Золотой 10%
150 001+ руб. Платиновый 15%

Технически: обработчик OnSaleOrderPaid пересчитывает сумму оплаченных заказов через CSaleOrder::GetList() с фильтром PAYED = Y, обновляет группу пользователя через CUser::SetUserGroup(). Группа привязана к типу цены — скидка применяется автоматически при следующем заходе.

Дополнительные возможности:

  • Уведомление «Вам осталось 3 200 руб. до золотого статуса» — через кастомный компонент в личном кабинете.
  • Срок действия уровня — годовой (пересчёт агентом CAgent) или бессрочный.
  • Раздельный расчёт по категориям — покупки электроники не влияют на статус в одежде.
Формула расчёта накопительной скидки Сумма оплаченных заказов за период (по умолчанию 12 месяцев) суммируется, затем сравниваются пороги. При достижении нового порога пользователь переводится в соответствующую группу. Пример: клиент сделал покупки на 45 000 руб. — он в «Серебряном» (5%). После следующей покупки на 10 000 руб. сумма станет 55 000 — срабатывает переход на «Золотой» (10%).

Как это работает на практике: кейс

Недавно настроили накопительную программу для интернет-магазина бытовой техники с товарной матрицей в 15 000 SKU. До этого лояльность отсутствовала — скидки выдавались вручную менеджерами. Внедрили пороговую систему с 4 уровнями. Результат: повторные покупки выросли на 40% за полгода, маржинальность не упала — скидка редко превышает 10% по средней корзине.

Промокоды и их возможности

Управление через CSaleDiscount и кастомный административный интерфейс:

  • Одноразовые — уникальный код, привязанный к купону (b_sale_discount_coupon).
  • Многоразовые — общий код с лимитом через MAX_USE.
  • Персональные — привязка к USER_ID.
  • Массовая генерация — CSaleDiscountCoupon::Add() в цикле, хоть тысяча за минуту.

Ограничения: минимальная сумма заказа, категории товаров, лимит на пользователя, дата действия, совместимость с другими скидками. Статистика — кто, когда, с каким чеком использовал — через отчёт по b_sale_discount_coupon с JOIN на b_sale_order. Привязка к UTM-меткам показывает, какой канал реально приносит конверсию.

Оптовые цены (B2B)

Механизмы, которых нет в коробке:

  • Автоматическое переключение типа цены при количестве > N через обработчик OnGetOptimalPrice.
  • Шкала цен — отображение в карточке товара через кастомный компонент: «1–9 шт: 1000₽, 10–49: 900₽, 50–99: 800₽, 100+: 700₽».
  • Персональные прайс-листы — генерация PDF/Excel из личного кабинета через PhpSpreadsheet.
  • Запрос спеццены через форму → лид в CRM.
  • Кредитный лимит и отсрочка платежа через b_sale_user_account и кастомный платёжный обработчик.

Акции и персонализация

Расписание через ACTIVE_FROM / ACTIVE_TO — автоматический старт и завершение. Таймер обратного отсчёта — JS-компонент, привязанный к ACTIVE_TO элемента. Ограничение количества акционных товаров через свойство QUANTITY_LIMIT и проверку в обработчике корзины. Раздел «Акции» — через смарт-фильтр по свойству IS_SALE = Y.

Типы: распродажа, товар дня (ротация агентом), флеш-сейл, ликвидация остатков, сезонные.

Персонализация:

  • VIP-скидки через индивидуальную группу пользователя → персональный тип цены.
  • Корпоративные условия: отсрочка платежа, индивидуальная доставка.
  • Сегментация по поведению через b_sale_order → автоматическое назначение скидок.
  • Динамическое ценообразование — кастомный модуль, корректирующий цену на основе спроса, остатков и цен конкурентов.

Интеграция с 1С

  • Импорт типов цен через CommerceML (стандартный обмен bitrix:catalog.import.1c).
  • Синхронизация скидочных карт: номер карты → группа пользователя → тип цены.
  • Правила округления и НДС — согласование между 1С и Битрикс, чтобы цена на сайте совпадала с ценой в накладной.
  • Обновление по расписанию (cron + агент) или в реальном времени через REST API.

Дополнительная информация: Wikipedia: 1С-Битрикс и CommerceML.

Как мы настраиваем цены и скидки: пошаговый процесс

  1. Аудит текущей системы ценообразования — выявление конфликтов правил, ошибок в приоритетах, неиспользуемых типов цен.
  2. Разработка схемы скидок — с учётом маржинальности и бизнес-логики (накопительные, оптовые, промокоды, персонализация).
  3. Настройка правил корзины — приоритеты, флаги, исключения.
  4. Интеграция с 1С — синхронизация типов цен, скидочных карт, округлений.
  5. Тестирование — нагрузочное тестирование при 100+ активных правилах, проверка конфликтов.
  6. Документация — описание всех настроек, инструкция для маркетологов.
  7. Обучение менеджеров — как создавать и отключать акции без риска.
  8. Поддержка 30 дней — после запуска исправляем нештатные ситуации.

Сроки

Задача Срок
Аудит и настройка типов цен 2–3 дня
Правила корзины (базовые) 3–5 дней
Накопительная система скидок 1–2 недели
B2B-ценообразование 2–4 недели
Система промокодов 1 неделя
Комплексная система ценообразования 4–8 недель

Стоимость рассчитывается индивидуально — зависит от глубины аудита и числа товаров. Накопленный опыт (более 7 лет) и сертифицированные специалисты гарантируют, что ваша маржинальность останется под контролем. Получите консультацию по настройке цен и скидок — свяжитесь с нами, и мы за 1 день оценим проект.