使用 Stripe 和 ASP.NET Core 向现有客户收费

Charge an existing customer with Stripe and ASP.NET Core

这是我使用条纹支付的自定义表单集成的工作代码。

问题是:如何处理回头客?我正在存储他们第一次 purchase.The 下次客户结账时的客户 ID,我不希望他们重新输入信用卡信息。

我可以找到很多关于如何使用费用 API 执行此操作的示例,但现在他们鼓励使用 PaymentIntents API。

自定义表单:

 <div class="campagin_start content" style="max-width:100%">
       <div class="cell example example2" id="">
            <form>
               <div class="row">
                   <div class="field">
                         <div id="example2-card-number" class="input empty"></div>
                            <label for="example2-card-number" data-tid="elements_examples.form.card_number_label">Card number</label>
                                <div class="baseline"></div>
                            </div>
                        </div>
                        <div class="row">
                            <div class="field half-width">
                                <div id="example2-card-expiry" class="input empty"></div>
                                <label for="example2-card-expiry" data-tid="elements_examples.form.card_expiry_label">Expiration</label>
                                <div class="baseline"></div>
                            </div>
                            <div class="field half-width">
                                <div id="example2-card-cvc" class="input empty"></div>
                                <label for="example2-card-cvc" data-tid="elements_examples.form.card_cvc_label">CVC</label>
                                <div class="baseline"></div>
                            </div>
                        </div>
                     
                        <button id="card-button">@WebResources.Donate $@Model.budget</button>
                        <a href="#" class="btn btn-border mt-10" style="display: none;margin-top: 10px;margin-left: 15px;" id="canceltran"> Cancel</a>
                    </form>
                   
                    <p id="payment-result"><!-- we'll pass the response from the server here --></p>
                </div>

            </div>

Javascript:

var stripe = Stripe('@ViewBag.StripePublishKey');
var elementStyles = {
    base: {
        color: '#32325D',
        fontWeight: 500,
        fontFamily: 'Source Code Pro, Consolas, Menlo, monospace',
        fontSize: '16px',
        fontSmoothing: 'antialiased',

        '::placeholder': {
            color: '#CFD7DF',
        },
        ':-webkit-autofill': {
            color: '#e39f48',
        },
    },
    invalid: {
        color: '#E25950',

        '::placeholder': {
            color: '#FFCCA5',
        },
    },
};

var elementClasses = {
    focus: 'focused',
    empty: 'empty',
    invalid: 'invalid',
};
var elements = stripe.elements({
    fonts: [
        {
            cssSrc: 'https://fonts.googleapis.com/css?family=Source+Code+Pro',
        },
    ],
    // Stripe's examples are localized to specific languages, but if
    // you wish to have Elements automatically detect your user's locale,
    // use `locale: 'auto'` instead.
    locale: window.__exampleLocale
});
var Id = @Html.Raw(Json.Encode(Model.Id)); // Get Id From Model
var cardNumber = elements.create('cardNumber', {
        showIcon: true,
        style: elementStyles,
        classes: elementClasses,
    });
    cardNumber.mount('#example2-card-number');

    var cardExpiry = elements.create('cardExpiry', {
        style: elementStyles,
        classes: elementClasses,
    });
    cardExpiry.mount('#example2-card-expiry');

    var cardCvc = elements.create('cardCvc', {
        style: elementStyles,
        classes: elementClasses,
    });
    cardCvc.mount('#example2-card-cvc');
var formClass = '.example2';
var example = document.querySelector(formClass);
var form = example.querySelector('form');
var resultContainer = document.getElementById('payment-result');

// Payment Button Handle

 form.addEventListener('submit', function (event) {
    $('#AjaxLoader').show();
    event.preventDefault();
    resultContainer.textContent = "";
    stripe.createPaymentMethod({
        type: 'card',
        card: cardNumber,
    }).then(handlePaymentMethodResult);
});

function handlePaymentMethodResult(result) {
    if (result.error) {
        $('#AjaxLoader').hide();
        $("#canceltran").show(); 
        // An error happened when collecting card details, show it in the payment form
        resultContainer.textContent = result.error.message;
    } else {
        // Otherwise send paymentMethod.id to your server 
        fetch('/cart/pay', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ PaymentMethodId: result.paymentMethod.id, Id: Id}) 
        }).then(function (result) {
            return result.json();
        }).then(handleServerResponse);

    }
}

function handleServerResponse(responseJson) {
    if (responseJson.error) {
        // An error happened when charging the card, show it in the payment form
        resultContainer.textContent = responseJson.error;
        $('#AjaxLoader').hide();
        $("#canceltran").show();
    } else if (responseJson.requiresAction) {

        // Use Stripe.js to handle required card action
        stripe.handleCardAction(
            responseJson.clientSecret
        ).then(function (result) {

            if (result.error) {
               
                $('#AjaxLoader').hide();
                resultContainer.textContent = result.error.message;
                $("#canceltran").show();
                // Show `result.error.message` in payment form
            } else {
                // The card action has been handled
                // The PaymentIntent can be confirmed again on the server
                fetch('/cart/pay', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ PaymentIntentId: result.paymentIntent.id, Id:Id })
                }).then(function (confirmResult) {
                    return confirmResult.json();
                }).then(handleServerResponse);
                $('#AjaxLoader').hide();
            }
        });
    }
    else {
        // Show a success message or Required action
        
      }
}

Asp.net 控制器

public class CartController : ControllerBase
{
    public CartController()
    {
        StripeConfiguration.ApiKey = YOUR API KEY; // Replace your API KEY here
    }
    string stripePublishKey = YOUR PUBLISHER KEY; // Replace your PUBLISHER KEY here

    private class StripeDataReq
    {
        public string PaymentMethodId { get; set; }
        public string PaymentIntentId { get; set; }
        public string Id { get; set; }
    }

    public async Task<ActionResult> Pay(StripeDataReq stripeDataReq)
    {
        // From Id you can get the value 
        var cart = await Cart.Table.LookupAsync(stripeDataReq.Id);
        // We set amount (amout*100) because here amount consider in cent (100 cent charge ) so 
        var amount = cart.Budget * 100;
        var email = ""; // Set Email Id for payment Receiver

        var service = new PaymentIntentService();
        PaymentIntent paymentIntent = null;
        try
        {
            if (stripeDataReq.PaymentMethodId != null)
            {
                // Create the PaymentIntent
                var options = new PaymentIntentCreateOptions
                {
                    Description = cart.Desc,
                    PaymentMethod = stripeDataReq.PaymentMethodId,
                    ReceiptEmail = email,
                    Amount = amount,
                    Currency = "usd",
                    Confirm = true,
                    //ErrorOnRequiresAction = true,
                    ConfirmationMethod = "manual",
                };

                paymentIntent = service.Create(options);
            }
            if (stripeDataReq.PaymentIntentId != null)
            {
                var confirmOptions = new PaymentIntentConfirmOptions { };
                paymentIntent = service.Confirm(
                    stripeDataReq.PaymentIntentId,
                    confirmOptions
                );
            }
        }

        // StripeException handle all types of failure error and then return the message into FE 
        catch (StripeException e)
        {

            return Json(new { error = e.StripeError.Message });
        }
        TempData["Id"] = stripeDataReq.Id;
        return await generatePaymentResponse(paymentIntent);
    }



    //For 3D secure card 
    private async Task<ActionResult> generatePaymentResponse(PaymentIntent intent)
    {
        var CartId = TempData["Id"];

        if (intent.Status.ToString().ToLower() == "succeeded")
        {
            // create a stripe customer if there isn't one
            if (string.IsNullOrWhiteSpace(user.StripeCustomerId))
            {
                var customer = CreateStripeCustomer(user.Id);
                var userModel = Context.BackendUsers.SingleOrDefault(x => x.Id == user.Id);
                if (userModel != null)
                {
                    userModel.StripeCustomerId = customer.Id;
                    _context.Update(userModel);
                }
            }

            await _context.SaveChangesAsync();
            // Handle post-payment fulfillment
            return Json(new { success = true });

        }
        // requires_action means 3d secure card required more authentications for payment
        else if (intent.Status == "requires_action")
        {
            // Tell the client to handle the action
            return Json(new
            {
                requiresAction = true,
                clientSecret = intent.ClientSecret
            });
        }
        else
        {

            // Any other status would be unexpected, so error
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Invalid PaymentIntent status");
        }
    }

}

回答我自己的问题:

  1. 在创建 Stripe 客户时,将 paymentMethodId 附加到它。

    var paymentMethodAttachOptions = new PaymentMethodAttachOptions { 客户 = customer.Id }; var paymentMethodService = new PaymentMethodService(); paymentMethodService.Attach(paymentMethodId, paymentMethodAttachOptions);

  2. 下次付款,在服务器端,获取客户paymentMethods

    var 选项 = 新的 PaymentMethodListOptions { 客户 = user.StripeCustomerId, 类型 = "卡片", }; var service = new PaymentMethodService(); StripeList paymentmethods = await service.ListAsync(options);

  3. 在服务器上,向客户收费

    var paymentIntentCreateOptions = new PaymentIntentCreateOptions { 说明 = "...", PaymentMethod = paymentmethods.First().Id, 客户 = user.StripeCustomerId, 收据邮箱 = user.Email, 数量 = 5500, 货币 = "欧元", 确认=真,

                 ConfirmationMethod = "manual",
             };