我正在将带有支付意图的Stripe SCA集成到我的Rails5.2.3(Ruby2.5.1)应用程序中。我成功地使一次性付款正常工作,但是在我集成订阅(成功地工作)之后,一次性付款在Stripe上接收到一个不完整的状态“客户尚未输入他们的付款方法”(the customer has not interned their payment method)。查看JSON,我可以看到我的支付意图,ID被成功创建,但是我的收费,数据显示为空。我不明白为什么数据没有传递给Stripe。下面是相应的文件:
purchases.show.html.erb
<div class="container">
<h1>Purchasing <%= @recipe.title %> for <%= number_to_currency(@recipe.price) %></h1>
<%= form_with url: recipe_purchase_path(@recipe.id), local: true, id: "payment-form", data: { payment_intent_id: @payment_intent.client_secret } do |form| %>
<div class="form-group">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element" class="form-control">
</div>
<div id="card-errors" role="alert">
</div>
</div>
<div class="form-group">
<label>Name on Card</label>
<%= form.text_field :name_on_card, placeholder: "Full name", class: "form-control" %>
</div>
<div class="form-group">
<%= form.hidden_field :payment_intent_id, value: @payment_intent.id %>
<button class="btn btn-outline-primary buy-recipe">Submit Payment</button>
</div>
<% end %>
</div>
purchases_controller.rb
class PurchasesController < ApplicationController
before_action :authenticate_user!
before_action :set_recipe, only:[:show, :create]
def receipt
@purchase = Purchase.find_by_uuid(params[:id])
@recipe = Recipe.find(@purchase.recipe_id)
end
def show
@payment_intent = Stripe::PaymentIntent.create(
amount: @recipe.price_in_cents,
currency: 'usd',
payment_method_types: params['card'],
metadata: {integration_check: 'accept_a_payment'},
)
end
def create
@payment_intent = Stripe::PaymentIntent.retrieve(params[:payment_intent_id])
if @payment_intent.status == "succeeded"
charge = @payment_intent.charges.data.first
card = charge.payment_method_details.card
purchase = Purchase.create(
customer_id: charge.id,
user_id: current_user.id,
recipe_id: @recipe.id,
uuid: SecureRandom.uuid,
amount: @recipe.price
)
current_user.favorites << @recipe
redirect_to recipe_path(@recipe.slug), notice: "#{@recipe.title} has been added to your Cookbook, thanks for purchasing!"
else
flash[:alert] = "Your order was unsuccessful. Please try again."
redirect_to recipe_purchase_path(@recipe.id)
end
end
private
def set_recipe
@recipe = Recipe.find(params[:recipe_id])
end
end
purchases.index.js
document.addEventListener("turbolinks:load", () => {
const form = document.querySelector("#payment-form")
if (form == null) { return }
const public_key = document.querySelector("meta[name='stripe-key']").getAttribute("content")
const stripe = Stripe(public_key)
const elements = stripe.elements()
const card = elements.create('card')
card.mount('#card-element')
card.addEventListener("change", (event) => {
var displayError = document.getElementById('card-errors')
if (event.error) {
displayError.textContent = event.error.message
} else {
displayError.textContent = ''
}
})
form.addEventListener("submit", (event) => {
event.preventDefault()
let data = {
payment_method: {
card: card,
billing_details: {
name: form.querySelector("#name_on_card").value
}
}
}
stripe.confirmCardPayment(form.dataset.paymentIntentId, data).then((result) => {
if (result.error) {
var errorElement = document.getElementById('card-errors')
errorElement.textContent = result.error.message
} else {
//
//
form.submit()
}
})
})
})
下面是我的subscriptions.js文件
document.addEventListener("turbolinks:load", () => {
let cardElement = document.querySelector("#card-element")
if (cardElement !== null) { setupStripe() }
})
function setupStripe() {
const stripe_key = document.querySelector("meta[name='stripe-key']").getAttribute("content")
const stripe = Stripe(stripe_key)
const elements = stripe.elements()
const card = elements.create('card')
card.mount('#card-element')
var displayError = document.getElementById('card-errors')
card.addEventListener('change', (event) => {
if (event.error) {
displayError.textContent = event.error.message
} else {
displayError.textContent = ''
}
})
const form = document.querySelector("#payment-form")
let paymentIntentId = form.dataset.paymentIntent
let setupIntentId = form.dataset.setupIntent
if (paymentIntentId) {
if (form.dataset.status == "requires_action") {
stripe.confirmCardPayment(paymentIntentId, { setup_future_usage: 'off_session' }).then((result) => {
if (result.error) {
displayError.textContent = result.error.message
form.querySelector("#card-details").classList.remove("d-none")
} else {
form.submit()
}
})
}
}
form.addEventListener('submit', (event) => {
event.preventDefault()
let name = form.querySelector("#name_on_card").value
let data = {
payment_method_data: {
card: card,
billing_details: {
name: name,
}
}
}
// Complete a payment intent
if (paymentIntentId) {
stripe.confirmCardPayment(paymentIntentId, {
payment_method: data.payment_method_data,
setup_future_usage: 'off_session',
save_payment_method: true,
}).then((result) => {
if (result.error) {
displayError.textContent = result.error.message
form.querySelector("#card-details").classList.remove("d-none")
} else {
form.submit()
}
})
// Updating a card or subscribing with a trial (using a SetupIntent)
} else if (setupIntentId) {
stripe.confirmCardSetup(setupIntentId, {
payment_method: data.payment_method_data
}).then((result) => {
if (result.error) {
displayError.textContent = result.error.message
} else {
addHiddenField(form, "payment_method_id", result.setupIntent.payment_method)
form.submit()
}
})
} else {
//subscribing w no trial
data.payment_method_data.type = 'card'
stripe.createPaymentMethod(data.payment_method_data).then((result) => {
if (result.error) {
displayError.textContent = result.error.message
} else {
addHiddenField(form, "payment_method_id", result.paymentMethod.id)
form.submit()
}
})
}
})
}
function addHiddenField(form, name, value) {
let input = document.createElement("input")
input.setAttribute("type", "hidden")
input.setAttribute("name", name)
input.setAttribute("value", value)
form.appendChild(input)
}
所以特别感谢Chris Oliver在这方面。。。但是需要做的是在show.html.erb上我必须将表单数据中的payment_intent_id更改为:payment_intent。
<%= form_with url: recipe_purchase_path(@recipe.id), local: true, id: "payment-form", data: { payment_intent: @payment_intent.client_secret } do |form| %>
然后在purchases_controller.rb中的show操作中,我需要添加customer
def show
@payment_intent = Stripe::PaymentIntent.create(
amount: @recipe.price_in_cents,
currency: 'usd',
payment_method_types: ['card'],
customer: current_user.stripe_id || current_user.stripe_customer.id
)
end
然后我完全删除了我的purchases.js,因为一次性付款是在subscription.js中处理的。
我试图在stripe中收取一次性的第一个月订阅费,但我不知道怎么做,因为他们更改了界面。 在第一个月订阅费的初始费用之后,它应该按月滚动。 理想的情况下,我期待着这样做与拉威尔收银员。 欢迎提供任何想法和示例。
问题内容: 我有一个要添加“立即付款”按钮的产品列表,这样我就可以允许我的客户通过Paypal付款。 我已经阅读了文档,找不到如何执行此操作。我可以添加多个项目,但这不会很方便,因为我已经有要处理的项目列表。我还需要结帐流程来逐项列出订单,因此以1个价格“立即购买”也不是一件好事。 任何帮助表示赞赏的人,我都尝试过(没有运气): 问题答案: 请参阅此示例,并相应地进行更改。基本上将下划线添加到项目
wx.BaaS.pay(OBJECT) OBJECT 参数说明 参数 类型 必填 参数描述 totalCost Number Y 支付总额 merchandiseDescription String Y 微信支付凭证-商品详情的内容 merchandiseSchemaID Integer N 商品表 ID,可用于定位用户购买的物品 merchandiseRecordID String N 商品记录
1、新版支付宝支付配置 配置支付宝支付之前,需要到支付宝商家中心开通手机网站应用和电脑网站应用两个产品。 产品开通链接:快捷手机wap支付 电脑网站支付 一个工作日即可通过审核,完成产品签约。 接下来,介绍支付宝支付配置教程。 第一步 登录商城后台,设置->交易设置->支付配置 ,选择支付宝支付,点击配置,进入到支付宝支付参数配置界面,选择新版支付宝。 需要我们配置应用APPID、应用私钥、应用公
本文向大家介绍支付宝支付开发——当面付条码支付和扫码支付实例,包括了支付宝支付开发——当面付条码支付和扫码支付实例的使用技巧和注意事项,需要的朋友参考一下 本文介绍支付宝中当面付下属的条码支付、扫码支付、订单查询、退款申请的集成开发过程。 本文分为以下五个部分: 条码支付和扫码支付介绍 申请应用 密钥生成及配置 API及SDK集成 条码支付、扫码支付、订单查询、退款申请 一、条码支付及二维码支
本文向大家介绍SpringBoot集成支付宝沙箱支付(支付、退款),包括了SpringBoot集成支付宝沙箱支付(支付、退款)的使用技巧和注意事项,需要的朋友参考一下 前言 支付宝推出一个沙箱环境,能够很好的模拟支付宝支付,并且还提供了demo,但demo是一个普通web项目,怎么整合到Spring Boot项目呢,其实很简单 简单配置请参照支付宝沙箱支付开发文档 一、支付部分 AlipayCon
说明 微信扫码支付(模式一)SDK。 不通过接口,直接生成以weixin://开头的url,并生成二维码让用户扫描。 用户支付后,公众平台后台设置的支付回调URL会接收到消息。 官方文档: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4 https://pay.weixin.qq.com/wiki/doc/api/nati
更新问题-添加更多详细信息。当我尝试支付订单时,我从PayPal收到一个500(内部服务错误)错误。 我从创建订单中获得ok,并获得创建的orderID订单状态。订单被买方成功批准,订单状态成为批准。 由创建的订单https://api.sandbox.paypal.com/v1/checkout/orders 批准使用贝宝https://www.paypalobjects.com/api/che