Как работает корзина Opencart 2.3 и почему ее не так просто изменить (но у нас все получится). Цель: сделать одностраничное оформление заказа без регистраций и смс.
Ввиду последнего обновления opencart и грядущих, которые переписывают контроллеры – примеры кода беcполезны, главное общий ход размышлений.
Загрузка начинается с контроллера checkout/checkout. В нем происходит подготовка страницы и вывод “болванки” под работу корзины. Далее работает все на js, обработчиках которые по шагам ведут пользователя к победному заказу.
0 Шаг. Его пользователи не видят – он происходит в tpl части контроллера checkout/checkout. Определяется зарегистрирован ли покупатель, если не зарегистрирован вызывается контроллер checkout/login (Чтобы увидеть шаг 1.) – либо контроллер для зарегистрированных пользователей (здесь не рассматривается).
1 Шаг. На этом этапе заказчик делает первый выбор – зарегистрироваться, войти или оформить заказ без регистрации.
Для оформления без регистрации (обязательно разрешить в админке) исследуем форму:
Сначала идет проверка зарегистрирован ли пользователь. Очень похоже на наследие прошлой версии, так как мы еще в шаге 0 проверили это. В браузере смотрим id кнопки, которая поможет оформить без регистрации: button-account. И находим обработчик для таковой кнопки. Обработчик получает значение радио-кнопки, оно важно – так как является названием следующего контроллера.
Получая значение этой кнопки “guest” – переходим к шагу 2. Так же, просмотрев контроллер на предмет изменений каких либо данных в сессии или других местах понимаем, что контроллер только ПОЛУЧАЕТ данные, но не сохраняет их куда либо. Этот факт разрешает нам безболезненно пропустить шаг 1 и сразу перейти к 2.
2 Шаг. Запрос к контроллеру checkout/guest.
Этот контроллер важен, так как устанавливает в сессию (хранилище данных для каждого, кто вошел на сайт) дефолтные значения важных для opencart переменных. Его вызывать будем по любому. Далее, установив стандартные значения и получив нужные для шаблона переменные – он его вызывает.
Открываем tpl файл, написанный в контроллере, видим много-много html с формами, но интересует нас js. В js наблюдаются по порядку: сортировки полей, ajax запросы при изменении некоторых полей, можно прикрепить какой то файл.. И все, обработчика для кнопки отправить нет. Значит файл нам по сути не нужен, отправляемся искать его к контроллеру шага 0.
На данном этапе обработчик кнопки отправки платежной информации собирает данные со всей формы, пакует их в json и отправляет контроллеру checkout/guest/ и функции в нем save.
Для того, чтобы не заниматься долгим разбором формы можно “перехватить” данные.
Разберемся с функцией save контроллера checkout/guest:
- Проверка не зарегистрирован ли пользователь
- Проверка есть ли у него чего в корзине
- Еще разок проверка можно ли гостям заказывать
- Если до сих пор все хорошо – идет проверка полей
- Самый интересный пункт – заполнение полей. Здесь то мы и остановим работу стандартного контроллера и напишем ответ – запишем в json все данные, которые получили при заполнении формы.
$json = $this->request->post; |
Заполнив правильно все поля – получаем массив, который пригодится нам для заполнения фейковыми данными.
Возвращаем все на место, Смотрим что происходит далее. Далее мы видим снова развилку в логике:
- Может быть нужна доставка
- Если нужна – может стоять галочка совпадения адреса, может нет.
- Если не нужны доставка – пропуск кучи шагов.
Выберем для себя что доставка нужна всегда (добавим “самовывоз” в методы доставки), так же что адрес плательщика совпадает. Почему так? Потому, что 2 адреса – оплаты и доставки – в СНГ не нужны, да и за границей, не так часто люди используют функционал налогов.
Шаг 4. (3 шаг пропущен галочкой совпадения адреса). Запрос к контроллеру checkout/shipping_method. Никаких данных ему не отправляется, все уже записано в сессию (важное замечание).
Этот контроллер так же ничего не меняет, только получает данные формы, НО при успешном его вызове – сразу посылается второй ajax запрос на контроллер checkout/guest_shipping, который заполняет в тихую Шаг 3. Это тоже важный контроллер, который пишет в сессию дефолтные значения.
На этом этапе у нас висит форма добавления комментария и выбор доставки. Так же в сессию уже записаны все данные пользователя, следующие действия выполнятся по нажатию кнопки “Продолжить” на Шаге 4. и мы перейдем к следующему:
Шаг 5. По нажатию кнопки продолжить js отправляет ajax запрос контроллеру checkout/shipping_method, его методу save. В этом месте на всякий случай проверяется минимальное количество продукции в корзине, но мы предварительно выключили контроль в админке, радиокнопка доставки гарантированно установлена и все проверки пройдут успешно. И главное – будет сохранен комментарий и способ доставки.
В случае удачного прохождения этого этапа – идет запрос к checkout/payment_method. Опять таки важный контроллер, который заполняет некоторые дефолтные значения.
Он получает методы оплаты и выводит их в форму (и комментарий).
Нажатие кнопки “продолжить” – делает все по накатанной. Вызываем функцию save, валидируем, пишем что не так, вдруг что – и стучимся к следующему контроллеру.
Шаг 6. checkout/confirm.
Этот контроллер окончательно проверяет нужные шаги, оформляет заказ. Но опять таки в локальное хранилище, вызывая следующий контроллер – оплаты.
Так как модуль оплаты нужно использовать любой – в том числе и разных платежных систем типа визы трогать этот этап не будем.
Подытожим что нам нужно сделать:
- Поменять в контроллере checkout/checkout вызов шаблона на, к примеру, checkout2.tpl.
- В нем написать кучу ajax вызовов для получения данных (скопировать с существующих скриптов, вырезав функции save)
- По кнопке проверить данные – вызвать по очереди все функции save()
- Если все хорошо – получить ответ от последнего этапа с табличкой заказа и кнопкой “продолжить”, которая сгенерирована каким либо платежным модулем.
Порядок запросов:
- checkout/guest
- checkout/guest/save
- checkout/shipping_method
- checkout/guest_shipping/save
- checkout/shipping_method/save
- checkout/payment_method
- checkout/payment_method/save
Так же придется в checkout/shipping_method/save и checkout/payment_method/save скопировать получение методом доставки и оплаты (они в начале контроллера) в начало функции.
Такой порядок Позволит не нарушить логику заказа и все будет работать как надо.
Файлы с osStore 2.3, которые использовались при написании статьи (внимание, заменяют системные!):
1pagecart2.3.zip
Тоже самое, но модулем: web-porosya-page-cart1.0.ocmod (2.3)
UPD: опенкарт как обычно что-то поменял втихую и куча модулей сломалась. На этот раз валидация почты. Если ошибка в корзине на эту тему – пот патч: guest2. (пока только на новейшей сборке опенкарта 2.3.0.2 чистого, русские сборки не поменялись)