YooKassa
Handle payments through YooKassa
Платежи YooKassa для Medusa
Плагин Medusa для приёма платежей через YooKassa.
Read README in English →
Возможности
- 🔗 Бесшовная интеграция с платёжной системой YooKassa
- 🧾 Формирование онлайн-чеков в соответствии с 54-ФЗ
- 1️⃣ Одностадийные (автосписание) и 2️⃣ двухстадийные (авторизация/холдирование) сценарии оплаты
- 🔄 Возвраты и отмена заказов
- 🔔 Вебхук-уведомления о статусах платежей в реальном времени
- 🛡 Проверка вебхуков для обеспечения безопасности
- 🔍 Подробное логирование для отладки
💬 Чат поддержки плагина YooKassa
Есть вопросы или идеи по новым функциям плагина?
Присоединяйтесь к чату в Telegram – @medusajs_yookassa
👥 Чат сообщества Medusa.js
Общайтесь в Telegram с другими разработчиками Medusa – @medusajs_chat
Требования
- Medusa v2.7.0 или выше
- Node.js v20 или выше
- Аккаунт YooKassa – зарегистрируйтесь или войдите
Установка
123yarn add medusa-payment-yookassa# илиnpm install medusa-payment-yookassa
Настройка
Добавьте конфигурацию провайдера в файл Copy to clipboardmedusa-config.js
в приложении Medusa Admin:
1234567891011121314151617181920// ...module.exports = defineConfig({// ...modules: [{resolve: "@medusajs/medusa/payment",options: {providers: [{resolve: "medusa-payment-yookassa/providers/payment-yookassa",id: "yookassa",options: {shopId: process.env.YOOKASSA_SHOP_ID,secretKey: process.env.YOOKASSA_SECRET_KEY,capture: true,paymentDescription: "Test payment",useReceipt: true,useAtolOnlineFFD120: true,taxSystemCode: 1,taxItemDefault: 1,
Добавьте следующие переменные окружения: идентификатор магазина Copy to clipboardshopId
и секретный ключ Copy to clipboardsecretKey
:
12YOOKASSA_SHOP_ID=1234567YOOKASSA_SECRET_KEY=live_secret_api_key
Затем настройте URL вебхука для уведомлений от YooKassa здесь. URL должен иметь следующий формат:
1https://{YOUR_MEDUSA_DOMAIN}/hooks/payment/yookassa_yookassa
Параметры провайдера
Параметр Описание Обязательный По умолчанию Copy to clipboardshopId
Идентификатор вашего магазина в ЮKassa Да - Copy to clipboardsecretKey
Секретный ключ, который используется для проведения операций через ЮKassa Да - Copy to clipboardpaymentDescription
Описание платежа по умолчанию, если контекст не указан в YooKassa Нет - Copy to clipboardcapture
Определяет тип проведения платежа:
- Copy to clipboardtrue
— одностадийная оплата
- Copy to clipboardfalse
— двухстадийная оплата Нет Copy to clipboardtrue
Copy to clipboarduseReceipt
Включает формирование онлайн-чеков по 54-ФЗ Нет Copy to clipboardfalse
Copy to clipboarduseAtolOnlineFFD120
Включается, если вы используете онлайн-кассу Атол Онлайн, обновленную до ФФД 1.2
Применимо только при Copy to clipboarduseReceipt=true
Нет Copy to clipboardfalse
Copy to clipboardtaxSystemCode
Система налогообложения:
- Copy to clipboard1
: — общая СН
- Copy to clipboard2
: — упрощенная СН (доходы)
- Copy to clipboard3
: — упрощенная СН (доходы минус расходы)
- Copy to clipboard4
: — единый налог на вмененный доход
- Copy to clipboard5
: — единый сельскохозяйственный налог
- Copy to clipboard6
: — патентная СН
Обязательный, если вы используете онлайн-кассу Атол Онлайн, обновленную до ФФД 1.2
Применимо только при Copy to clipboarduseReceipt=true
Нет - Copy to clipboardtaxItemDefault
Ставка НДС по товарам::
- Copy to clipboard1
: — без НДС
- Copy to clipboard2
: — 0%
- Copy to clipboard3
: — 10%
- Copy to clipboard4
: — 20%
- Copy to clipboard5
: — 10/110
- Copy to clipboard6
: — 20/110
- Copy to clipboard7
: — 5%
- Copy to clipboard8
: — 7%
- Copy to clipboard9
: — 5/105
- Copy to clipboard10
: — 7/107
Для самозанятый - фиксированное значеие Copy to clipboard1
Применимо только при Copy to clipboarduseReceipt=true
Нет - Copy to clipboardtaxShippingDefault
Ставка НДС для доставки (аналогично Copy to clipboardtaxItemDefault
)
Применимо только при Copy to clipboarduseReceipt=true
Нет -
Интеграция с Storefront (витриной магазина)
Для интеграции платёжного провайдера YooKassa с storefront на Next.js начните с добавления необходимых UI-компонентов. Таким образом провайдер будет отображаться на странице оформления заказа наряду с другими доступными методами оплаты.
Когда пользователь выбирает YooKassa, витрина должна вызвать метод Copy to clipboardinitiatePayment
с нужными параметрами. Это создаст платёжную сессию через API YooKassa и подготовит покупателя к перенаправлению. После этого кнопка Place Order должна отправить пользователя на страницу оплаты YooKassa, где он сможет выбрать предпочтительный способ оплаты.
После завершения оплаты YooKassa одновременно отправит вебхук и перенаправит покупателя обратно в витрину. То событие, которое придёт первым, завершит корзину и создаст новый заказ в Medusa.
Для запуска на Next.js необходимо внести следующие изменения:
1. Конфигурация платежного провайдера
Чтобы сделать YooKassa доступным в качестве способа оплаты на странице оформления заказа витрины магазина, необходимо добавить её конфигурацию в маппинг платёжных провайдеров в файле с константами вашего storefront. Этот маппинг определяет как каждый провайдер отображается в интерфейсе.
Откройте Copy to clipboardsrc/lib/constants.tsx
и добавьте следующий код:
123456789101112131415export const paymentInfoMap: Record<string,{ title: string; icon: React.ReactNode }> = {// ... другие провайдерыpp_yookassa_yookassa: {title: "YooKassa",icon: <CreditCard />,}}// Вспомогательная функция для проверки, является ли провайдер YooKassaexport const isYookassa = (providerId?: string) => {return providerId?.startsWith("pp_yookassa")}
Вы расширяете объект Copy to clipboardpaymentInfoMap
, добавляя в него запись Copy to clipboardpp_yookassa_yookassa
. Эта запись определяет заголовок и иконку, которые будут отображаться для YooKassa на странице оформления заказа.
Вспомогательная функция Copy to clipboardisYookassa
проверяет, принадлежит ли переданный Copy to clipboardproviderId
к YooKassa. Это используется при рендеринге UI-компонентов, специфичных для конкретного провайдера.
2. Настройки Cookie
При подключении YooKassa настройте политику cookie так, чтобы поддерживались междоменные редиректы. Это нужно для сохранения платёжной сессии при возврате пользователя в магазин.
Откройте Copy to clipboardsrc/lib/data/cookies.ts
и обновите конфигурацию файлов cookie следующим образом:
123456export const setCartId = async (cartId: string) => {cookies.set("_medusa_cart_id", cartId, {// ... другие настройки cookiesameSite: "lax", // Переключено с режима «Strict» для междоменных редиректов})}
Эта вспомогательная функция сохраняет идентификатор корзины в cookie с именем Copy to clipboard_medusa_cart_id
.
Опция Copy to clipboardsameSite
установлена в значение Copy to clipboardlax
вместо Copy to clipboardstrict
. Это изменение гарантирует, что cookie будет отправляться при кросс-доменных запросах во время процесса редиректа через YooKassa, предотвращая потерю платёжной сессии.
3. Инициализация платёжной сессии
Чтобы перенаправить покупателя в YooKassa, платёжная сессия должна быть корректно инициализирована с необходимыми параметрами, включая return URL после оплаты и корзину для формирования онлайн-чеков.
Откройте Copy to clipboardsrc/modules/checkout/components/payment/index.tsx
и обновите логику инициализации платежа, включив в нее данные корзины и URL возврата для YooKassa:
12345678910await initiatePaymentSession(cart, {provider_id: selectedPaymentMethod,data: {confirmation: {type: "redirect",return_url: `${getBaseURL()}/api/capture-payment/${cart?.id}?country_code=${countryCode}`},cart: cart}})
При инициировании платёжной сессии для YooKassa передайте объект Copy to clipboardconfirmation
с Copy to clipboardtype: "redirect"
и Copy to clipboardreturn_url
. Позже YooKassa предоставит Copy to clipboardconfirmation_url
, на которое клиент должен быть перенаправлен.
Параметр Copy to clipboardreturn_url
указывает на конечную точку захвата вашего магазина и используется как для успешных, так и для неудачных попыток оплаты.
Объект Copy to clipboardcart
включается в данные инициализации для формирования чека в соответствии с Федеральным законом № 54.
4. Компонент кнопки оплаты
В storefront для каждого платёжного провайдера необходим отдельный компонент кнопки оплаты. Он отвечает за обработку оформления заказа после подтверждения пользователем и, используя данные платёжного сеанса, перенаправляет его на страницу оплаты YooKassa.
Откройте Copy to clipboardsrc/modules/checkout/components/payment-button/index.tsx
и добавьте следующий код:
1234567891011121314151617181920const PaymentButton: React.FC<PaymentButtonProps> = ({cart,"data-testid": dataTestId,}) => {// ...switch (true) {// ... другие проверкиcase isYookassa(paymentSession?.provider_id):return (<YookassaPaymentButtonnotReady={notReady}cart={cart}data-testid={dataTestId}/>)default:return <Button disabled>Select a payment method</Button>}}
Этот компонент находит Copy to clipboardpayment_session
YooKassa в активной корзине и извлекает значение Copy to clipboarddata.confirmation.confirmation_url
. Когда пользователь нажимает кнопку Place an order, он перенаправляется на этот URL для завершения оплаты на странице YooKassa.
Если Copy to clipboardconfirmation_url
отсутствует, компонент отображает сообщение об ошибке вместо продолжения процесса. Состояние Copy to clipboardisLoading
обеспечивает визуальную обратную связь во время подготовки перенаправления.
Родительский компонент Copy to clipboardPaymentButton
использует функцию Copy to clipboardisYookassa
, чтобы определить, нужно ли отобразить Copy to clipboardYookassaPaymentButton
для текущей сессии; в противном случае показывается неактивная кнопка Select a payment method.
5. API-роут подтверждения платежа
После того как покупатель завершает оплату на странице YooKassa, он перенаправляется обратно на витрину магазина. Необходимо создать API-роут, который обработает этот callback, проверит статус платежа и завершит корзину.
Создайте файл Copy to clipboardsrc/app/api/capture-payment/[cartId]/route.ts
со следующим содержимым:
1234567891011121314151617181920import { NextRequest, NextResponse } from "next/server"import { revalidateTag } from "next/cache"import {getCacheTag,getAuthHeaders,removeCartId} from "@lib/data/cookies"import { sdk } from "@lib/config"import { placeOrder } from "@lib/data/cart"type Params = Promise<{ cartId: string }>export async function GET(req: NextRequest, { params }: { params: Params }) {const { cartId } = await paramsconst { origin, searchParams } = req.nextUrlconst countryCode = searchParams.get("country_code") || ""const headers = { ...(await getAuthHeaders()) }// Retrieve fresh cart values
Этот API-роут обрабатывает редирект от YooKassa после попытки оплаты. Он получает актуальное состояние корзины, чтобы убедиться, что все изменения, внесённые во время оплаты, были отражены.
Если в корзине нет связанного идентификатора заказа, обработчик роута пытается оформить заказ. В случае успеха покупатель перенаправляется на страницу подтверждения заказа. Если же при обработке корзины возникла ошибка, покупатель возвращается на страницу оформления заказа с указанием ошибки и может повторить процесс оплаты заказа.
Когда оплата проходит успешно, роут повторно валидирует кэшированные данные корзины и заказа, удаляет cookie корзины и перенаправляет покупателя на страницу подтверждения заказа. Это гарантирует корректное завершение платёжного процесса и сохранение актуальных данных в storefront.
Пример
Вы можете ознакомиться с изменениями, внесенными в стартовый шаблон Medusa Next.js Starter Template в директории Copy to clipboardexamples/medusa-storefront
.
Полный код интеграции можно посмотреть в разделе comparison page, откройте вкладку Copy to clipboardFiles changed
и изучите различия в каталоге Copy to clipboardexamples/medusa-storefront
. Или запустите Copy to clipboarddiff
в терминале:
123git clone https://github.com/sergkoudi/medusa-payment-yookassacd medusa-payment-yookassagit diff v0.0.3...main -- examples/medusa-storefront
Разработка
Документацию по развертыванию окружения для разработки можно найти здесь.
Лицензия
Распространяется на условиях лицензии MIT.