paypal-recurring 0.1.0
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/.gitignore +3 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +45 -0
- data/README.rdoc +128 -0
- data/Rakefile +5 -0
- data/docs/PP_NVPAPI_DeveloperGuide.pdf +0 -0
- data/docs/PP_WPP_IntegrationGuide.pdf +0 -0
- data/lib/paypal-recurring.rb +1 -0
- data/lib/paypal/recurring.rb +106 -0
- data/lib/paypal/recurring/base.rb +149 -0
- data/lib/paypal/recurring/cacert.pem +3987 -0
- data/lib/paypal/recurring/request.rb +143 -0
- data/lib/paypal/recurring/response.rb +26 -0
- data/lib/paypal/recurring/response/base.rb +74 -0
- data/lib/paypal/recurring/response/checkout.rb +11 -0
- data/lib/paypal/recurring/response/details.rb +26 -0
- data/lib/paypal/recurring/response/manage_profile.rb +12 -0
- data/lib/paypal/recurring/response/payment.rb +22 -0
- data/lib/paypal/recurring/response/profile.rb +69 -0
- data/lib/paypal/recurring/version.rb +10 -0
- data/paypal-recurring.gemspec +25 -0
- data/spec/fixtures/checkout/failure.yml +26 -0
- data/spec/fixtures/checkout/success.yml +26 -0
- data/spec/fixtures/create_profile/failure.yml +26 -0
- data/spec/fixtures/create_profile/success.yml +26 -0
- data/spec/fixtures/details/cancelled.yml +26 -0
- data/spec/fixtures/details/failure.yml +26 -0
- data/spec/fixtures/details/success.yml +26 -0
- data/spec/fixtures/payment/failure.yml +26 -0
- data/spec/fixtures/payment/success.yml +26 -0
- data/spec/fixtures/profile/cancel/failure.yml +26 -0
- data/spec/fixtures/profile/cancel/success.yml +26 -0
- data/spec/fixtures/profile/failure.yml +26 -0
- data/spec/fixtures/profile/reactivate/failure.yml +26 -0
- data/spec/fixtures/profile/reactivate/success.yml +26 -0
- data/spec/fixtures/profile/success.yml +26 -0
- data/spec/fixtures/profile/suspend/failure.yml +26 -0
- data/spec/fixtures/profile/suspend/success.yml +26 -0
- data/spec/paypal/recurring_spec.rb +87 -0
- data/spec/paypal/request_spec.rb +102 -0
- data/spec/paypal/response/checkout_details_spec.rb +51 -0
- data/spec/paypal/response/checkout_spec.rb +32 -0
- data/spec/paypal/response/create_recurring_profile_spec.rb +39 -0
- data/spec/paypal/response/manage_profile_spec.rb +62 -0
- data/spec/paypal/response/profile_spec.rb +41 -0
- data/spec/paypal/response/request_payment_spec.rb +35 -0
- data/spec/spec_helper.rb +24 -0
- metadata +187 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --format documentation
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
paypal-recurring (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
archive-tar-minitar (0.5.2)
|
10
|
+
columnize (0.3.3)
|
11
|
+
diff-lcs (1.1.2)
|
12
|
+
fakeweb (1.3.0)
|
13
|
+
linecache19 (0.5.12)
|
14
|
+
ruby_core_source (>= 0.1.4)
|
15
|
+
rake (0.8.7)
|
16
|
+
rspec (2.6.0)
|
17
|
+
rspec-core (~> 2.6.0)
|
18
|
+
rspec-expectations (~> 2.6.0)
|
19
|
+
rspec-mocks (~> 2.6.0)
|
20
|
+
rspec-core (2.6.4)
|
21
|
+
rspec-expectations (2.6.0)
|
22
|
+
diff-lcs (~> 1.1.2)
|
23
|
+
rspec-mocks (2.6.0)
|
24
|
+
ruby-debug-base19 (0.11.25)
|
25
|
+
columnize (>= 0.3.1)
|
26
|
+
linecache19 (>= 0.5.11)
|
27
|
+
ruby_core_source (>= 0.1.4)
|
28
|
+
ruby-debug19 (0.11.6)
|
29
|
+
columnize (>= 0.3.1)
|
30
|
+
linecache19 (>= 0.5.11)
|
31
|
+
ruby-debug-base19 (>= 0.11.19)
|
32
|
+
ruby_core_source (0.1.5)
|
33
|
+
archive-tar-minitar (>= 0.5.2)
|
34
|
+
vcr (1.10.0)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
fakeweb (~> 1.3.0)
|
41
|
+
paypal-recurring!
|
42
|
+
rake (~> 0.8.7)
|
43
|
+
rspec (~> 2.6)
|
44
|
+
ruby-debug19
|
45
|
+
vcr (~> 1.10)
|
data/README.rdoc
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
= PayPal Recurring Billing
|
2
|
+
|
3
|
+
PayPal Express Checkout API Client for recurring billing.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
gem install paypal-recurring
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
First, you need to set up your credentials:
|
12
|
+
|
13
|
+
require "paypal/recurring"
|
14
|
+
|
15
|
+
PayPal::Recurring.configure do |config|
|
16
|
+
config.sandbox = true
|
17
|
+
config.username = "seller_1308793919_biz_api1.simplesideias.com.br"
|
18
|
+
config.password = "1308793931"
|
19
|
+
config.signature = "AFcWxV21C7fd0v3bYYYRCpSSRl31AzaB6TzXx5amObyEghjU13.0av2Y"
|
20
|
+
end
|
21
|
+
|
22
|
+
Then, you can request a new payment authorization:
|
23
|
+
|
24
|
+
ppr = PayPal::Recurring.new({
|
25
|
+
:return_url => "http://example.com/paypal/thank_you",
|
26
|
+
:cancel_url => "http://example.com/paypal/canceled",
|
27
|
+
:ipn_url => "http://example.com/paypal/ipn",
|
28
|
+
:description => "Awesome - Monthly Subscription",
|
29
|
+
:amount => "9.00",
|
30
|
+
:currency => "USD"
|
31
|
+
})
|
32
|
+
|
33
|
+
response = ppr.checkout
|
34
|
+
puts response.checkout_url if response.valid?
|
35
|
+
|
36
|
+
You need to redirect your user to the url returned by <tt>response.checkout_url</tt>.
|
37
|
+
After the user accepts or rejects your payment request, he will be redirected to one of those urls you specified.
|
38
|
+
The return url will receive two parameters: <tt>PAYERID</tt> and <tt>TOKEN</tt>. You can use the <tt>TOKEN</tt>
|
39
|
+
parameter to identify your user on your database.
|
40
|
+
|
41
|
+
If you need to retrieve information about your buyer, like address or e-mail, you can use the
|
42
|
+
<tt>checkout_details()</tt> method.
|
43
|
+
|
44
|
+
ppr = PayPal::Recurring.new(:token => "EC-05C46042TU8306821")
|
45
|
+
response = ppr.checkout_details
|
46
|
+
|
47
|
+
Now, you need to request payment. The information you provide here should be exactly the same when you started
|
48
|
+
the checkout process.
|
49
|
+
|
50
|
+
ppr = PayPal::Recurring.new({
|
51
|
+
:token => "EC-05C46042TU8306821",
|
52
|
+
:payer_id => "WTTS5KC2T46YU",
|
53
|
+
:amount => "9.00",
|
54
|
+
:description => "Awesome - Monthly Subscription"
|
55
|
+
})
|
56
|
+
response = ppr.request_payment
|
57
|
+
response.approved?
|
58
|
+
response.completed?
|
59
|
+
|
60
|
+
Finally, you need to create a new recurring profile.
|
61
|
+
|
62
|
+
ppr = PayPal::Recurring.new({
|
63
|
+
:amount => "9.00",
|
64
|
+
:currency => "USD",
|
65
|
+
:description => "Awesome - Monthly Subscription",
|
66
|
+
:ipn_url => "http://example.com/paypal/ipn",
|
67
|
+
:frequency => 1,
|
68
|
+
:token => "EC-05C46042TU8306821",
|
69
|
+
:period => :monthly,
|
70
|
+
:reference => "1234",
|
71
|
+
:payer_id => "WTTS5KC2T46YU",
|
72
|
+
:start_at => Time.now,
|
73
|
+
:failed => 1,
|
74
|
+
:outstanding => :next_billing
|
75
|
+
})
|
76
|
+
|
77
|
+
response = ppr.create_recurring_profile
|
78
|
+
puts response.profile_id
|
79
|
+
|
80
|
+
You can manage your recurring profile.
|
81
|
+
|
82
|
+
ppr = PayPal::Recurring.new(:profile_id => "I-VCEL6TRG35CU")
|
83
|
+
|
84
|
+
ppr.suspend
|
85
|
+
ppr.reactivate
|
86
|
+
ppr.cancel
|
87
|
+
|
88
|
+
=== What information do I need to keep?
|
89
|
+
|
90
|
+
You should save two paramaters to your database: <tt>TOKEN</tt> and <tt>PROFILEID</tt>.
|
91
|
+
<tt>TOKEN</tt> is required when user returns to your website after he authorizes (or not) the billing process. You
|
92
|
+
need to save it so you can find him later. You can remove this info after payment and recurring profile are set.
|
93
|
+
|
94
|
+
The <tt>PROFILEID</tt> allows you to manage the recurring profile, like canceling billing when an user don't
|
95
|
+
want to use your service anymore.
|
96
|
+
|
97
|
+
<b>NOTE:</b> TOKEN will expire after approximately 3 hours.
|
98
|
+
|
99
|
+
== TO-DO
|
100
|
+
|
101
|
+
* handle Instant Payment Notifications (IPN)
|
102
|
+
|
103
|
+
== Maintainer
|
104
|
+
|
105
|
+
* Nando Vieira (http://nandovieira.com.br)
|
106
|
+
|
107
|
+
== License
|
108
|
+
|
109
|
+
(The MIT License)
|
110
|
+
|
111
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
112
|
+
a copy of this software and associated documentation files (the
|
113
|
+
'Software'), to deal in the Software without restriction, including
|
114
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
115
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
116
|
+
permit persons to whom the Software is furnished to do so, subject to
|
117
|
+
the following conditions:
|
118
|
+
|
119
|
+
The above copyright notice and this permission notice shall be
|
120
|
+
included in all copies or substantial portions of the Software.
|
121
|
+
|
122
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
123
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
124
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
125
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
126
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
127
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
128
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
require "paypal/recurring"
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "net/https"
|
2
|
+
require "cgi"
|
3
|
+
require "uri"
|
4
|
+
require "logger"
|
5
|
+
require "ostruct"
|
6
|
+
require "time"
|
7
|
+
|
8
|
+
module PayPal
|
9
|
+
module Recurring
|
10
|
+
autoload :Base, "paypal/recurring/base"
|
11
|
+
autoload :Request, "paypal/recurring/request"
|
12
|
+
autoload :Response, "paypal/recurring/response"
|
13
|
+
autoload :Version, "paypal/recurring/version"
|
14
|
+
|
15
|
+
ENDPOINTS = {
|
16
|
+
:sandbox => {
|
17
|
+
:api => "https://api-3t.sandbox.paypal.com/nvp",
|
18
|
+
:site => "https://www.sandbox.paypal.com/cgi-bin/webscr"
|
19
|
+
},
|
20
|
+
:production => {
|
21
|
+
:api => "https://api-3t.paypal.com/nvp",
|
22
|
+
:site => "https://www.paypal.com/cgi-bin/webscr"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
class << self
|
27
|
+
# Define if requests should be made to PayPal's
|
28
|
+
# sandbox environment. This is specially useful when running
|
29
|
+
# on development or test mode.
|
30
|
+
#
|
31
|
+
# PayPal::Recurring.sandbox = true
|
32
|
+
#
|
33
|
+
attr_accessor :sandbox
|
34
|
+
|
35
|
+
# Set PayPal's API username.
|
36
|
+
#
|
37
|
+
attr_accessor :username
|
38
|
+
|
39
|
+
# Set PayPal's API password.
|
40
|
+
#
|
41
|
+
attr_accessor :password
|
42
|
+
|
43
|
+
# Set PayPal's API signature.
|
44
|
+
#
|
45
|
+
attr_accessor :signature
|
46
|
+
|
47
|
+
# Set application logger. By default, will send output to +STDOUT+.
|
48
|
+
#
|
49
|
+
attr_accessor :logger
|
50
|
+
end
|
51
|
+
|
52
|
+
self.logger = Logger.new(STDOUT)
|
53
|
+
|
54
|
+
# Just a shortcut for <tt>PayPal::Recurring::Base.new</tt>.
|
55
|
+
#
|
56
|
+
def self.new(options = {})
|
57
|
+
Base.new(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Configure PayPal::Recurring options.
|
61
|
+
#
|
62
|
+
# PayPal::Recurring.configure do |config|
|
63
|
+
# config.sandbox = true
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
def self.configure(&block)
|
67
|
+
yield PayPal::Recurring
|
68
|
+
end
|
69
|
+
|
70
|
+
# Detect if sandbox mode is enabled.
|
71
|
+
#
|
72
|
+
def self.sandbox?
|
73
|
+
sandbox == true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return a name for current environment mode (sandbox or production).
|
77
|
+
#
|
78
|
+
def self.environment
|
79
|
+
sandbox? ? :sandbox : :production
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return URL endpoints for current environment.
|
83
|
+
#
|
84
|
+
def self.endpoints
|
85
|
+
ENDPOINTS[environment]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Return API endpoint based on current environment.
|
89
|
+
#
|
90
|
+
def self.api_endpoint
|
91
|
+
endpoints[:api]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return PayPal's API version.
|
95
|
+
#
|
96
|
+
def self.api_version
|
97
|
+
"72.0"
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return site endpoint based on current environment.
|
101
|
+
#
|
102
|
+
def self.site_endpoint
|
103
|
+
endpoints[:site]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module PayPal
|
2
|
+
module Recurring
|
3
|
+
class Base
|
4
|
+
attr_accessor :amount
|
5
|
+
attr_accessor :cancel_url
|
6
|
+
attr_accessor :currency
|
7
|
+
attr_accessor :description
|
8
|
+
attr_accessor :failed
|
9
|
+
attr_accessor :frequency
|
10
|
+
attr_accessor :ipn_url
|
11
|
+
attr_accessor :outstanding
|
12
|
+
attr_accessor :payer_id
|
13
|
+
attr_accessor :period
|
14
|
+
attr_accessor :profile_id
|
15
|
+
attr_accessor :reference
|
16
|
+
attr_accessor :return_url
|
17
|
+
attr_accessor :start_at
|
18
|
+
attr_accessor :token
|
19
|
+
attr_accessor :email
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
options.each {|name, value| send("#{name}=", value)}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Just a shortcut convenience.
|
26
|
+
#
|
27
|
+
def request # :nodoc:
|
28
|
+
@request ||= Request.new
|
29
|
+
end
|
30
|
+
|
31
|
+
# Request a checkout token.
|
32
|
+
#
|
33
|
+
# ppr = PayPal::Recurring.new({
|
34
|
+
# :return_url => "http://example.com/checkout/thank_you",
|
35
|
+
# :cancel_url => "http://example.com/checkout/canceled",
|
36
|
+
# :ipn_url => "http://example.com/paypal/ipn",
|
37
|
+
# :description => "Awesome - Monthly Subscription",
|
38
|
+
# :amount => "9.00",
|
39
|
+
# :currency => "USD"
|
40
|
+
# })
|
41
|
+
#
|
42
|
+
# response = ppr.request_token
|
43
|
+
# response.checkout_url
|
44
|
+
#
|
45
|
+
def checkout
|
46
|
+
params = collect(:amount, :return_url, :cancel_url, :currency, :description, :ipn_url).merge(:payment_action => "Authorization", :no_shipping => 1, :L_BILLINGTYPE0 => "RecurringPayments")
|
47
|
+
request.post(:checkout, params)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Suspend a recurring profile.
|
51
|
+
# Suspended profiles can be reactivated.
|
52
|
+
#
|
53
|
+
# ppr = PayPal::Recurring.new(:profile_id => "I-HYRKXBMNLFSK")
|
54
|
+
# response = ppr.suspend
|
55
|
+
#
|
56
|
+
def suspend
|
57
|
+
request.post(:manage_profile, :action => :suspend, :profile_id => profile_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Reactivate a suspended recurring profile.
|
61
|
+
#
|
62
|
+
# ppr = PayPal::Recurring.new(:profile_id => "I-HYRKXBMNLFSK")
|
63
|
+
# response = ppr.reactivate
|
64
|
+
#
|
65
|
+
def reactivate
|
66
|
+
request.post(:manage_profile, :action => :reactivate, :profile_id => profile_id)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Cancel a recurring profile.
|
70
|
+
# Cancelled profiles cannot be reactivated.
|
71
|
+
#
|
72
|
+
# ppr = PayPal::Recurring.new(:profile_id => "I-HYRKXBMNLFSK")
|
73
|
+
# response = ppr.cancel
|
74
|
+
#
|
75
|
+
def cancel
|
76
|
+
request.post(:manage_profile, :action => :cancel, :profile_id => profile_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Return checkout details.
|
80
|
+
#
|
81
|
+
# ppr = PayPal::Recurring.new(:token => "EC-6LX60229XS426623E")
|
82
|
+
# response = ppr.checkout_details
|
83
|
+
#
|
84
|
+
def checkout_details
|
85
|
+
request.post(:details, :token => token)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Request payment.
|
89
|
+
#
|
90
|
+
# # ppr = PayPal::Recurring.new({
|
91
|
+
# :token => "EC-6LX60229XS426623E",
|
92
|
+
# :payer_id => "WTTS5KC2T46YU",
|
93
|
+
# :amount => "9.00",
|
94
|
+
# :description => "Awesome - Monthly Subscription"
|
95
|
+
# })
|
96
|
+
# response = ppr.request_payment
|
97
|
+
# response.completed? && response.approved?
|
98
|
+
#
|
99
|
+
def request_payment
|
100
|
+
params = collect(:amount, :return_url, :cancel_url, :ipn_url, :currency, :description, :payer_id, :token).merge(:payment_action => "Sale")
|
101
|
+
request.post(:payment, params)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Create a recurring billing profile.
|
105
|
+
#
|
106
|
+
# ppr = PayPal::Recurring.new({
|
107
|
+
# :amount => "9.00",
|
108
|
+
# :currency => "USD",
|
109
|
+
# :description => "Awesome - Monthly Subscription",
|
110
|
+
# :ipn_url => "http://example.com/paypal/ipn",
|
111
|
+
# :frequency => 1,
|
112
|
+
# :token => "EC-05C46042TU8306821",
|
113
|
+
# :period => :monthly,
|
114
|
+
# :reference => "1234",
|
115
|
+
# :payer_id => "WTTS5KC2T46YU",
|
116
|
+
# :start_at => Time.now,
|
117
|
+
# :failed => 1,
|
118
|
+
# :outstanding => :next_billing
|
119
|
+
# })
|
120
|
+
#
|
121
|
+
# response = ppr.create_recurring_profile
|
122
|
+
#
|
123
|
+
def create_recurring_profile
|
124
|
+
params = collect(:amount, :currency, :description, :payer_id, :token, :reference, :start_at, :failed, :outstanding, :ipn_url, :frequency, :period, :email)
|
125
|
+
request.post(:create_profile, params)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Retrieve information about existing recurring profile.
|
129
|
+
#
|
130
|
+
# ppr = PayPal::Recurring.new(:profile_id => "I-VCEL6TRG35CU")
|
131
|
+
# response = ppr.profile
|
132
|
+
#
|
133
|
+
def profile
|
134
|
+
request.post(:profile, :profile_id => profile_id)
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
# Collect specified attributes and build a hash out of it.
|
139
|
+
#
|
140
|
+
def collect(*args) # :nodoc:
|
141
|
+
args.inject({}) do |buffer, attr_name|
|
142
|
+
value = send(attr_name)
|
143
|
+
buffer[attr_name] = value if value
|
144
|
+
buffer
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|