Декабрь 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(0, 99999);
$pos = strpos($newLogin, '@');
if ($pos !== false)
$newLogin = substr($newLogin, 0, $pos);
if (strlen($newLogin) > 47)
$newLogin = substr($newLogin, 0, 47);
$newLogin = str_pad($newLogin, 3, '_');
$dbUserLogin = \CUser::GetByLogin($newLogin);
if ($userLoginResult = $dbUserLogin->Fetch())
{
do
{
$newLoginTmp = $newLogin.mt_rand(0, 99999);
$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");