Заказ из кода - чтение, поиск по номеру, изменение состава
Читаем заказ из кода, находим его по номеру заказа и правим состав так, чтобы итоговые суммы пересчитались правильно.
Решение
Загружаем заказ и читаем его состав:
use Bitrix\Main\Loader;use Bitrix\Sale\Order;
Loader::includeModule('sale');$order = Order::load($orderId); // null, если заказа с таким номером нет// загрузка собирает всё дерево заказа: корзину, оплаты, отгрузки, свойстваprintf("номер=%s сумма=%.2f оплачен=%s\n", $order->getField('ACCOUNT_NUMBER'), $order->getPrice(), $order->isPaid() ? 'да' : 'нет');foreach ($order->getBasket() as $item) { printf(" %-30s %s x %.2f\n", $item->getField('NAME'), $item->getQuantity(), $item->getPrice());}Заказ загружается целиком, вместе с корзиной, оплатами и отгрузками. Отдельные выборки по таблицам дают те же данные, но мимо бизнес-логики: пересчёт и события при этом не работают.
Ищем заказ по номеру, а не по идентификатору:
use Bitrix\Sale\Internals\OrderTable;
$row = OrderTable::getRow([ 'select' => ['ID'], 'filter' => ['=ACCOUNT_NUMBER' => '2024-000145'], // номер, видимый покупателю]);$order = $row ? Order::load($row['ID']) : null;Номер заказа и его идентификатор - разные поля. Покупатель называет номер, код чаще работает с идентификатором, и путаница между ними даёт «заказ не найден» при существующем заказе.
Меняем состав заказа:
$basket = $order->getBasket();$item = $basket->getItemById($basketItemId);$item->setField('QUANTITY', 3); // изменение количества позиции// $item->delete(); // или удаление позиции целиком$result = $order->save();if (!$result->isSuccess()) { print_r($result->getErrorMessages());}Сохранение пересчитывает скидки, доставку и итоговую сумму. Прямая правка количества в таблице этого не делает, и заказ остаётся с несогласованными суммами - расхождение всплывает при выгрузке в учётную систему.
Читаем свойства заказа:
foreach ($order->getPropertyCollection() as $prop) { printf("%-20s %s\n", $prop->getField('CODE'), $prop->getValue());}// фильтровать заказы по значению свойства можно через таблицу значений свойств// свои дописки рядом с сохранением заказа оборачивают транзакцией самиСвойства заказа лежат отдельной коллекцией, а не полями самого заказа. Поэтому выборка заказов по значению свойства строится соединением с таблицей значений, а не простым условием.
Отчёты и массовое чтение удобнее делать выборкой по таблицам заказов. Она не поднимает бизнес-логику и на десяти тысячах заказов работает в разы быстрее загрузки объектов. Правило простое: читать можно как угодно, а менять - только через объект заказа.
Изменение заказа кодом запускает те же события, что и правка из админки. Это удобно, пока обработчики не начинают конфликтовать: обработчик, который сам меняет заказ при сохранении, легко уходит в рекурсию.
Проверять результат сохранения нужно всегда, без исключений. Метод возвращает объект результата вместо исключения, и молчаливый провал по правам или по проверке данных выглядит снаружи как «код отработал, а ничего не изменилось».
Типичные проблемы
Заказ по номеру не находится.
Поиск идёт по идентификатору вместо номера. Это разные поля, и совпадают они только на первых заказах.
Суммы заказа разошлись после правки.
Количество менялось прямой записью в таблицу. Пересчёт скидок и доставки выполняется только при сохранении объекта заказа.
Сохранение молча ничего не меняет.
Не проверяется результат: ошибка прав или проверки данных возвращается объектом, а не исключением.
Выборка по свойству заказа не работает.
Свойства лежат в отдельной таблице значений. Условие по ним строится соединением, а не полем заказа.
Обработчик события зациклился.
Он меняет и сохраняет заказ внутри обработки сохранения. Такие правки делают до сохранения, а не после.
Частые вопросы
Можно ли создать заказ полностью из кода?
Да, объект заказа собирают из корзины, свойств и отгрузок и сохраняют. Так делают импорт заказов и оформление в один клик.
Как получить стоимость доставки заказа?
Из коллекции отгрузок: там лежит и служба, и цена. В полях самого заказа хранится итог, а не его составляющие.
Почему номера заказов идут не подряд?
Номер присваивается по своему правилу и может включать префиксы и год. Разрывы возникают из-за незавершённых оформлений.
Что быстрее для отчётов - объект или таблицы?
Для чтения больших выборок - таблицы: они не поднимают бизнес-логику. Для любых изменений - только объект заказа.
Смежное
-
Заказы и статусы - оглавление подтемы
-
Заказ из кода не сохраняется: разбор причин - когда сохранение молча не проходит
-
Статусы заказов: смена, права, письма - что происходит при смене статуса
-
Свойства заказов - как устроены поля заказа
-
Свои номера документов и заявок: шаблон, счётчики, уникальность - номер для своей сущности рядом с заказом
-
Каталог и продажи - устройство магазина целиком
-
Личный кабинет покупателя: список заказов, повтор и отмена - что из этого видит покупатель
-
Оплаты и отгрузки заказа: объекты, признаки, частичные операции - операции внутри заказа
-
Список заказов из кода: фильтры, постраничность, позиции - когда заказов нужен целый список
-
События оформления заказа: свои проверки, запрет и допданные - что срабатывает при сохранении заказа
-
Очередь обмена со сторонней системой: задания, повторы, сверка - куда отправлять созданный заказ
-
Транзакции при записи: откат, границы, что не откатится - заказ и его позиции вместе
-
Перенос заказов и клиентов со старого сайта: порядок и сверка - создание заказов пачкой при переезде
-
Заказ в один клик: форма, заказ из кода, уведомления - типовой сценарий создания из кода
-
Заказ изнутри: коллекции, пересчёт, сохранение, события - устройство объекта заказа целиком