Skip to content

Instantly share code, notes, and snippets.

@weapp
Last active February 8, 2017 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weapp/f7a8fcb8a810c49c6761d7855b216b28 to your computer and use it in GitHub Desktop.
Save weapp/f7a8fcb8a810c49c6761d7855b216b28 to your computer and use it in GitHub Desktop.
Paypal + Sinatra Integration
require 'sinatra'
require 'uri'
require 'pry'
require 'uri'
require 'faraday'
String.class_eval do
def join
self
end
def each
yield self
end
end
require 'uri'
def unscape msg
URI.unescape(msg.to_s)
rescue
msg.to_s
end
def faraday_logger
@faraday_logger ||= Logger.new("faraday.log").tap do |logger|
logger.formatter = proc { |severity, datetime, progname, msg| "\n<<<\n#{unscape(msg)}\n>>>\n" }
end
end
class MyLogger < Faraday::Response::Logger
def initialize(app)
super(app, faraday_logger)
end
end
def nvm(options)
faraday_logger.info( "\nSTART\n" )
conn = Faraday.new(:url => "https://api-3t.sandbox.paypal.com") do |faraday|
# faraday.response :logger # log requests to STDOUT
faraday.use MyLogger
faraday.adapter Faraday.default_adapter
end
response = conn.get '/nvp', {
USER: ENV['USER'],
PWD: ENV['PWD'],
SIGNATURE: ENV['SIGNATURE'],
VERSION: '204',
IPADDRESS: '127.0.0.1',
}.merge(options)
faraday_logger.info(response.body)
faraday_logger.info( "\nEND\n" )
Rack::Utils.parse_nested_query(response.body)
end
def request_pairing(base)
response = nvm(RETURNURL: "#{base}/return",
CANCELURL: "#{base}/cancel",
NOSHIPPING: 1,
METHOD: 'SetExpressCheckout',
BILLINGTYPE: 'MerchantInitiatedBilling')
puts "SetExpressCheckout (request_pairing):"
pp response
token = response['TOKEN']
"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#{token}"
end
get '/' do
paypal_url = request_pairing(request.base_url)
%{
<h3>
<a style="display:block;padding:20% 3em 0;" href="#{paypal_url}">#{paypal_url}</a>
<br>
<a style="display:block;padding:0 3em 20%;" href="/transactions">transactions</a>
</h3>
}
end
def details(token)
nvm(METHOD: "GetExpressCheckoutDetails", TOKEN: token)
end
def pairing(token)
nvm(METHOD: "CreateBillingAgreement", TOKEN: token)
end
def do_reference_transaction(options)
description = options[:description].gsub(/[^a-zA-Z0-9\-\*\.\s]/, '')
nvm(METHOD: "DoReferenceTransaction",
PAYMENTACTION: 'Sale',
IPADDRESS: options[:ip],
MERCHANTSESSIONID: options[:user_id],
SOFTDESCRIPTOR: description,
ReferenceID: options[:billing_agreement_id],
AMT: options[:amount],
CURRENCYCODE: options[:currency],
BUTTONSOURCE: options[:transaction_key],
L_NAME0: description,
L_AMT0: options[:amount],
L_QTY0: 1)
end
get '/return' do
puts "GetExpressCheckoutDetails:"
pp details(request.params['token'])
puts
response = pairing(request.params['token'])
puts "CreateBillingAgreement (pairing)"
pp response
agreemt_id = response['BILLINGAGREEMENTID']
redirect to("/do_reference_transaction?agreemt_id=#{agreemt_id}")
end
get '/do_reference_transaction' do
agreemt_id = params[:agreemt_id]
response = do_reference_transaction(ip: '127.0.0.1',
user_id: 1,
description: 'desc',
amount: 0.20,
currency: :EUR,
billing_agreement_id: agreemt_id,
transaction_key: "tid")
puts "DoReferenceTransaction"
pp response
"<pre>#{response.to_s.split(",").join(",\n")}</pre>"
end
require 'json'
def transactions_from(date=nil)
response = nvm(METHOD: "TransactionSearch", STARTDATE: date || '2015-01-01T00:00:00Z')
r = 100.times.map do |idx|
if response["L_TIMESTAMP#{idx}"]
{
timestamp: response.delete("L_TIMESTAMP#{idx}"),
timezone: response.delete("L_TIMEZONE#{idx}"),
type: response.delete("L_TYPE#{idx}"),
email: response.delete("L_EMAIL#{idx}"),
name: response.delete("L_NAME#{idx}"),
transaction_id: response.delete("L_TRANSACTIONID#{idx}"),
status: response.delete("L_STATUS#{idx}"),
amt: response.delete("L_AMT#{idx}"),
currency: response.delete("L_CURRENCYCODE#{idx}"),
fee: response.delete("L_FEEAMT#{idx}"),
net: response.delete("L_NETAMT#{idx}"),
}
end
end
response['max_timestamp'] = (r.compact.max_by { |x| x[:timestamp] })
response['max_timestamp'] = response['max_timestamp'] && response['max_timestamp'][:timestamp]
response['transactions'] = r.compact
p response
if response['transactions'].count == 100
[response, *transactions_from(date=response['max_timestamp'])]
else
[response]
end
end
get '/transactions/:date?' do
response = transactions_from(params[:date])
"<pre>#{JSON.pretty_generate(response)}</pre>"
end
# -*- coding: utf-8 -*-
source 'https://rubygems.org'
gem 'sinatra'
gem 'faraday'
GEM
remote: https://rubygems.org/
specs:
faraday (0.9.1)
multipart-post (>= 1.2, < 3)
multipart-post (2.0.0)
rack (1.6.0)
rack-protection (1.5.3)
rack
sinatra (1.4.5)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
tilt (1.4.1)
PLATFORMS
ruby
DEPENDENCIES
faraday
sinatra
BUNDLED WITH
1.13.6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment