Created
March 8, 2014 10:03
-
-
Save manuelmeurer/9428199 to your computer and use it in GitHub Desktop.
Paypal Recurring stuff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Admin::PaypalController < AdminController | |
skip_load_and_authorize_resource | |
before_filter :load_current_account, except: :ipn | |
skip_before_filter :authenticate_admin_user!, :verify_authenticity_token, :redirect_to_dashboard_if_account_is_disabled, :redirect_to_dashboard_if_maintenance, only: :ipn | |
rescue_from PaypalNotification::RecordInvalid, with: :notify_airbrake_and_render_nothing | |
rescue_from PaypalNotification::ResponseInvalid, with: :notify_airbrake_and_render_nothing | |
rescue_from PaypalNotification::HandlingFailed, with: :notify_airbrake_and_render_nothing | |
def setup_recurring | |
redirect_to PaypalRecurring.new(@account).checkout_url | |
end | |
def confirm_recurring | |
raise StandardError, 'No PayerID supplied.' if params[:PayerID].blank? | |
@account.paypal_customer_token = params[:PayerID] | |
@account.paypal_payment_token = params[:token] | |
response = PaypalRecurring.new(@account).make_recurring | |
@account.paypal_recurring_profile_token = response.profile_id | |
@account.save! | |
redirect_to admin_my_account_path, notice: 'Successfully set up Paypal subscription.' | |
end | |
def ipn | |
response = RestClient.post( | |
PayPal::Recurring.site_endpoint, | |
['cmd=_notify-validate', request.raw_post].join('&') | |
) | |
begin | |
paypal_notification = PaypalNotification.create!(params: params.except('controller', 'action')) | |
rescue PaypalNotification::DuplicateRecord | |
# Duplicate | |
render nothing: true and return | |
rescue ActiveRecord::RecordInvalid => e | |
raise PaypalNotification::RecordInvalid, e.message | |
end | |
if response.code == 200 | |
case response.body | |
when 'VERIFIED' | |
paypal_notification.handle! if paypal_notification.persisted? | |
when 'INVALID' | |
raise PaypalNotification::ResponseInvalid, "Paypal said notification validation request was invalid: #{response.inspect}" | |
else | |
raise PaypalNotification::ResponseInvalid, "Unexpected response from Paypal: #{response.inspect}" | |
end | |
else | |
raise PaypalNotification::ResponseInvalid, "Unexpected response code from Paypal: #{response.inspect}" | |
end | |
render nothing: true | |
end | |
private | |
def notify_airbrake_and_render_nothing(exception) | |
notify_airbrake exception | |
render nothing: true | |
end | |
def load_current_account | |
@account = current_admin_user.account | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# == Schema Information | |
# | |
# Table name: paypal_notifications | |
# | |
# id :integer(4) not null, primary key | |
# status :string(255) | |
# transaction_id :string(255) | |
# params :text | |
# account_id :integer(4) | |
# created_at :datetime | |
# updated_at :datetime | |
# payment_id :integer(4) | |
# | |
class PaypalNotification < ActiveRecord::Base | |
belongs_to :account | |
belongs_to :payment | |
validates :account, presence: true | |
validates :params, presence: true | |
validates :transaction_id, | |
uniqueness: true, | |
allow_blank: true | |
serialize :params, Hash | |
before_validation :set_defaults, on: :create | |
before_validation :check_for_duplicate, on: :create | |
class RecordInvalid < StandardError; end | |
class ResponseInvalid < StandardError; end | |
class DuplicateRecord < StandardError; end | |
class HandlingFailed < StandardError; end | |
def handle! | |
return unless self.status == 'Completed' | |
raise StandardError, 'Paypal notification has already been handled.' if self.payment.present? | |
payment = self.account.payments.build( | |
title: self.params['item_name'], | |
amount: self.params['mc_gross'].gsub(/[.,]/, '').to_i | |
) | |
if self.params.has_key?('item_number') | |
payment.product_package = ProductPackage.from_template(self.params['item_number'].to_i) | |
payment.product_package.account = self.account | |
else | |
Airbrake.notify \ | |
error_class: 'PaypalNotificationWithoutItemNumberReceived', | |
error_message: "Paypal notification #{self.id} does not have a item number so no product package has been created." | |
end | |
payment.save! | |
self.payment = payment | |
self.save! | |
rescue StandardError => e | |
raise HandlingFailed, e.message | |
end | |
private | |
def set_defaults | |
self.account ||= Account.find(self.params['custom']) if self.params.has_key?('custom') | |
self.transaction_id ||= self.params['txn_id'] if self.params.has_key?('txn_id') | |
self.status ||= self.params['payment_status'] if self.params.has_key?('payment_status') | |
end | |
def check_for_duplicate | |
raise DuplicateRecord if self.transaction_id.present? && self.class.exists?(transaction_id: self.transaction_id) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PaypalRecurring | |
include ApplicationHelper | |
def initialize(account) | |
@account = account | |
end | |
def checkout_url | |
process(:checkout).checkout_url | |
end | |
def make_recurring | |
process :request_payment | |
process :create_recurring_profile, | |
period: :monthly, | |
frequency: 1, | |
start_at: @account.trial_end_date.advance(days: 1) | |
end | |
private | |
def process(action, options = {}) | |
opts = options.reverse_merge( | |
return_url: Rails.application.routes.url_helpers.admin_paypal_confirm_recurring_url(host: "admin.#{AppConfig.host}"), | |
cancel_url: Rails.application.routes.url_helpers.admin_my_account_url(host: "admin.#{AppConfig.host}"), | |
ipn_url: Rails.application.routes.url_helpers.admin_paypal_ipn_url(host: "admin.#{AppConfig.host}"), | |
token: @account.paypal_payment_token, | |
payer_id: @account.paypal_customer_token, | |
description: I18n.t(:paypal, amount: format_price(@account.current_plan.amount), date: @account.current_billing_period.next.start_date.to_s(:long)), | |
amount: '%.2f' % @account.current_plan.amount, | |
currency: 'USD', | |
locale: :us | |
) | |
PayPal::Recurring.new(opts).send(action).tap do |response| | |
raise response.errors.inspect if response.errors.present? | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment