我正在为艺术家搭建一个出售艺术品的网站。它使用条纹结帐进行付款。我已经设置了结帐和Webhook,一旦Webhook命中并且结帐会话完成,我需要将产品的数量更新为0。
这里是结帐控制器(认为是产品)
class CheckoutController < ApplicationController
def create
piece = Piece.find(params[:id])
if piece.nil?
redirect_to root_path
return
end
@session = Stripe::Checkout::Session.create(
payment_method_types: [:card],
line_items: [{
name: piece.name,
description: piece.description,
amount: (piece.price*100).to_i,
currency: 'usd',
quantity: 1
}],
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},
success_url: checkout_success_url,
cancel_url: checkout_cancel_url
)
respond_to do |format|
format.js
end
end
def success
end
def cancel
end
end
这里是webhook事件控制器
class WebhookEventsController < ApplicationController
# ignore CSRF
skip_before_action :verify_authenticity_token
def create
if !valid_signatures?
render json: { message: "Invalid sigs"}, status: 400
return
end
# idempotent
if !WebhookEvent.find_by(source: params[:source], external_id: external_id).nil?
render json: { message: "Already Processed #{ external_id }"}
return
end
event = WebhookEvent.create(webhook_params)
ProcessEventsJob.perform_later(event.id)
render json: params
end
def valid_signatures?
if params[:source] == 'stripe'
begin
wh_secret = Rails.application.credentials.dig(:stripe, :wh)
Stripe::Webhook.construct_event(
request.body.read,
request.env["HTTP_STRIPE_SIGNATURE" ],
wh_secret
)
rescue Stripe::SignatureVerificationError => e
return false
end
end
true
end
def external_id
return params[:id] if params[:source] == 'stripe'
SecureRandom.hex
end
def webhook_params
{
source: params[:source],
data: params.except(:source, :action, :controller).permit!,
external_id: external_id
}
end
end
这里是条带处理程序,我认为更新单件数量的代码应该在其中
module Events
class StripeHandler
def self.process(event)
stripe_event = Stripe::Event.construct_from(event.data)
case stripe_event.type
when 'checkout.session.completed'
checkout_session = stripe_event.data.object
# now can do #{ checkout_session.customer }.. or some attribute of checkout_session object
puts "*** Do things here i.e. logic for emails/inventory management"
end
end
end
end
所有这些,因此我基本上可以禁用艺术品上的购买按钮。
这里有几点注意事项:
[您可能想将client_reference_id
设置为片段的ID,这使协调更容易:https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-client_reference_id
您需要在完成的会话中检查line_items
或使用client_reference_id
查找客户在会话完成后购买的商品。
到目前为止,您的控制器逻辑看起来正确。在Piece上需要一个quantity
字段。我假设您在CheckoutSession创建中通过了{client_reference_id: piece.id}
。在这种假设下,您的Webhook处理逻辑如下所示:
module Events
class StripeHandler
def self.process(event)
stripe_event = Stripe::Event.construct_from(event.data)
case stripe_event.type
when 'checkout.session.completed'
Piece.transaction do
piece = Piece.find(id: checkout.client_reference_id)
raise Exception.new("item already purchased!") if piece.quantity == 0
piece.quantity = 0
piece.save!
end
end
end
end
end
这实现了一个简单的“第一人称赢钱”的情况,因此,首先通过Checkout支付给定作品的第一人付款,然后将其checkout.session.completed
Webhook发送到您的应用程序并首先进行处理的人将获得该作品。如果两个人同时付款,那么只有一个人可以得到该件,因此您可能想要执行一些操作,例如自动退款给客户并向他们发送电子邮件。
[我使用database transaction更新了商品,因此,如果两个客户以某种方式确切地同时付款,我们将不会不小心将both客户给予该商品。