Из-за часто меняющегося компонента оформления заказа приведенное здесь решение не является полным и окончательным, а следить за актуальностью я не могу. Поэтому прошу пост рассматривать лишь для подспорья в написании собственного кода, а не использовать "как есть".
ЗЫ: Вот последняя актуальная (примерно на июнь 2014) версия компонента, которую я запилил под одного клиента: скачать. Пользуйтесь как есть, пожалуйста. Измененные блоки (менялся только component.php) я выделил фразой customization (конкретно для клиента менял еще некоторые строчки). Кодировка cp1251.
Оформление заказа почти идеально, но есть минус - если гость вводит e-mail, который есть в базе, ему дадут от ворот поворот - мол такой пользователь уже есть. А если подойти с точки зрения покупателя, это ломает - вспоминать пароль, или еще что. В общем, лояльность падает. Исправим ситуацию (сразу хочу огорчить - решение подразумевает +2 байта в системном компоненте, так что если вам не пойдет - пост бесполезен (хотя, вы можете просто вынести компонент в свое пространство, код все равно будет рабочим). [spoiler] Речь пойдет про компонент sale.order.ajax, одношаговое оформление заказа. Почему нельзя вынести компонент в свое пространство и изменить? Потому что это центровой компонент магазина, который постоянно улучшается компанией Битрикс, и лично я против его изменения. Так как же подошел к проблеме я.
Все методы ниже - методы класса CSaleHandlers, внутри которого содержатся необходимые обработчики событий.
Также класс имеет переменную
private static $bGuestOrder = false;
Поехали
1. Событие OnSaleComponentOrderOneStepProcess
//AddEventHandler('sale', 'OnSaleComponentOrderOneStepProcess', Array('CSaleHandlers', 'OnSaleComponentOrderOneStepProcessHandler'));
public static function OnSaleComponentOrderOneStepProcessHandler($arResult, $arUserResult, $arParams) {
if (empty($arResult['ERROR']) && $arUserResult['CONFIRM_ORDER']=='Y' && !$GLOBALS['USER']->IsAuthorized()) {
if ($arUser = CUser::GetList($by='id', $order='asc', array('=EMAIL' => $arUserResult['USER_EMAIL']))->Fetch()) {
if (!in_array(1, CUser::GetUserGroup($arUser['ID']))) {
$GLOBALS['USER']->Authorize($arUser['ID']);
self::$bGuestOrder = true;
}
}
}
}
Перед самым созданием заказа, перехватываем исполнение и смотрим - если пользователь с введенным e-mail, есть, то авторизуем его. От греха подальше, НЕ авторизуем если пользователь из группы админов. Это достаточно важный момент, потому что ошибка может произойти на любой строчке кода, и тогда гость может остаться админом.
В переменной self::$bGuestOrder запоминаем, что заказ создает гость.
2. Событие OnOrderUpdate
//AddEventHandler('sale', 'OnOrderUpdate', Array('CSaleHandlers', 'OnOrderUpdateHandler'));
public static function OnOrderUpdateHandler($ID, $arFields) {
if (self::$bGuestOrder && $GLOBALS['USER']->IsAuthorized() && isset($arFields['PRICE'])) {
$_SESSION['SAVED_UID'] = $GLOBALS['USER']->GetID();
$GLOBALS['USER']->Logout();
}
}
Разавторизовываем пользователя после создания заказа (в понятиях кода, а не сайта). Почему нельзя использовать OnOrderAdd? Потому что после добавления идет еще привязка корзины пользователя, и мы потеряем ее в случае OnOrderAdd. Также в сессии запоминаем предыдущий ID пользователя, который нам пригодится
3. Событие OnSaleComponentOrderOneStepComplete
//AddEventHandler('sale', 'OnSaleComponentOrderOneStepComplete', Array('CSaleHandlers', 'OnSaleComponentOrderOneStepCompleteHandler'));
public static function OnSaleComponentOrderOneStepCompleteHandler($ID, $arOrder, $arParams) {
if ($ID <= 0) {
if (self::$bGuestOrder) {
$GLOBALS['USER']->Logout();
}
}
}
Здесь мы страхуемся и делаем логаут пользователю, если случилась ошибка при создании заказа.
4. Событие OnSaleComponentOrderOneStepFinal
//AddEventHandler('sale', 'OnSaleComponentOrderOneStepFinal', Array('CSaleHandlers', 'OnSaleComponentOrderOneStepFinalHandler'));
public static function OnSaleComponentOrderOneStepFinalHandler($ID, $arOrder, $arParams) {
if ((!$GLOBALS['USER']->IsAuthorized() && $_SESSION['SAVED_UID']!=$arOrder['USER_ID']) ||
($GLOBALS['USER']->IsAuthorized() && $GLOBALS['USER']->GetID()!=$arOrder['USER_ID'])
) {
$arOrder = array();
}
}
Здесь мы запрещаем просмотр заказа на финальном шаге (оплата), если это гость и не создал его только что сам.
По идее все. Где же надо поправить системный компонент sale.order.ajax/component.php?
Для версии Магазина до 12.5.4. примерно на 2079 строчке (но строчки постоянно скачут при изменениях, так что ориентироваться лучше на окружающий код) идет выборка созданного заказа с проверкой пользователя - вот пользователя надо закомментировать:
После версии 12.5.4 модуля Магазин, код иной:
Обратите внимание. Данное изменение компонента может работать только вкупе с данными обработчиками. Иначе доступ к финальному шагу (системе оплаты) получает любой пользователь.
Изменения компонента не было бы, если бы реализованная идея, просьба поддержать.
Класс необходимых обработчиков вы можете скачать ниже. Достаточно просто подключить его в init.php
Это для случая на миллион, когда страшный левый баг вкрадется и кто-то получит доступ админа. Это крайне редкая ситуация, но админом я и в этом случае не мог рисковать.
Авторизации не происходит, смотрите, пожалуйста, описание кода
В OnSaleComponentOrderOneStepProcess - CUser::Authorize($arUser['ID']); Далее Logout , только в OnOrderUpdate и OnSaleComponentOrderOneStepFinal. Если я правильно понимаю, то OnOrderUpdate - произойдет уже после того, как будет нажато оформление заказа?
У меня основное непонимание сценария использования, и преимущества перед стандартным функционалом - убранной галочки "Проверять E-mail на уникальность при регистрации". Есть пример, где внедрен данный способ?
Далее Logout , только в OnOrderUpdate и OnSaleComponentOrderOneStepFinal. Если я правильно понимаю, то OnOrderUpdate - произойдет уже после того, как будет нажато оформление заказа?
Ну файл то один идет выполнение скрипта - авторизовались.... создался заказ... логаут... На выходе все равно гость. Есть риск, что во время создания заказа вывалится баг (крашнутая таблица, кривые апдейты), вот тут есть риск остаться авторизованным. Случай на миллион (для админа), поэтому я не стал рисковать.
и преимущества перед стандартным функционалом - убранной галочки "Проверять E-mail на уникальность при регистрации"
Как же так? А то, что все время новые пользователи? История не хранится?
Есть пример, где внедрен данный способ?
У меня тоже есть паранойя и я тоже человек, делающий ошибки Если здесь найдут таракана, не хочу, чтобы он сразу был применен на боевых сайтах.
Иван, внедрил здесь http://test.d-it.ru/ , можно погонять под пользователем с мейлом test@d-it.ru. При желании можно и авторизоваться под ним (test / 111111) посмотрев историю заказов.
PS: Добавил обработчики в виде файла, чтобы не копипастить с поста. Достаточно их подключить в init, внести изменения в компонент, и все заработает.
Евгений, верно, но всего одну строку закомментить. Как минимум, это очень упрощает поддержку когда выходит обновленный компонент заказа (просто снова скопировал и закомментил строчку).
serg ase , вчера накатывал последние обновления, там теперь иначе логика кода устроена, и комментировать в другом месте надо. Сейчас внесу изменения в пост, на тесте поправил у себя.
Спасибо! Эта ошибка исчезла. Но появилась у меня другая (которая у вас в демке не проявляется): при оформлении заказа под гостем при существующем емейле - в свойствах заказа сумма - 0, хотя списке товаров в заказе присутствуют цены на товары. Версия магазина 2.5.3
serg ase , нашел причину (скорее всего в этом). После последних обновлений в OnOrderUpdateHandler надо проверять наличие ключа PRICE. В пост внесу изменения позже:
public static function OnOrderUpdateHandler($ID, $arFields) {
if (self::$bGuestOrder && $GLOBALS['USER']->IsAuthorized() && isset($arFields['PRICE'])) {
......
Антон, да, в самом конце. Ввожу e-mail зарегистрированного пользователя, любые данные (имя, адрес и т.д.), нажимаю оформить заказ и получаю ошибку "Заказ № не найден". Сам заказ оформляется, но пользователь видит такое вот сообщение. Тоже самое сообщение получил и на вашем демо-сайте, используя адрес test@d-it.ru
Антон, куки поддерживаются. Сейчас попробовал на вашем демо оформить через другой браузер - все нормально прошло, но до этого через этот же браузер оформлял заказ на своем сайте и получил ошибку.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».