Довольно часто интернет-магазины на битрикс реализованы таким образом, что работа магазина включает множество нестандартных решений. Так к примеру, я столкнулся с необходимостью создания дополнительной возможности повтора заказа. Суть задачи заключается в том, что у покупателя уже есть существующий заказ в системе. При необходимости пользователь может посредством одной кнопки повторить создание заказа. Повтор заказа подразумевает копирование товаров из предыдущего заказа в новый, копирование свойств заказа, данных клиента, метода оплаты и других данных.
Давайте рассмотрим пример реализации подобного функционала. Перед тем как приступать, стоит озвучить принцип, по которому будет работать скрипт. На одной из страниц сайта, там, где отображается существующий заказ, будет размещена кнопка повтора заказа. Детали размещения мы отпустим, лишь обсудим принцип основной работы в этой части.
По нажатию на кнопку отправляется Ajax запрос, с параметром ORDER_ID существующего заказа. В php-скрипте все данные по ID заказа будут выбираться из базы. После этого будет созданы новые записи в корзине и новый заказ, с переносом всех основных данных.
В качестве результата на Ajax запрос, в json-ответ будет отправляться поле status, значение которого будет равно true или false (сообщает форме об успешном создании заказа).
Что касается формы, то тут всё просто. В заголовке подключатся JQuery, второй в низу страницы form.js где будет выполняться отправка запроса по ajax. Сама форма состоит из двух ключевых блоков, это блок с классом .response-msg куда будут выводиться сообщения, и сама кнопка button. Номер заказа передаётся через атрибут кнопки data-order-id.
<!DOCTYPE html> <html> <head> <title>Повтор заказа</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> </head> <body> <div class="text-center"> <div class="response-msg"></div><!--статус запроса--> <button class="btn btn-repeat" data-order-id="5">Повторить заказ</button> </div> <script src="form.js"></script> </body> </html>
Для простоты примера, форма сделана на отдельной странице. Вы же можете использовать её как вам удобно в своих шаблонах.
Принцип работы js-скрипта так же прост. Прописан обработчик события по клику на кнопке, находится в файле form.js. При нажатии кнопки срабатывает это событие, которое получает значение атрибута data-order-id на кнопке, и отправляет его на сервер по ajax. После успешной отправки кнопка скрывается. Так же выводится сообщение, отправленное скриптом на стороне сервера. Сообщение так же может иметь статус true/false, который обозначает об успешной отправке либо об ошибке.
$(".btn-repeat").on("click", function(){ var order_id = $(this).attr('data-order-id'), // ID исходного заказа btn = $(this); // объект кнопки $(".response-msg").html(''); // очищаем текст сообщений if (order_id > 0){ // отправка ajax-запроса $.ajax({ type: "POST", url: './ajax-order-repeat.php', data: { 'ORDER_ID': order_id, }, dataType: "json", success: function(data){ // если статус успешный if (data.status == true){ btn.hide(); // скрываем кнопку } // показ текстовых сообщений if (data.msg && data.msg.length > 0){ $(".response-msg").fadeIn(); $.each( data.msg, function( key,field ) { if (field.type == true){ $(".response-msg").append('<p class="text-advance">'+field.text+'</p>'); } else { $(".response-msg").append('<p class="text-error">'+field.text+'</p>'); } }); } } }); } });
Статусы сообщений в скрипте удобно использовать, когда есть необходимость вывести сообщение в советующем цвете. В нашем примере сообщениям присваиваются классы text-advance и text-error.
Так как скрип выполняет роль ajax-обработчика, то начале скрипта подключается само ядро, без загрузки основного шаблона сайта. Это позволит возвращать результат в формате json а не html. Код скрипта я постарался писать с комментариями, которые и объясняют суть происходящего сценария в нём. Стоит обратить внимание что в скрипте используются API актуальные для ядра D7. Таким образом, в старых версиях битрикса (где ядро не D7), функционал естественно работать не будет.
<?require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php"); global $USER; use Bitrix\Main, Bitrix\Sale\Basket, Bitrix\Sale; CModule::IncludeModule("sale"); CModule::IncludeModule("catalog"); $arResult = array('status' => false); // проверяем параметр ORDER_ID if (isset($_REQUEST['ORDER_ID']) && $_REQUEST['ORDER_ID'] > 0){ $ORDER_ID = intval($_REQUEST['ORDER_ID']); // ID текущего заказа $order = \Bitrix\Sale\Order::load($ORDER_ID); // объект заказа if ($order){ // методы оплаты $paymentCollection = $order->getPaymentCollection(); foreach ($paymentCollection as $payment) { $paySysID = $payment->getPaymentSystemId(); // ID метода оплаты $paySysName = $payment->getPaymentSystemName(); // Название метода оплаты } // службы доставки $shipmentCollection = $order->getShipmentCollection(); foreach ($shipmentCollection as $shipment) { if($shipment->isSystem()) continue; $shipID = $shipment->getField('DELIVERY_ID'); // ID службы доставки $shipName = $shipment->getField('DELIVERY_NAME'); // Название службы доставки } // объект нового заказа $orderNew = \Bitrix\Sale\Order::create(SITE_ID, $USER->GetID()); // код валюты $orderNew->setField('CURRENCY', $order->getCurrency()); // задаём тип плательщика $orderNew->setPersonTypeId( $order->getPersonTypeId() ); // создание корзины $basketNew = Basket::create(SITE_ID); // дублируем корзину заказа $basket = $order->getBasket(); foreach ($basket as $key => $basketItem){ $item = $basketNew->createItem('catalog', $basketItem->getProductId()); $item->setFields( array( 'QUANTITY' => $basketItem->getQuantity(), 'CURRENCY' => $order->getCurrency(), 'LID' => SITE_ID, 'PRODUCT_PROVIDER_CLASS'=>'\CCatalogProductProvider', ) ); } // привязываем корзину к заказу $orderNew->setBasket($basketNew); // задаём службу доставки $shipmentCollectionNew = $orderNew->getShipmentCollection(); $shipmentNew = $shipmentCollectionNew->createItem(); $shipmentNew->setFields( array( 'DELIVERY_ID' => $shipID, 'DELIVERY_NAME' => $shipName, 'CURRENCY' => $order->getCurrency() ) ); // пересчёт стоимости доставки $shipmentCollectionNew->calculateDelivery(); // задаём метод оплаты $paymentCollectionNew = $orderNew->getPaymentCollection(); $paymentNew = $paymentCollectionNew->createItem(); $paymentNew->setFields( array( 'PAY_SYSTEM_ID' => $paySysID, 'PAY_SYSTEM_NAME' => $paySysName ) ); // задаём свойства заказа $propertyCollection = $order->getPropertyCollection(); $propertyCollectionNew = $orderNew->getPropertyCollection(); foreach ($propertyCollection as $property){ // получаем свойство в коллекции нового заказа $somePropValue = $propertyCollectionNew->getItemByOrderPropertyId( $property->getPropertyId() ); // задаём значение свойства $somePropValue->setValue( $property->getField('VALUE') ); } // сохраняем новый заказ $orderNew->doFinalAction(true); $rs = $orderNew->save(); // проверяем результат, присваивает статус ответа if ($rs->isSuccess()){ $arResult['status'] = true; $arResult['msg'][] = array('type' => true, 'text' => 'Успешно создан новый заказ, №'.$orderNew->getId()); } else { $arResult['msg'][] = array('type' => false, 'text' => $rs->getErrorMessages()); } } else { $arResult['msg'][] = array('type' => false, 'text' => 'Не удалось получить заказ №'.$ORDER_ID); } } else { $arResult['msg'][] = array('type' => false, 'text' => 'Не передан параметр ORDER_ID'); } echo json_encode($arResult); ?>
Вот собственно и всё, переделывать данный скрипт вы можете на своё усмотрение, под свои задачи. Здесь код приведён в качестве примера, и он может послужить наглядной шпаргалкой для создания своего функционала. Вы можете скачать исходники со скриптами по этой ссылке.
Сохраняйте страницу у себя в закладках, надеюсь этот скрипт вам помог с реализацией!
UPD: Так же может возникнуть ситуация, когда создавать заказ не нужно, а достаточно положить товары из существующего заказа в корзину текущего пользователя. С такой поправкой на сайте появился пост, с которым вы так же можете ознакомиться.
Спасибо за статью!
Редко встретишь по битриксу такой хороший материал - все подробно, понятно, красиво, еще и работает на кастоме с минимальными доработками
Попался старый проект на Битрикс в работе. Копировать заказ можно более коротким механизмом.
....
$orderNew = $order->createClone();
$orderNew->save();
....
Ну а вообще Битрикс это деградация для разработчика..
Вы не правы. (new Order)->createClone(); не сбрасывает ID у сущностей, так что для копирования он не пригоден.