astrails-paypal_adaptive 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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