Rails/Stripe - 接受多次付款 [英] Rails / Stripe - taking multiple payments

查看:36
本文介绍了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: [] ,这里可以传递 <代码>数量.在您的情况下,它将是一项.

请查看

  • 填写您需要的任何内容.在您的情况下,currencypriceinventory,也许是 image.ID 将自动生成.按添加SKU
  • 现在您将拥有此 productSKU.您可能已经猜到了,同一个 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 属性来验证订单的当前状态并做出相应的响应.

    阅读订购指南了解更多详情.

    现在您应该在 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:

    1. Login to Stripe account, create a product and make it active. This will be your booking. Save it.
    2. When you inside the product, you'll see Inventory. Find + Add SKU. Click it.
    3. You'll see the popup window like this
    4. Fill in whatever you need to. In your case currency, price and inventory, perhaps image. ID will be generated automatically. Press Add SKU
    5. 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.
    6. Copy newly created SKU id
    7. 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.

    Read order guide for more details.

    Now you should see new order in Stripe's dashboard

    Hope this helps.

    这篇关于Rails/Stripe - 接受多次付款的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    前端开发最新文章
    热门教程
    热门工具
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆