问题
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.
回答1:
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 aproduct
and make itactive
. 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
andinventory
, perhapsimage
.ID
will be generated automatically. PressAdd SKU
- Now you'll have
SKU
for thisproduct
. As you probably guessed already, you can have many SKU's for the sameproduct
and theprice
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’sstatus
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
ofcreated
.- When an order is paid,
status
changes topaid
. You should now fulfill the order.- After fulfilling the order, update the
Order
object to changestatus
tofulfilled
. Only orders in thepaid
state can be marked asfulfilled
.- If the customer cancels the order (through your site) before it’s been fulfilled, update
status
tocanceled
which will refund the payment.- If the order has been fulfilled and the customer returns the purchased items, update
status
toreturned
which will refund the payment.
Read order guide for more details.
Now you should see new order in Stripe's dashboard
Hope this helps.
来源:https://stackoverflow.com/questions/39410536/rails-stripe-taking-multiple-payments