Создание заказа через api

Модуль расширенного управления меню для битрикс

Декабрь 8, 2018

Теги: Магазин, Как это сделать?

Создание заказа через api d7. Заказ корзины либо конкретных товаров минуя корзину.

Для начала необходим класс функций, которая будет создавать пользователя, если заказ происходит без авторизации. Данный класс создает пользователя с логином соответствующим номеру телефона, либо возвращает ID пользователя, если таковой уже есть. Второй параметр $newUserProps функции getByPhone может содержать другие параметры пользователя, например, E-mail. Эти параметры используются только при создании пользователя. Если заказ происходит только после авторизации, данный класс не нужен:


<?php

    
namespace Partner;

use 
\Bitrix\Main\Config\Option;

class 
OrderUser
{
    function 
getByPhone($phone,$newUserProps)
    {
        
$phone \NormalizePhone($phone,7);
        if(!
$phone)
            return 
false;        
        
$user \Bitrix\Main\UserTable::getRow(array(
            
'filter' => array(
                
'=LOGIN' => $phone,
            ),
            
'select' => array('ID')
        ));
        if(
$user['ID'])
        {
            return 
$user['ID'];
        }
        else
        {
            
$user = new \CUser;
            
$fields self::getDefaultData(array_merge($newUserProps,array('PHONE'=>$phone)));
            
$fields array_merge($newUserProps,$fields);
            
$addRes $user->Add($fields);
            if(!
intval($addRes))
                
$GLOBALS['APPLICATION']->ThrowException($user->LAST_ERROR); 
            return 
intval($addRes);
        }
    }
    
    function 
getDefaultData($userProps)
    {
        
$userEmail = isset($userProps['EMAIL']) ? trim((string)$userProps['EMAIL']) : '';
        
$userPhone $userProps['PHONE'];
        if(!
$userPhone)
            return 
false;
        
        if(!
$userEmail)
            
$userEmail $userPhone.'@autouser.autouser';
        
        
$newName '';
        
$newLastName '';
        
$fio = isset($userProps['FIO']) ? trim((string)$userProps['FIO']) : '';

        if (!empty(
$fio))
        {
            
$arNames explode(' '$fio);
            if (isset(
$arNames[1]))
            {
                
$newName $arNames[1];
                
$newLastName $arNames[0];
            }
            else
            {
                
$newName $arNames[0];
            }
        }

        
$groupIds = [];
        
$defaultGroups Option::get('main''new_user_registration_def_group''');

        if (!empty(
$defaultGroups))
        {
            
$groupIds explode(','$defaultGroups);
        }

        
$arPolicy $GLOBALS["USER"]->GetGroupPolicy($groupIds);

        
$passwordMinLength = (int)$arPolicy['PASSWORD_LENGTH'];
        if (
$passwordMinLength <= 0)
        {
            
$passwordMinLength 6;
        }

        
$passwordChars = array(
            
'abcdefghijklnmopqrstuvwxyz',
            
'ABCDEFGHIJKLNMOPQRSTUVWXYZ',
            
'0123456789',
        );
        if (
$arPolicy['PASSWORD_PUNCTUATION'] === 'Y')
        {
            
$passwordChars[] = ",.<>/?;:'\"[]{}\|`~!@#\$%^&*()-_+=";
        }

        
$newPassword randString($passwordMinLength 2$passwordChars);

        return array(
            
'EMAIL' => $userEmail,
            
'LOGIN' => $userPhone,
            
'NAME' => $newName,
            
'LAST_NAME' => $newLastName,
            
'PASSWORD' => $newPassword,
            
'PASSWORD_CONFIRM' => $newPassword,
            
'GROUP_ID' => $groupIds
        
);
        
    }
    
}

Другой вариант функции авторегистрации - пользователь создается в любом случае, независимо от того, регистрировался ли он ранее:


function autoRegisterUser($definedProps)

{
    
$userEmail = isset($definedProps['EMAIL']) ? trim((string)$definedProps['EMAIL']) : '';
    
$newLogin $userEmail;

    if (empty(
$userEmail))
    {
        
$newEmail false;
        
$normalizedPhone \NormalizePhone((string)$definedProps['PHONE'], 3);
        if (!empty(
$normalizedPhone))
            
$newLogin $normalizedPhone;
    }
    else
        
$newEmail $userEmail;

    if (empty(
$newLogin))
        
$newLogin randString(5).mt_rand(099999);

    
$pos strpos($newLogin'@');
    if (
$pos !== false)
        
$newLogin substr($newLogin0$pos);

    if (
strlen($newLogin) > 47)
        
$newLogin substr($newLogin047);

    
$newLogin str_pad($newLogin3'_');

    
$dbUserLogin \CUser::GetByLogin($newLogin);
    if (
$userLoginResult $dbUserLogin->Fetch())
    {
        do
        {
            
$newLoginTmp $newLogin.mt_rand(099999);
            
$dbUserLogin \CUser::GetByLogin($newLoginTmp);
        }
        while (
$userLoginResult $dbUserLogin->Fetch());

        
$newLogin $newLoginTmp;
    }

    
$newName $newLastName '';
    
$fio = isset($definedProps['FIO']) ? trim((string)$definedProps['FIO']) : '';
    if (
$fio)
        list(
$newName,$newLastName) = explode(' '$fio);

    
$groupIds = [];
    
$defaultGroups \Bitrix\Main\Config\Option::get('main''new_user_registration_def_group''');

    if (!empty(
$defaultGroups))
        
$groupIds explode(','$defaultGroups);
    
$arPolicy $GLOBALS['USER']->GetGroupPolicy($groupIds);

    
$passwordMinLength = (int)$arPolicy['PASSWORD_LENGTH']>0?(int)$arPolicy['PASSWORD_LENGTH']:6;
    
$passwordChars = array('abcdefghijklnmopqrstuvwxyz','ABCDEFGHIJKLNMOPQRSTUVWXYZ','0123456789');
    if (
$arPolicy['PASSWORD_PUNCTUATION'] === 'Y')
        
$passwordChars[] = ",.<>/?;:'\"[]{}\|`~!@#\$%^&*()-_+=";
    
$newPassword $newPasswordConfirm \randString($passwordMinLength 2$passwordChars);

    if(!
$newEmail)
        
$newEmail $newLogin.'@'.$newLogin.'.autoreg';

    
$fields = array(
        
'LOGIN' => $newLogin,
        
'NAME' => $newName,
        
'LAST_NAME' => $newLastName,
        
'PASSWORD' => $newPassword,
        
'CONFIRM_PASSWORD' => $newPasswordConfirm,
        
'EMAIL' => $newEmail,
        
'GROUP_ID' => $groupIds,
        
'ACTIVE' => 'Y',
        
'LID' => \Bitrix\Main\Context::getCurrent()->getSite(),
        
'PERSONAL_PHONE' => isset($definedProps['PHONE']) ? \NormalizePhone($definedProps['PHONE']) : '',
        
'PERSONAL_ZIP' => isset($definedProps['ZIP']) ? $definedProps['ZIP'] : '',
        
'PERSONAL_STREET' => isset($definedProps['ADDRESS']) ? $definedProps['ADDRESS'] : '',
    );

    
$user = new \CUser;
    
$addResult $user->Add($fields);

    if (
intval($addResult) <= 0)
        
$GLOBALS['APPLICATION']->ThrowException('Ошибка регистрации пользователя: '.((strlen($user->LAST_ERROR) > 0) ? ': '.$user->LAST_ERROR ''),'GENERATE_USER_ERROR');
        
    return 
intval($addResult);
}

Непосредственно код создания заказа:


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

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

$arErrors = array();

/* если нужно сделать заказ с существующей корзиной */
$basket \Bitrix\Sale\Basket::loadItemsForFUser(\Bitrix\Sale\Fuser::getId(), \Bitrix\Main\Context::getCurrent()->getSite());
/* или если нужно заказать конкретный товар минуя корзину:
$basket = \Bitrix\Sale\Basket::create($siteId);
foreach($arProductId as $productId=>$quantity)
{
    $item = $basket->createItem('catalog', $productId);
    $item->setFields(array( // стандартный вариант, цена берется из каталога
        'QUANTITY' => $quantity,
        'PRODUCT_PROVIDER_CLASS' => \Bitrix\Catalog\Product\Basket::getDefaultProviderName(),
        'LID' => $siteId,
    ));
    $item = $basket->createItem('catalog', $productId);
    $item->setFields(array( // вариант с указанием цены вручную
        'QUANTITY' => $quantity,
        'CURRENCY' => $currency,
        'LID' => $siteId,
        'PRICE' => 500,
    ));
}
*/

$currency \Bitrix\Currency\CurrencyManager::getBaseCurrency();

if(
count($basket)<=0)
    
$arErrors[]="Ваша корзина пуста";

// если пользователь авторизован, можно просто использовать $USER->GetID()
if(!!$phone && !($userId=\Partner\OrderUser::getByPhone($phone,array('EMAIL'=>$email,'FIO'=>$fio)))) 
{
    if(
$ex $APPLICATION->GetException())
        
$arErrors[]="Ошибка регистрации пользователя: ".$ex->GetString();
    else
        
$arErrors[]="Ошибка регистрации пользователя: ".$phone;        
}

$deliveryId 1// ID службы доставки, можно также использовать \Bitrix\Sale\Delivery\Services\EmptyDeliveryService::getEmptyDeliveryServiceId()

if(!$arErrors)
{
    if(
$order \Bitrix\Sale\Order::create($siteId,$userId,$currency))
    {        
        
$order->setPersonTypeId(1);    
        
        
$shipment $shipmentCollection->createItem();  // exactly here to avoid "System shipment not empty" error with manual adding

        
$order->setBasket($basket);        
    
        
$basketSum $order->getPrice();
    
        
/* shipment */
        
        
$shipmentCollection $order->getShipmentCollection();
        
$service Bitrix\Sale\Delivery\Services\Manager::getById($deliveryId);
        
$delivery $service['NAME'];
        
$shipment->setFields(array(
            
'DELIVERY_ID' => $service['ID'],
            
'DELIVERY_NAME' => $service['NAME'],
        ));
        
$shipmentItemCollection $shipment->getShipmentItemCollection();
        foreach (
$basket as $item)
        {
            
$shipmentItem $shipmentItemCollection->createItem($item);
            
$shipmentItem->setQuantity($item->getQuantity());
        }
        
        
/* /shipment */
        
        /* order properties */
    
        
$propertyCollection $order->getPropertyCollection();
        
$propertyCodeToId = array();
        foreach(
$propertyCollection as $propertyValue)
            
$propertyCodeToId[$propertyValue->getField('CODE')] = $propertyValue->getField('ORDER_PROPS_ID');
            
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['FIO']);
        
$propertyValue->setValue($fio);
    
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['PHONE']);
        
$propertyValue->setValue($phone);
    
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['EMAIL']);
        
$propertyValue->setValue($email);
            
        
/* /order properties */
        
        
$order->doFinalAction(true);
        
$result $order->save();
        if(
$result->isSuccess())
        {
            
$orderId $order->getId();
        
            
//$order = Order::load($orderId);
    
            
$accountNumber $order->getField('ACCOUNT_NUMBER'); // генерируемый номер заказа
            // можно выполнить обработчики из sale.order.ajax для обеспечения совместимости
            // foreach (\GetModuleEvents('sale', 'OnSaleComponentOrderOneStepComplete', true) as $arEvent) 
                // \ExecuteModuleEventEx($arEvent, array($order->getId(), $order->getFieldValues(), array()));
        
}
        else
        {
            
$arErrors[] = "Ошибка создания заказа: ".implode(", ",$result->getErrorMessages());
        }
    }
}

Пример ajax-обработчика для создания заказа с одним товаром (11 и 12 - это идентификаторы инфоблока товаров и предложений соответственно):


<?php


define
("NO_KEEP_STATISTIC""Y");
define("NO_AGENT_STATISTIC","Y");
define("NOT_CHECK_PERMISSIONS"true);

require(
$_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

use 
\Bitrix\Main\Application;
use 
\Bitrix\Main\Context;
use 
\Bitrix\Main\Loader;

$request Application::getInstance()->getContext()->getRequest();
$siteId Context::getCurrent()->getSite();

$productId intval($request->get('product_id'));
$storeId intval($request->get('store_id'));
$fio strval($request->get('fio'));
$email strval($request->get('email'));
$phone strval($request->get('phone'));
$quantity intval($request->get('quantity'));
if(
$quantity<=0)
    
$quantity 1;
$comment strval($request->get('comment'));

$errors = array();

if(!
Loader::includeModule("sale") || !Loader::includeModule("catalog") || !Loader::includeModule("iblock"))
    
$errors[] = "Модули не установлены";

if(
$productId<=0)
    
$errors[] = "Не задан идентификатор товара";

if(!
$errors)
{
    if(
$productId<=0
    {
        
$errors[] = "Не задан идентификатор товара";
    }
    elseif(!(
$product=\Bitrix\Iblock\ElementTable::getById($productId)->fetch()))
    {
        
$errors[] = "Товар не найден";
    }
    elseif(
$product['IBLOCK_ID']==11)
    {
        
$productName $product['NAME'];
    }
    elseif(
$product['IBLOCK_ID']==12)
    {
        
$productName '';
        if(
$parentProduct \Bitrix\Iblock\ElementTable::getById(Constants::getParentProduct($productId))->fetch())
            
$productName .= $parentProduct['NAME'];
        
$productName .= ", ".$product['NAME'];
    }
    else
    {
        
$errors[] = "Товар не найден";    
    }
}

if(
$storeId<=0)
    
$errors[] = "Не задан идентификатор склада";
if(!
check_bitrix_sessid())
    
$errors[] = "Ваша сессия истекла, пожалуйста, обновите страницу";

if(!
$errors)
{
    
$currency \Bitrix\Currency\CurrencyManager::getBaseCurrency();

    
$basket \Bitrix\Sale\Basket::create($siteId);

    
$price '200';

    
$item $basket->createItem('catalog'$productId);
    
$item->setFields(array(
        
'QUANTITY' => $quantity,
        
'CURRENCY' => $currency,
        
'PRICE' => $price['price'],
        
'LID' => $siteId,
        
'NAME' => $productName,
    ));

    if(
count($basket)<=0)
        
$errors[]=($ex $APPLICATION->GetException())?$ex->GetString():'Ошибка добавления в корзину';
    
$userId $USER->IsAuthorized()?$USER->GetID():autoRegisterUser(array('FIO'=>$fio,'EMAIL'=>$email,'PHONE'=>$phone));
    if(!
$userId)
        
$errors[]=($ex $APPLICATION->GetException())?$ex->GetString():'Ошибка регистрации пользователя';
}

if(!
$errors)
{
    if(
$order \Bitrix\Sale\Order::create($siteId,$userId,$currency))
    {        
        
$order->setPersonTypeId(1);    
        
$order->setBasket($basket);
        
$order->setField("STATUS_ID","DM");
    
        
/* shipment */
        
        
$shipmentCollection $order->getShipmentCollection();
        
$shipment $shipmentCollection->createItem();
        
$service \Bitrix\Sale\Delivery\Services\Manager::getById(4); // доставка - забрать из бесплатного пункта выдачи
        
$delivery $service['NAME'];
        
$shipment->setFields(array(
            
'DELIVERY_ID' => $service['ID'],
            
'DELIVERY_NAME' => $service['NAME'],
        ));
        
$shipment->setStoreId($storeId); // ID беспллатного пункта выдачи
        
        
$shipmentItemCollection $shipment->getShipmentItemCollection();
        foreach (
$basket as $item)
        {
            
$shipmentItem $shipmentItemCollection->createItem($item);
            
$shipmentItem->setQuantity($item->getQuantity());
        }
        
        
/* /shipment */

        /* payment */
        
        
$paymentCollection $order->getPaymentCollection();
        
$payment $paymentCollection->createItem();
        
$payment->setField('SUM'$order->getPrice());
        
$paySystemService \Bitrix\Sale\PaySystem\Manager::getObjectById(6);
        
$payment->setFields(array(
            
'PAY_SYSTEM_ID' => $paySystemService->getField("PAY_SYSTEM_ID"),
            
'PAY_SYSTEM_NAME' => $paySystemService->getField("NAME"),
        ));        
        
        
/* /payment */
        
        /* order properties */
    
        
$propertyCollection $order->getPropertyCollection();
        
$propertyCodeToId = array();
        foreach(
$propertyCollection as $propertyValue)
            
$propertyCodeToId[$propertyValue->getField('CODE')] = $propertyValue->getField('ORDER_PROPS_ID');
            
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['FIO']);
        
$propertyValue->setValue($fio);
    
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['PHONE']);
        
$propertyValue->setValue($phone);
    
        
$propertyValue=$propertyCollection->getItemByOrderPropertyId($propertyCodeToId['EMAIL']);
        
$propertyValue->setValue($email);
            
        
/* /order properties */

        
$order->setField('USER_DESCRIPTION',$comment); // комментарий покупателя
        
        
$order->doFinalAction(true);
        if(
$result $order->save())
        {
            
$orderId $order->getId();
            
//$order = Order::load($orderId);
            
$accountNumber $order->getField('ACCOUNT_NUMBER'); // генерируемый номер заказа
        
}
        else
        {
            
$errors[] = "Ошибка создания заказа: ".implode(", ",$result->getErrorMessages());
        }
    }
    else
    {
        
$errors[] = "Ошибка создания заказа";
    }
}

$return = array();

if(
$errors)
{
    
$return["errors"] = $errors;    
}
else
{
    
$return["order_id"] = $orderId;
    
$return["account_number"] = $accountNumber;
}

$APPLICATION->RestartBuffer();
echo 
json_encode($return);

require(
$_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_after.php");

См. также:

← Переход к списку