require 'net/http' module AbtainBilling #:nodoc: module Billing #:nodoc: module Integrations #:nodoc: module Paypal # Parser and handler for incoming Instant payment notifications from paypal. # The Example shows a typical handler in a rails application. Note that this # is an example, please read the Paypal API documentation for all the details # on creating a safe payment controller. # # Example # # class BackendController < ApplicationController # include AbtainBilling::Billing::Integrations # # def paypal_ipn # notify = Paypal::Notification.new(request.raw_post) # # order = Order.find(notify.item_id) # # if notify.acknowledge # begin # # if notify.complete? and order.total == notify.amount # order.status = 'success' # # shop.ship(order) # else # logger.error("Failed to verify Paypal's notification, please investigate") # end # # rescue => e # order.status = 'failed' # raise # ensure # order.save # end # end # # render :nothing # end # end class Notification < AbtainBilling::Billing::Integrations::Notification include PostsData # Was the transaction complete? def complete? status == "Completed" end # When was this payment received by the client. # sometimes it can happen that we get the notification much later. # One possible scenario is that our web application was down. In this case paypal tries several # times an hour to inform us about the notification def received_at Time.parse params['payment_date'] end # Status of transaction. List of possible values: # Canceled-Reversal:: # Completed:: # Denied:: # Expired:: # Failed:: # In-Progress:: # Partially-Refunded:: # Pending:: # Processed:: # Refunded:: # Reversed:: # Voided:: def status params['payment_status'] end # Id of this transaction (paypal number) def transaction_id params['txn_id'] end # What type of transaction are we dealing with? # "cart" "send_money" "web_accept" are possible here. def type params['txn_type'] end # the money amount we received in X.2 decimal. def gross params['mc_gross'] end # the markup paypal charges for the transaction def fee params['mc_fee'] end # What currency have we been dealing with def currency params['mc_currency'] end # This is the item number which we submitted to paypal # The custom field is also mapped to item_id because PayPal # doesn't return item_number in dispute notifications def item_id params['item_number'] || params['custom'] end # This is the invoice which you passed to paypal def invoice params['invoice'] end # Was this a test transaction? def test? params['test_ipn'] == '1' end def account params['business'] || params['receiver_email'] end # Acknowledge the transaction to paypal. This method has to be called after a new # ipn arrives. Paypal will verify that all the information we received are correct and will return a # ok or a fail. # # Example: # # def paypal_ipn # notify = PaypalNotification.new(request.raw_post) # # if notify.acknowledge # ... process order ... if notify.complete? # else # ... log possible hacking attempt ... # end def acknowledge payload = raw response = ssl_post(Paypal.service_url + '?cmd=_notify-validate', payload, 'Content-Length' => "#{payload.size}", 'User-Agent' => "Active Merchant -- http://activemerchant.org" ) raise StandardError.new("Faulty paypal result: #{response}") unless ["VERIFIED", "INVALID"].include?(response) response == "VERIFIED" end end end end end end