Начиная с 16 версии используется новая версия ядра магазина Битрикс, являющаяся частью ядра Битрикс D7. Многое описанное здесь может работать и в переходной версии 15.5. Все классы для работы с магазином собраны в модуле sale, поэтому для работы примером используем use для пространства модуля интернет-магазина.

use Bitrix\Sale;

Заказ (Sale\Order)

Заказ представляет собой объект класса Bitrix\Sale\Order. Нужно запомнить, что пока не вызван метод save() этот объект необязательно связан с сохранённым заказом. Также пока вы не вызовете save(), изменения в заказе не будут сохранены в базе данных.

Существующий заказ можно получить следующим образом:

/** int $orderId ID заказа */
$order = Sale\Order::load($orderId);

/** mixed $orderNumber номер заказа */
$order = Sale\Order::loadByAccountNumber($orderNumber);

Поля заказа можно получить короткими вызовами:

$order->getId(); // ID заказа
$order->getSiteId(); // ID сайта
$order->getDateInsert(); // объект Bitrix\Main\Type\DateTime
$order->getPersonTypeId(); // ID типа покупателя
$order->getUserId(); // ID пользователя

$order->getPrice(); // Сумма заказа
$order->getDiscountPrice(); // Размер скидки
$order->getDeliveryPrice(); // Стоимость доставки
$order->getSumPaid(); // Оплаченная сумма
$order->getCurrency(); // Валюта заказа

$order->isPaid(); // true, если оплачен
$order->isAllowDelivery(); // true, если разрешена доставка
$order->isShipped(); // true, если отправлен
$order->isCanceled(); // true, если отменен

Также любое поле по имени можно получить так:

$order->getField("ORDER_WEIGHT"); // Вес заказа
$order->getField('PRICE'); // Сумма заказа
// Изменение поля:
$order->setField('USER_DESCRIPTION', 'Комментарий к заказу');
$order->save();

Список доступных полей можно получить, вызвав $order->getAvailableFields().

Заказ имеет связь один-ко-многим с несколькими объектами в виде коллекций - коллекция товаров в корзине (Sale\Basket), коллекция отгрузок (Sale\ShipmentCollection), коллекция оплат (Sale\PaymentCollection) и коллекция свойств заказа (Sale\PropertyValueCollection).

Самый простой способ получить список способов доставки и оплаты - короткие вызовы:

$paymentIds = $order->getPaymentSystemId(); // массив id способов оплат
$deliveryIds = $order->getDeliverySystemId(); // массив id способов доставки

Чтобы получить список примененных к заказу скидок, нужно вызвать:

$discountData = $order->getDiscount()->getApplyResult();

В массиве $discountData['DISCOUNT_LIST'] содержится список скидок, в $discountData['COUPON_LIST'] содержится список купонов. Т.к. скидки можно отключать в админке, следует проверять поле APPLY: если Y - скидка/купон применёны, если N - были отключены менеджером.

Корзина заказа (Sale\Basket)

Про работу с корзиной была отдельная статья, привязать и получить корзину заказа можно так:

/** Sale\Basket $basket */
$order->setBasket($basket);

$basket = $order->getBasket();

Свойства заказа (Sale\PropertyValueCollection)

Свойства заказа - объекты Bitrix\Sale\PropertyValue - собраны в коллекции propertyCollection

$propertyCollection = $order->getPropertyCollection();

Получить значения всех свойств и группы свойств можно так:

$ar = $propertyCollection->getArray(); // массив ['properties' => [..], 'groups' => [..] ];
$ar = $propertyCollection->getGroups(); // массив групп
$ar = $propertyCollection->getGroupProperties($groupId); // массив свойств, относящихся к группе

У многих свойств заказа есть определенное встроенное назначение (атрибуты IS_EMAIL, IS_PAYER, IS_LOCATION, IS_LOCATION4TAX, IS_PROFILE_NAME, IS_ZIP, IS_PHONE, IS_ADDRESS). Такие свойства можно получить следующими методами:

$emailPropValue = $propertyCollection->getUserEmail();
$namePropValue  = $propertyCollection->getPayerName();
$locPropValue   = $propertyCollection->getDeliveryLocation();
$taxLocPropValue = $propertyCollection->getTaxLocation();
$profNamePropVal = $propertyCollection->getProfileName();
$zipPropValue   = $propertyCollection->getDeliveryLocationZip();
$phonePropValue = $propertyCollection->getPhone();
$addrPropValue  = $propertyCollection->getAddress();

Получить значение свойства по ID:

$somePropValue = $propertyCollection->getItemByOrderPropertyId($orderPropertyId);

В любом случае получаем значение свойства - экземпляр класса Bitrix\Sale\PropertyValue. Из него мы можем получить значение свойства:

$somePropValue->getValue(); // значение свойства
$somePropValue->getViewHtml(); // представление значения в читаемом виде (напр. для местоположения - путь страна, регион, город)

И информацию о самом свойстве:

$arProp  = $somePropValue->getProperty(); // массив данных о самом свойстве
$propId  = $somePropValue->getPropertyId(); // ID свойства
$propName = $somePropValue->getName(); // Название
$isRequired = $somePropValue->isRequired(); // true, если свойство обязательное
$propPerson = $somePropValue->getPersonTypeId(); // Тип плательщика
$propGroup  = $somePropValue->getGroupId(); // ID группы

Чтобы изменить значение свойства следует вызвать метод setValue и сохранить сущность

$somePropValue->setValue("value");
$order->save(); 
// можно $somePropValue->save(), но пересчета заказа не произойдёт

Оплаты заказа (Sale\PaymentCollection)

$paymentCollection = $order->getPaymentCollection();

Из коллекции оплат также можно получить информацию об оплате, что и из объекта заказа. Оплата с внутреннего счета также считается одной из оплат:

$paymentCollection->isPaid(); // true, если все оплаты оплачены
$paymentCollection->hasPaidPayment(); // true, если хотя бы одна оплата оплачена
$paymentCollection->getPaidSum(); // оплаченная сумма
$paymentCollection->isExistsInnerPayment(); // true, если осуществлена оплата с внутреннего счета

Коллекция содержит объекты оплаты Sale\Payment с информацией об оплатах:

foreach ($paymentCollection as $payment) {
    $sum = $payment->getSum(); // сумма к оплате
    $isPaid = $payment->isPaid(); // true, если оплачена
    $isReturned = $payment->isReturn(); // true, если возвращена

    $ps = $payment->getPaySystem(); // платежная система (объект Sale\PaySystem\Service)
    $psID = $payment->getPaymentSystemId(); // ID платежной системы
    $psName = $payment->getPaymentSystemName(); // название платежной системы
    $isInnerPs = $payment->isInner(); // true, если это оплата с внутреннего счета
}

Оплатить или вернуть оплату можно методами setPaid(), setReturn():

$onePayment = $paymentCollection[0];
$onePayment->setPaid("N"); // отмена оплаты
$onePayment->setPaid("Y"); // оплата
$onePayment->setReturn("Y"); // возврат (деньги возвращаются на внутренний счет или в платежную систему, если обработчик реализует интерфейс Sale\PaySystem\IRefund)
// после любых действий нужно сохранить сущность:
$order->save();

Инициировать оплату (вывести шаблон оплаты: форму, кнопку и т.п.) можно следующим образом:

$service = Sale\PaySystem\Manager::getObjectById($onePayment->getPaymentSystemId());
$context = \Bitrix\Main\Application::getInstance()->getContext();
$service->initiatePay($onePayment, $context->getRequest());

Пример оформления заказа в D7

Для примера приведу простейший код оформления заказа с комментариями

use Bitrix\Main\Context,
    Bitrix\Currency\CurrencyManager,
    Bitrix\Sale\Order,
    Bitrix\Sale\Basket,
    Bitrix\Sale\Delivery,
    Bitrix\Sale\PaySystem;

global $USER;

Bitrix\Main\Loader::includeModule("sale");
Bitrix\Main\Loader::includeModule("catalog");

// Допустим некоторые поля приходит в запросе
$request = Context::getCurrent()->getRequest();
$productId = $request["PRODUCT_ID"];
$phone = $request["PHONE"];
$name = $request["NAME"];
$comment = $request["COMMENT"];

$siteId = Context::getCurrent()->getSite();
$currencyCode = CurrencyManager::getBaseCurrency();

// Создаёт новый заказ
$order = Order::create($siteId, $USER->isAuthorized() ? $USER->GetID() : 539);
$order->setPersonTypeId(1);
$order->setField('CURRENCY', $currencyCode);
if ($comment) {
    $order->setField('USER_DESCRIPTION', $comment); // Устанавливаем поля комментария покупателя
}

// Создаём корзину с одним товаром
$basket = Basket::create($siteId);
$item = $basket->createItem('catalog', $productId);
$item->setFields(array(
    'QUANTITY' => 1,
    'CURRENCY' => $currencyCode,
    'LID' => $siteId,
    'PRODUCT_PROVIDER_CLASS' => '\CCatalogProductProvider',
));
$order->setBasket($basket);

// Создаём одну отгрузку и устанавливаем способ доставки - "Без доставки" (он служебный)
$shipmentCollection = $order->getShipmentCollection();
$shipment = $shipmentCollection->createItem();
$service = Delivery\Services\Manager::getById(Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId());
$shipment->setFields(array(
    'DELIVERY_ID' => $service['ID'],
    'DELIVERY_NAME' => $service['NAME'],
));
$shipmentItemCollection = $shipment->getShipmentItemCollection();
$shipmentItem = $shipmentItemCollection->createItem($item);
$shipmentItem->setQuantity($item->getQuantity());

// Создаём оплату со способом #1
$paymentCollection = $order->getPaymentCollection();
$payment = $paymentCollection->createItem();
$paySystemService = PaySystem\Manager::getObjectById(1);
$payment->setFields(array(
    'PAY_SYSTEM_ID' => $paySystemService->getField("PAY_SYSTEM_ID"),
    'PAY_SYSTEM_NAME' => $paySystemService->getField("NAME"),
));

// Устанавливаем свойства
$propertyCollection = $order->getPropertyCollection();
$phoneProp = $propertyCollection->getPhone();
$phoneProp->setValue($phone);
$nameProp = $propertyCollection->getPayerName();
$nameProp->setValue($name);

// Сохраняем
$order->doFinalAction(true);
$result = $order->save();
$orderId = $order->getId();

Подробнее можно прочитать по этой ссылке или в компоненте sale.order.ajax.


Читайте также: