Как добавить профиль покупателя в Битрикс

Для самых нетерпеливых, кому лень читать статью полностью, публикую в самом начале код добавления профиля покупателя в CMS-1С-Битрикс

<? //Подключаем модуль «Интернет-магазин» \Bitrix\Main\Loader::includeModule('sale'); //Массив полей профиля покупателя $profileFields = [ 'NAME' => 'Тестовый профиль',//Название профиля 'USER_ID' => (int) $USER->GetID(),//ID пользователя, в данном случае это ID текущего пользователя 'PERSON_TYPE_ID' => $personTypeId,//ID типа плательщика (физическое лицо, юридическое лицо) ]; $profileAddResult = \Bitrix\Sale\Internals\UserPropsTable::Add($profileFields);//Создаем профиль покупателя //Если профиль создался, то заполняем значения свойств заказа в этом профиле if($profileAddResult->isSuccess()) { $prop = [ 'USER_PROPS_ID' => $profileAddResult->getId(),//ID профиля (созданного выше) 'ORDER_PROPS_ID' => $saleOrderPropertyId,//ID свойства заказа 'NAME' => 'Имя',//Название свойства заказа 'VALUE' => 'Иван',//Подставляем нужное значение свойства заказа ]; //Добавляем значение свойства заказа в профиль покупателя $propertyAddResult = \Bitrix\Sale\Internals\UserPropsValueTable::Add($prop); //Проверка, добавилось ли значение свойства в профиль if($propertyAddResult->isSuccess()) { } } ?>

Теперь опишу подробно все шаги, для более внимательного читателя, как создать функционал для добавления профиля покупателя в личном кабинете пользователя.

По умолчанию в битриксе профиль покупателя создается в момент оформления заказа, с помощью компонента bitrix:sale.order.ajax, но некоторые, шибко умные заказчики сайтов, просят создать функционал в личном кабинете пользователя, по добавлению профилей покупателя. И данный функционал (на момент написания этой статьи) в коробочном варианте Битрикс отсутствует. Поэтому опишу все шаги подробно по созданию данного функционала.

  1. Получение списка типов плательщика
  2. Получение списка свойств заказа
  3. Вывод формы для создания профиля покупателя на странице
  4. Скрипт для создания профиля покупателя

Получение списка типов плательщика

<? //Подключаем модуль «Интернет-магазин» \Bitrix\Main\Loader::includeModule('sale'); //Создадим массив с нужными данными, для вывода формы добавления профиля покупателя $profiles = []; $rs = \Bitrix\Sale\Internals\PersonTypeTable::getList( [ 'order' => [ 'SORT' => 'ASC', 'ID' => 'ASC', ], 'filter' => [ 'ACTIVE' => 'Y',//Только активные типы плательщиков 'LID' => SITE_ID,//ID сайта (в данном случает ID текущего сайта) ], 'select' => [ 'ID', 'NAME', ], ] ); while ($personType = $rs->fetch()) { $profiles[$personType['ID']] = [ 'ID' => $personType['ID'],//ID типа плательщика 'NAME' => $personType['NAME'],//Название типа плательщика 'PROPERTIES' => [],//Сюда ниже мы добавим список всех свойств заказа для данного типа плательщика ]; } ?>

Получение списка свойств заказа

<? $rs = \Bitrix\Sale\Internals\OrderPropsTable::getList( [ 'order' => [ 'SORT' => 'ASC', 'ID' => 'ASC', ], 'filter' => [ 'ACTIVE' => 'Y',//Только активные свойства 'USER_PROPS' => 'Y',//Только свойства входящие в профиль пользователя 'UTIL' => 'N',//Свойство не является служебным (служебные свойства заказа могут добавляться например модулями служб доставок, они заполняются автоматически в момент создания заказа и не нужно давать пользователю тут что то заполнять самостоятельно) ], 'select' => [ 'ID', 'PERSON_TYPE_ID',//ID типа плательщика 'CODE',//Символьный код 'NAME',//Название 'DEFAULT_VALUE',//Значение по умолчанию 'TYPE',//Тип поля (например NUMBER, STRING, LOCATION) 'REQUIRED',//Признак обязательности для заполнения 'MULTIPLE',//Признак множественности ], ] ); while ($orderProperty = $rs->fetch()) { if(isset($profiles[$orderProperty['PERSON_TYPE_ID']])) { $profiles[$orderProperty['PERSON_TYPE_ID']]['PROPERTIES'][$orderProperty['ID']] = $orderProperty; } } ?>

Вывод формы для создания профиля покупателя на странице

В данном примере рассмотрим случай когда типы свойств заказа ограничиваются списком (NUMBER, STRING, LOCATION), для остальных типов вы сможете сделать сами по аналогии.

Выше мы набрали массив $profiles в котором есть информация о типах плательщика и свойствах заказа для каждого типа. Теперь создаем форму.

Предположим что форма будет находиться по адресу /personal/profiles/, а скрипт по созданию самого профиля по адресу /personal/profiles/profile-add.php.

Код формы (/personal/profiles/):

<? <div class="profile-tabs"> <? $j = 0; foreach($profiles as $profile) { $j++; ?> <input id="PERSON_TYPE_<?=$profile['ID']?>" type="radio" name="PERSON_TYPE" value="<?=$profile['ID']?>" <?=$j === 1 ? 'checked' : ''?>> <label for="PERSON_TYPE_<?=$profile['ID']?>"><?=$profile['NAME']?></label> <form method="POST" action="/personal/profiles/profile-add.php" enctype="multipart/form-data"> <input type="hidden" name="PERSON_TYPE_ID" value="<?=$profile['ID']?>"> <label> <p>Название профиля:</p> <input autocomplete="off" type="text" name="PROFILE_NAME" value="" placeholder="Название профиля" required> </label> <? foreach($profile['PROPERTIES'] as $orderProperty) { $inputName = 'ORDER_PROP_' . $orderProperty['ID']; if ( $orderProperty['TYPE'] == 'STRING' || $orderProperty['TYPE'] == 'NUMBER' ) {//Для типов строка и число //Если свойство множественное if($orderProperty['MULTIPLE'] == 'Y') { ?> <span><?=$orderProperty['NAME']?>:</span> <? //Тут задаете нужное количество значений множественного свойства, в данном примере их выведется 5 for($k = 0; $k < 5; $k++) { ?> <div> <input type="<?=strtolower($orderProperty['TYPE'])?>" name="<?=$inputName?>[]" value="<?=isset($orderProperty['DEFAULT_VALUE'][$k]) ? $orderProperty['DEFAULT_VALUE'][$k] : ''?>" placeholder="<?=$orderProperty['NAME']?>" <?=$orderProperty['REQUIRED'] == 'Y' && $k === 0 ? 'required' : ''/*если поле обязательно для заполнения, то делаем обязательным только первый инпут, потому что могут ввести всего одно значение*/?>> </div> <? } } else {//Если свойство НЕ множественное ?> <label> <span><?=$orderProperty['NAME']?>:</span> <input type="<?=strtolower($orderProperty['TYPE'])?>" name="<?=$inputName?>" value="<?=$orderProperty['DEFAULT_VALUE']?>" placeholder="<?=$orderProperty['NAME']?>" <?=$orderProperty['REQUIRED'] == 'Y' ? 'required' : ''?>> </label> <? } } elseif ($orderProperty['TYPE'] == 'LOCATION') { //Для типа свойства «Местоположение» выводим стандартный код Битрикс для полей этого типа \CSaleLocation::proxySaleAjaxLocationsComponent( [ 'AJAX_CALL' => 'N', 'CITY_OUT_LOCATION' => 'Y', 'COUNTRY_INPUT_NAME' => $inputName.'_COUNTRY', 'CITY_INPUT_NAME' => $inputName, 'LOCATION_VALUE' => $orderProperty['DEFAULT_VALUE'], ], [], 'popup',//Название шаблона компонента bitrix:sale.ajax.locations true, 'location-block-wrapper'//CSS-класс для контейнера этого поля ); } } ?> <button type="submit">Создать профиль</button> </form> <? } ?> </div> ?>

CSS-стили для этой формы, а вдруг пригодятся (потому что табы сделаны на чистом CSS)

<style> .profile-tabs { display: flex; flex-direction: row; justify-content: space-between; flex-wrap: wrap; } .profile-tabs input[type="radio"] { display: none; } .profile-tabs input[type="radio"] + label { line-height: 1; background-color: #f8f8f8; border-radius: 10px; white-space: nowrap; padding: 15px; display: block; width: calc(50% - 15px); cursor: pointer; order: 0; } .profile-tabs input[type="radio"] + label:hover, .profile-tabs input[type="radio"]:checked + label { color: #fff; background-color: #e54b4b; } .profile-tabs input[type="radio"] + label + form { display: none; order: 10; width: 100%; flex: 0 0 100%; } .profile-tabs input[type="radio"]:checked + label + form { display: block; } .profile-tabs label { display: block; } .profile-tabs label span { display: block; margin: 20px 0 5px 0; } .profile-tabs label input { border: 1px solid #000; line-height: 1; padding: 5px 10px; } </style>

Скрипт для создания профиля покупателя

<? //На приемной стороне /personal/profiles/profile-add.php require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php'); header('Content-Type: application/json');//Это только для случая когда вы делаете запрос через AJAX и используете тип JSON //Подключаем модуль «Интернет-магазин» \Bitrix\Main\Loader::includeModule('sale'); //Снова получаем список типов плательщика и список свойств заказа, что бы проверить правильность заполненных данных в форме $profiles = [];//Массив с данными свойств заказа //Массив с результатом создания профиля $result = [ 'success' => false, 'errors' => [], ]; //Проверяем передано ли название профиля if( !isset($_POST['PROFILE_NAME'])//Не передано «Название профиля» || !is_string($_POST['PROFILE_NAME'])//«Название профиля» не строка || !$_POST['PROFILE_NAME']//Пустое «Название профиля» ) { $result['errors'][] = [ 'INPUT_NAME' => 'PROFILE_NAME', 'TEXT' => 'Не заполнено обязательное поле «Название профиля»', ]; } //Получаем список ID типов плательщиков, сортировка нам тут не нужна $rs = \Bitrix\Sale\Internals\PersonTypeTable::getList( [ 'filter' => [ 'ACTIVE' => 'Y',//Только активные типы плательщиков 'LID' => SITE_ID,//ID сайта (в данном случает ID текущего сайта) ], 'select' => [ 'ID', ], ] ); while ($personType = $rs->fetch()) { $profiles[$personType['ID']] = [ 'PROPERTIES' => [],//Сюда ниже мы добавим список свойств заказа для данного типа плательщика ]; } //Проверяем, существует ли в базе тип плательщика с ID $_POST['PERSON_TYPE_ID'] if( !isset($_POST['PERSON_TYPE_ID'])//Не передан ID типа плательщика || !isset($profiles[$_POST['PERSON_TYPE_ID']])//Переданный ID типа плательщика не существует ) { $result['errors'][] = [ 'INPUT_NAME' => 'PERSON_TYPE_ID', 'TEXT' => 'Не заполнено обязательное поле «Тип плательщика»', ]; } else { $profileAddPropsValue = [];//Массив с данными свойств заказа для сохранения в профиль покупателя //Получаем список всех свойств заказа входящих в профиль покупателя и не являющихся системными $rs = \Bitrix\Sale\Internals\OrderPropsTable::getList( [ 'filter' => [ 'ACTIVE' => 'Y',//Только активные свойства 'USER_PROPS' => 'Y',//Только свойства входящие в профиль пользователя 'UTIL' => 'N',//Свойство не является служебным (служебные свойства заказа могут добавляться например модулями служб доставок, они заполняются автоматически в момент создания заказа и не нужно давать пользователю тут что то заполнять самостоятельно) 'PERSON_TYPE_ID' => $_POST['PERSON_TYPE_ID'],//Выбираем свойство только для выбранного типа плательщика ], 'select' => [ 'ID', 'NAME',//Название 'REQUIRED',//Признак обязательности для заполнения 'MULTIPLE',//Признак множественности ], ] ); while ($orderProperty = $rs->fetch()) { //Набираем массив значений свойств заказа, заполненных в форме $inputName = 'ORDER_PROP_' . $orderProperty['ID']; $inputValue = ''; if(isset($_POST[$inputName])) {//Если это свойство передано в POST-запросе if($orderProperty['MULTIPLE'] == 'Y') {//Если свойство множественное $inputValue = []; if(is_array($_POST[$inputName])) { foreach($_POST[$inputName] as $value) { if( is_string($value) && $value ) { $inputValue[] = $value; } } } } else { if( is_string($_POST[$inputName]) && $_POST[$inputName] ) { $inputValue = $_POST[$inputName]; } } } $profileAddPropsValue[] = [ 'ORDER_PROPS_ID' => $orderProperty['ID'], 'NAME' => $orderProperty['NAME'], 'VALUE' => $inputValue, ]; //Проверка заполнения свойств заказа в форме if( $orderProperty['REQUIRED'] == 'Y'//Если свойство обязательно к заполнению && !$inputValue//Свойство не заполнено ) { $result['errors'][] = [ 'INPUT_NAME' => $inputName, 'TEXT' => 'Не заполнено обязательное поле «' . $orderProperty['NAME'] . '»', ]; } } } if(empty($result['errors'])) {//Если нет ошибок в заполнении формы, то создаем профиль $profileFields = [ 'NAME' => htmlspecialchars($_POST['PROFILE_NAME']), 'USER_ID' => (int) $USER->GetID(), 'PERSON_TYPE_ID' => $_POST['PERSON_TYPE_ID'], ]; $profileAddResult = \Bitrix\Sale\Internals\UserPropsTable::Add($profileFields); if($profileAddResult->isSuccess()) {//Профиль создался $result['success'] = true; $profileId = $profileAddResult->getId();//ID созданного профиля покупателя //Заполняем значения свойств профиля foreach($profileAddPropsValue as $value) { $value['USER_PROPS_ID'] = $profileId; //Сохраняем значение свойства в профиле $propertyAddResult = \Bitrix\Sale\Internals\UserPropsValueTable::Add($value); } } else { $result['errors'][] = [ 'TEXT' => 'Не удалось создать профиль', ]; } } //Если вы делаете запрос через AJAX и используете тип JSON, то выводите массив с результатом который обрабатываете результат, в этом массиве присутствует информация о неверно заполненных полях, которые можно будет подсветить echo json_encode($result); require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_after.php'); ?>

Для удаления профиля используйте метод \CSaleOrderUserProps::Delete($profileId);

ОЧЕНЬ ВАЖНО!!! Не используйте для удаления профайла метод \Bitrix\Sale\Internals\UserPropsTable::Delete($profileId); он удалит только профиль, но свойства заказа этого профиля останутся в базе, поэтому используйте \CSaleOrderUserProps::Delete($profileId);

Теги: 1С-Битрикс, PHP, Ядро D7, Профиль покупателя