Trace: • activemerchant
ActiveMerchant
ActiveMerchant is a plugin that interfaces with payment gateways. I'm using it to connect to paypal.com, so all information presented here is based on that premise. It's easy to use, but there are a few details to be aware of.
Sources:
Testing
ActiveMerchant operates in a special test mode. Configure your Rails app accordingly:
unless RAILS_ENV == 'production' PAYPAL_ACCOUNT = 'seller@example.com' ActiveMerchant::Billing::Base.mode = :test else PAYPAL_ACCOUNT = 'paypalaccount@example.com' end
Put this code in your config/environment.rb
file.
You're now ready to follow the instructions from the sites mentioned above (under Sources). First, however, we're going to make a small modification to ActiveMerchant. By default, ActiveMerchant tries to communicate with paypal through ssl. In Paypal's sandbox however, ssl only seems to work through port 80 (instead of the default 443 ssl port). Let's adjust ActiveMerchant accordingly:
In the file vendor/plugins/activemerchant/lib/active_merchant/lib/posts_data.rb
, look for the method ssl_post
. Now change the method definition to look like this:
def ssl_post(url, data, headers = {}) uri = URI.parse(url) mode = ActiveMerchant::Billing::Base.mode case mode when :test port = 80 # Apparently paypal uses port 80 for testing purposes else port = uri.port end #http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, port) ...(etc.)... end
Here, we change the http port to 80 if we're in test mode.
We can take this one step further: why not communicate in plain text, while we're testing? In the same file, add this method:
def plain_post(url, data, headers = {}) uri = URI.parse(url) http = Net::HTTP.new(uri.host, 80) http.post(uri.request_uri, data, headers).body end
This is just a trimmed down post method. If you want to, you can copy the error handling over from def ssl_post
. Now, move to vendor/plugins/activemerchant/lib/active_merchant/billing/integrations/paypal/notification.rb
. In this file, modify the acknowledge
method:
def acknowledge(method = 'ssl_post') payload = raw response = self.send(method, 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
Here, we call ssl_post by default (so ActiveMerchant's default behavior is not in any way altered). But if you call the acknowledge method in your payment_controller
, you can now supply the argument plain_post
if you're in test mode and don't want to use ssl at all:
def notify notification = Paypal::Notification.new(request.raw_post) if notification.acknowledge('plain_post') ... (etc.) ... end
Exposing IPN Variables
If you use Paypal's Instant Payment Notification (IPN) service, Paypal will keep you informed about the details of the transaction by posting the IPN variables to a url on your server. ActiveMerchant exposes these variables for you, so you can do stuff like:
transaction = Transaction.new(:status => notification.status, :order_id => order.id, :user_id => game.user_id, :invoice => notification.invoice.to_s, :currency_code => notification.currency.to_s, :amount => notification.amount.to_s, :invoice_date => DateTime.now, :raw_paypal_data => request.raw_post)
The IPN variables are stored in an object of class Notification
. By default, the custom
field (which you can use to store your own value) is mapped to item_id because PayPal doesnât return item_number in dispute notifications. That's great, but what if we really need to send along our own custom variable? Here's a fix, applied in ActiveMerchant::Billing::Integrations::Notification
:
# Expose the custom variable separately (added by Onno Schuit, o.schuit residing_at_or_around solin.nl) def custom params['custom'] end
You are here: start » ror » activemerchant