надо срочно сюда
что-нибудь добавить
Это рассказ от автора модуля: зачем мы взялись за корзину OpenCart, что в ней меняли и чему нас научили магазины, которые уже с модулем работают. Все картинки ниже - настоящие экраны, а не макеты: большинство из работающих магазинов, а счёт, письмо и уведомление сняты на нашем тестовом магазине с вымышленными компаниями. Где-то видны чужие опечатки и демо-товары, мы их не трогали.
Так выглядит касса магазина стройматериалов на oCheckout: контакты, доставка с картой, слоты времени, сводка заказа и допродажи на одном экране.
Стандартное оформление заказа в OpenCart собрано из шести панелей. Покупатель открывает первую, заполняет, жмёт «Продолжить», ждёт перезагрузку, открывает вторую, и так шесть раз. На каждом шаге он не видит ни итоговой суммы, ни состава заказа. Если на четвёртом шаге выяснится, что доставка стоит больше, чем он рассчитывал, он просто закроет вкладку.
Мы смотрели на это в вебвизоре у нескольких магазинов. Картина везде одинаковая: до первой панели доходят почти все, до кнопки оплаты заметно меньше. Люди отваливаются не потому, что передумали, а потому что процесс длинный и непонятно, сколько ещё осталось.
Вот касса магазина электроники. Слева контакты, способ доставки и оплата, справа состав заказа. Покупатель видит всё сразу: процессор за 25 990 рублей, смартфон за 18 990, три способа оплаты и две кнопки доставки. Никаких «шаг 3 из 6».
Магазин электроники. Способ доставки сведён к двум кнопкам, «Самовывоз (пункты выдачи)» и «Курьером (по адресу)», оплата подписана словами магазина, справа сводка с допродажей и рекомендациями.
Обратите внимание на подписи под способами оплаты: «Менеджер пришлет QR-код для оплаты на ваш Email и в Telegram», «Отменяет скидку 10% за наличный расчет». Это не наш текст, это магазин написал сам в настройках. Стандартный OpenCart такое не умеет: там у способа оплаты есть только название.
Адрес страницы при этом не меняется, остаётся тот же index.php?route=checkout/checkout. Все ваши ссылки, счётчики и цели в Метрике продолжают работать.
Это самая незаметная и самая важная часть модуля. На том же скриншоте магазина электроники в сводке справа есть галочка «Гидрогелевая пленка с бесплатной установкой, 490 ₽» и опция «Настройка устройства, +1 000 ₽». Покупатель ставит галочку, и итог внизу меняется тут же, без перезагрузки. Выбрал другой способ доставки - пересчиталось. Ввёл промокод - пересчиталось.
Устроено это не на клиентской магии, а на честном пересчёте. Модуль на каждое изменение заново собирает на сервере три блока: доставку, оплату и сводку, и подменяет их на странице. Состояние лежит в тех же ключах сессии, что и у стандартной корзины. Из этого следует важное: все ваши расширения доставки, оплаты и итогов продолжают работать как работали. Мы ничего не переписываем под себя, мы отдаём им ту же сессию и показываем их ответы.
Хороший пример на следующем экране: строка «Отмена скидки за наличный расчет, 4 528 ₽» в сводке. Магазин даёт скидку 10% за наличные, и в настройках модуля у каждого способа оплаты есть своя скидка или наценка с любым названием в «Итого». Покупатель переключился на «Онлайн оформление кредита», строка появилась, итог пересчитался. Под способами оплаты магазин честно написал, почему: «Отменяет скидку 10% за наличный расчет».
Пункт выдачи выбран: адрес, дата «13 августа», стоимость 300 ₽, режим работы и как добраться. В сводке справа появились строка доставки за 300 ₽ и наценка «Отмена скидки за наличный расчет» за выбранный способ оплаты, итог пересчитан до 49 808 ₽.
Здесь мы потратили больше всего времени, потому что российская доставка - это не одна кнопка.
Магазин в Петербурге возит курьером по городу и ближнему пригороду. На карте нарисованы зоны доставки, две из них подписаны, «Санкт-Петербург (в пределах КАД)» и «Ближний пригород», и стоит метка склада на Софийской. Покупатель ставит точку или пишет адрес, модуль определяет зону и считает цену: 490 рублей. Под картой слоты: завтра, суббота, понедельник, интервалы времени, и вечерний интервал «18:00-21:00» с надбавкой 300 рублей. Ниже ещё три пункта выдачи, включая «Ozon - До ПВЗ (3-13 дн.), 107 р».
Петербургский магазин: зоны доставки нарисованы на карте, вечерний слот стоит дороже, а в сводке модуль напоминает, что до минимальной суммы заказа не хватает 368 рублей.
Посмотрите на розовую плашку в сводке: «Минимальная сумма заказа 500 р - добавьте товаров ещё на 368 р». Это правило, которое магазин задал в настройках. Покупателю не нужно доходить до конца, чтобы узнать об ограничении: подсказка стоит прямо над кнопкой «Оформить заказ».
Зоны можно рисовать сколько угодно, у каждой своя цена и порог бесплатной доставки. Если зон нет, цена считается по расстоянию от ближайшего склада с коэффициентом кривизны дорог. За лимитом радиуса способ гаснет с вашим текстом.
У магазина электроники подключён ApiShip: один договор и один токен вместо отдельной интеграции с каждой службой. Покупатель нажимает «Самовывоз (пункты выдачи)» и получает окно «Куда доставить». В нём город, поиск по адресу, фильтры по службам («Яндекс Доставка», «СДЭК», «Почта России»), по типу точки («Пункт выдачи», «Постамат») и сортировка «Сначала дешевле» или «Сначала быстрее».
Самара, вкладка «В пункт выдачи». Почтомат Почты России от 500 ₽ за 3 дня, пункт Яндекс Доставки от 300 ₽ за 6 дней, СДЭК от 500 ₽ за 5-6 дней. Справа карта с кластерами точек.
Каждая карточка показывает реальную цену и срок именно до этой точки, а не «от 300 рублей по региону». Цена считается на сервере по адресу покупателя один раз для всех служб сразу, так что переключение фильтров ничего не ждёт.
Вторая вкладка того же окна, «Курьером». Покупатель вводит улицу и дом, метка встаёт на карту, и три службы называют цену до двери: Яндекс Доставка 700 рублей за 6 дней, СДЭК 800 за 5-6, Почта России 1 000 за 1-3 дня. Дальше он сам решает, что ему важнее, цена или скорость.
Вкладка «Курьером»: адрес «Самара, улица Луначарского, 5», метка на карте и три перевозчика с ценой и сроком до двери.
Не все готовы переезжать на ApiShip, у многих давно настроены отдельные модули перевозчиков. Мы это учли. Вот магазин футболок из Казани: у него стоят сторонние модули 5Post, СДЭК и Яндекс.Доставки. Все четыре способа видны в кассе со своими ценами, 223, 208, 268 и 398 рублей, и у каждого пункта выдачи есть кнопка «ВЫБРАТЬ ПВЗ».
Магазин футболок. Способы доставки приходят из сторонних модулей, oCheckout только рисует их и добавляет кнопки выбора пункта. В сводке товары с опциями (модель, размер, цвет), допродажа «Брендированная коробка» со скидкой 30% и рекомендации.
Кнопка «ВЫБРАТЬ ПВЗ» открывает окно самого модуля СДЭК с его картой и списком. Мы не пишем вторую интеграцию и не просим второй ключ, мы просто вызываем их функцию из нашей кассы. Заказ и накладная дальше идут по их обычному пути.
Окно «Пункты самовывоза» стороннего модуля СДЭК, открытое из oCheckout: список точек по Казани, метки с ценой «от 208 р» на карте и балун с кнопкой «Забрать отсюда».
Если вы продаёте компаниям, переключатель «Покупаю как: Физлицо / Юрлицо / ИП» экономит вам и покупателю много переписки. Магазин бытовой техники ниже включил его прямо в контактных данных. Покупатель выбрал «ИП», и форма показала «Название организации / ИП», «ИНН» и «Юридический адрес». Физлицу эти поля не показываются вообще.
Магазин бытовой техники. Выбран тип плательщика «ИП», появились ИНН и юридический адрес. В сводке «Всего без НДС», полоса «До бесплатной доставки осталось 59 659 ₽», три отдельных согласия и значки принимаемых карт.
Для юрлица включается автозаполнение по ИНН через DaData: человек вводит десять цифр, модуль подставляет название, КПП и адрес. Счёт на оплату формируется в кассе, с вашими реквизитами и позициями заказа, включая опции товаров.
Вот такой счёт получил покупатель на нашем тестовом магазине сразу после нажатия «Оформить заказ». Реквизиты продавца и покупателя, основание, таблица позиций с доставкой отдельной строкой, НДС по каждой строке, сумма прописью, срок действия и печать. Ставку НДС модуль берёт из налоговых классов товаров, поэтому доставка без НДС так и печатается «Без НДС», а не размазывается по всем строкам. Номер счёта идёт по своему счётчику с вашим префиксом, ссылка на него открывается без входа в кабинет, и бухгалтеру её можно просто переслать.
Счёт № ЛУ-77 на тестовом магазине: продавец и покупатель с ИНН и КПП, позиции заказа, доставка отдельной строкой, НДС по строкам, сумма прописью и печать. Компании на скриншоте вымышленные.
На этом же экране видно несколько мелочей, которые магазин включил в настройках: полоса «До бесплатной доставки осталось» с прогрессом, строка «Оплата с чеком по 54-ФЗ», «Возврат и обмен в течение 14 дней», значки МИР, Visa, Mastercard, СБП и «Счёт». Это блок доверия, его состав магазин собирает сам.
Касса - последнее место, где покупатель ещё готов что-то добавить. На экранах выше это видно трижды.
Допродажа. В магазине электроники это «Гидрогелевая пленка с бесплатной установкой, 490 ₽» в рамке «Добавьте к заказу». В магазине футболок «Брендированная коробка Futbolki Russ, 245 р вместо 350 р, -30%». Одна галочка, товар в корзине, итог пересчитан.
Рекомендации. Блок «Рекомендуем к заказу» с плюсиками. У магазина электроники там пять смартфонов той же линейки, у футболок семь принтов.
Дополнительные услуги. «Настройка устройства, +1 000 ₽» у электроники. Подъём на этаж, разгрузка, страховка у стройматериалов. Каждая со своей ценой или процентом от суммы, уезжает в заказ отдельной строкой.
Есть ещё «Поделиться корзиной». Покупатель собрал корзину, нажал кнопку, получил ссылку и QR-код. Тот, кто откроет ссылку, увидит те же товары в своей корзине. Магазины используют это для согласования заказа с бухгалтерией или с семьёй.
Боковая корзина магазина футболок с кнопкой «Поделиться корзиной»: QR-код, ссылка, «Скопировать ссылку» и «Открыть».
Стандартное письмо OpenCart о заказе выглядит как таблица из 2010 года и ломается в половине почтовых клиентов. Мы сделали своё. Это то же письмо покупателю с тем же тестовым заказом: логотип, заголовок и вступление с вашим текстом и подстановками вроде имени и суммы, состав заказа с картинками и опциями, итоги, доставка, оплата, адрес, реквизиты компании и комментарий.
Тексты письма редактируются в админке по каждому языку, там же есть предпросмотр на последнем реальном заказе и тестовая отправка себе. Цвет полосы сверху и ссылок берётся из акцентного цвета кассы, так что письмо и сайт выглядят одинаково. Письмо собрано на таблицах с инлайновыми стилями и явно помечено светлой темой, иначе Gmail в тёмном режиме перекрашивал фон карточки и текст пропадал.
Письмо о заказе № 100 на тестовом магазине: логотип, обращение по имени, состав заказа с картинками, итоги, доставка и оплата, реквизиты юрлица, комментарий покупателя и контакты магазина внизу.
Менеджер редко сидит в админке, зато телефон всегда рядом. Модуль умеет присылать новый заказ в Telegram или Max сразу после оформления: бот, чат и набор полей вы задаёте в настройках. Ниже текст уведомления по тому же заказу № 100, ровно в том виде, в каком его собирает модуль. Состав включается галочками: номер и дата, покупатель и контакты, товары с опциями, ценой и количеством, доставка, оплата, сумма, адрес, комментарий и реквизиты компании.
Уведомление о заказе № 100. Текст сообщения собран модулем, окно чата нарисовано для наглядности: у тестового магазина нет своего бота.
Пока делали этот скриншот, нашли и починили мелочь: реквизиты юрлица попадали в уведомление дважды, один раз в блоке полей и второй внутри комментария, куда касса дописывает их для стандартной страницы заказа. Теперь письмо, его предпросмотр и уведомление вырезают их из комментария одинаково.
Согласие на обработку персональных данных - это не только галочка в форме. Если придёт проверка, нужно показать, кто и когда согласился и с каким именно текстом.
На экранах выше согласий два или три: «Даю согласие на обработку моих персональных данных», «Я прочитал(а) и согласен(на) с публичной офертой», «Хочу получать новости и специальные предложения». Каждое магазин настраивает отдельно: текст, ссылка, обязательное или нет. Модуль ведёт журнал: дата, номер заказа, почта, телефон, IP, браузер и снимок текста, который человек видел в тот момент. Если вы отредактируете текст, старые записи сохранят свою редакцию. Журнал смотрится в админке и выгружается в CSV.
Все настройки в одной панели, шестнадцать вкладок слева: поля, корзина, регистрация, правила, доставка, способы доставки и оплаты, допопции, продажи, B2B, сервисы, письмо, 152-ФЗ, дизайн, документация. Документация встроена в админку, по каждой вкладке своя.
Первая вкладка настроек: статус, режим регистрации, маска телефона, автоподтверждение оплат, контакт для чека по 54-ФЗ, резервная копия настроек.
Ставится как обычный ocmod-архив, файлы ядра не трогаются. Модуль подключается к событию OpenCart и подменяет вывод стандартного контроллера корзины. Выключили - вернулась стандартная корзина, ничего не сломалось. Вёрстка своя, адаптивная, на телефоне сводка сворачивается в одну строку с итогом.
Для разработчиков есть события ocheckout:updated и ocheckout:confirmed, свой CSS и JS в настройках, экспорт и импорт всей конфигурации файлом. Электронная коммерция Метрики и GA4 включается галочкой.
Самое полезное в модуле появилось не из плана разработки, а из обращений. Три истории, которые изменили код.
«Кнопка не работает, заказ не создаётся». Магазин писал, что касса умерла. На деле заказы создавались все до одного, просто оставались без статуса, а OpenCart прячет такие заказы из списка по умолчанию. За месяц там накопилось 97 живых покупателей, которых владелец не видел. Причина оказалась в почте: у магазина отвалился пароль SMTP, почтовая библиотека OpenCart на отказ сервера бросает исключение, а происходит это внутри смены статуса заказа. Никто не ловил, запрос падал, покупателю вместо ответа приходила страница с ошибкой, и кнопка молча ничего не делала. Теперь смена статуса обёрнута: почта не отправилась - в журнал пишется причина, а заказ всё равно получает статус и виден в админке.
«Заказы приходят с пустым адресом». Магазин просил сделать поле адреса обязательным. Оказалось, дело не в обязательности: покупатели выбирали точку на карте, карта заполняла город и улицу, а модуль перед сохранением очищал поля, которые считал скрытыми. Адрес исчезал уже после того, как человек его указал. Нашли это только после того, как сами оформили заказ на их сайте и посмотрели, что легло в базу.
«В половине городов нет цены доставки». Магазин на ApiShip: в Новосибирске и Омске цены считаются, в Казани и Челябинске нет ни одного тарифа. Перебрали два десятка городов и нашли закономерность: ApiShip не узнаёт часть городов, если прислать название без типа. «Казань» - ноль тарифов, «г Казань» - 1 640 рублей СДЭК и 442 Яндекс. Теперь модуль, получив пустой ответ, переспрашивает с типом города. На тех городах, где и так всё считалось, лишнего запроса не делается.
Мы рассказываем это не для красоты. Модуль такого объёма невозможно написать один раз и закрыть. Помощь с установкой и настройкой входит в цену, и обращения вроде этих мы разбираем до причины, а не до «у вас что-то с хостингом».
Понятнее всего выигрыш виден там, где оформление сложнее пары полей: доставка по городу и по России одновременно, пункты выдачи, оптовики и юрлица рядом с розницей, дополнительные услуги, самовывоз с нескольких точек. Строительные материалы, мебель, техника, оптовые каталоги, товары с монтажом.
Если у вас три товара и одна доставка по всей стране за фиксированную цену, стандартной корзины вам, скорее всего, хватит. Мы не считаем, что модуль нужен всем.
Что закрывает один модуль: одностраничная касса, доставка по карте, ПВЗ и ApiShip, онлайн-оплата и счёт для юрлиц, допродажи и покупка в один клик, 152-ФЗ, 54-ФЗ и DaData.
oCheckout собирает оформление заказа в один экран, пересчитывает доставку и оплату без перезагрузок и закрывает то, чего в OpenCart нет из коробки для российского магазина: карту с зонами и пунктами выдачи, перевозчиков через ApiShip, юрлиц со счётом, журнал согласий по 152-ФЗ и допродажи в кассе. При этом он не переписывает ядро и не мешает вашим расширениям, что видно на экранах магазина футболок.
Посмотреть можно в демо витрины и демо админки, они открыты. Вопросы по настройке под конкретный магазин задавайте автору, отвечаем сами.