Skip to content

💳 pbShop

pbShop — оплата и заказы поверх PageBlocks: тарифы, разовые покупки и подписки.

Это не магазин целиком

Корзины, доставки и складского учёта здесь нет. pbShop закрывает другое — деньги: заказ, оплата, подтверждение, продление. Что именно продаётся, решает сайт, поэтому один и тот же слой обслуживает и тариф доступа, и участие в событии, и услугу.

Требует установленного PageBlocks: компонент опирается на его модели, маршрутизацию, шаблоны и миграции.

⚙️ Возможности

  • 💰 Заказы с историей и составом
  • 🔁 Подписки с автопродлением
  • 🧾 Счета на банковский перевод, с реквизитами покупателя
  • 🌍 Несколько валют с фиксированными ценами
  • 🔌 Пять платёжных драйверов из коробки и возможность добавить свой
  • 📣 События для выдачи доступа на стороне сайта
  • 🗂️ Каталог тарифов на фронте

💳 Способы оплаты

ДрайверЧто этоАвтопродлениеВозврат через API
manualОфлайн: менеджер подтверждает вручнуюНетНет
billСчёт на банковский перевод, PDF или HTMLНетНет
payanywayMONETA.Assistant, редирект с колбэкомНетНет
yoomoneyКнопка ЮMoney, перевод на кошелёк. Только рублиНетНет
maibЭквайринг maib, прямой APIДаДа

Ключи и секреты задаются не в системных настройках, а в самом способе оплаты: pbShop → Справочники → Способы оплаты, поле с настройками в JSON. Так на одном сайте уживаются несколько способов с разными доступами.

Свой драйвер регистрируется в core/App/config/pbshop.php.

Рекуррентные платежи умеет только maib

Остальные драйверы берут деньги один раз. Подписку на них завести можно, но продлеваться она будет только новой ручной оплатой.

🔁 Подписки

Отдельной сущности «подписка» нет: это заказ, у которого продукт имеет период, а сам заказ — срок действия и флаг автопродления. При первой оплате с автопродлением шлюз привязывает карту и возвращает токен, который сохраняется в заказе; продления идут по нему.

Расписание продлений — задача сайта

Компонент даёт методы: OrderService::dueForRenewal() находит заказы, которым скоро истекать, renew() списывает, expire() снимает просроченные. А вот когда их звать, он не решает — крон пишется на стороне сайта.

Настройка pbshop_renew_days_before задаёт, за сколько дней до срока браться за заказ.

📣 События

Главный способ связать оплату с тем, что она открывает. Слушатели регистрируются в site-owned core/App/config/pbshop.php:

СобытиеКогда
pbShopOrderCreateЗаказ создан
pbShopOrderPaidЗаказ оплачен
pbShopOrderExtendСрок продлён
pbShopOrderExpireСрок истёк
pbShopOrderCancelЗаказ отменён
pbShopOrderStatusСменился статус
pbShopPaymentCreate, pbShopPaymentSuccess, pbShopPaymentFail, pbShopPaymentRefundЖизненный цикл платежа

Доступ выдаёт сайт: компонент сообщает, что оплачено, а что это значит — знает только он.

🗺️ Маршруты

  • POST /pay/checkout — оформление заказа
  • GET|POST /pay/{method}/result — колбэк платёжной системы
  • GET /pay/form/{uuid} — страница с формой для шлюзов, принимающих только POST
  • GET /pay/success/{uuid}, /pay/fail/{uuid}, /pay/pending/{uuid} — возврат клиента
  • POST /pay/orders/{id}/cancel — отмена подписки
  • /pay/requisites — реквизиты покупателя

Каталог появляется, если задан префикс маршрута: список категорий, категория, продукт.

Колбэк идёт без проверки CSRF, и так и должно быть

Платёжная система не знает вашего токена, поэтому с /pay/{method}/result защита снята намеренно. Подлинность проверяет сам драйвер — по подписи своего шлюза, — а сверх того компонент сверяет сумму из колбэка с выставленной. Пишете свой драйвер — проверка подписи целиком на вас.

🧮 Деньги

Суммы хранятся целыми числами в минорных единицах: копейках, центах, бань. Никаких дробных типов — 149.99 лежит как 14999.

Цены заданы на каждую валюту отдельно и по курсу не пересчитываются: сколько указали в евро, столько и будет.

🖥️ В менеджере

Раздел pbShop с четырьмя пунктами: Заказы, Платежи, Продукты и Справочники (категории, валюты, статусы, способы оплаты). У платежа есть кнопки подтверждения и возврата — для maib возврат уходит в шлюз по-настоящему.

© PageBlocks 2019-present