Rails/Stripe - 接受多次付款
[英] Rails / Stripe - taking multiple payments
本文介绍了Rails/Stripe - 接受多次付款的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我正在构建一个使用 Rails 和 Stripe 处理付款的事件应用程序.我在我的预订页面上使用了 javascript,以允许用户预订和支付多个空间,而不是一次一个.正如您在此处看到的,预订页面允许这样做 -
但是在我的 Stripe 仪表板上,一个空间只支付了一笔费用 -
我该如何解决这个问题,以便在预订视图中显示全额付款?
这是我的控制器和视图代码 -
bookings_controller.rb
class BookingsController <应用控制器before_action :authenticate_user!定义新# 预订表格# 我需要找到我们预订的活动@event = Event.find(params[:event_id])# 因为事件 "has_many :bookings"@booking = @event.bookings.new(数量:参数[:数量])# 谁在预订活动?@booking.user = current_user#@booking.quantity = @booking.quantity@total_amount = @booking.quantity.to_f * @event.price.to_f结尾定义创建# 实际处理预订@event = Event.find(params[:event_id])@booking = @event.bookings.new(booking_params)@booking.user = current_userBooking.transaction做@event.reload如果@event.bookings.count >@event.number_of_spacesflash[:warning] = "抱歉,此活动已满."引发 ActiveRecord::Rollback,事件已满"结尾结尾如果@booking.save# 向已预订的用户收费# #{} == 将变量放入字符串Stripe::Charge.create(amount: @event.price_pennies, 货币: "gbp",卡片:@booking.stripe_token,描述:预订编号#{@booking.id}")flash[:success] = "您在我们活动中的位置已被预订"重定向到事件路径(@event)别的flash[:error] = "支付失败"呈现新"结尾如果@event.is_free?@booking.save!flash[:success] = "您在我们活动中的位置已被预订"重定向到事件路径(@event)结尾结尾私人的def booking_paramsparams.require(:booking).permit(:stripe_token, :quantity)结尾结尾
booking.new.html.erb
<div class="row"><div class="panel panel-default"><div class="panel-heading"><h2>确认您的预订</h2>
<div class="calculate-total"><p>在此处确认您要预订的车位数量:<input type="number" placeholder="1" min="1" value="1" class="num-spaces"></p><p>总金额£<span class="total" data-unit-cost="<%= @event.price %>">0</span></p>
<%= simple_form_for [@event, @booking], id: "new_booking" do |form|%><span class="payment-errors"></span><div class="form-row"><标签><span>卡号</span><input type="text" size="20" data-stripe="number"/>标签>
<div class="form-row"><标签><span>CVC</span><input type="text" size="4" data-stripe="cvc"/>标签>
<div class="form-row"><标签><span>到期 (MM/YYYY)</span><input type="text" size="2" data-stripe="exp-month"/>标签><跨度>/</span><input type="text" size="4" data-stripe="exp-year"/>
<div class="panel-footer"><%= form.button :submit %>
<%结束%><%结束%>
<script type="text/javascript">$('.calculate-total input').on('keyup', calculateBookingPrice);函数计算预订价格(){var unitCost = parseFloat($('.calculate-total .total').data('unit-cost')),numSpaces = parseInt($('.calculate-total .num-spaces').val()),总计 = (numSpaces * unitCost).toFixed(2);如果(isNaN(总计)){总计 = 0;}$('.calculate-total span.total').text(total);}$(document).ready(calculateBookingPrice)<script type="text/javascript" src="https://js.stripe.com/v2/"></script><script type="text/javascript">Stripe.setPublishableKey('<%= STRIPE_PUBLIC_KEY %>');var stripeResponseHandler = 函数(状态,响应){var $form = $('#new_booking');如果(响应.错误){//在表单上显示错误$form.find('.payment-errors').text(response.error.message);$form.find('input[type=submit]').prop('disabled', false);} 别的 {//token 包含 id、last4 和卡片类型var token = response.id;//将令牌插入到表单中,以便将其提交给服务器$form.append($('<input type="hidden" name="booking[stripe_token]"/>').val(token));//并提交$form.get(0).submit();}};//jQuery(function($) { - 改为下面一行$(document).on("准备好页面:加载", function () {$('#new_booking').submit(function(event) {var $form = $(this);//禁用提交按钮以防止重复点击$form.find('input[type=submit]').prop('disabled', true);Stripe.card.createToken($form, stripeResponseHandler);//防止表单使用默认操作提交返回假;});});
我需要在我的 booking_params 中添加价格"吗?我已经有数量"了?
我需要在我的预订表中添加total_amount"列吗?还是和我在控制器中的Stripe动作和数量有关?
感谢任何帮助.
解决方案
需要创建 Stripe.order
并传递 items: []
,这里可以传递 <代码>数量代码>.在您的情况下,它将是一项.
请查看
填写您需要的任何内容.在您的情况下,currency
、price
和 inventory
,也许是 image
.ID
将自动生成.按添加SKU
现在您将拥有此 product
的 SKU
.您可能已经猜到了,同一个 product
可以有多个 SKU,price
可以不同.复制新创建的SKU id
现在你可以像这样创建Stripe::Order
:
<前>response = Stripe::Order.create(货币:美元',项目: [{类型:'sku',父级:'sku_9AJ4OfKbdRuoGi',# SKU id数量:2}],customer: nil, # 如果需要,替换为客户 ID电子邮件:'michael.thompson@example.com')这是您的响应
的样子:
#JSON:{"id": "or_18ryyuBq3wgBfJrxa44Jzm3T",对象":订单",金额":19998,amount_returned":空,应用程序":空,application_fee":空,收费":空,创建":1473465868,货币:美元",客户":空,"email": "michael.thompson@example.com",项目": [{"object":"order_item","amount":19998,"currency":"usd","description":"booking","parent":"sku_9AJ4OfKbdRuoGi","quantity":2,"type":"sku"},{"object":"order_item","amount":0,"currency":"usd","description":"Taxes (included)","parent":null,"quantity":null,"type":税"},{"object":"order_item","amount":0,"currency":"usd","description":"免运费","parent":"ship_free-shipping","quantity":null,"type:运输"}],实时模式":假,元数据":{},"returns": {"object":"list","data":[],"has_more":false,"total_count":0,"url":"/v1/order_returns?order=or_18ryyuBq3wgBfJrxa44Jzm3T"},"selected_shipping_method": "ship_free-shipping",运输":空,运输方法":[{"id":"ship_free-shipping","amount":0,"currency":"usd","delivery_estimate":null,"description":"免运费"}],"状态": "已创建",status_transitions":空,更新":1473465868}
<块引用>
在检查任何 API 调用或 webhook 通知的响应时,使用 Order
对象的 status
属性来验证订单的当前状态并做出相应的响应.
- 当第一次请求订单时,生成的订单对象有一个
created
的初始 status
. - 当订单支付后,
status
会变成 paid
.你现在应该满足订单. - 完成订单后,更新
Order
对象以改变status
到完成
.只有处于 paid
状态的订单才能被标记为已完成
. - 如果客户在订单取消之前(通过您的网站)取消订单已完成,将
status
更新为 canceled
这将退还付款. - 如果订单已完成并且客户退回购买的物品,将
status
更新为 returned
这将退还支付.
阅读订购指南了解更多详情.
现在您应该在 Stripe 的仪表板
中看到新订单希望这会有所帮助.
I'm building an events app using Rails and Stripe to handle payments. I've used javascript for my booking page in order to allow a user to book and pay for multiple spaces rather than just one at a time. The booking page allows for this as you can see here -
However on my Stripe dashboard only one payment has been taken for one space -
How do I solve this so it takes the full payment indicated on the booking view?
Here's my Controller and view code -
bookings_controller.rb
class BookingsController < ApplicationController
before_action :authenticate_user!
def new
# booking form
# I need to find the event that we're making a booking on
@event = Event.find(params[:event_id])
# and because the event "has_many :bookings"
@booking = @event.bookings.new(quantity: params[:quantity])
# which person is booking the event?
@booking.user = current_user
#@booking.quantity = @booking.quantity
@total_amount = @booking.quantity.to_f * @event.price.to_f
end
def create
# actually process the booking
@event = Event.find(params[:event_id])
@booking = @event.bookings.new(booking_params)
@booking.user = current_user
Booking.transaction do
@event.reload
if @event.bookings.count > @event.number_of_spaces
flash[:warning] = "Sorry, this event is fully booked."
raise ActiveRecord::Rollback, "event is fully booked"
end
end
if @booking.save
# CHARGE THE USER WHO'S BOOKED
# #{} == puts a variable into a string
Stripe::Charge.create(amount: @event.price_pennies, currency: "gbp",
card: @booking.stripe_token, description: "Booking number #{@booking.id}")
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(@event)
else
flash[:error] = "Payment unsuccessful"
render "new"
end
if @event.is_free?
@booking.save!
flash[:success] = "Your place on our event has been booked"
redirect_to event_path(@event)
end
end
private
def booking_params
params.require(:booking).permit(:stripe_token, :quantity)
end
end
booking.new.html.erb
<div class="col-md-6 col-md-offset-3" id="eventshow">
<div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2>Confirm Your Booking</h2>
</div>
<div class="calculate-total">
<p>
Confirm number of spaces you wish to book here:
<input type="number" placeholder="1" min="1" value="1" class="num-spaces">
</p>
<p>
Total Amount
£<span class="total" data-unit-cost="<%= @event.price %>">0</span>
</p>
</div>
<%= simple_form_for [@event, @booking], id: "new_booking" do |form| %>
<span class="payment-errors"></span>
<div class="form-row">
<label>
<span>Card Number</span>
<input type="text" size="20" data-stripe="number"/>
</label>
</div>
<div class="form-row">
<label>
<span>CVC</span>
<input type="text" size="4" data-stripe="cvc"/>
</label>
</div>
<div class="form-row">
<label>
<span>Expiration (MM/YYYY)</span>
<input type="text" size="2" data-stripe="exp-month"/>
</label>
<span> / </span>
<input type="text" size="4" data-stripe="exp-year"/>
</div>
</div>
<div class="panel-footer">
<%= form.button :submit %>
</div>
<% end %>
<% end %>
</div>
</div>
</div>
<script type="text/javascript">
$('.calculate-total input').on('keyup', calculateBookingPrice);
function calculateBookingPrice() {
var unitCost = parseFloat($('.calculate-total .total').data('unit-cost')),
numSpaces = parseInt($('.calculate-total .num-spaces').val()),
total = (numSpaces * unitCost).toFixed(2);
if (isNaN(total)) {
total = 0;
}
$('.calculate-total span.total').text(total);
}
$(document).ready(calculateBookingPrice)
</script>
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('<%= STRIPE_PUBLIC_KEY %>');
var stripeResponseHandler = function(status, response) {
var $form = $('#new_booking');
if (response.error) {
// Show the errors on the form
$form.find('.payment-errors').text(response.error.message);
$form.find('input[type=submit]').prop('disabled', false);
} else {
// token contains id, last4, and card type
var token = response.id;
// Insert the token into the form so it gets submitted to the server
$form.append($('<input type="hidden" name="booking[stripe_token]" />').val(token));
// and submit
$form.get(0).submit();
}
};
// jQuery(function($) { - changed to the line below
$(document).on("ready page:load", function () {
$('#new_booking').submit(function(event) {
var $form = $(this);
// Disable the submit button to prevent repeated clicks
$form.find('input[type=submit]').prop('disabled', true);
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from submitting with the default action
return false;
});
});
</script>
Do I need to add 'price' to my booking_params? I already have 'quantity' in there?
Do I need to add a 'total_amount' column to my bookings table? Or is it related to my Stripe action in the controller and the amount?
Any help is appreciated.
解决方案
You need to create Stripe.order
and pass items: []
, where you can pass quantity
. In your case it will be one item.
Please check out Stripe API for more information
Update
Here step by step guide:
- Login to
Stripe
account, create a product
and make it active
. This will be your booking. Save it.
- When you inside the product, you'll see
Inventory
. Find + Add SKU
. Click it.
- You'll see the popup window like this
- Fill in whatever you need to. In your case
currency
, price
and inventory
, perhaps image
. ID
will be generated automatically. Press Add SKU
- Now you'll have
SKU
for this product
. As you probably guessed already, you can have many SKU's for the same product
and the price
can be different.
- Copy newly created
SKU id
Now you can create Stripe::Order
like this:
response = Stripe::Order.create(
currency: 'usd',
items: [
{
type: 'sku',
parent: 'sku_9AJ4OfKbdRuoGi', # SKU id
quantity: 2
}
],
customer: nil, # replace with customer id if needed
email: 'michael.thompson@example.com'
)
This is how your response
would look like:
#<Stripe::Order:0x3ff36d37e2b8 id=or_18ryyuBq3wgBfJrxa44Jzm3T> JSON: {
"id": "or_18ryyuBq3wgBfJrxa44Jzm3T",
"object": "order",
"amount": 19998,
"amount_returned": null,
"application": null,
"application_fee": null,
"charge": null,
"created": 1473465868,
"currency": "usd",
"customer": null,
"email": "michael.thompson@example.com",
"items": [
{"object":"order_item","amount":19998,"currency":"usd","description":"booking","parent":"sku_9AJ4OfKbdRuoGi","quantity":2,"type":"sku"},
{"object":"order_item","amount":0,"currency":"usd","description":"Taxes (included)","parent":null,"quantity":null,"type":"tax"},
{"object":"order_item","amount":0,"currency":"usd","description":"Free shipping","parent":"ship_free-shipping","quantity":null,"type":"shipping"}
],
"livemode": false,
"metadata": {},
"returns": {"object":"list","data":[],"has_more":false,"total_count":0,"url":"/v1/order_returns?order=or_18ryyuBq3wgBfJrxa44Jzm3T"},
"selected_shipping_method": "ship_free-shipping",
"shipping": null,
"shipping_methods": [
{"id":"ship_free-shipping","amount":0,"currency":"usd","delivery_estimate":null,"description":"Free shipping"}
],
"status": "created",
"status_transitions": null,
"updated": 1473465868
}
When examining the response of any API call or webhook notification, use the Order
object’s status
attribute to verify the current status of the order and respond accordingly.
- When an order is first requested, the resulting order object has an
initial
status
of created
.
- When an order is paid,
status
changes to paid
. You should now fulfill
the order.
- After fulfilling the order, update the
Order
object to change status
to fulfilled
. Only orders in the paid
state can be marked as
fulfilled
.
- If the customer cancels the order (through your site) before it’s
been fulfilled, update
status
to canceled
which will refund the
payment.
- If the order has been fulfilled and the customer returns the
purchased items, update
status
to returned
which will refund the
payment.
Read order guide for more details.
Now you should see new order in Stripe's dashboard
Hope this helps.
这篇关于Rails/Stripe - 接受多次付款的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文