Задача: в детальной карточке товара сделать возможность добавления услуги или опции, при добавлении товара в корзину.
Связка элементов каталога с другим каталогом
В реалиях 1С-Битрикс нельзя добавить несуществующий товар в корзину: для реализации потребуется создать отдельный инфоблок с услугами/опциями, который будет так же (как и основной каталог) являться торговым каталогом.
На самом деле: можно добавить не существующий товар в корзину и учесть при оформлении заказа, подробнее в этой заметке: Добавление в корзину и заказ не существующего товара.
В настройках основного каталога нужно создать свойство типа "Привязка к элементам" и в качестве назначения указать этот дополнительный торговый каталог. В моем случае, к товарам каталога предлагается дополнительная услуга "Поверка оборудования" с кодом TSENA_POVERKI
В инфоблоке с дополнительными услугами нужно создать свойство типа "Строка", в моем случае названо "Для оборудования" (код ATT_FORE). Оно нужно для того, что бы эти услуги не объединялись в корзине и не перемешивались.
Создаем нужные, дополнительные услуги но это свойство оставляем пустым. И связываем товары основного каталога с дополнительными услугами.
Добавление товара в корзину на API Битрикс
Данная заметка написана как базис/ориентир по данному функционалу. Можно расширить опции к товару, сделать их множественными и вывести в виде чекбоксов. При реализации использовать AJAX, c собственным компонентом.
Открываем шаблон детальной карточки catalog.element и в том месте, где планируете выводить дополнительные услуги добавляем:
<? if (!empty($arResult['PROPERTIES']['TSENA_POVERKI']['VALUE'])) {
$page = $APPLICATION->GetCurPage();
if (!empty($arResult['PROPERTIES']['TSENA_POVERKI']['VALUE'])) {
$res = CIBlockElement::GetByID($arResult['PROPERTIES']['TSENA_POVERKI']['VALUE']);
if ($ar_res = $res->Fetch()) {
$poverkaName = $ar_res['NAME'];
}
}
?>
Доступна услуга поверки оборудования:
<?= $poverkaName ?> руб.
<form action="/local/ajax/add_poverka.php" method="post">
<input type="hidden" value="<?= $arResult['PROPERTIES']['TSENA_POVERKI']['VALUE'] ?>"
name="ADD_POVERKA_PRICE">
<input type="hidden" value="<?= $arResult['NAME'] ?>" name="ADD_POVERKA_FOR">
<input type="hidden" value="<?= $page ?>" name="ADD_POVERKA_COMEBACK">
<button type="submit" class="btn btn-info">В корзину с поверкой + <?= $poverkaName ?> руб.
</button>
</form>
<?
if ($_REQUEST['ADD_ITEM_TO_CART'] == 'Y') { ?>
<script>
$(document).ready(function () {
$('#<?= $itemIds['ADD_BASKET_LINK'] ?>').click();
});
</script>
<? }
} ?>
Проверили есть ли для этого товара дополнительная услуга. Если есть, собираем данные о товаре и дополнительной услуге в форму. В скрытых полях формы:
- ID элемента дополнительной услуги из свойства инфоблока, со связанным товаром.
- Название текущего элемента-товара
- Адрес страницы текущего товара, полученные методом $APPLICATION->GetCurPage();
Под формой добавляем js код который имитирует нажатие на кнопку добавления в корзину (основного товара) если в параматрах URL есть запрос вида ?ADD_ITEM_TO_CART=Y
Форму, при нажатии на кнопку, отправляем на файл add_poverka.php в директории /local/ajax.. В этом файле размещаем код:
require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php");
use \Bitrix\Main\Loader;
if (!$_POST['ADD_POVERKA_PRICE']) {
LocalRedirect('/');
}
Loader::includeModule('iblock');
Loader::includeModule('sale');
Loader::includeModule('catalog');
$resPrice = CIBlockElement::GetList(
array(),
array('=ID' => $_POST['ADD_POVERKA_PRICE']),
false, false,
array(
'ID',
'NAME'
)
);
while ($obPrice = $resPrice->Fetch()) {
$arFields = array(
"PRODUCT_ID" => $obPrice['ID'],
"PRODUCT_PRICE_ID" => 1,
"PRICE" => (int)$obPrice['NAME'],
"CURRENCY" => "RUB",
"WEIGHT" => '',
"QUANTITY" => 1,
"LID" => LANG,
"DELAY" => "N",
"CAN_BUY" => "Y",
"NAME" => "Поверка оборудования",
"CALLBACK_FUNC" => "",
"MODULE" => "",
"NOTES" => "",
"ORDER_CALLBACK_FUNC" => "",
"DETAIL_PAGE_URL" => ""
);
$arProps = array();
$arProps[] = array(
"NAME" => "Для",
"CODE" => "ATT_FORE",
"VALUE" => $_POST['ADD_POVERKA_FOR']
);
$arFields["PROPS"] = $arProps;
CSaleBasket::Add($arFields);
}
LocalRedirect($_POST['ADD_POVERKA_COMEBACK'].'?ADD_ITEM_TO_CART=Y');
exit();
Здесь мы обрабатываем $_POST запрос с данными переданными формой:
- Методом CIBlockElement::GetList получаем данные о дополнительной услуге.
- Собираем поля для формирования добавляемого товара в корзину.
- В полях изменяем название услуги, если это нужно.
- В свойство ATT_FORE записываем название элемента, для которого добавляется услуга.
- Методом CSaleBasket::Add добавляем услугу в корзину
- C помощью LocalRedirect($_POST['ADD_POVERKA_COMEBACK'].'?ADD_ITEM_TO_CART=Y'); отправляем на страницу товара, добавив параметр URL ?ADD_ITEM_TO_CART=Y
Таким образом: когда пользователь нажимает на кнопку заказа, с дополнительной услугой, мы отправляем его на обработчик добавляющий услугу в корзину, с изменением названия товара-услуги. Сразу после этого возвращаем на страницу товара, добавляя в параметр URL запрос. Если этот запрос есть в параметрах, иммитируем нажатие на кнопку добавления в корзину самого товара.
В итоге, в корзине будут и сами товары и дополнительные опции/услуги с указанием к какому товару они относятся. Все будет чередоваться правильно: каждая опция над товаром к которому относится и дополнительным указанием в свойстве "Для оборудования".
Повторюсь: эта заметка только базис. На реальном проекте и под конкретные задачи, лучше всего вынести всю эту логику в собственный компонент и реализовать AJAX. Что бы для пользователя все проходило максимально гладко.