Очистить корзину. Удалить все товары в корзине. API Битрикс

1. Клиентская реализация через JavaScript

Принцип работы: Итеративное срабатывание события удаления для всех товаров.

<div class="clean-basket-wr">
    <button type="button" class="btn-clean-basket" onclick="cleanBasket()">
        Очистить корзину
    </button>
</div>
function cleanBasket() {
    // Проверка подтверждения действия
    if (!confirm('Вы уверены, что хотите очистить корзину?')) return;

    const deleteButtons = document.querySelectorAll(
        '[data-entity="basket-item-delete"]'
    );

    if (deleteButtons.length === 0) {
        alert('Корзина уже пуста');
        return;
    }

    // Асинхронное последовательное удаление
    let index = 0;
    const deleteNext = () => {
        if (index < deleteButtons.length) {
            deleteButtons[index].click();
            index++;
            setTimeout(deleteNext, 300); // Интервал для избежания блокировки
        }
    };

    deleteNext();
}

Ограничения метода:

  • Зависит от структуры DOM
  • Не обрабатывает асинхронные операции
  • Нет обработки ошибок
  • Не удаляет отложенные товары

2. Серверная реализация через Legacy API

Безопасное удаление только активных товаров:

/**
 * Очищает текущую активную корзину пользователя
 * 
 * @return array Результат операции
 */
function cleanActiveBasket(): array
{
    if (!CModule::IncludeModule('sale')) {
        return ['success' => false, 'error' => 'Module "sale" not installed'];
    }

    $fuserId = CSaleBasket::GetBasketUserID();
    $siteId = SITE_ID;
    $errors = [];

    $filter = [
        'FUSER_ID' => $fuserId,
        'LID' => $siteId,
        'ORDER_ID' => 'null', // Только неоформленные товары
        'DELAY' => 'N',       // Исключить отложенные
        'CAN_BUY' => 'Y',     // Только доступные к покупке
        'SUBSCRIBE' => 'N'    // Исключить товары по подписке
    ];

    $res = CSaleBasket::GetList(['ID' => 'ASC'], $filter);
    while ($item = $res->Fetch()) {
        if (!CSaleBasket::Delete($item['ID'])) {
            $errors[] = "Ошибка удаления позиции ID: {$item['ID']}";
        }
    }

    return [
        'success' => empty($errors),
        'count_deleted' => $res->SelectedRowsCount(),
        'errors' => $errors
    ];
}

Ключевые параметры фильтра:

  • ORDER_ID => 'null': Только товары не в оформленных заказах
  • DELAY => 'N': Исключает отложенные товары
  • CAN_BUY => 'Y': Только доступные для покупки товары
  • SUBSCRIBE => 'N': Исключает товары по подписке

3. Современная реализация через D7 API

Оптимальный подход для новых проектов:

use Bitrix\Main\Loader;
use Bitrix\Sale\Basket;
use Bitrix\Sale\Fuser;

class BasketService
{
    public static function getUserBasket():object
    {
        return Sale\Basket::loadItemsForFUser(
            \Bitrix\Sale\Fuser::getId(),
            \Bitrix\Main\Context::getCurrent()->getSite()
        );
    }

    /**
     * Очищает активную корзину пользователя
     * 
     * @return array
     * @throws \Bitrix\Main\ArgumentException
     * @throws \Bitrix\Main\ObjectPropertyException
     * @throws \Bitrix\Main\SystemException
     */
    public static function cleanActiveBasket(): array
    {
        if (!Loader::includeModule('sale')) {
            return ['success' => false, 'error' => 'Module "sale" not installed'];
        }

        $basket = self::getUserBasket();

        $removedItems = [];
        $errors = [];

        foreach ($basket as $item) {
            if ($item->isDelay() || $item->getField('SUBSCRIBE') === 'Y') {
                continue; // Пропускаем отложенные и подписки
            }

            $itemId = $item->getId();
            $result = $item->delete();

            if ($result->isSuccess()) {
                $removedItems[] = $itemId;
            } else {
                $errors[] = implode(', ', $result->getErrorMessages());
            }
        }

        $result = $basket->save();

        if (!$result->isSuccess()) {
            $errors = array_merge($errors, $result->getErrorMessages());
        }

        return [
            'success' => empty($errors),
            'removed_items' => $removedItems,
            'errors' => $errors
        ];
    }

    /**
     * Проверяет пуста ли корзина
     * 
     * @return bool
     */
    public static function isBasketEmpty(): bool
    {
        $basket = Basket::loadItemsForFUser(
            Fuser::getId(), 
            SITE_ID
        );

        return $basket->count() === 0;
    }
}

4. Интеграция с AJAX-контроллером

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true) {
    die();
}

use Bitrix\Main\Engine\Controller;

class BasketController extends Controller
{
    public function configureActions(): array
    {
        return [
            'clean' => [
                'prefilters' => [
                    new \Bitrix\Main\Engine\ActionFilter\Csrf(),
                ],
            ],
            'check' => [
                'prefilters' => [
                    new \Bitrix\Main\Engine\ActionFilter\Csrf(),
                ],
            ],
        ];
    }

    /**
     * AJAX-действие для очистки корзины
     * 
     * @return array
     */
    public function cleanAction(): array
    {
        return BasketService::cleanActiveBasket();
    }

    /**
     * Проверка состояния корзины
     * 
     * @return array
     */
    public function checkAction(): array
    {
        return [
            'empty' => BasketService::isBasketEmpty(),
            'count' => BasketService::getBasketItemsCount()
        ];
    }
}

JavaScript для AJAX-вызова:

function cleanBasketViaAPI() {
BX.ajax.runComponentAction('vendor:component.name', 'clean', {
    mode: 'ajax', 
}).then(function (response) {
    console.log(response);
  // тут логика после удаления
}, function (response) {
    // сюда будут приходить все ответы, у которых status !== 'success'
    loader(false)
    statusContainer.classList.add('_refused')
    statusContainer.textContent = 'Ошибка запроса.'
    console.log(response);
});
}

5. Особенности и лучшие практики

  1. Безопасное удаление:

    // Всегда проверяем контекст
    if (!$this->getCurrentUser()->isAuthorized()) {
       $this->error('Access denied');
    }
  2. Обработка событий:

    // После очистки корзины
    $event = new \Bitrix\Main\Event('sale', 'НужноеСобытиеКорзины');
    $event->send();
  3. Производительность:

    // Пакетное сохранение вместо удаления по одному
    $basket->save(); // Один запрос вместо N
  4. Отложенные товары:

    if ($item->isDelay()) {
       // Сохраняем для будущего использования
    }
  5. Логирование:

    Bitrix\Main\Diag\Debug::writeToFile(
       "Basket cleared for user: {$userId}",
       'INFO',
       'basket.log'
    );

6. Тестирование и отладка

Юнит-тест для очистки корзины:

class BasketCleanTest extends \Bitrix\Main\Test\TestCase
{
    public function testCleanBasket()
    {
        // Создаем тестовые товары
        $basket = Basket::create(SITE_ID);
        $item = $basket->addItem(...);
        $basket->save();

        // Очищаем корзину
        $result = BasketService::cleanActiveBasket();

        // Проверяем результат
        $this->assertTrue($result['success']);
        $this->assertEmpty(BasketService::getBasketItems());
    }
}

7. Альтернативные сценарии

Очистка по расписанию:

// Агент для очистки неактивных корзин
function cleanInactiveBaskets()
{
    $days = 30; // Период неактивности
    $date = new \Bitrix\Main\Type\DateTime("-{$days} days");

    $filter = [
        '<=DATE_UPDATE' => $date,
        'ORDER_ID' => 'null',
        'LID' => SITE_ID
    ];

    $res = \Bitrix\Sale\Basket::getList([
        'filter' => $filter
    ]);

    while ($basket = $res->fetchObject()) {
        $basket->delete();
    }

    return "cleanInactiveBaskets();";
}

Миграция корзины:

// Перенос корзины при авторизации
AddEventHandler('main', 'OnAfterUserAuthorize', function($params) {
   // https://dev.1c-bitrix.ru/community/forums/forum6/topic68560/
});

Заключение

Для корректной очистки корзины в Bitrix:

  1. Используйте D7 API - для новых проектов
  2. Фильтруйте отложенные товары - через isDelay()
  3. Применяйте пакетное сохранение - для оптимизации
  4. Реализуйте AJAX-интерфейс - для UX
  5. Тестируйте edge-case сценарии - пустая корзина, параллельные запросы