Корзина и заказ в Битрикс: разбор на живом проекте
Разбираем магазин на 1С-Битрикс с каталогом, доставкой и онлайн-оплатой: какие задачи отдать стандартным компонентам, где подключать D7 API и почему корзина часто ломается уже на оформлении заказа.

В интернет-магазине на 1С-Битрикс корзина может выглядеть рабочей, но терять товар при авторизации, показывать неверную цену после скидки или создавать заказ без доставки. В разборе используем связку «1С-Битрикс: Управление сайтом 24.x», PHP 8.1, интернет-магазин с модулем каталога, двумя способами доставки и оплатой картой. Цель — получить предсказуемый путь от кнопки «В корзину» до созданного заказа, а не просто вывести форму на странице.
Сценарий проекта и точка конфликта
Представим магазин бытовой техники. Товар хранится в инфоблоке каталога, цена зависит от типа клиента, остатки ведутся в торговом учёте, а заказ должен содержать доставку, оплату и контактные данные покупателя.
На сайте есть три страницы:
- /catalog/ — каталог и карточка товара;
- /cart/ — компонент
bitrix:sale.basket.basket; - /personal/order/make/ — компонент
bitrix:sale.order.ajax.
Проблема появилась после переделки шаблона оформления: товар добавлялся, но после выбора доставки сумма менялась не всегда. Причина оказалась не в одном баге. В шаблоне смешали отображение корзины, расчёт заказа и собственную AJAX-логику. Стандартный механизм Битрикс пересчитывал данные, а JavaScript повторно подставлял старую сумму.
В Битрикс корзина — это не просто список товаров. Итоговый заказ складывается из товара, цены, скидок, доставки, оплаты и правил пересчёта.
Три подхода к реализации
Для этого проекта были возможны три стратегии. Они дают разный баланс между скоростью запуска и контролем над процессом.
| Подход | Что используем | Цена решения | Когда выбирать |
|---|---|---|---|
| Стандартный | sale.basket.basket и sale.order.ajax | Меньше кода, но сложнее радикально изменить интерфейс | Обычный магазин с типовыми полями и службами доставки |
| Кастомный | D7 API модуля Sale, собственные обработчики и форма | Полный контроль, но больше тестов и поддержки | Нестандартный checkout, сложная логика резервирования |
| Гибридный | Стандартный расчёт Битрикс, собственный внешний вид | Нужно аккуратно сохранить AJAX-контракт компонента | Когда дизайн уникальный, а бизнес-правила типовые |
Для живого проекта выбрали гибрид. Расчёт цены, скидок, доставки и оплаты остался у Битрикс. Свой код отвечает только за интерфейс и подготовку дополнительных данных. Это сокращает риск рассинхронизации с каталогом и торговым учётом.
Корзина: что проверить до оформления
1. Добавление товара
Кнопка карточки должна передавать идентификатор товара, а не только цену из HTML. Цена в браузере не может считаться источником истины: она меняется из-за скидки, группы пользователя или обновления каталога.
Если товар добавляется программно, используйте D7 API и сохраняйте корзину текущего пользователя. Ниже фрагмент для 1С-Битрикс 24.x; он рассчитан на товар каталога и требует подключённых модулей sale и catalog.
<?php
use Bitrix\Main\Loader;
use Bitrix\Sale\Basket;
use Bitrix\Currency\CurrencyManager;
if (!Loader::includeModule('sale') || !Loader::includeModule('catalog')) {
throw new RuntimeException('Не подключены модули sale или catalog');
}
$productId = 123; // ID товара из каталога
$siteId = SITE_ID;
$fUserId = CSaleBasket::GetBasketUserID();
$basket = Basket::loadItemsForFUser($fUserId, $siteId);
$item = $basket->createItem('catalog', $productId);
$result = $item->setFields([
'QUANTITY' => 1,
'CURRENCY' => CurrencyManager::getBaseCurrency(),
'LID' => $siteId,
'PRODUCT_PROVIDER_CLASS' => '\\Bitrix\\Catalog\\Product\\Basket',
]);
if (!$result->isSuccess()) {
throw new RuntimeException(implode('; ', $result->getErrorMessages()));
}
$saveResult = $basket->save();
if (!$saveResult->isSuccess()) {
throw new RuntimeException(implode('; ', $saveResult->getErrorMessages()));
}
Перед копированием проверьте, что ID 123 заменён на существующий товар, а класс поставщика товара соответствует версии и конфигурации каталога. После сохранения откройте страницу корзины и убедитесь, что товар виден для того же браузера, в котором нажимали кнопку.
2. Пересчёт количества и цены
Количество изменяйте через штатную форму компонента, а не прямой записью в таблицу корзины. Компонент проверит минимальное количество, доступный остаток и применит правила каталога. Если цена в карточке отличается от цены в корзине, сначала проверяйте тип цены, группу пользователя и активные скидки, а не шаблон.
В проекте отдельно проверили четыре состояния:
- гость добавляет товар, затем авторизуется;
- авторизованный пользователь меняет количество;
- товар заканчивается между добавлением и оформлением;
- у товара есть скидка или несколько ценовых типов.
Авторизация особенно важна. У гостя корзина связана с FUSER — внутренним идентификатором покупателя[1]. После входа Битрикс должен корректно объединить её с корзиной пользователя. Если кастомный JavaScript создаёт новую корзину или отправляет другой идентификатор сайта, товары могут исчезнуть из интерфейса.
Оформление заказа: где чаще всего ломается логика
Состав заказа
Компонент sale.order.ajax собирает данные покупателя, доставки, оплаты и корзины. Его шаблон можно менять, но имена полей и события пересчёта нельзя произвольно заменять своими. Сначала сохраните штатный шаблон в шаблон сайта, затем меняйте разметку небольшими шагами.
В настройках компонента проверьте:
- код сайта и тип плательщика;
- доступные свойства заказа: имя, телефон, электронная почта, адрес;
- службы доставки, доступные выбранному типу плательщика;
- платёжные системы, привязанные к этому типу плательщика;
- страницу успешного оформления и страницу ошибки.
Если поле есть в HTML, но не появляется в заказе, смотрите не только шаблон. Проверьте, создано ли свойство заказа и связано ли оно с нужным типом плательщика. В Битрикс «визуально показать поле» и «сохранить значение в заказ» — разные задачи.
Доставка и оплата
В нашем сценарии покупатель выбирает курьерскую доставку или самовывоз. Стоимость доставки должна приходить из службы Битрикс после пересчёта. Не подставляйте её вручную из JavaScript: пользователь может изменить город, состав корзины или способ получения.
Проверка должна идти в таком порядке:
- выбрать город или заполнить адрес;
- выбрать способ доставки;
- дождаться серверного пересчёта;
- выбрать платёжную систему;
- снова проверить состав заказа и итоговую сумму;
- нажать кнопку оформления и проверить созданный заказ в административной части.
Каждый пересчёт должен завершаться изменением итоговой суммы или сообщением об ошибке. Если интерфейс показывает бесконечный индикатор, откройте вкладку Network в браузере и проверьте ответ AJAX: там обычно видны ошибки PHP, отказ службы доставки или неверно переданное свойство.
Что ломается на практике
Собственный AJAX поверх стандартного
Частая ошибка — отправить свою форму на отдельный обработчик, а затем ожидать, что стандартный компонент знает о новых данных. В результате адрес виден на экране, но в заказе его нет. Либо доставка пересчитывается дважды, и пользователь видит скачущую сумму.
Если нужен свой интерфейс, оставьте один источник пересчёта. Либо полностью используйте механизм sale.order.ajax, либо пишите собственный процесс на D7 API и принимаете на себя валидацию, права доступа, повторные запросы и обработку ошибок.
Типичные симптомы и причины
- «Корзина пуста после входа». Проверьте объединение гостевой и пользовательской корзины, домен, HTTPS и наличие нескольких сайтов в установке.
- «Не удалось рассчитать доставку». Проверьте город, ограничения службы доставки, вес и габариты товаров.
- «Поле заполнено, но в заказе пусто». Проверьте свойство заказа и его привязку к типу плательщика.
- «Сумма в заказе отличается от суммы на странице». Сравните скидки, тип цены, валюту и момент последнего серверного пересчёта.
- «После оплаты заказ остаётся в неопределённом статусе». Проверьте настройки платёжной системы и обработку уведомления от платёжного шлюза; это отдельная интеграция, а не часть вёрстки checkout.
Когда выбирать каждый подход
Стандартные компоненты подходят, если магазин использует обычные поля, типовые службы доставки и готовые платёжные системы. Кастомный D7-сценарий оправдан, если заказ уходит сразу в несколько внешних систем, требуется сложное резервирование или оформление состоит из нескольких независимых потоков.
Гибрид выбирайте, когда проблема только в интерфейсе. Оставьте Битрикс расчётчиком, а в собственном коде не храните итоговую цену, стоимость доставки и скидку как окончательные значения. Их нужно получать после серверного пересчёта.
Что делать дальше
После настройки прогоните оформление на тестовом заказе для гостя и авторизованного пользователя. Снимите логи PHP и веб-сервера, проверьте ответы AJAX, а затем отмените тестовый заказ и убедитесь, что остаток товара вернулся по правилам проекта.
В продакшене наблюдайте три показателя: долю начатых оформлений, долю успешно созданных заказов и ошибки на шаге доставки или оплаты. Инвалидация кеша, обмен с 1С и настройка платёжного шлюза требуют отдельного разбора: здесь важна только связка корзины и checkout.
[1] FUSER — идентификатор покупателя, по которому Битрикс связывает корзину гостя или пользователя с текущей сессией.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: Документация 1С-Битрикс: класс Basket, Документация 1С-Битрикс: компонент sale.order.ajax
Частые вопросы
Можно ли полностью заменить sale.order.ajax своим checkout?
Почему товар исчезает из корзины после авторизации?
Почему цена в карточке товара не совпадает с ценой в корзине?
Что делать, если доставка не рассчитывается?
Можно ли сохранять данные заказа только в собственной таблице?
Нужно ли тестировать оформление после обновления Битрикс?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.