Skip to content

Instantly share code, notes, and snippets.

@lulalala
Last active August 29, 2015 14:09
Show Gist options
  • Select an option

  • Save lulalala/8263a700846412a080be to your computer and use it in GitHub Desktop.

Select an option

Save lulalala/8263a700846412a080be to your computer and use it in GitHub Desktop.
Payment Notification
# in OrdersController
def payment_notify
l = PaymentNotification.new
l.order_id = params[:id]
l.payment_method_id = params[:payment_method_id]
l.url = request.fullpath
l.raw_post = request.raw_post
l.data = {remote_ip:request.remote_ip}
begin
l.save!
rescue => e
l.update_attributes(error:e)
if Rails.env.production?
render text:'error', status:500 and return
else
raise
end
end
case PaymentMethod.find(params[:payment_method_id]).class.merchant_name
when :allpay
render text:'1|OK', status:200 and return
when :paypal
render text:'', status:200 and return
end
end
create_table "payment_notifications", force: true
t.integer "order_id", limit: 4
t.integer "payment_method_id", limit: 4
t.string "url", limit: 255
t.text "raw_post", limit: 65535
t.text "notification", limit: 65535
t.text "data", limit: 65535
t.text "error", limit: 65535
t.datetime "created_at"
end
class PaymentNotification < ActiveRecord::Base
belongs_to :order
belongs_to :payment_method
serialize :data
serialize :notification
serialize :error
validates :raw_post, :order_id, :payment_method_id, :url, presence:true
# Analyze notification
# and if all is well, mark order as paid.
def process
if order.payment_method != payment_method
raise MismatchError, 'payment method mismatch'
end
if !order.processing? && !order.paid_with_error?
raise IgnorableError, 'order already paid'
end
if notification.nil?
update_attributes(notification:get_notification)
end
# Check notification is legit
if notification.respond_to? :acknowledge
if !notification.acknowledge
raise MismatchError, 'acknowledge failed'
end
end
if !notification.complete?
raise IgnorableError, 'notification not complete'
end
if order_id.to_s != notification.item_id
raise MismatchError, 'order id mismatch'
end
if payment.total != notification.gross.amount.to_i
raise MismatchError, 'amount mismatch'
end
order.pay!
rescue => e
if e.is_a? ConsiderPaidError
if order.processing?
order.pay_with_error!
end
end
if e.is_a?(MismatchError) || e.is_a?(ConsiderPaidError)
# Let admin know about this.
end
self.error = {message:e.message, backtrace:e.backtrace}
save!
end
# Notification does not match our data, possible hack.
class MismatchError < StandardError; end
# Notification ignorable e.g. payment failed notification
class IgnorableError < StandardError; end
# Can be consider paid, just need to inform admin to take a look at.
class ConsiderPaidError < StandardError; end
# Obtain notification object from params
def get_notification
# Convert raw_post to utf-8 when necessary
if payment_method.class.merchant_name == :paypal && raw_post.include?('Big5')
utf8_raw_post = raw_post.encode('utf-8', 'big5')
else
utf8_raw_post = raw_post
end
payment_method.class.active_merchant.notification(utf8_raw_post)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment