Работа с заказами битрикс api d7


Подключаем модули
use \Bitrix\Main,   
    \Bitrix\Main\Localization\Loc as Loc,    
    Bitrix\Main\Loader,
    Bitrix\Main\Application,
   Bitrix\Currency,    
    Bitrix\Sale\Delivery,
    Bitrix\Sale\PaySystem,
    Bitrix\Sale,
    Bitrix\Sale\Order,
    Bitrix\Sale\Affiliate,
    Bitrix\Sale\DiscountCouponsManager,
    Bitrix\Main\Context; 
Получить заказ
инициализируем класс сдля работы с купонами
если не поключить, то слетят скидки
DiscountCouponsManager::init();
непосредственно получаем заказ
$order = \Bitrix\Sale\Order::load($orderId); //по ID заказа
$order = \Bitrix\Sale\Order::loadByAccountNumber($accountNumber); //по номеру заказа (ACCOUNT_NUMBER)
Получить заказы по фильтру
$dbRes = \Bitrix\Sale\Order::getList([
    'select' => ['ID'],
  'filter' => [
      "USER_ID" => $USER->GetID(), //по пользователю       
      ">=DATE_INSERT" => date($DB->DateFormatToPHP(CSite::GetDateFormat("SHORT")), mktime(0, 0, 0, date("n"), 1, date("Y"))), //по дате 
      "PAY_SYSTEM_ID" => $paysystemId, //по платежной системе
      "DELIVERY_ID" => $deliveryId, //по службе доставки
      "STATUS_ID" =>$statusId, //по статусу
      "PAYED" => "Y", //оплаченные
      "CANCELED" =>"N", //не отмененные
      "PROPERTY.ORDER_PROPS_ID" => $propId, //по свойству
      "PROPERTY.VALUE" => 'значение', //и по его значению      
  ],
  'order' => ['ID' => 'DESC']
]);
while ($order = $dbRes->fetch()){
    var_dump($order);
}
Создать новый заказ
Ид сайта устанавливаем
$siteId = Bitrix\Main\Context::getCurrent()->getSite(); //работает только для публичного раздела
$siteId = "s1"; //или указать жестко
//или из запроса
if (array_key_exists('site_id', $_REQUEST) && is_string($_REQUEST['site_id'])){
   $siteId = $_REQUEST['site_id'];
   if($siteId !== '' && preg_match('/^[a-z0-9_]{2}$/i', $siteId) === 1){
      define('SITE_ID', $siteId);
   }   
}
идентификатор покупателя (отличается от id пользователя)
$fuser = Sale\Fuser::getId(); //Идентификатор покупателя текущего пользователя
$fuser = Sale\Fuser::getIdByUserId($userId) //Идентификатор покупателя по id пользователя
получаем валюту базовую  ("RUB","USD",...)
$currencyCode = Option::get('sale', 'default_currency', 'RUB'); //вариант 1
$currencyCode = Bitrix\Currency\CurrencyManager::getBaseCurrency(); //вариант 2
$currencyCode = 'RUB'; //вариант 3
инициализируем класс для работы с купонами
DiscountCouponsManager::init();
создаем заказ
$order = \Bitrix\Sale\Order::create($siteId, $userId,$currencyCode);
Устанавливаем тип плательшика
$order->setPersonTypeId($payTypeId); //вариант 1
$order->setField("PERSON_TYPE_ID",$payTypeId); //вариант 2

Корзина заказа
для работы с корзиной на api d7 отдельная статья
получить текущую корзину покупателя
$basket = Sale\Basket::loadItemsForFUser($fuser, $siteId); //по идентификатор покупателя, ид сайта
создать корзину
$basket = \Bitrix\Sale\Basket::create($siteId);

$item = $basket->createItem('catalog', $productId);
$item->setField('QUANTITY', 1);
$item->setField('CURRENCY', $currencyCode);
$item->setField('PRODUCT_PROVIDER_CLASS', '\Bitrix\Catalog\Product\CatalogProvider');

$basket->refresh();

$order->setBasket($basket); //добавляем заказ в корзину
получить корзину заказа
$basket = $order->getBasket();
Доставка заказа
создать доставку
$shipmentCollection = $order->getShipmentCollection();
$shipment = $shipmentCollection->createItem();

$deliveryId = Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId(); //доставка "без доставки"

$service = Delivery\Services\Manager::getById($deliveryId);
 
$shipment->setFields(array(
    'DELIVERY_ID' => $service['ID'],
    'DELIVERY_NAME' => $service['NAME'],                         
));
$shipmentItemCollection = $shipment->getShipmentItemCollection();
foreach ($order->getBasket() as $item){
    $shipmentItem = $shipmentItemCollection->createItem($item);
    $shipmentItem->setQuantity($item->getQuantity());
}
получить службу доставки и разрешить оплату
$shipmentCollection = $order->getShipmentCollection(); 
foreach ($shipmentCollection as $shipment) {
    if (!$shipment->isSystem()) {
        $shipment->allowDelivery(); // разрешаем отгрузку
    }
}
Платежная система заказа
добавление
//вариант 1
$paymentCollection = $order->getPaymentCollection();
$payment = $paymentCollection->createItem();

$paySystemService = PaySystem\Manager::getObjectById($paySystemId); //$paySystemId  - ИД платежной системы
$payment->setFields(array(
    'PAY_SYSTEM_ID' => $paySystemId,
    'PAY_SYSTEM_NAME' => $paySystemService->getField("NAME"),
    'SUM'=> $order->getPrice()
));

//вариант 2
$paymentCollection = $order->getPaymentCollection();
$payment = $paymentCollection->createItem(\Bitrix\Sale\PaySystem\Manager::getObjectById($paySystemId)); //$paySystemId  - ИД платежной системы
$payment->setField('SUM', $order->getPrice());
получить ограничения для доставки, в т.ч. по платежным системам
$dbDelivery = \Bitrix\Sale\Delivery\Restrictions\Manager::getList(array(
   'filter' => array('SERVICE_ID' => $deliveryId) // ID службы доставки

));
while ($arDelivery = $dbDelivery->fetch()) {
   if($arDelivery["PARAMS"]) { // Если есть ограничения у доставки
   $arParams = $arDelivery["CLASS_NAME"]::prepareParamsValues($arDelivery["PARAMS"], $deliveryId); // Получаем ВСЕ ограничения для данной доставки                 
   if ($arParams['PAY_SYSTEMS']){
       //тут обрабатываем ограничения по платежным системам

   }
    }
}
получить объект платежной системы
$service = $payment->getPaySystem(); // \Bitrix\Sale\PaySystem\Service
получить настройки платежной системы
$list = \CSalePaySystemAction::getParamsByConsumer('PAYSYSTEM_'.$id, $personTypeId);
получить состояния: оплачено или нет
$isPaid = $payment->isPaid(); //true или false
Получение оплаченной суммы по заказу
$paymentCollection = $order->getPaymentCollection();
$paymentCollection->getPaidSum();
Возврат средств
  • 'Y' - при возврате на внутренний счет
  • 'P' - при возврате через платежную систему(если она поддерживает данный функционал);
  • 'N' - при отмене возврата
$result = $payment->setReturn($f); //$f - Y/P/N
if (!$result->isSuccess()){
    var_dump($r->getErrorMessages());
}
Свойства заказа
Получить свойства
$propertyCollection = $order->getPropertyCollection();

$property = $propertyCollection->getProfileName();
$property = $propertyCollection->getUserEmail();
$property = $propertyCollection->getPhone();
$property = $propertyCollection->getDeliveryLocation();
$property = $propertyCollection->getDeliveryLocationZip();


$property = $propertyCollection->getItemByOrderPropertyCode($orderPropertyCode); //по коду свойства вернет 1 свойство
$property = $propertyCollection->getItemsByOrderPropertyCode($orderPropertyCode); //по коду свойства вернет все найденные свойства
$property = $propertyCollection->getItemByOrderPropertyId($orderPropertyId); //по id 

//свой фильтр для свойств
$propertyCode = 'CODE_PROP';
$property = $propertyCollection->getItemsByFilter(
  //тут функция с нужной логикой
  function ($propertyValue) use ($propertyCode){
                return (
                    $propertyValue->getField('CODE') == $propertyCode
                );
  }
);

группы свойств
$ar = $propertyCollection->getArray(); // массив ['properties' => [..], 'groups' => [..] ];
$ar = $propertyCollection->getGroups(); // массив групп
$ar = $propertyCollection->getGroupProperties($groupId); // массив свойств, относящихся к группе
Получаем данные совйства
$ar = $property->getProperty(); // массив данных о самом свойстве
$propId  = $property->getPropertyId(); // ID свойства
$propName = $property->getName(); // Название
$isRequired = $property->isRequired(); // true, если свойство обязательное
$propPerson = $property->getPersonTypeId(); // Тип плательщика
$propGroup  = $property->getGroupId(); // ID группы

$propValue = $property->getValue(); //значение свойства
$propCode = $property->getField('CODE'); //любое другое поле свойства

Устанавливаем свойства заказа
$property->setField('VALUE', 'значение свойства'); //вариант 1
$property->setValue('значение свойства'); //вариант 2
Удаляем свойство
 $property->delete();
Поля заказа
заполняем
$order->setField('CURRENCY', $currencyCode); //валюта
$order->setField('USER_DESCRIPTION', $userDescription); //комментарии пользователя
$order->setField('COMMENTS', $managerComments);    //комментарии служебные
$order->setField('AFFILIATE_ID', $affiliateId); //аффилиат
$order->setFields('RESPONSIBLE_ID', $managerId); //для crm - ответственный 
получаем

$order->getField('USER_DESCRIPTION'); //комментарии пользователя 
$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, если отменен

Cохранение заказа
$order->doFinalAction(true);

$result = $order->save();
if ($result->isSuccess()) {
    echo 'Заказ успешно создан!';
} 
else {
    echo $result->getError();
}
Блокировка заказа
$order->lock(); //заблокировать
$order->unlock(); //разблокировать

Для CRM связь с контактом, компанией
получить список контактов
$communications = $order->getContactCompanyCollection();
foreach ($communications as $communication) {
   $arCom = $communication->getFields()->getValues(); //с ключами ID, ORDER_ID, ENTITY_ID, ENTITY_TYPE_ID, SORT, ROLE_ID, IS_PRIMARY
}
добавить новый
$itemCom = $communications->createCompany(); //компания
$itemCom = $communications->createContact();//контакт

изменить поля 
$itemCom ->setField('ENTITY_ID', 36); //ID контакта или компании
$itemCom ->setField('IS_PRIMARY', 'Y'); // необязательно  

получить поля
$itemCom ->getField('IS_PRIMARY'); 
так теперь не работает, изменилось api
//\Bitrix\Crm\Binding\OrderContactCompanyTable::bindContactIDs($orderId, array($contactId)); //\Bitrix\Crm\Binding\OrderContactCompanyTable::bindContacts($orderId, array(array("ENTITY_ID"=>$contactId,"IS_PRIMARY"=>"Y")));    
Устанавливаем статусы, флаги оплаты у уже созданного заказа
$payment->setPaid("Y"); //вариант 1
$order->setField('PAYED', 'Y');   //вариант 2

$order->setField('STATUS_ID', $statusId); //статус
$order->save();
получаем сгенерированную форму  оплаты (в виде счета, или ссылка на оплату)
if (!empty($paySystemService)) {      
      $arPaySysAction = $paySystemService->getFieldsValues();
      if ($paySystemService->getField('NEW_WINDOW') === 'N' || $paySystemService->getField('ID') == PaySystem\Manager::getInnerPaySystemId()){
            $initResult = $paySystemService->initiatePay($payment, null, PaySystem\BaseServiceHandler::STRING);
            if ($initResult->isSuccess())
                  $arPaySysAction['BUFFERED_OUTPUT'] = $initResult->getTemplate(); // получаем форму оплаты из обработчика
            else
                  $arPaySysAction["ERROR"] = $initResult->getErrorMessages();
            }
      }
}
Статусы заказа
языконезависимая информация о статусе
$statusResult = \Bitrix\Sale\Internals\StatusTable::getList(array(
    'order' => array('SORT'=>'ASC'),
    'filter' => array('TYPE'=>'O'),
));
while($arStatus = $statusResult->fetch()){
    print_r($arStatus); //поля статуса ID, TYPE, SORT, NOTIFY
}

языкозависимая информация о статусе
'STATUS.TYPE'=>'O' статусы заказа
'STATUS.TYPE'=>'D' статусы доставки
$statusResult = \Bitrix\Sale\Internals\StatusLangTable::getList(array(
    'order' => array('STATUS.SORT'=>'ASC'),
    'filter' => array('STATUS.TYPE'=>'O','LID'=>LANGUAGE_ID),
    'select' => array('STATUS_ID','NAME','DESCRIPTION'),
));
while($arStatus = $statusResult->fetch()){
    print_r($arStatus);  //STATUS_ID, NAME (на нужном языке),DESCRIPTION (на нужном языке)
}
не d7

if ($arStatus = CSaleStatus::GetByID($STATUS_ID,LANGUAGE_ID)){     print_r($arStatus); //массив с ключами ID, SORT, NAME, DESCRIPTION

}

Обработчики примеры
запретить удаление заказа всем, кроме определенного пользователя
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale',
    'OnSaleBeforeOrderDelete',
    'MyOnSaleBeforeOrderDelete'
);


//пользователь с ID 1
function MyOnSaleBeforeOrderDelete(Main\Event $event){
   if(!isset($_SESSION["SESS_AUTH"]["USER_ID"]) || ($_SESSION["SESS_AUTH"]["USER_ID"]!=1) || !isset($_SESSION["SESS_AUTH"]["AUTHORIZED"]) || ($_SESSION["SESS_AUTH"]["AUTHORIZED"]!=='Y')){
       return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::ERROR, new \Bitrix\Sale\ResultError('Ошибка при удалении заказа', 'code'), 'sale');
   }       
}

смена статуса, шел корявый статус из 1С, в CRM были ошибки
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale',
    'OnBeforeSaleOrderItemSetField',
    'setRightStatus'
);

function setRightStatus(\Bitrix\Main\Event $event){
    $name = $event->getParameter('NAME');
    if ($name === 'STATUS_ID'){
        if($event->getParameter('VALUE') == "CL"){
            $event->addResult(
              new Main\EventResult(
                   Main\EventResult::SUCCESS, array('VALUE' => "D")
               )
            );
        }
    }
}
старый api, после оплаты в нужный статус
AddEventHandler("sale", "OnSalePayOrder", "MyOnSalePayOrderChangeStatus");
function MyOnSalePayOrderChangeStatus($id,$val){   
        if($val=="Y" && CModule::IncludeModule('sale') && ($arOrder = CSaleOrder::GetByID($id))) { 
            if(in_array($arOrder['STATUS_ID'], array("N","NP"))){//если на стадии "В обработке", "Ожидает оплаты""            
                CSaleOrder::StatusOrder($id, "P"); //переводим в статус "оплачен, формируется к отправке"
            }
            elseif(in_array($arOrder['STATUS_ID'], array("S","Z"))){//если на стадии "Отправлен", "Отправлен, ожидание оплаты"            
                CSaleOrder::StatusOrder($id, "F"); //переводим в статус "выполнен"
            }
        }   
}
что-нибудь для нового заказа сделать
Main\EventManager::getInstance()->addEventHandler(
    'sale',
    'OnSaleOrderSaved',
    'MyOnSaleOrderSaved'
);


function MyOnSaleOrderSaved(Main\Event $event){   
    $order = $event->getParameter("ENTITY");
    if ($event->getParameter("IS_NEW")){
       //Ваша логика
    }
}