elucid-adaptive_pay 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/.gitignore +1 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +186 -0
  4. data/Rakefile +39 -0
  5. data/VERSION +1 -0
  6. data/config/adaptive_pay.yml +19 -0
  7. data/elucid-adaptive_pay.gemspec +90 -0
  8. data/init.rb +1 -0
  9. data/install.rb +4 -0
  10. data/lib/adaptive_pay.rb +12 -0
  11. data/lib/adaptive_pay/abstract_payment_request.rb +44 -0
  12. data/lib/adaptive_pay/callback.rb +17 -0
  13. data/lib/adaptive_pay/cancel_preapproval_request.rb +16 -0
  14. data/lib/adaptive_pay/interface.rb +93 -0
  15. data/lib/adaptive_pay/parser.rb +43 -0
  16. data/lib/adaptive_pay/payment_request.rb +48 -0
  17. data/lib/adaptive_pay/preapproval_request.rb +24 -0
  18. data/lib/adaptive_pay/recipient.rb +17 -0
  19. data/lib/adaptive_pay/refund_request.rb +46 -0
  20. data/lib/adaptive_pay/request.rb +124 -0
  21. data/lib/adaptive_pay/response.rb +76 -0
  22. data/lib/adaptive_pay/sender.rb +13 -0
  23. data/spec/adaptive_pay/abstract_payment_request_spec.rb +41 -0
  24. data/spec/adaptive_pay/callback_spec.rb +17 -0
  25. data/spec/adaptive_pay/cancel_preapproval_request_spec.rb +22 -0
  26. data/spec/adaptive_pay/interface_spec.rb +184 -0
  27. data/spec/adaptive_pay/parser_spec.rb +47 -0
  28. data/spec/adaptive_pay/payment_request_spec.rb +53 -0
  29. data/spec/adaptive_pay/preapproval_request_spec.rb +9 -0
  30. data/spec/adaptive_pay/recipient_spec.rb +20 -0
  31. data/spec/adaptive_pay/refund_request_spec.rb +51 -0
  32. data/spec/adaptive_pay/request_spec.rb +178 -0
  33. data/spec/adaptive_pay/response_spec.rb +87 -0
  34. data/spec/adaptive_pay/sender_spec.rb +20 -0
  35. data/spec/fixtures/config/adaptive_pay.yml +16 -0
  36. data/spec/rails_mocks.rb +3 -0
  37. data/spec/spec_helper.rb +13 -0
  38. data/uninstall.rb +1 -0
  39. metadata +106 -0
@@ -0,0 +1 @@
1
+ pkg
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Frederik Fix
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 ADDED
@@ -0,0 +1,186 @@
1
+ Adaptive Pay
2
+ ============
3
+
4
+ A wrapper for the Paypal Adaptive Payments API. For details see: https://www.x.com/docs/DOC-1408
5
+
6
+ The adaptive payments API allows you to:
7
+ 1) send money to multiple (up to 5) recipients in one transaction
8
+ 2) preapprove payments, which can then be executed later without user intervention
9
+
10
+
11
+ Installation
12
+ -----------
13
+ As plugin:
14
+ script/plugin install git://github.com/derfred/adaptive_pay.git
15
+
16
+ As gem:
17
+ (in config/environment.rb)
18
+ config.gem "adaptive_pay"
19
+ Then run:
20
+ rake gems:install
21
+
22
+
23
+ Configuration
24
+ -------------
25
+
26
+ This plugin expects a file named config/adaptive_pay.yml to contain the configuration
27
+
28
+ development:
29
+ instance: "sandbox"
30
+ username: "my_development_username"
31
+ password: "my_development_password"
32
+ signature: "my_development_signature"
33
+ application_id: "my_development_app_id"
34
+
35
+ test:
36
+ retain_requests_for_test: true
37
+
38
+ production:
39
+ instance: "production"
40
+ username: "my_production_username"
41
+ password: "my_production_password"
42
+ signature: "my_production_signature"
43
+ application_id: "my_production_app_id"
44
+
45
+ Description of config parameters:
46
+ instance: can be either sandbox or production and refers to which instance of the Paypal service should be used
47
+ username, password, signature, application_id: the relevant authentication parameters for your account
48
+ retain_requests_for_test: mark this Rails environment as a test environment. If this parameter is set then all interactions with the API will remain local. For details see the testing section.
49
+
50
+
51
+ Chained/Split Payment Usage
52
+ -------------------------------------
53
+
54
+ The following example shows how to set up a chained payment for a total of 110 GBP, 10 GBP going to a primary receipient with the paypal account "agent@email.com" and 100 GBP going to the account "supplier@email.com". Because this is a chained payment it will seem to the user that the complete total will go to the primary account.
55
+
56
+ interface = AdaptivePay::Interface.new
57
+ response = interface.request_payment do |request|
58
+ request.currency_code = "GBP"
59
+
60
+ request.cancel_url = "http://example.com/cancelled_payment" # this is where the user will be redirected should he cancel the payment
61
+ request.return_url = "http://example.com/completed_payment" # and here should the payment be succesful
62
+ request.ipn_notification_url = "http://example.com/ipn_callback"
63
+
64
+ request.add_recipient :email => "supplier@email.com",
65
+ :amount => 100,
66
+ :primary => false
67
+
68
+ request.add_recipient :email => "agent@email.com",
69
+ :amount => 10,
70
+ :primary => true
71
+ end
72
+
73
+ if response.created?
74
+ # the payment has been setup successfully, now the user will need to be redirected to the Paypal site:
75
+ redirect_to response.payment_page_url
76
+ else
77
+ # the payment could not be setup, most likely because of a missing parameter or validation error
78
+ # the array of errors reported by the service can be retrieved using:
79
+ response.errors
80
+ end
81
+
82
+ This example could be changed to a Split Payment by setting the primary parameter to false for each recipient.
83
+
84
+ After the payment has been set up and the user has been redirected to the payment page url, the application will need to wait for the IPN callback which indicates whether the payment has actually gone through. This is done in the next snippet. For this to work the ipn_callback_url specified above needs to be connected to a controller action.
85
+
86
+ def ipn_callback
87
+ callback = AdaptivePay::Callback.new params
88
+ if callback.completed?
89
+ # payment has been processed, now mark order as paid etc
90
+ else
91
+ # payment failed
92
+ end
93
+ end
94
+
95
+
96
+
97
+ Preapproved Payment Usage
98
+ ---------------------------
99
+
100
+ The next example will ask the user to preapprove a payment of 300 dollars and then distribute it equally among three recipients at a later date
101
+
102
+ interface = AdaptivePay::Interface.new
103
+ response = interface.request_preapproval do |request|
104
+ request.currency_code = "USD"
105
+
106
+ request.max_total_amount_of_all_payments = 300
107
+ request.ending_date = 3.months.from_now
108
+ request.starting_date = Time.now
109
+ end
110
+
111
+ if response.created?
112
+ # The preapproval has been set up. In addition to redirecting the user to the payment page we will have to keep track of the
113
+ # preapproval key for making the payment at a later time:
114
+ Approval.create :key => response.preapproval_key
115
+ redirect_to response.payment_page_url
116
+ else
117
+ # error in request, same as above
118
+ end
119
+
120
+ Now at a later time the payment can be initiated without user intervention, in a cron job or rake task etc:
121
+
122
+ approval = Approval.first :conditions => .... # find the approval object created above
123
+ interface = AdaptivePay::Interface.new
124
+ response = interface.request_payment do |request|
125
+ request.currency_code = "USD"
126
+
127
+ request.ipn_notification_url = "http://example.com/ipn_callback"
128
+
129
+ request.preapproval_key = approval.key # this is the preapproval key generated in the first step
130
+ request.add_recipient :email => "recipient1@email.com", :amount => 100
131
+ request.add_recipient :email => "recipient2@email.com", :amount => 100
132
+ request.add_recipient :email => "recipient3@email.com", :amount => 100
133
+ end
134
+
135
+ if response.pending?
136
+ # some payment methods require longer to process, in that case the API will return pending and notify using IPN callback
137
+ elsif response.completed?
138
+ # payment has been processed, mark the order as paid etc
139
+ else
140
+ # there was an error, see the errors array for details
141
+ response.errors
142
+ end
143
+
144
+
145
+ Object based calls
146
+ -----------------
147
+
148
+ Rather than using the block based calls shown above you can explicitly create a Request object and pass it to the perform method:
149
+
150
+ payment_request = AdaptivePay::PaymentRequest.new
151
+ payment_request.currency_code = "USD"
152
+ payment_request.ipn_notification_url = "http://example.com/ipn_callback"
153
+ payment_request.add_recipient :email => "recipient1@email.com", :amount => 100
154
+
155
+ interface = AdaptivePay::Interface.new
156
+ interface.perform payment_request
157
+
158
+
159
+ This is equivalent to:
160
+
161
+ interface = AdaptivePay::Interface.new
162
+ response = interface.request_payment do |request|
163
+ request.currency_code = "USD"
164
+ request.ipn_notification_url = "http://example.com/ipn_callback"
165
+ request.add_recipient :email => "recipient1@email.com", :amount => 100
166
+ end
167
+
168
+ Since the Request objects are stateless you can reuse them.
169
+
170
+
171
+ Testing
172
+ ---------
173
+
174
+ The main benefit to using this library is the support for testing. When a RAILS_ENV has the retain_requests_for_test parameter set in the config/adaptive_pay.yml file requests will not be delivered to the Paypal servers but rather added to a queue, just like ActionMailer does. One difference though is that you need to provide a stub response.
175
+
176
+ it "should create preapproval request" do
177
+ AdaptivePay::Interface.test_response = stub(:response, :completed? => true, :pending? => false)
178
+ @payment_processor.process @order
179
+
180
+ AdaptivePay::Interface.requests.size.should == 1
181
+ request = AdaptivePay::Interface.requests.first
182
+
183
+ request.should be_a(AdaptivePay::PreapprovalRequest)
184
+ request.max_total_amount_of_all_payments.should == 130
185
+ request.currency_code.should == "GBP"
186
+ end
@@ -0,0 +1,39 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ # Rakefile
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gemspec|
9
+ gemspec.name = "elucid-adaptive_pay"
10
+ gemspec.summary = "Wrapper around the Paypal Adaptive Payments API"
11
+ gemspec.description = "Wrapper around the Paypal Adaptive Payments API"
12
+ gemspec.email = %q{elucid@gmail.com}
13
+ gemspec.homepage = "http://github.com/elucid/adaptive_pay"
14
+ gemspec.authors = ["Frederik Fix", "Justin Giancola"]
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
19
+ end
20
+
21
+ desc 'Default: run unit tests.'
22
+ task :default => :test
23
+
24
+ desc 'Test the <%= file_name %> plugin.'
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.libs << 'lib'
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = true
30
+ end
31
+
32
+ desc 'Generate documentation for the <%= file_name %> plugin.'
33
+ Rake::RDocTask.new(:rdoc) do |rdoc|
34
+ rdoc.rdoc_dir = 'rdoc'
35
+ rdoc.title = '<%= class_name %>'
36
+ rdoc.options << '--line-numbers' << '--inline-source'
37
+ rdoc.rdoc_files.include('README')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
@@ -0,0 +1,19 @@
1
+ development:
2
+ environment: "sandbox"
3
+ username: "my_development_username"
4
+ password: "my_development_password"
5
+ signature: "my_development_signature"
6
+ application_id: "APP-80W284485P519543T"
7
+
8
+ test:
9
+ retain_requests_for_test: true
10
+
11
+ cucumber:
12
+ retain_requests_for_test: true
13
+
14
+ production:
15
+ environment: "production"
16
+ username: "my_production_username"
17
+ password: "my_production_password"
18
+ signature: "my_production_signature"
19
+ application_id: "APP-80W284485P519543T"
@@ -0,0 +1,90 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{elucid-adaptive_pay}
8
+ s.version = "0.2.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Frederik Fix", "Justin Giancola"]
12
+ s.date = %q{2010-08-05}
13
+ s.description = %q{Wrapper around the Paypal Adaptive Payments API}
14
+ s.email = %q{elucid@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "MIT-LICENSE",
21
+ "README",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "config/adaptive_pay.yml",
25
+ "elucid-adaptive_pay.gemspec",
26
+ "init.rb",
27
+ "install.rb",
28
+ "lib/adaptive_pay.rb",
29
+ "lib/adaptive_pay/abstract_payment_request.rb",
30
+ "lib/adaptive_pay/callback.rb",
31
+ "lib/adaptive_pay/cancel_preapproval_request.rb",
32
+ "lib/adaptive_pay/interface.rb",
33
+ "lib/adaptive_pay/parser.rb",
34
+ "lib/adaptive_pay/payment_request.rb",
35
+ "lib/adaptive_pay/preapproval_request.rb",
36
+ "lib/adaptive_pay/recipient.rb",
37
+ "lib/adaptive_pay/refund_request.rb",
38
+ "lib/adaptive_pay/request.rb",
39
+ "lib/adaptive_pay/response.rb",
40
+ "lib/adaptive_pay/sender.rb",
41
+ "spec/adaptive_pay/abstract_payment_request_spec.rb",
42
+ "spec/adaptive_pay/callback_spec.rb",
43
+ "spec/adaptive_pay/cancel_preapproval_request_spec.rb",
44
+ "spec/adaptive_pay/interface_spec.rb",
45
+ "spec/adaptive_pay/parser_spec.rb",
46
+ "spec/adaptive_pay/payment_request_spec.rb",
47
+ "spec/adaptive_pay/preapproval_request_spec.rb",
48
+ "spec/adaptive_pay/recipient_spec.rb",
49
+ "spec/adaptive_pay/refund_request_spec.rb",
50
+ "spec/adaptive_pay/request_spec.rb",
51
+ "spec/adaptive_pay/response_spec.rb",
52
+ "spec/adaptive_pay/sender_spec.rb",
53
+ "spec/fixtures/config/adaptive_pay.yml",
54
+ "spec/rails_mocks.rb",
55
+ "spec/spec_helper.rb",
56
+ "uninstall.rb"
57
+ ]
58
+ s.homepage = %q{http://github.com/elucid/adaptive_pay}
59
+ s.rdoc_options = ["--charset=UTF-8"]
60
+ s.require_paths = ["lib"]
61
+ s.rubygems_version = %q{1.3.5}
62
+ s.summary = %q{Wrapper around the Paypal Adaptive Payments API}
63
+ s.test_files = [
64
+ "spec/adaptive_pay/abstract_payment_request_spec.rb",
65
+ "spec/adaptive_pay/callback_spec.rb",
66
+ "spec/adaptive_pay/cancel_preapproval_request_spec.rb",
67
+ "spec/adaptive_pay/interface_spec.rb",
68
+ "spec/adaptive_pay/parser_spec.rb",
69
+ "spec/adaptive_pay/payment_request_spec.rb",
70
+ "spec/adaptive_pay/preapproval_request_spec.rb",
71
+ "spec/adaptive_pay/recipient_spec.rb",
72
+ "spec/adaptive_pay/refund_request_spec.rb",
73
+ "spec/adaptive_pay/request_spec.rb",
74
+ "spec/adaptive_pay/response_spec.rb",
75
+ "spec/adaptive_pay/sender_spec.rb",
76
+ "spec/rails_mocks.rb",
77
+ "spec/spec_helper.rb"
78
+ ]
79
+
80
+ if s.respond_to? :specification_version then
81
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
82
+ s.specification_version = 3
83
+
84
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
85
+ else
86
+ end
87
+ else
88
+ end
89
+ end
90
+
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "adaptive_pay"
@@ -0,0 +1,4 @@
1
+ config_path = File.join('config', 'adaptive_pay.yml')
2
+ unless File.exist?(File.join(RAILS_ROOT, config_path))
3
+ FileUtils.cp File.join(File.dirname(__FILE__), config_path), File.join(RAILS_ROOT, config_path)
4
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/interface')
2
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/request')
3
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/abstract_payment_request')
4
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/preapproval_request')
5
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/payment_request')
6
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/refund_request')
7
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/cancel_preapproval_request')
8
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/parser')
9
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/response')
10
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/sender')
11
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/recipient')
12
+ require File.expand_path(File.dirname(__FILE__) + '/adaptive_pay/callback')
@@ -0,0 +1,44 @@
1
+ module AdaptivePay
2
+ class AbstractPaymentRequest < Request
3
+
4
+ attribute "requestEnvelope.detailLevel"
5
+ attribute "requestEnvelope.errorLanguage", :default => "en_US"
6
+
7
+ attribute "clientDetails.ipAddress"
8
+ attribute "clientDetails.applicationId"
9
+ attribute "clientDetails.customerId"
10
+ attribute "clientDetails.customerType"
11
+ attribute "clientDetails.deviceId"
12
+ attribute "clientDetails.geoLocation"
13
+ attribute "clientDetails.model"
14
+ attribute "clientDetails.partnerName"
15
+
16
+ attribute "currencyCode"
17
+ attribute "ipnNotificationUrl"
18
+ attribute "cancelUrl"
19
+ attribute "returnUrl"
20
+
21
+ attribute "memo"
22
+ attribute "senderEmail"
23
+
24
+ attr_reader :sender
25
+
26
+ def sender=(sender_options)
27
+ if sender_options.is_a?(AdaptivePay::Sender)
28
+ @sender = sender_options
29
+ else
30
+ @sender = AdaptivePay::Sender.new sender_options
31
+ end
32
+ end
33
+
34
+ protected
35
+ def extra_attributes
36
+ return super if sender.blank?
37
+ result = {}
38
+ result["clientDetails.ipAddress"] = sender.client_ip
39
+ result["senderEmail"] = sender.email unless sender.email.blank?
40
+ super.merge(result)
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,17 @@
1
+ module AdaptivePay
2
+ class Callback
3
+
4
+ def initialize(params)
5
+ @params = params
6
+ end
7
+
8
+ def method_missing(name, *args)
9
+ @params[name.to_s] || super
10
+ end
11
+
12
+ def completed?
13
+ payment_status == "Completed"
14
+ end
15
+
16
+ end
17
+ end