Search for a command to run...
Для интеграции платёжного провайдера Т-Касса с storefront на Next.js начните с добавления необходимых UI-компонентов. Таким образом провайдер будет отображаться на странице оформления заказа наряду с другими доступными методами оплаты.
Когда пользователь выбирает Т-Касса, витрина должна вызвать метод с нужными параметрами. Это создаст платёжную сессию через API Т-Касса и подготовит покупателя к перенаправлению. После этого кнопка Place Order должна отправить пользователя на страницу оплаты Т-Касса, где он сможет выбрать предпочтительный способ оплаты.
После завершения оплаты Т-Касса одновременно отправит вебхук и перенаправит покупателя обратно в витрину. То событие, которое придёт первым, завершит корзину и создаст новый заказ в Medusa.
Для запуска на Next.js необходимо внести следующие изменения:
Чтобы сделать Т-Касса доступным в качестве способа оплаты на странице оформления заказа витрины магазина, необходимо добавить её конфигурацию в маппинг платёжных провайдеров в файле с константами вашего storefront. Этот маппинг определяет как каждый провайдер отображается в интерфейсе.
Откройте и добавьте следующий код:
export const paymentInfoMap: Record<string,{ title: string; icon: React.ReactNode }> = {// ... другие провайдерыpp_tkassa_tkassa: {title: "T-Kassa",icon: <CreditCard />,},}// Вспомогательная функция для проверки, является ли провайдер Т-Кассаexport const isTkassa = (providerId?: string) => {return providerId?.startsWith("pp_tkassa")}
Вы расширяете объект , добавляя в него запись . Эта запись определяет заголовок и иконку, которые будут отображаться для Т-Касса на странице оформления заказа.
Вспомогательная функция проверяет, принадлежит ли переданный к Т-Касса. Это используется при рендеринге UI-компонентов, специфичных для конкретного провайдера.
При подключении Т-Касса настройте политику cookie так, чтобы поддерживались междоменные редиректы. Это нужно для сохранения платёжной сессии при возврате пользователя в магазин.
Откройте и обновите конфигурацию файлов cookie следующим образом:
export const setCartId = async (cartId: string) => {cookies.set("_medusa_cart_id", cartId, {// ... другие настройки cookiesameSite: "lax", // Переключено с режима «Strict» для междоменных редиректов})}
Эта вспомогательная функция сохраняет идентификатор корзины в cookie с именем .
Опция установлена в значение вместо . Это изменение гарантирует, что cookie будет отправляться при кросс-доменных запросах во время процесса редиректа через Т-Касса, предотвращая потерю платёжной сессии.
Чтобы перенаправить покупателя в Т-Касса, платёжная сессия должна быть корректно инициализирована с обязательными параметрами, включая return URL для обоих случаев: успешной и неуспешной оплаты.
Откройте и обновите логику инициализации платежа, включив в нее данные корзины и URL возврата для Т-Касса:
await initiatePaymentSession(cart, {provider_id: selectedPaymentMethod,data: {SuccessURL: `${getBaseURL()}/api/capture-payment/${cart?.id}?country_code=${countryCode}`,FailURL: `${getBaseURL()}/api/capture-payment/${cart?.id}?country_code=${countryCode}`,cart: cart,}})
При инициализации платёжной сессии для Т-Касса параметры и определяют, куда будет перенаправлен покупатель после попытки оплаты. Оба URL динамически формируются на основе базового URL storefront, идентификатора корзины и выбранного кода страны.
Объект включается в данные инициализации для формирования чека в соответствии с Федеральным законом № 54.
В storefront для каждого платёжного провайдера необходим отдельный компонент кнопки оплаты. Он отвечает за обработку оформления заказа после подтверждения пользователем и, используя данные платёжного сеанса, перенаправляет его на страницу оплаты Т-Касса.
Откройте и добавьте следующий код:
const TkassaPaymentButton: React.FC<TkassaPaymentProps> = ({ cart, notReady }) => {const [submitting, setSubmitting] = useState(false)const [errorMessage, setErrorMessage] = useState<string | null>(null)const router = useRouter()const paymentSession = cart.payment_collection?.payment_sessions?.find(session => session.provider_id === "pp_tkassa_tkassa")const handlePayment = () => {setSubmitting(true)const paymentUrl = (paymentSession?.data as any).PaymentURLif (paymentUrl) {router.push(paymentUrl)} else {setErrorMessage("Payment URL отсутствует")setSubmitting(false)}}}
Этот компонент находит для Т-Касса в текущей корзине и извлекает , предоставленный бэкендом. При нажатии кнопки Place order покупатель перенаправляется на этот URL для завершения транзакции на странице оплаты Т-Касса.
Если отсутствует, компонент выводит сообщение об ошибке, не позволяя продолжить. Состояние обеспечивает визуальную обратную связь во время подготовки перенаправления.
Компонент определяет, принадлежит ли текущая платёжная сессия к Т-Касса, с помощью вспомогательной функции . Если да, он рендерит для обработки процесса оплаты.
Интеграция этого компонента гарантирует, что процесс оплаты через Т-Касса будет запускаться при оформлении заказа.
После того как покупатель завершает оплату на странице Т-Касса, он перенаправляется обратно на витрину магазина. Необходимо создать API-роут, который обработает этот callback, проверит статус платежа и завершит корзину.
Создайте файл со следующим содержимым:
import { 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()) }// Получить актуальные значения корзиныconst cartCacheTag = await getCacheTag("carts")revalidateTag(cartCacheTag)const { cart } = await sdk.store.cart.retrieve(cartId, {fields: "id, order_link.order_id"},headers)if (!cart) {return NextResponse.redirect(`${origin}/${countryCode}`)}const orderId = (cart as unknown as Record<string, any>).order_link?.order_idif (!orderId) {await placeOrder(cartId)// Ошибка при неавторизованном платежеreturn NextResponse.redirect(`${origin}/${countryCode}/checkout?step=review&error=payment_failed`)}const orderCacheTag = await getCacheTag("orders")revalidateTag(orderCacheTag)removeCartId()return NextResponse.redirect(`${origin}/${countryCode}/order/${orderId}/confirmed`)}
Этот API-роут обрабатывает редирект от Т-Касса после попытки оплаты. Он получает актуальное состояние корзины, чтобы убедиться, что все изменения, внесённые во время оплаты, были отражены.
Если в корзине нет связанного идентификатора заказа, обработчик роута пытается оформить заказ. В случае успеха покупатель перенаправляется на страницу подтверждения заказа. Если же при обработке корзины возникла ошибка, покупатель возвращается на страницу оформления заказа с указанием ошибки и может повторить процесс оплаты заказа.
Когда оплата проходит успешно, роут повторно валидирует кэшированные данные корзины и заказа, удаляет cookie корзины и перенаправляет покупателя на страницу подтверждения заказа. Это гарантирует корректное завершение платёжного процесса и сохранение актуальных данных в storefront.
Вы можете ознакомиться с изменениями, внесенными в стартовый шаблон Medusa Next.js Starter Template, в директории .
Полный код интеграции можно посмотреть в разделе сomparison page, откройте вкладку и изучите различия в каталоге . Или запустите в терминале:
git clone https://github.com/gorgojs/medusa-pluginscd medusa-pluginsgit diff @gorgo/medusa-payment-tkassa@0.0.1...main -- examples/payment-tkassa/medusa-storefront