为 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的主要内容,如果未能解决你的问题,请参考以下文章

Paypal IPN,缺少 POST 数据

PHP Paypal IPN:交易未确认

paypal 按钮/IPN 发票名称

Paypal IPN - 返回时自定义为空

wordpress 的简单 php paypal ipn

PayPal 即时付款通知 (IPN) 无法正常工作 ASP.NET C#