Rails Stripe webhook 更新钱包余额
Posted
技术标签:
【中文标题】Rails Stripe webhook 更新钱包余额【英文标题】:Rails Stripe webhook to update wallet balance 【发布时间】:2021-08-31 18:53:46 【问题描述】:最近怎么样?我需要一点帮助。
我正在开发一个应用程序,允许用户购买 credits 可用于预订activities
credits 存储在用户的wallet
中,并通过多态wallet_entries
添加到其中(这些wallet_entries
也连接到bookings
表,当用户预订活动,积分会被扣除)
我正在使用 Stripe 来处理 payments
。当用户想要购买积分时,会创建一个 order
,它包含 credit_package
id 以及设置为待处理的 "state" 属性。
我设法设置了 Stripe Checkout 并配置了一个 webhook,当付款成功时,它会将 order's
状态从 pending 更新为 paid
我的目标是在 Stripe 的 Webhook 更新 order's
状态时创建一个 wallet_entry
。说wallet_entry
包含诸如number_of_credits
和wallet
参考之类的信息,以便用正确的number_of_credits
更新用户的wallet
余额
我尝试在处理 Stripe 事件的控制器中执行此操作,我将其包装在一个原子事务中,以确保只有在 order's
状态 时,信用才会添加到 wallet
更新为付费
webhook 正在成功更新 order's
state,但如果我添加更多行会中断,这是我在 Stripe Webhooks 日志中遇到的错误:
NameError in StripeEvent::WebhookController#event undefined local variable or method current_user for <StripeCheckoutSessionService:0x000056103da42a38&>;
。我的猜测是这个逻辑应该在其他地方处理。
这是我的文件:
条带初始化器
Rails.configuration.stripe =
publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'],
secret_key: ENV['STRIPE_SECRET_KEY'],
signing_secret: ENV['STRIPE_WEBHOOK_SECRET_KEY']
Stripe.api_key = Rails.configuration.stripe[:secret_key]
StripeEvent.signing_secret = Rails.configuration.stripe[:signing_secret]
StripeEvent.configure do |events|
events.subscribe 'checkout.session.completed', StripeCheckoutSessionService.new
end
条带结帐会话服务
class StripeCheckoutSessionService
def call(event)
ActiveRecord::Base.transaction do
order = Order.find_by(checkout_session_id: event.data.object.id)
order.update(state: 'paid')
# Extra stuff that breaks code
wallet = current_user.wallet
wallet_entry = WalletEntry.create!(type: "Deposit", total_credits: order.credit_package.number_of_credits, wallet: wallet, entryable: order)
wallet.credit_total += wallet_entry.total_credits
end
end
end
支付控制器
class PaymentsController < ApplicationController
before_action :authenticate_user!
def new
@order = Order.where(state: 'pending').find(params[:order_id])
end
end
订单控制器
class OrdersController < ApplicationController
def create
credit_package = CreditPackage.find(params[:credit_package_id].to_i)
order = Order.create!(credit_package: credit_package, amount: credit_package.price, state: 'pending', amount_of_packages: 1 )
session = Stripe::Checkout::Session.create(
payment_method_types: ['card'],
line_items: [
name: credit_package.name,
amount: credit_package.price_cents,
currency: 'eur',
quantity: order.amount_of_packages
],
success_url: order_url(order),
cancel_url: order_url(order)
)
order.update(checkout_session_id: session.id)
redirect_to new_order_payment_path(order)
end
def show
@order = Order.find(params[:id])
end
end
路线
Rails.application.routes.draw do
get 'user_interests/destroy'
# Admin dashboard routes
namespace :admin do
resources :activities
resources :bookings
resources :coaches
resources :coach_profiles, except: :index
resources :coach_activities, except: :index
resources :activity_sessions
resources :taggings, except: :index
resources :tags
resources :users
resources :user_profiles, except: :index
resources :user_interests, except: :index
root to: 'coaches#index'
end
devise_for :coaches, controllers:
sessions: 'coaches/sessions'
devise_for :users, controllers:
sessions: 'users/sessions'
match '/users/:id', :to => 'users#destroy', :as => :destroy_user, :via => :delete
root 'pages#home'
# static pages
get 'pages/contact'
get 'pages/nousrejoindre'
get 'pages/notrehistoire'
get 'pages/mentionslegales'
get 'pages/politiques'
get 'pages/listeactivites'
resources :activities do
resources :sessions, only: [:index]
end
resources :activity_sessions do
resources :bookings, only: [:create]
end
resources :orders, only: [:show, :create] do
resources :payments, only: :new
end
resources :bookings, only: [:destroy]
resources :contacts
resources :users
resources :user_profiles
resources :coach_profiles
resources :user_interests, only: [:destroy]
resources :credit_packages, only: [:index]
# route for stripe endpoint
mount StripeEvent::Engine, at: '/stripe-webhooks'
end
关于如何进行的任何建议?我愿意完全改变这种方法,甚至是支付网关架构。谢谢
【问题讨论】:
【参考方案1】:对于 Stripe webhook,请求由 Stripe 向您自己的应用程序发出。在此请求的上下文中,没有登录用户,因此 current_user
在执行 wallet = current_user.wallet
的行上不可用。
您可能需要做的是使用不同的方法来获取链接到此订单的用户。我可以想象您的 Order
模型以某种方式与用户相关联,在这种情况下您可以这样做:
order = Order.find_by(checkout_session_id: event.data.object.id)
order.update(state: 'paid')
wallet = order.user.wallet
【讨论】:
以上是关于Rails Stripe webhook 更新钱包余额的主要内容,如果未能解决你的问题,请参考以下文章
如何延迟 Rails 控制器操作,直到 Stripe 的 webhook 成功?
仅在 Stripe 中的平台余额更新时收到通知 - WebHook