astrails-paypal_adaptive 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Tommy Chheng
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,107 @@
1
+ # paypal_adaptive
2
+ This gem is a lightweight wrapper for the paypal adaptive payments API.
3
+
4
+ This is very much a work in progress! Use at your own risk or submit bug fixes :)
5
+
6
+ Before you need start, read the API manual https://www.x.com/docs/DOC-1531 and check out the forums on http://x.com
7
+ It'll be invaluable for parameters and error messages. The gem keeps the request/response as hashes so you will have to
8
+ read the manual to make the proper calls. I made a few test cases for further examples at http://github.com/tc/paypal_adaptive/tree/master/test/
9
+
10
+ ## Changes to the Lottay Version
11
+ This branch adds support for PayPal Adaptive Accounts. An Adaptive Accounts request looks very similar to the Pay Request.
12
+ You simply post a hash of signup parameters to PayPal using the "create_account" method, and receive a URL to which you redirect the user to finish signup.
13
+
14
+ See the unit tests in "create_account_test.rb" for a good example.
15
+
16
+ ###Installation Instructions
17
+ Install the gem:
18
+ sudo gem install lottay-paypal_adaptive --source http://gemcutter.org
19
+ In environment.rb:
20
+ require 'paypal_adaptive'
21
+
22
+ ## HOWTO
23
+ Create paypal_adaptive.yml to your config folder:
24
+ development:
25
+ environment: "sandbox"
26
+ username: "sandbox_username"
27
+ password: "sandbox_password"
28
+ signature: "sandbox_signature"
29
+ application_id: "sandbox_app_id"
30
+ sandbox_email: "paypal_account_email_with_your_sandbox_account"
31
+
32
+ test:
33
+ environment: "sandbox"
34
+ username: "sandbox_username"
35
+ password: "sandbox_password"
36
+ signature: "sandbox_signature"
37
+ application_id: "sandbox_app_id"
38
+ sandbox_email: "paypal_account_email_with_your_sandbox_account"
39
+
40
+ production:
41
+ environment: "production"
42
+ username: "my_production_username"
43
+ password: "my_production_password"
44
+ signature: "my_production_signature"
45
+ application_id: "my_production_app_id"
46
+
47
+ Make the payment request:
48
+
49
+ pay_request = PaypalAdaptive::Request.new
50
+
51
+ data = {
52
+ "returnUrl" => "http://testserver.com/payments/completed_payment_request",
53
+ "requestEnvelope" => {"errorLanguage" => "en_US"},
54
+ "currencyCode"=>"USD",
55
+ "receiverList"=>{"receiver"=>[{"email"=>"testpp_1261697850_per@nextsprocket.com", "amount"=>"10.00"}]},
56
+ "cancelUrl"=>"http://testserver.com/payments/canceled_payment_request",
57
+ "actionType"=>"PAY",
58
+ "ipnNotificationUrl"=>"http://testserver.com/payments/ipn_notification"
59
+ }
60
+
61
+ pay_response = pay_request.pay(data)
62
+
63
+ if pay_response.success?
64
+ redirect_to pay_response.approve_paypal_payment_url
65
+ else
66
+ puts pay_response.errors.first['message']
67
+ redirect_to failed_payment_url
68
+ end
69
+
70
+ ---
71
+ Once the user goes to pay_response.approve_paypal_payment_url, they will be prompted to login to Paypal for payment.
72
+
73
+ Upon payment completion page, they will be redirected to http://testserver.com/payments/completed_payment_request.
74
+
75
+ They can also click cancel to go to http://testserver.com/payments/canceled_payment_request
76
+
77
+ The actual payment details will be sent to your server via "ipnNotificationUrl"
78
+ You have to create a listener to receive POST messages from paypal. I added a Rails metal template in the templates folder which handles the callback.
79
+
80
+ Additionally, you can make calls to Paypal Adaptive's other APIs:
81
+ payment_details, preapproval, preapproval_details, cancel_preapproval, convert_currency, refund
82
+
83
+ Input is just a Hash just like the pay method. Refer to the Paypal manual for more details.
84
+
85
+ ## Changelog
86
+ 0.1.0
87
+ Fixed IPN rails metal template by sending the correct params back: ipn.send_back(env['rack.request.form_vars'])
88
+ Thanks to github.com/JoN1oP for fixing this.
89
+
90
+ 0.0.5
91
+ Added Preapproval preapproval_paypal_payment_url along with test case.
92
+
93
+ 0.0.4
94
+ Preapproval now returns a PaypalAdaptive::Response class. Added preapproval test cases.
95
+
96
+ 0.0.3
97
+ Renamed PayRequest, PayResponse into Request, Response since other api calls use the class as well.
98
+
99
+ 0.0.2
100
+ Fixed initialized constant warning.
101
+
102
+ 0.0.1
103
+ First release.
104
+
105
+ ## Copyright
106
+
107
+ Copyright (c) 2009 Tommy Chheng. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "astrails-paypal_adaptive"
9
+ gem.summary = %Q{initial import}
10
+ gem.description = %Q{Lightweight wrapper for Paypal's Adaptive Payments API.}
11
+ gem.email = "boris@astrails.com"
12
+ gem.homepage = "http://github.com/astrails/paypal_adaptive"
13
+ gem.authors = ["Tommy Chheng", "Ross Hale", "Boris Nadion"]
14
+ gem.add_development_dependency "json", ">= 0"
15
+ gem.add_development_dependency "jsonschema", ">= 0"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/*_test.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
41
+ end
42
+
43
+ task :test => :check_dependencies
44
+
45
+ task :default => :test
46
+
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "lottay-paypal_adaptive #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,78 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{astrails-paypal_adaptive}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tommy Chheng", "Ross Hale", "Boris Nadion"]
12
+ s.date = %q{2011-02-09}
13
+ s.description = %q{Lightweight wrapper for Paypal's Adaptive Payments API.}
14
+ s.email = %q{boris@astrails.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ "LICENSE",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "astrails-paypal_adaptive.gemspec",
25
+ "config/paypal_adaptive.yml",
26
+ "lib/config.rb",
27
+ "lib/ipn_notification.rb",
28
+ "lib/pay_request_schema.json",
29
+ "lib/paypal_adaptive.rb",
30
+ "lib/request.rb",
31
+ "lib/response.rb",
32
+ "templates/paypal_ipn.rb",
33
+ "test/create_account_test.rb",
34
+ "test/data/invalid_chain_pay_request.json",
35
+ "test/data/invalid_parallel_pay_request.json",
36
+ "test/data/invalid_preapproval.json",
37
+ "test/data/invalid_simple_pay_request_1.json",
38
+ "test/data/valid_chain_pay_request.json",
39
+ "test/data/valid_create_account_request.json",
40
+ "test/data/valid_parallel_pay_request.json",
41
+ "test/data/valid_preapproval.json",
42
+ "test/data/valid_simple_pay_request_1.json",
43
+ "test/helper.rb",
44
+ "test/pay_request_schema_test.rb",
45
+ "test/pay_request_test.rb",
46
+ "test/payment_details_test.rb",
47
+ "test/preapproval_test.rb"
48
+ ]
49
+ s.homepage = %q{http://github.com/astrails/paypal_adaptive}
50
+ s.require_paths = ["lib"]
51
+ s.rubygems_version = %q{1.3.7}
52
+ s.summary = %q{initial import}
53
+ s.test_files = [
54
+ "test/create_account_test.rb",
55
+ "test/helper.rb",
56
+ "test/pay_request_schema_test.rb",
57
+ "test/pay_request_test.rb",
58
+ "test/payment_details_test.rb",
59
+ "test/preapproval_test.rb"
60
+ ]
61
+
62
+ if s.respond_to? :specification_version then
63
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
64
+ s.specification_version = 3
65
+
66
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
67
+ s.add_development_dependency(%q<json>, [">= 0"])
68
+ s.add_development_dependency(%q<jsonschema>, [">= 0"])
69
+ else
70
+ s.add_dependency(%q<json>, [">= 0"])
71
+ s.add_dependency(%q<jsonschema>, [">= 0"])
72
+ end
73
+ else
74
+ s.add_dependency(%q<json>, [">= 0"])
75
+ s.add_dependency(%q<jsonschema>, [">= 0"])
76
+ end
77
+ end
78
+
@@ -0,0 +1,22 @@
1
+ test:
2
+ environment: "sandbox"
3
+ username: "andy_1246488382_biz_api1.lottay.com"
4
+ password: "1246488389"
5
+ signature: "AHCkey.eVc0sNgG3SP.iiLKXx5EmALu43DmEPM6wmWg.snEFzyBrSfE2"
6
+ application_id: "APP-80W284485P519543T"
7
+ sandbox_email: "andy@lottay.com"
8
+
9
+ development:
10
+ environment: "sandbox"
11
+ username: "signupforuseratsandboxpaypal"
12
+ password: "signupforuseratsandboxpaypal"
13
+ signature: "signupforuseratsandboxpaypal"
14
+ application_id: "APP-TEST"
15
+ sandbox_email: "paypal_sandbox_email"
16
+
17
+ production:
18
+ environment: "production"
19
+ username: "my_production_username"
20
+ password: "my_production_password"
21
+ signature: "my_production_signature"
22
+ application_id: "my_production_app_id"
data/lib/config.rb ADDED
@@ -0,0 +1,58 @@
1
+ module PaypalAdaptive
2
+ class Config
3
+ PAYPAL_BASE_URL_MAPPING = {
4
+ :production => "https://www.paypal.com",
5
+ :sandbox => "https://www.sandbox.paypal.com",
6
+ :beta_sandbox => "https://www.beta-sandbox.paypal.com"
7
+ } unless defined? PAYPAL_BASE_URL_MAPPING
8
+
9
+ API_BASE_URL_MAPPING = {
10
+ :production => "https://svcs.paypal.com",
11
+ :sandbox => "https://svcs.sandbox.paypal.com",
12
+ :beta_sandbox => "https://svcs.beta-sandbox.paypal.com"
13
+ } unless defined? API_BASE_URL_MAPPING
14
+
15
+ attr_accessor :config_filepath, :paypal_base_url, :api_base_url, :headers
16
+
17
+ def initialize(env=nil)
18
+ if env
19
+ #non-rails env
20
+ @config_filepath = "./config/paypal_adaptive.yml"
21
+ load(env)
22
+ else
23
+ @config_filepath = File.join(Rails.root, "config/paypal_adaptive.yml")
24
+ load(Rails.env)
25
+ end
26
+ end
27
+
28
+ def load(rails_env)
29
+ config= YAML.load_file(@config_filepath)[rails_env]
30
+
31
+ if config["retain_requests_for_test"] == true
32
+ @retain_requests_for_test = true
33
+ else
34
+ pp_env = config['environment'].to_sym
35
+
36
+ @paypal_base_url = PAYPAL_BASE_URL_MAPPING[pp_env]
37
+ @api_base_url = API_BASE_URL_MAPPING[pp_env]
38
+ @headers = {
39
+ "X-PAYPAL-SECURITY-USERID" => config['username'],
40
+ "X-PAYPAL-SECURITY-PASSWORD" => config['password'],
41
+ "X-PAYPAL-SECURITY-SIGNATURE" => config['signature'],
42
+ "X-PAYPAL-APPLICATION-ID" => config['application_id'],
43
+ "X-PAYPAL-REQUEST-DATA-FORMAT" => "JSON",
44
+ "X-PAYPAL-RESPONSE-DATA-FORMAT" => "JSON",
45
+ "X-PAYPAL-DEVICE-IPADDRESS" => "0.0.0.0"
46
+ }
47
+
48
+ @headers["X-PAYPAL-SANDBOX-EMAIL-ADDRESS"] = config['sandbox_email'] if pp_env == :sandbox
49
+
50
+ end
51
+ end
52
+
53
+ def retain_requests_for_test?
54
+ !!@retain_requests_for_test
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'json'
4
+ require 'config'
5
+
6
+ module PaypalAdaptive
7
+ class IpnNotification
8
+
9
+ def initialize(env=nil)
10
+ @env = env
11
+ @@config ||= PaypalAdaptive::Config.new(@env)
12
+ @@paypal_base_url ||= @@config.paypal_base_url
13
+ end
14
+
15
+ def send_back(data)
16
+ data = "cmd=_notify-validate&#{data}"
17
+ url = URI.parse @@paypal_base_url
18
+ http = Net::HTTP.new(url.host, 443)
19
+ http.use_ssl = (url.scheme == 'https')
20
+
21
+ path = "#{@@paypal_base_url}/cgi-bin/webscr"
22
+ resp, response_data = http.post(path, data)
23
+
24
+ @verified = response_data == "VERIFIED"
25
+ end
26
+
27
+ def verified?
28
+ @verified
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ {"description":"Paypal PayRequest API",
2
+ "type":"object",
3
+ "properties":
4
+ {
5
+ "actionType": {"type":"string", "options":[{"value":"PAY", "label":"PAY"}]},
6
+ "cancelUrl": {"type":"string"},
7
+ "clientDetails": {"type":"object", "optional": true},
8
+ "currencyCode": {"type":"string"},
9
+ "feesPayer": {"type":"string", "optional":true,
10
+ "options":[
11
+ {"value":"SENDER", "label":"SENDER"},
12
+ {"value":"PRIMARYRECEIVER", "label":"PRIMARYRECEIVER"},
13
+ {"value":"EACHRECEIVER", "label":"EACHRECEIVER"},
14
+ {"value":"SECONDARYONLY", "label":"SECONDARYONLY"}
15
+ ]},
16
+ "fundingConstraint": {"type":"object", "optional": true},
17
+ "ipnNotificationUrl": {"type":"string", "optional": true},
18
+ "memo": {"type":"string", "optional": true},
19
+ "pin": {"type":"string", "optional": true},
20
+ "preapprovalKey": {"type":"string", "optional": true},
21
+ "receiverList": {
22
+ "type":"object", "properties":{
23
+ "receiver":{
24
+ "type":"array",
25
+ "items":{
26
+ "email":{"type":"string"},
27
+ "amount":{"type":"string"},
28
+ "primary":{"type":"string","optional": true}}
29
+ }
30
+ }
31
+ },
32
+
33
+ "requestEnvelope": {"type":"object", "properties":{"errorLanguage":{"type":"string"}}},
34
+ "returnUrl": {"type":"string"},
35
+ "reverseAllParallelPaymentsOnError": {"type":"boolean", "optional": true},
36
+ "senderEmail": {"type":"string", "optional": true},
37
+ "trackingId": {"type":"string", "optional": true}
38
+ }
39
+ }
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "config"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "request"))
3
+ require File.expand_path(File.join(File.dirname(__FILE__), "response"))
4
+ require File.expand_path(File.join(File.dirname(__FILE__), "ipn_notification"))
data/lib/request.rb ADDED
@@ -0,0 +1,95 @@
1
+ require 'json'
2
+ require 'config'
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'response'
6
+
7
+ module PaypalAdaptive
8
+ class NoDataError < Exception
9
+ end
10
+
11
+ class Request
12
+ def initialize(env = nil)
13
+ @env = env
14
+ @@config ||= PaypalAdaptive::Config.new(@env)
15
+ @@api_base_url ||= @@config.api_base_url
16
+ @@headers ||= @@config.headers
17
+ end
18
+
19
+ def validate
20
+ #TODO the receiverList field not validating properly
21
+
22
+ # @@schema_filepath = "../lib/pay_request_schema.json"
23
+ # @@schema = File.open(@@schema_filepath, "rb"){|f| JSON.parse(f.read)}
24
+ # see page 42 of PP Adaptive Payments PDF for explanation of all fields.
25
+ #JSON::Schema.validate(@data, @@schema)
26
+ end
27
+
28
+ def pay(data)
29
+ raise NoDataError unless data
30
+
31
+ response_data = call_api(data, "/AdaptivePayments/Pay")
32
+ PaypalAdaptive::Response.new(response_data, @env)
33
+ end
34
+
35
+ def payment_details(data)
36
+ raise NoDataError unless data
37
+
38
+ call_api(data, "/AdaptivePayments/PaymentDetails")
39
+ end
40
+
41
+ def preapproval(data)
42
+ raise NoDataError unless data
43
+
44
+ response_data = call_api(data, "/AdaptivePayments/Preapproval")
45
+ PaypalAdaptive::Response.new(response_data, @env)
46
+ end
47
+
48
+ def preapproval_details(data)
49
+ raise NoDataError unless data
50
+
51
+ call_api(data, "/AdaptivePayments/PreapprovalDetails")
52
+ end
53
+
54
+ def cancel_preapproval(data)
55
+ raise NoDataError unless data
56
+
57
+ call_api(data, "/AdaptivePayments/CancelPreapproval")
58
+ end
59
+
60
+ def convert_currency(data)
61
+ raise NoDataError unless data
62
+
63
+ call_api(data, "/AdaptivePayments/ConvertCurrency")
64
+ end
65
+
66
+ def refund(data)
67
+ raise NoDataError unless data
68
+
69
+ call_api(data, "/AdaptivePayments/Refund")
70
+ end
71
+
72
+ def create_account(data)
73
+ raise NoDataError unless data
74
+
75
+ response_data = call_api(data, "/AdaptiveAccounts/CreateAccount")
76
+ PaypalAdaptive::Response.new(response_data, @env)
77
+ end
78
+
79
+ def call_api(data, path)
80
+ logger = data.delete(:logger) || data.delete("logger")
81
+ #hack fix: JSON.unparse doesn't work in Rails 2.3.5; only {}.to_json does..
82
+ api_request_data = JSON.unparse(data) rescue data.to_json
83
+ url = URI.parse @@api_base_url
84
+ http = Net::HTTP.new(url.host, 443)
85
+ http.use_ssl = (url.scheme == 'https')
86
+
87
+ logger.request(path, api_request_data, @@headers) if logger
88
+ resp, response_data = http.post(path, api_request_data, @@headers)
89
+ logger.response(resp, response_data) if logger
90
+
91
+ JSON.parse(response_data)
92
+ end
93
+ end
94
+
95
+ end
data/lib/response.rb ADDED
@@ -0,0 +1,38 @@
1
+ module PaypalAdaptive
2
+ class Response < Hash
3
+ def initialize(response, env=nil)
4
+ @@config ||= PaypalAdaptive::Config.new(env)
5
+ @@paypal_base_url ||= @@config.paypal_base_url
6
+
7
+ self.merge!(response)
8
+ end
9
+
10
+ def success?
11
+ self['responseEnvelope']['ack'] == 'Success'
12
+ end
13
+
14
+ def errors
15
+ if success?
16
+ return []
17
+ else
18
+ self['error']
19
+ end
20
+ end
21
+
22
+ def error_message
23
+ if success?
24
+ return nil
25
+ else
26
+ self['error'].first['message'] rescue nil
27
+ end
28
+ end
29
+
30
+ def approve_paypal_payment_url
31
+ self['payKey'].nil? ? nil : "#{@@paypal_base_url}/webscr?cmd=_ap-payment&paykey=#{self['payKey']}"
32
+ end
33
+
34
+ def preapproval_paypal_payment_url
35
+ self['preapprovalKey'].nil? ? nil : "#{@@paypal_base_url}/webscr?cmd=_ap-preapproval&preapprovalkey=#{self['preapprovalKey']}"
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ # Allow the metal piece to run in isolation
2
+ require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails)
3
+
4
+ class PaypalIpn
5
+ def self.call(env)
6
+ if env["PATH_INFO"] =~ /^\/paypal_ipn/
7
+ request = Rack::Request.new(env)
8
+ params = request.params
9
+
10
+ ipn = PaypalAdaptive::IpnNotification.new
11
+ ipn.send_back(env['rack.request.form_vars'])
12
+ if ipn.verified?
13
+ #mark transaction as completed in your DB
14
+ output = "Verified."
15
+ else
16
+ output = "Not Verified."
17
+ end
18
+
19
+ [200, {"Content-Type" => "text/html"}, [output]]
20
+ else
21
+ [404, {"Content-Type" => "text/html"}, ["Not Found"]]
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,30 @@
1
+ require 'helper'
2
+
3
+ class CreateAccountTest < Test::Unit::TestCase
4
+ def setup
5
+ @account_request = PaypalAdaptive::Request.new("test")
6
+ end
7
+
8
+ def test_valid_create_account
9
+ data = read_json_file("valid_create_account_request")
10
+
11
+ data["emailAddress"] = "joetester_#{Time.now.to_i}@example.com"
12
+
13
+ pp_response = @account_request.create_account(data)
14
+
15
+ assert pp_response.success?
16
+ assert pp_response["redirectURL"]
17
+ end
18
+
19
+ # TODO: this test fails, seems you can create as many emails as you want
20
+ def test_create_account_email_address_already_an_account
21
+ data = read_json_file("valid_create_account_request")
22
+
23
+ data["emailAddress"] = "joetester@example.com"
24
+ pp_response = @account_request.create_account(data)
25
+
26
+ assert !pp_response.success?
27
+ assert_equal "An account already exists for the specified email address", pp_response["error"].first["message"]
28
+ end
29
+
30
+ end
@@ -0,0 +1,13 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[
6
+ {"email":"testpp_1261697850_per@nextsprocket.com", "amount":"50.00", "primary": "true"},
7
+ {"email":"sender_1261713739_per@nextsprocket.com", "amount":"100.00", "primary": "false"},
8
+ {"email":"ppsell_1261697921_biz@nextsprocket.com", "amount":"100.00", "primary": "false"}
9
+ ]},
10
+ "cancelUrl":"http://127.0.0.1:3000/payments/cancelled_payment",
11
+ "actionType":"PAY"
12
+ }
13
+
@@ -0,0 +1,13 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[
6
+ {"email":"dummy@account.com", "amount":"100.00"},
7
+ {"email":"dummy@account.com", "amount":"50.00"},
8
+ {"email":"dummy@account.com", "amount":"50.00"}
9
+ ]},
10
+ "cancelUrl":"http://127.0.0.1:3000/payments/cancelled_payment",
11
+ "actionType":"PAY"
12
+ }
13
+
@@ -0,0 +1,12 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
6
+ "actionType":"PAY",
7
+ "maxTotalAmountOfAllPayments": "1500.00",
8
+ "maxNumberOfPayments":"30",
9
+ "startingDate":"2010-07-13T07sdf00.000Z",
10
+ "endingDate":"2010-12-13T07dfg0000.000Z"
11
+ }
12
+
@@ -0,0 +1,8 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[{"email":"testpp_1261697850_per@nextsprocket.com", "amount":"10.0"}]},
6
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment",
7
+ "actionType":1
8
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[
6
+ {"email":"testpp_1261697850_per@nextsprocket.com", "amount":"100.00", "primary": "true"},
7
+ {"email":"ppsell_1261697921_biz@nextsprocket.com", "amount":"90.00", "primary": "false"}
8
+ ]},
9
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
10
+ "actionType":"PAY"
11
+ }
12
+
@@ -0,0 +1,22 @@
1
+ {
2
+ "name":{"firstName":"Joe", "lastName":"Tester"},
3
+ "preferredLanguageCode":"en_US",
4
+ "address": {
5
+ "line1":"1234 Imaginary Ln",
6
+ "line2":"",
7
+ "city":"Ventura",
8
+ "state":"CA",
9
+ "postalCode":"93001",
10
+ "countryCode":"US"
11
+ },
12
+ "accountType":"Personal",
13
+ "citizenshipCountryCode":"US",
14
+ "contactPhoneNumber":"805-555-5555",
15
+ "createAccountWebOptions":{"returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request"},
16
+ "emailAddress":"joetester@example.com",
17
+ "requestEnvelope":{"errorLanguage":"en_US"},
18
+ "currencyCode":"USD",
19
+ "registrationType":"WEB",
20
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
21
+ "notificationURL":"http://127.0.0.1:3000/payments/ipn_notification"
22
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[
6
+ {"email":"testpp_1261697850_per@nextsprocket.com", "amount":"100.00"},
7
+ {"email":"sender_1261713739_per@nextsprocket.com", "amount":"50.00"},
8
+ {"email":"ppsell_1261697921_biz@nextsprocket.com", "amount":"50.00"}
9
+ ]},
10
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
11
+ "actionType":"PAY",
12
+ "senderEmail": "a@a.com"
13
+ }
14
+
@@ -0,0 +1,9 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
6
+ "maxTotalAmountOfAllPayments": "1500.00",
7
+ "maxNumberOfPayments":"30"
8
+ }
9
+
@@ -0,0 +1,9 @@
1
+ {
2
+ "returnUrl":"http://127.0.0.1:3000/payments/completed_payment_request",
3
+ "requestEnvelope":{"errorLanguage":"en_US"},
4
+ "currencyCode":"USD",
5
+ "receiverList":{"receiver":[{"email":"testpp_1261697850_per@nextsprocket.com", "amount":"10.00"}]},
6
+ "cancelUrl":"http://127.0.0.1:3000/payments/canceled_payment_request",
7
+ "actionType":"PAY",
8
+ "ipnNotificationUrl":"http://127.0.0.1:3000/payments/ipn_notification"
9
+ }
data/test/helper.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require "yaml"
3
+ require 'JSON'
4
+ require 'test/unit'
5
+ require "request"
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ def read_json_file(filepath)
13
+ File.open("./test/data/#{filepath}.json", "rb"){|f| JSON.parse(f.read)}
14
+ end
15
+
16
+ end
@@ -0,0 +1,44 @@
1
+ require 'helper'
2
+ require 'json'
3
+ require 'jsonschema'
4
+
5
+ class PayRequestSchemaTest < Test::Unit::TestCase
6
+ def setup
7
+ @schema_filepath = "./lib/pay_request_schema.json"
8
+ @schema = File.open(@schema_filepath, "rb"){|f| JSON.parse(f.read)}
9
+ end
10
+
11
+ def xtest_valid_simple_pay
12
+ data = read_json_file("valid_simple_pay_request_1")
13
+
14
+ #receiverList not validating correctly, is it due to the schema or jsonschema parsing?
15
+ assert_nothing_raised do
16
+ JSON::Schema.validate(data, @schema)
17
+ end
18
+ end
19
+
20
+ def test_invalid_simple_pay
21
+ data = read_json_file("invalid_simple_pay_request_1")
22
+
23
+ assert_raise JSON::Schema::ValueError do
24
+ JSON::Schema.validate(data, @schema)
25
+ end
26
+ end
27
+
28
+ def test_valid_chain_pay
29
+ #TODO
30
+ end
31
+
32
+ def test_invalid_chain_pay
33
+ #TODO
34
+ end
35
+
36
+ def test_valid_parallel_pay
37
+ #TODO
38
+ end
39
+
40
+ def test_invalid_parallel_pay
41
+ #TODO
42
+ end
43
+
44
+ end
@@ -0,0 +1,85 @@
1
+ require 'helper'
2
+
3
+ class PayRequestTest < Test::Unit::TestCase
4
+ def setup
5
+ @pay_request = PaypalAdaptive::Request.new("test")
6
+ end
7
+
8
+ def test_valid_simple_pay
9
+ puts "-------"
10
+ puts "simple"
11
+
12
+ data = read_json_file("valid_simple_pay_request_1")
13
+ pp_response = @pay_request.pay(data)
14
+
15
+ puts "redirect url to\n #{pp_response.approve_paypal_payment_url}"
16
+ assert pp_response.success?
17
+ end
18
+
19
+ def test_invalid_simple_pay
20
+ data = read_json_file("invalid_simple_pay_request_1")
21
+ pp_response = @pay_request.pay(data)
22
+ puts pp_response.errors
23
+ assert pp_response.success? == false
24
+ end
25
+
26
+ def test_valid_chain_pay
27
+ puts "-------"
28
+ puts "chain"
29
+ data = read_json_file("valid_chain_pay_request")
30
+ pp_response = @pay_request.pay(data)
31
+ puts "redirect url to\n #{pp_response.approve_paypal_payment_url}"
32
+
33
+ unless pp_response.success?
34
+ puts pp_response.errors
35
+ end
36
+
37
+ assert pp_response.success?
38
+ end
39
+
40
+ def test_invalid_chain_pay
41
+ data = read_json_file("invalid_chain_pay_request")
42
+ pp_response = @pay_request.pay(data)
43
+ puts pp_response.errors
44
+ assert pp_response.success? == false
45
+ end
46
+
47
+ def test_valid_parallel_pay
48
+ puts "-------"
49
+ puts "parallel"
50
+
51
+ data = read_json_file("valid_chain_pay_request")
52
+ pp_response = @pay_request.pay(data)
53
+ puts "redirect url to\n #{pp_response.approve_paypal_payment_url}"
54
+ assert pp_response.success?
55
+ end
56
+
57
+ def test_invalid_parallel_pay
58
+ data = read_json_file("invalid_parallel_pay_request")
59
+ pp_response = @pay_request.pay(data)
60
+ puts pp_response.errors
61
+ assert pp_response.success? == false
62
+ end
63
+
64
+
65
+ def test_preapproval
66
+ #TODO
67
+ end
68
+
69
+ def test_preapproval_details
70
+ #TODO
71
+ end
72
+
73
+ def test_cancel_preapproval
74
+ #TODO
75
+ end
76
+
77
+ def test_convert_currency
78
+ #TODO
79
+ end
80
+
81
+ def test_refund
82
+ #TODO
83
+ end
84
+
85
+ end
@@ -0,0 +1,28 @@
1
+ require 'helper'
2
+
3
+ class PaymentDetailsTest < Test::Unit::TestCase
4
+ def setup
5
+ @pay_request = PaypalAdaptive::Request.new("test")
6
+ @payment_details_request = PaypalAdaptive::Request.new("test")
7
+ end
8
+
9
+ def test_payment_details
10
+ puts "-------"
11
+ puts "payment details"
12
+ data = read_json_file("valid_chain_pay_request")
13
+ pp_response = @pay_request.pay(data)
14
+ puts "redirect url to\n #{pp_response.approve_paypal_payment_url}"
15
+
16
+ unless pp_response.success?
17
+ puts pp_response.errors
18
+ end
19
+
20
+ assert pp_response.success?
21
+
22
+ data = {"requestEnvelope"=>{"errorLanguage"=>"en_US"}, "payKey" => pp_response['payKey']}
23
+
24
+ response = @payment_details_request.payment_details(data)
25
+ assert_equal 'CREATED', response['status']
26
+ end
27
+
28
+ end
@@ -0,0 +1,64 @@
1
+ require "time"
2
+ require 'helper'
3
+
4
+ class PreapprovalTest < Test::Unit::TestCase
5
+ def setup
6
+ @preapproval_request = PaypalAdaptive::Request.new("test")
7
+ end
8
+
9
+ def set_dates(data)
10
+ data["startingDate"] = Time.now.utc.iso8601
11
+ data["endingDate"] = (Time.now.utc + 20*24*3600).iso8601
12
+ end
13
+
14
+ def test_preapproval
15
+ puts "-------"
16
+ puts "valid test"
17
+ data = read_json_file("valid_preapproval")
18
+ set_dates(data)
19
+
20
+ pp_response = @preapproval_request.preapproval(data)
21
+ puts "preapproval code is #{pp_response['preapprovalKey']}"
22
+
23
+ assert pp_response.success?
24
+ assert_not_nil pp_response.preapproval_paypal_payment_url
25
+ assert_not_nil pp_response['preapprovalKey']
26
+ end
27
+
28
+ class Logger
29
+ attr_accessor :path, :request_data, :headers, :status, :response_data
30
+ def request(path, request_data, headers)
31
+ @path, @request_data, @headers = path, request_data, headers
32
+ end
33
+
34
+ def response(status, response_data)
35
+ @status, @response_data = status.code.to_i, response_data
36
+ end
37
+ end
38
+
39
+ def test_invalid_preapproval_with_logger
40
+ data = read_json_file("invalid_preapproval")
41
+ logger = Logger.new
42
+ pp_response = @preapproval_request.preapproval(data.merge(:logger => logger))
43
+
44
+ assert pp_response.success? == false
45
+ assert logger.path == "/AdaptivePayments/Preapproval"
46
+ assert logger.request_data == "{\"cancelUrl\":\"http://127.0.0.1:3000/payments/canceled_payment_request\",\"endingDate\":\"2010-12-13T07dfg0000.000Z\",\"returnUrl\":\"http://127.0.0.1:3000/payments/completed_payment_request\",\"maxTotalAmountOfAllPayments\":\"1500.00\",\"startingDate\":\"2010-07-13T07sdf00.000Z\",\"maxNumberOfPayments\":\"30\",\"requestEnvelope\":{\"errorLanguage\":\"en_US\"},\"actionType\":\"PAY\",\"currencyCode\":\"USD\"}"
47
+ assert logger.headers == {"X-PAYPAL-RESPONSE-DATA-FORMAT"=>"JSON", "X-PAYPAL-SANDBOX-EMAIL-ADDRESS"=>"andy@lottay.com", "X-PAYPAL-REQUEST-DATA-FORMAT"=>"JSON", "X-PAYPAL-SECURITY-USERID"=>"andy_1246488382_biz_api1.lottay.com", "X-PAYPAL-DEVICE-IPADDRESS"=>"0.0.0.0", "X-PAYPAL-SECURITY-PASSWORD"=>"1246488389", "X-PAYPAL-APPLICATION-ID"=>"APP-80W284485P519543T", "X-PAYPAL-SECURITY-SIGNATURE"=>"AHCkey.eVc0sNgG3SP.iiLKXx5EmALu43DmEPM6wmWg.snEFzyBrSfE2"}
48
+ assert logger.status == 200
49
+ assert logger.response_data =~ /responseEnvelope/
50
+ assert logger.response_data =~ /Error in parsing time zone/
51
+ end
52
+
53
+ def test_invalid_preapproval
54
+ puts "-------"
55
+ puts "invalid"
56
+ data = read_json_file("invalid_preapproval")
57
+ pp_response = @preapproval_request.preapproval(data)
58
+ puts "error message is #{pp_response.error_message}"
59
+
60
+ assert pp_response.success? == false
61
+ assert_nil pp_response.preapproval_paypal_payment_url
62
+ assert_nil pp_response['preapprovalKey']
63
+ end
64
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: astrails-paypal_adaptive
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Tommy Chheng
14
+ - Ross Hale
15
+ - Boris Nadion
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2011-02-09 00:00:00 +02:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: json
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 3
32
+ segments:
33
+ - 0
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: jsonschema
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ description: Lightweight wrapper for Paypal's Adaptive Payments API.
52
+ email: boris@astrails.com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files:
58
+ - LICENSE
59
+ - README.markdown
60
+ files:
61
+ - LICENSE
62
+ - README.markdown
63
+ - Rakefile
64
+ - VERSION
65
+ - astrails-paypal_adaptive.gemspec
66
+ - config/paypal_adaptive.yml
67
+ - lib/config.rb
68
+ - lib/ipn_notification.rb
69
+ - lib/pay_request_schema.json
70
+ - lib/paypal_adaptive.rb
71
+ - lib/request.rb
72
+ - lib/response.rb
73
+ - templates/paypal_ipn.rb
74
+ - test/create_account_test.rb
75
+ - test/data/invalid_chain_pay_request.json
76
+ - test/data/invalid_parallel_pay_request.json
77
+ - test/data/invalid_preapproval.json
78
+ - test/data/invalid_simple_pay_request_1.json
79
+ - test/data/valid_chain_pay_request.json
80
+ - test/data/valid_create_account_request.json
81
+ - test/data/valid_parallel_pay_request.json
82
+ - test/data/valid_preapproval.json
83
+ - test/data/valid_simple_pay_request_1.json
84
+ - test/helper.rb
85
+ - test/pay_request_schema_test.rb
86
+ - test/pay_request_test.rb
87
+ - test/payment_details_test.rb
88
+ - test/preapproval_test.rb
89
+ has_rdoc: true
90
+ homepage: http://github.com/astrails/paypal_adaptive
91
+ licenses: []
92
+
93
+ post_install_message:
94
+ rdoc_options: []
95
+
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ requirements: []
117
+
118
+ rubyforge_project:
119
+ rubygems_version: 1.3.7
120
+ signing_key:
121
+ specification_version: 3
122
+ summary: initial import
123
+ test_files:
124
+ - test/create_account_test.rb
125
+ - test/helper.rb
126
+ - test/pay_request_schema_test.rb
127
+ - test/pay_request_test.rb
128
+ - test/payment_details_test.rb
129
+ - test/preapproval_test.rb