为 PayPal 创建 IPN URL
Posted
技术标签:
【中文标题】为 PayPal 创建 IPN URL【英文标题】:Creating IPN URL for PayPal 【发布时间】:2014-07-17 23:18:39 【问题描述】:我使用 paypal recurring gem 设置了 PayPal。我需要帮助了解如何实施 PayPal IPN。
任何帮助将不胜感激,因为这是我项目的最后一步。我需要设置 IPN,以便当用户从他们的 PayPal 帐户取消/暂停计费时,它将显示为从我的数据库中取消。
Paypal_payment.rb:
def initialize(subscription)
@subscription = subscription
end
def checkout_details
process :checkout_details
end
def checkout_url(options)
process(:checkout, options).checkout_url
end
def make_recurring
process :request_payment
process :create_recurring_profile, period: :monthly, frequency: 1, start_at: Time.zone.now
end
def suspend
process :suspend, :profile_id => @subscription.paypal_recurring_profile_token
end
def reactivate
process :reactivate, :profile_id => @subscription.paypal_recurring_profile_token
end
private
def process(action, options = )
options = options.reverse_merge(
token: @subscription.paypal_payment_token,
payer_id: @subscription.paypal_customer_token,
description: @subscription.plan.name,
amount: @subscription.plan.price,
ipn_url: "http://mydomain.com/paypal/ipn",
currency: "USD"
)
response = PayPal::Recurring.new(options).send(action)
raise response.errors.inspect if response.errors.present?
response
end
end
订阅.rb:
belongs_to :plan
belongs_to :subscription
belongs_to :user
validates_presence_of :plan_id
validates_presence_of :email
attr_accessor :stripe_card_token, :paypal_payment_token
def expires_at
self.updated_at + plan.duration.days
end
def save_with_payment
if valid?
if paypal_payment_token.present?
save_with_paypal_payment
else
save_with_stripe_payment
end
end
end
def paypal
PaypalPayment.new(self)
end
def save_with_paypal_payment
response = paypal.make_recurring
self.paypal_recurring_profile_token = response.profile_id
save!
end
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
save!
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while creating customer: #e.message"
errors.add :base, "There was a problem with your credit card."
false
end
def payment_provided?
stripe_card_token.present? || paypal_payment_token.present?
end
def suspend_paypal
paypal.suspend
save
end
def reactivate_paypal
paypal.reactivate
save
end
def update_card(subscriber, card_info)
token = Stripe::Token.create(
card:
number: card_info[:number],
exp_month: card_info[:exp_month],
exp_year: card_info[:exp_year],
cvc: card_info[:cvc]
)
customer = Stripe::Customer.retrieve(user.subscription.stripe_customer_token)
card = customer.cards.create(card: token.id)
card.save
customer.default_card = card.id
customer.save
rescue Stripe::InvalidRequestError => e
logger.error "Stripe error while updating card info: #e.message"
errors.add :base, "#e.message"
false
end
end
订阅控制器:
def new
plan = Plan.find(params[:plan_id])
@subscription = plan.subscriptions.build
if params[:PayerID]
@subscription.paypal_customer_token = params[:PayerID]
@subscription.paypal_payment_token = params[:token]
@subscription.email = @subscription.paypal.checkout_details.email
end
end
def create
@subscription = Subscription.new(params[:subscription])
if @subscription.save_with_payment
redirect_to @subscription, :notice => "Thank you for subscribing!"
else
render :new
end
end
def show
@subscription = Subscription.find(params[:id])
end
def paypal_checkout
plan = Plan.find(params[:plan_id])
subscription = plan.subscriptions.build
redirect_to subscription.paypal.checkout_url(
return_url: new_subscription_url(:plan_id => plan.id),
cancel_url: root_url
)
end
def updatesubscription
@user = current_user
@customer = Stripe::Customer.retrieve(@user.subscription.stripe_customer_token)
if @user.subscription.plan_id == 12
@customer.update_subscription(:plan => "1", :prorate => true)
current_user.subscription.update_attributes(:plan_id => 1)
flash.alert = 'Your subscription has been changed to monthly!'
redirect_to root_url
elsif @user.subscription.plan_id == 1
@customer.update_subscription(:plan => "12", :prorate => true)
current_user.subscription.update_attributes(:plan_id => 12)
current_user.save!
flash.alert = 'Your subscription has been changed to annually!'
redirect_to root_url
end
end
def cancelsubscription
@user = current_user
@customer = Stripe::Customer.retrieve(@user.subscription.stripe_customer_token)
@customer.cancel_subscription()
current_user.subscription.update_attributes(:cancelled => 1)
current_user.save!
flash.alert = 'Your subscription has been cancelled successfully!'
redirect_to root_url
end
def showcard
@user = current_user
Stripe::Customer.retrieve(@user.subscription.stripe_customer_token).cards.all()
end
def suspend
@user = current_user
@user.subscription.suspend_paypal
current_user.subscription.update_attributes(:cancelled => 1)
flash.alert = 'Billing has been suspended!'
redirect_to root_url
end
def reactivate
@user = current_user
@user.subscription.reactivate_paypal
current_user.subscription.update_attributes(:cancelled => nil)
flash.alert = 'Billing has been activated!'
redirect_to root_url
end
def edit_card
@user = current_user
end
def update_card
@user = current_user
card_info =
name: params[:name],
number: params[:number],
exp_month: params[:date][:month],
exp_year: params[:date][:year],
cvc: params[:cvc]
if @user.subscription.update_card(@subscriber, card_info)
flash.alert = 'Saved. Your card information has been updated.'
redirect_to root_url
else
flash.alert = 'Stripe reported an error while updating your card. Please try again.'
redirect_to root_url
end
end
end
路线:
post "paypal/ipn" => "notifications#create"
付款通知控制器:
def index
redirect_to root_url
end
def create
PaymentNotification.create!(:params => params, :status => params[:payment_status], :transaction_id => params[:txn_id])
render :nothing => true
end
end
通知控制器:
def create
query = params
query[:cmd] = "_notify-validate"
if(response.body == "VERIFIED")
Rails.logger.debug params.inspect "Notification is valid"
end
end
end
【问题讨论】:
旁注:注意 PayPal 'refund' hack(etsy.com/teams/7718/questions/discuss/12758905) 【参考方案1】:你需要修正你的路线。
应该是:
match '/paypal/ipn' => 'notifications#create', :via => [:get, :post], :as => 'notifications_create'
【讨论】:
【参考方案2】:所以你唯一的问题是让 IPN 在你的测试帐户中触发..??当您使用模拟器时,一切都按预期工作吗?
要让 IPN 在沙盒中正常工作,您需要做的就是确保在您的沙盒卖家帐户资料中启用它。您可以通过http://sandbox.paypal.com 登录您的沙盒帐户,就像您使用真实帐户一样。一旦你在那里进入配置文件,然后进入 IPN 设置,这样你就可以启用它并相应地设置 URL。
【讨论】:
问题是我应该如何定义我的 IPN url,以便我可以为 PayPal 沙箱提供 IPN。 这就是我刚才解释的。 我了解如何启用/禁用 IPN。我问我是否需要在控制器中创建一个方法来创建一个我可以测试的 IPN URL?我不确定如何生成 IPN URL,以便可以与 Paypal 一起使用。 你可以按照你想要的任何方式构建它,真的。它只不过是可以通过公共 URL 访问的某种脚本(或至少对 PayPal 的 IP 地址开放)。 IPN 本质上只是一个用于 POST 的,因此您只需要设置一个可以相应地处理此 POST 数据的侦听器。 嗨,Cornelius,我想知道您是否需要隧道。如果是这种情况,那么试试这个:ngrok.com。如果它不起作用,请告诉我。【参考方案3】:PayPal developer site 中有一个 IPN 测试工具。您可以向它提供您的回调 URL 并发送示例调用。您必须先注册才能使用它。
【讨论】:
以上是关于为 PayPal 创建 IPN URL的主要内容,如果未能解决你的问题,请参考以下文章