Как программно удалить заказ в 1С-Битрикс на D7: полный гайд и частые ошибки
Работа с заказами в интернет-магазинах на 1С-Битрикс часто преподносит сюрпризы начинающим разработчикам. Одна из самых частых задач — написать скрипт для массовой очистки старых или тестовых заказов.
Казалось бы, достаточно вызвать один метод. На старом ядре это делали через CSaleOrder::Delete($id). На новом ядре D7 попытка выполнить Sale\Order::delete($id) часто заканчивается выбросом Exception и ошибкой "У заказа есть резервы" или "Заказ оплачен".
Дело в строгой архитектуре: заказ в D7 — это контейнер. Чтобы удалить контейнер, нужно сначала корректно разобрать его содержимое.
Почему заказ нельзя удалить «в лоб»
В D7 сущность Заказа (Bitrix\Sale\Order) неразрывно связана с коллекциями (Collections):
- Коллекция оплат (
PaymentCollection) — содержит транзакции. - Коллекция отгрузок (
ShipmentCollection) — отвечает за логистику и резервирование остатков на складах. - Корзина (
Basket) — товары внутри заказа.
Если хотя бы одна оплата проведена (статус «Оплачено») или товар зарезервирован/отгружен, ядро не даст удалить объект верхнего уровня. Это защита от нарушения финансовой и складской консистентности.
Алгоритм безопасного удаления состоит из строго последовательных шагов:
- Загрузить объект заказа.
- Перебрать все оплаты и отметить их как «возвращенные» (отменить оплату).
- Перебрать все отгрузки, снять признак
DEDUCTED(отгружено) и отменить резервы. - Сохранить изменения в коллекциях.
- Вызвать метод удаления самого заказа.
Рабочий пример кода на D7
Ниже представлен универсальный скрипт для удаления массива заказов. Его можно вызывать через агентов, крон-скрипты или CLI.
use Bitrix\Main\Loader;
use Bitrix\Sale;
// Проверяем подключение модуля интернет-магазина
if (!Loader::includeModule('sale')) {
die("Модуль sale не установлен");
}
// Массив ID заказов, которые нужно удалить
$orderIds = [1001, 1002, 1003];
$logFile = $_SERVER["DOCUMENT_ROOT"] . "/local/logs/order_delete.log";
foreach ($orderIds as $orderId) {
// 1. Загружаем объект заказа
$order = Sale\Order::load($orderId);
if (!$order) {
file_put_contents($logFile, "[$orderId] Заказ не найден\n", FILE_APPEND);
continue;
}
try {
// 2. Отменяем оплаты
$paymentCollection = $order->getPaymentCollection();
foreach ($paymentCollection as $payment) {
if ($payment->isPaid()) {
// Ставим флаг возврата
$payment->setReturn("Y");
}
}
// 3. Отменяем отгрузки и системную отгрузку (System shipment)
$shipmentCollection = $order->getShipmentCollection();
foreach ($shipmentCollection as $shipment) {
if (!$shipment->isSystem()) {
if ($shipment->isShipped()) {
// Снимаем флаг отгрузки (возвращает остатки)
$shipment->setField("DEDUCTED", "N");
}
// На всякий случай снимаем резервирование
$shipment->setField("RESERVED", "N");
}
}
// 4. Обязательно сохраняем сброшенные статусы до удаления!
$saveResult = $order->save();
if (!$saveResult->isSuccess()) {
throw new \Exception(implode(", ", $saveResult->getErrorMessages()));
}
// 5. Удаляем сам заказ
$deleteResult = Sale\Order::delete($orderId);
if ($deleteResult->isSuccess()) {
file_put_contents($logFile, "[$orderId] Успешно удален\n", FILE_APPEND);
} else {
throw new \Exception(implode(", ", $deleteResult->getErrorMessages()));
}
} catch (\Exception $e) {
file_put_contents($logFile, "[$orderId] Ошибка: " . $e->getMessage() . "\n", FILE_APPEND);
}
}Альтернатива: отмена, а не удаление
В 90% случаев интернет-магазинам вообще не нужно физически удалять заказы. Удаление нарушает сквозную нумерацию, портит статистику конверсий и мешает аналитике в дашбордах.
Правильный бизнес-сценарий — это отмена заказа.
$order = \Bitrix\Sale\Order::load($orderId);
$order->setField('CANCELED', 'Y');
$order->setField('REASON_CANCELED', 'Тестовый заказ / Ошибка клиента');
$order->save();При смене статуса CANCELED на Y, Битрикс автоматически вернет зарезервированные товары на склад, если это настроено в параметрах модуля Интернет-магазин. Физическое удаление лучше оставить только для очистки базы разработчиками после этапа тестовой эксплуатации.
Резюме
Работа с коллекциями — основополагающий принцип D7. Запомните главное правило: никогда не меняйте данные таблиц напрямую через SQL запросы типа DELETE FROM b_sale_order. База Битрикса глубоко реляционна, и прямой SQL-запрос оставит после себя битые индексы, мусор в таблицах корзины (b_sale_basket) и расхождение в складских остатках (b_catalog_store_product).
Нужна помощь с сопровождением и доработкой интернет-магазина на 1С-Битрикс? Разработчики NBM-IT пишут чистый код на D7, интегрируют сложные API и оптимизируют highload-проекты. Оставьте заявку на технический аудит.
Бесплатный SEO-аудит вашего сайта
Оставьте заявку, и наши специалисты найдут точки роста поискового трафика.
