简体   繁体   English

Javascript / jQuery-价格计算

[英]Javascript / jQuery - Price calculation

I'm building an events app using Ruby on Rails. 我正在使用Ruby on Rails构建事件应用程序。 At the moment a user who wishes to book onto an event can only book and pay for one space at a time. 目前,希望预订活动的用户一次只能预订并支付一个空间。 I need to offer the facility for them to book multiple spaces and pay the appropriate price - so 5 spaces for £10 each = £50 to pay etc. I've looked for appropriate solutions in RoR to sort this but I'm hitting a brick wall. 我需要为他们提供设施以预订多个空间并支付适当的价格-所以5个空间,每个空间10英镑=支付50英镑,等等。砖墙。 However, I believe I've perhaps approached this the wrong way and that a solution using javascript or jQuery is the best way forward. 但是,我相信我可能采用了错误的方法,使用javascript或jQuery的解决方案是最好的方法。 I'm very much a novice at both and need some assistance in achieving this objective. 我对这两者都是新手,因此在实现此目标方面需要一些帮助。

Here's my payment/booking page - 这是我的付款/预订页面-

预订页面

I want a User to be able to place the number of spaces in the first text area and for the price (total amount) to change accordingly. 我希望用户能够将空格数放在第一个文本区域中,并且价格(总计)可以相应地更改。

Here's my other relevant code - 这是我的其他相关代码-

booking.rb - booking.rb-

class Booking < ActiveRecord::Base

    belongs_to :event
    belongs_to :user

    def total_amount

        #quantity.to_i * @price_currency.to_money
        quantity.to_i * strip_currency(event.price)
    end

    private

        def strip_currency(amount = '')
            amount.to_s.gsub(/[^\D\.]/, '').to_f
        end



end

bookings_controller.rb 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
        @price = price
        @quantity = quantity
        #@total_amount = @booking.quantity.to_f * @event.price.to_f

        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

    #def total_amount
        #@total_amount = @booking.quantity * @event.price
    #end

    private

      def booking_params
        params.require(:booking).permit(:stripe_token, :quantity)
      end

end

bookings.new.html.erb bookings.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="panel-body">    
                <p>Confirm number of spaces you wish to book here:
                  <input type="number" placeholder="1"  min="1" value="1"></p>
                <p>Total Amount   £<%= @event.price %></p>
                <%= 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" 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>

One aspect of building this site which I didn't appreciate is how difficult and complex it can be to deal with money when using RoR. 我不喜欢建立该站点的一个方面是,使用RoR处理资金有多么困难和复杂。 A few of the suggestions I've received stated I should be using the monetize gem (I'm not, I'm using money-rails) and this coupled with some model method/MVC magic would achieve this. 我收到的一些建议指出,我应该使用可货币化的宝石(我不是,我使用的是钱轨),并且结合一些模型方法/ MVC魔术可以达到此目的。 However, I think I'd prefer this route if the right solution can be found. 但是,如果可以找到正确的解决方案,我想我会选择这种方法。

As you suggest, one approach is to use JavaScript to calculate the total. 正如您所建议的,一种方法是使用JavaScript计算总数。

You could change this snippet of your view: 您可以更改以下视图片段:

<p>
  Confirm number of spaces you wish to book here:
  <input type="number" placeholder="1"  min="1" value="1">
</p>
<p>Total Amount   £<%= @event.price %></p>

to make it easier to target with jQuery and to provide a reference to the price per space. 使其更易于使用jQuery定位,并提供每个空间价格的参考。 For example: 例如:

<div class="calculate-total">
  <p>
    Confirm number of spaces you wish to book here:
    <input type="number" placeholder="1"  min="1" value="1">
  </p>
  <p>
    Total Amount
    £<span class="total" data-unit-cost="<%= @event.price %>">0</span>
  </p>
</div>

Using JavaScript, you can listen for a keyup event on the input field and perform the calculation. 使用JavaScript,您可以在输入字段上侦听keyup事件并执行计算。

$('.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);
}

Having the function separated from the event listener means you could also call it when the page loads so that you have a starting value. 将函数与事件侦听器分开,意味着您也可以在页面加载时调用它,以便获得初始值。

Here's a fiddle to demonstrate (it assumes @event.price is 10). 这是一个小提琴来演示(假设@event.price为10)。

UPDATE 更新

The key here is that @event.price should return the unit price of a booking. 这里的关键是@event.price应该返回预订的单价。 Your new action can be as simple as this: 您的动作可以像这样简单:

def new
  # Find the event for the booking.
  @event = Event.find(params[:event_id])
  # @event.price should return the unit cost of a booking.

  # Don't need to set attributes here -- you can add them in create.
  @booking = @event.bookings.new
end

Also note that if you want to store quantity and/or total_amount on your @booking object, you should move the fields inside your form ( simple_form_for ) and adjust the markup so they are submitted as part of the booking. 另请注意,如果要将quantity和/或total_amount存储在@booking对象上,则应移动表单( simple_form_for )内的字段并调整标记,以便将其作为预订的一部分提交。 something like this: 像这样的东西:

<%= simple_form_for [@event, @booking], id: "new_booking" do |form| %>
  <%= f.input :quantity %>
  <%= f.input :total_amount %>
  ...

And adjust your JavaScript to target these inputs (instead of the input and span in my original post). 并调整JavaScript以定位这些输入(而不是我原始帖子中的inputspan )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM