如何基于 ajax 成功为 Stripe 令牌创建条件

How to create conditional for Stripe token based on ajax success

我正在使用 Stripe JS 和 Flask 在同一页面上创建和处理付款表单和优惠券表单。在提交付款表格之前,可选择通过 ajax 提交优惠券表格。如果优惠券提交成功,我想删除付款表格的付款部分,并提交不带 Stripe 的表格(因为我还有其他数据要收集和处理服务器端)。

我的优惠券代码表格如我所愿,我可以有条件地更改 DOM 以删除付款表格。但这会引发错误,因为 Stripe 已经在页面加载时创建了令牌。

但是我对 JS 的操作顺序感到困惑。如有任何帮助,我们将不胜感激!

我的 JS:

<script type="text/javascript">
Stripe.setPublishableKey('some_test_id');

var couponApplied;

var stripeResponseHandler = function(status, response) {
    var $form = $('#purchase_form');

    if (response.error) {
        // Show the errors on the form
        $form.find('.payment-errors').text(response.error.message);
        $form.find('input').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="stripeToken">').val(token));
        // and re-submit
        $form.get(0).submit();
    }
};

$(document).ready(function() {
    $('#purchase_form').submit(function(e) {
        var $form = $(this);
        // Disable the submit button to prevent repeated clicks
        $form.find('button').prop('disabled', true);
        Stripe.card.createToken($form, stripeResponseHandler);
        // Prevent the form from submitting with the default action
        return false;
    });
});

var csrftoken = $('meta[name=csrf-token]').attr('content');
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken)
        }
    }
});

$('form#couponcode_form').submit(function() {
    var code = $('input#coupon_code').val();

    $.ajax({
        data: JSON.stringify({
            code: code
        }),
        url: '/code_validate',
        type: 'POST',
        contentType: "application/json; charset=utf-8",
        dataType: 'json',
        success: function(json) {
            console.log(json);
            $(".ajax_response").text(json.response);
            $(".code_redemption").text(json.price);
            if (json.code_applied === true) {
                var couponApplied = true;
                $("#payment").remove();
            } else {
                var couponApplied = false;
            }
            console.log('Test coupon: ' + couponApplied);

        },
        error: function(request, errorType, errorMessage) {
            console.log(errorType +  ": " + errorMessage);
        }
        });

        return false;
    });

</script>

还有我 HTML 处理表格的一部分:

<form method='POST' action='/code_validate' id="couponcode_form">
        {{ couponcode_form.csrf_token }}
        {{ couponcode_form.coupon_code.label }} {{ couponcode_form.coupon_code(size=20) }}
        {{ couponcode_form.submit }}
    </form>

    <form action="/buy" method="POST" id="purchase_form">
        {{ form.csrf_token }}
        {{ form.coupon_used }}

        <div class="form_step">
            <h2>1. Your Friend's Name</h2>
        </div>

        <div class="field_grouper" id="recipient">

            <div class="form-group{% if form.recipient_name.errors %} has-error{% endif %}">
                {{ form.recipient_name.label }}
                {{ form.recipient_name(class_='form-control', maxlength='250') }}
                <span class="help_text">{{ form.recipient_name.description|safe }}</span> <span class="required">*</span>
            </div>

            <div class="form-group{% if form.recipient_email.errors %} has-error{% endif %}">
                    {{ form.recipient_email.label }}
                    {{ form.recipient_email(class_='form-control', maxlength='100') }}
                    <span class="help_text">{{ form.recipient_email.description|safe }}</span>
            </div>

        </div>

        <div class="form_step">
            <h2>2. Your Friend's Address</h2>
        </div>

        <div class="field_grouper" id="recipient_address">

            <div class="form-group{% if form.shipping_street_address_1.errors %} has-error{% endif %}">
                {{ form.shipping_street_address_1.label }}
                {{ form.shipping_street_address_1(class_='form-control', maxlength='250') }}
                <span class="help_text">{{ form.shipping_street_address_1.description|safe }}</span> <span class="required">*</span>
            </div>

            <div class="form-group{% if form.shipping_street_address_2.errors %} has-error{% endif %}">
                {{ form.shipping_street_address_2.label }}
                {{ form.shipping_street_address_2(class_='form-control', maxlength='250') }}
                <span class="help_text">{{ form.shipping_street_address_2.description|safe }}</span>
            </div>

            <div class="form-group{% if form.shipping_city.errors %} has-error{% endif %}">
                {{ form.shipping_city.label }}
                {{ form.shipping_city(class_='form-control', maxlength='250') }}
                <span class="help_text">{{ form.shipping_city.description|safe }}</span> <span class="required">*</span>
            </div>

            <div class="form-group{% if form.shipping_state.errors %} has-error{% endif %}">
                {{ form.shipping_state.label }}
                {{ form.shipping_state(class_='form-control', maxlength='2') }}
                <span class="help_text">{{ form.shipping_state.description|safe }}</span> <span class="required">*</span>
            </div>

            <div class="form-group{% if form.shipping_zip.errors %} has-error{% endif %}">
                {{ form.shipping_zip.label }}
                {{ form.shipping_zip(class_='form-control', maxlength='9') }}
                <span class="help_text">{{ form.shipping_zip.description|safe }}</span> <span class="required">*</span>
            </div>
        </div>

        <div class="form_step">
            <h2>3. Add your message</h2>
        </div>
        {% block prefilled_messages %}

        {% endblock %}

        <div class="field_grouper" id="message">
            <h3>Personalized Message:</h3>
            <div class="form-group{% if form.personal_message.errors %} has-error{% endif %}">
                {{ form.personal_message.label }}
                {{ form.personal_message(class_='form-control', rows='10') }}
                <span class="help_text">{{ form.personal_message.description|safe }}. You have <b><span id="charsleft"></span></b> characters left.</span><span class="required">*</span>
            </div>
        </div>

        <div class="field_grouper" id="purchaser">
            <h3>From:</h3>

            <div class="form-group{% if form.purchaser_name.errors %} has-error{% endif %}">
                {{ form.purchaser_name.label }}
                {{ form.purchaser_name(class_='form-control', maxlength='250') }}
                <span class="help_text">{{ form.purchaser_name.description|safe }}</span>
            </div>

            <div class="form-group{% if form.purchaser_email.errors %} has-error{% endif %}">
                {{ form.purchaser_email.label }}
                {{ form.purchaser_email(class_='form-control', maxLength='100') }}
                <span class="help_text">{{ form.purchaser_email.description|safe }}</span> <span class="required">*</span>
            </div>
        </div>

        <div class="form_step">
            <h2>4. Pay</h2>
        </div>

        <span class="code_redemption"></span>

        <div class="field_grouper" id="payment">

            <span class="payment-errors"></span>

            <h3>Credit card:</h3>

            <div class="form-group">
                <input type="text" size="20" data-stripe="number">

                <span class="help_text">Card number</span> <span class="required">*</span>
            </div>

            <div class="form-group">
                <input type="text" size="4" data-stripe="cvc">

                <span class="help_text">CVC</span> <span class="required">*</span>
            </div>

            <div class="form-group">
                <input type="text" size="2" data-stripe="exp-month">
                <span> / </span>
                <input type="text" size="4" data-stripe="exp-year">

                <span class="help_text">Expiration month and year (MM/YYYY)</span> <span class="required">*</span>
            </div>

        </div>

        <div class="field_grouper" id="submit">
            <button type="submit">Submit Payment</button>
        </div>
    </form>

如果我正确理解流程,您应该能够将变量声明 couponApplied 移动到两个表单提交处理程序都可以访问的范围级别。

然后在购买提交处理程序中,如果 couponApplied 为真,您可以绕过 Stripe API,让表单提交而不是从提交处理程序返回 false。

$(document).ready(function () {
    // declare variable with default false
    var couponApplied = false;

    $('#purchase_form').submit(function (e) {

        var $form = $(this);
        // Disable the submit button to prevent repeated clicks
        $form.find('button').prop('disabled', true);

        if (!couponApplied) {
            // only use stripe if no coupon
            Stripe.card.createToken($form, stripeResponseHandler);
        }
        // return true/false by variable will determine if browser submit occurs
        return couponApplied;
    });

    $('form#couponcode_form').submit(function () {
        var code = $('input#coupon_code').val();
        $.ajax({
            //some options not shown for clarity
            success: function (json) {
                // don't use "var" here
                couponApplied = json.code_applied;  
                /* other code */  
            }
        });
    });

});