Как предотвратить изменения корзины покупок при асинхронных платежах

#stripe-payments #e-commerce #shopping-cart

#stripe-платежи #электронная коммерция #корзина покупок

Вопрос:

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

  1. Клиент добавляет 10 x товаров A в свою корзину покупок, общая сумма теперь составляет 100 долларов
  2. Клиент переходит на страницу оформления заказа. Сервер создает платежное сообщение Stripe на общую сумму 100 долларов и отправляет ‘client_secret’ в браузер.
  3. Браузер клиента отображает страницу оформления заказа с указанием общей суммы в 100 долларов и платежной формы Stripe.
  4. Клиент открывает новую вкладку и добавляет 10 x товаров B в свою корзину покупок, общая сумма теперь составляет 200 долларов.
  5. Клиент возвращается на вкладку оформления заказа и завершает платеж в размере 100 долларов с помощью Stripe (сайт ничего не может сделать, чтобы предотвратить это — все происходит на стороне клиента)
  6. Асинхронно Stripe уведомляет сайт через webhooks о том, что мы получили платеж в размере 100 долларов. Что нам теперь делать?

Общая сумма платежа больше не соответствует общей сумме корзины. Должны ли мы вернуть платеж и отменить заказ? Как мы уведомляем клиента? Вероятно, мы уже показывали им страницу «заказ выполнен — спасибо», потому что у нас не было возможности узнать, что сумма была неправильной, пока не пришло асинхронное уведомление. Клиент, вероятно, уже покинул наш сайт. Что нам делать с их корзиной покупок?

— Немного дополнительной информации обо всем этом:

Раньше я всегда обращался к Stripe, когда мои клиенты хотели совершать онлайн-платежи на своих сайтах, потому что синхронная модель Stripe сделала мой код приятным и простым. Клиент вводил данные своей карты, Stripe затем возвращала токен, представляющий платеж, наконец, мой серверный код проверял правильность всех данных, использовал API Stripe для получения денег и возвращал сообщение «спасибо» в браузер клиента.

Но теперь, похоже, Stripe переходит от этой модели к асинхронной модели (PaymentIntents), где ваш сервер должен прослушивать уведомления о завершенных платежах, прежде чем выполнять заказы. В терминологии Stripe, мы должны настроить «webhooks» для прослушивания события «payment_intent.successed».

Все другие платежные шлюзы, которые я использовал в прошлом, также имеют асинхронную модель, в том смысле, что ваш веб-сервер должен дождаться какого-либо обратного вызова от шлюза, уведомляющего нас об оплате, прежде чем мы сможем безопасно начать обработку заказа. PayPal называет это «Мгновенным уведомлением о платеже», Worldpay называет это «Веб-заказами», Adflex называет это «Server2ServerNotification» … и т.д.

Я пытаюсь справиться с тем, что может произойти в промежутке между началом оформления заказа и получением уведомления о платеже. Учитывая, что все эти платежные шлюзы используют такого рода асинхронные модели, должно быть простое решение этой (и подобных) проблем, но я действительно застрял — любые предложения будут высоко оценены.

Ответ №1:

Я думаю, что основной момент, который вы здесь упускаете, заключается в том, что сумма платежа устанавливается на стороне сервера. Это означает, что когда ваш клиент открывает новую вкладку и добавляет больше товаров в свою корзину, вы должны обновлять PaymentIntent на своем сервере, чтобы отразить новую сумму. Затем, когда они переключатся обратно на другую вкладку и завершат платеж, у вас должна быть общая сумма, отраженная в вашем PaymentIntent.

Ваш клиент все еще может видеть процесс оформления заказа на сумму, отличную от фактически взимаемой, и в этом случае я предлагаю вам изучить внедрение websockets, чтобы убедиться, что они всегда видят общую сумму в своей корзине покупок.

Комментарии:

1. Спасибо, Пол, я действительно ценю ваш ответ. Но я чувствую, что решение неосуществимо. Теперь нам пришлось бы вызывать API Stripe при каждой загрузке страницы, чтобы проверить статус PaymentIntent, и, возможно, также выполнить другой вызов, чтобы обновить его новым итогом. Это сделает мой сайт неприемлемо медленным. Я понимаю, почему веб-сокеты могут быть полезны, но они, как известно, также сложны в реализации. Если нам нужны либо серверные вызовы API Stripe при каждой загрузке страницы, либо websockets, то PaymentIntents, на мой взгляд, нежизнеспособны. Если только в этом нет чего-то еще, чего я не понимаю.

2. Я думаю, возможно, я выразился недостаточно ясно. Давайте я попробую еще раз, используя ваши шаги: 1. Когда пользователь войдет в систему или начнется сеанс, создайте свой PaymentIntent и сохраните ID 2, 3 без изменений с ваших шагов 4. При открытии новой вкладки извлеките серверную часть PaymentIntent из вашего сеанса, интерфейс для логики загрузки страницы не требуется 5. PaymentIntent был обновлен на шаге 4, поэтому, хотя на старой вкладке все еще отображается старая цена, PaymentIntent имеет новое значение 6. Вы знаете, что платеж прошел успешно, если handleCardPayment возвращает 200, веб-справочник предназначен для вашего собственного ведения журнала.

3. Шаг 6 смотрите здесь: stripe.com/docs/payments/payment-intents/… Не должно быть никакой разницы между старым charge API и PaymentIntents, он может быть настолько синхронным, насколько вам нужно.

4. Вы сказали: «4. извлеките серверную часть PaymentIntent из вашего сеанса, логика загрузки интерфейса на странице не требуется» Я не говорил о логике загрузки внешнего интерфейса. Я говорил о серверной части. Пользователь открывает новую вкладку, что означает, что браузер отправляет новый запрос на наш сервер. Как мы реагируем? Из сеанса мы знаем, что PaymentIntent существует, поэтому мы должны извлечь его, чтобы проверить статус. Возможно, они уже заплатили, возможно, закрыли вкладку оформления заказа, не заплатив .. и т.д. Но с этого момента нам нужно проверять каждый раз. Переход на Stripe и обратно на каждую страницу сделает работу сайта неприемлемо медленной.

5. Также. «6. Вы знаете, что платеж прошел успешно, если handleCardPayment возвращает 200, веб-крючок предназначен для ваших собственных целей ведения журнала». Webhook предназначен не просто для регистрации — это единственный надежный источник информации о платеже. handleCardPayment — это функция на стороне клиента — мы не можем ничего делать на основе того, что сообщает нам браузер клиента (кроме показа сообщения с благодарностью), потому что они могут его подделать. Кроме того, мы могли бы сказать спасибо, даже если в конечном итоге заказ не выполняется (потому что они могли изменить корзину в другом месте, поэтому сумма платежа неверна).