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.
Files changed (49) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +45 -0
  5. data/README.rdoc +128 -0
  6. data/Rakefile +5 -0
  7. data/docs/PP_NVPAPI_DeveloperGuide.pdf +0 -0
  8. data/docs/PP_WPP_IntegrationGuide.pdf +0 -0
  9. data/lib/paypal-recurring.rb +1 -0
  10. data/lib/paypal/recurring.rb +106 -0
  11. data/lib/paypal/recurring/base.rb +149 -0
  12. data/lib/paypal/recurring/cacert.pem +3987 -0
  13. data/lib/paypal/recurring/request.rb +143 -0
  14. data/lib/paypal/recurring/response.rb +26 -0
  15. data/lib/paypal/recurring/response/base.rb +74 -0
  16. data/lib/paypal/recurring/response/checkout.rb +11 -0
  17. data/lib/paypal/recurring/response/details.rb +26 -0
  18. data/lib/paypal/recurring/response/manage_profile.rb +12 -0
  19. data/lib/paypal/recurring/response/payment.rb +22 -0
  20. data/lib/paypal/recurring/response/profile.rb +69 -0
  21. data/lib/paypal/recurring/version.rb +10 -0
  22. data/paypal-recurring.gemspec +25 -0
  23. data/spec/fixtures/checkout/failure.yml +26 -0
  24. data/spec/fixtures/checkout/success.yml +26 -0
  25. data/spec/fixtures/create_profile/failure.yml +26 -0
  26. data/spec/fixtures/create_profile/success.yml +26 -0
  27. data/spec/fixtures/details/cancelled.yml +26 -0
  28. data/spec/fixtures/details/failure.yml +26 -0
  29. data/spec/fixtures/details/success.yml +26 -0
  30. data/spec/fixtures/payment/failure.yml +26 -0
  31. data/spec/fixtures/payment/success.yml +26 -0
  32. data/spec/fixtures/profile/cancel/failure.yml +26 -0
  33. data/spec/fixtures/profile/cancel/success.yml +26 -0
  34. data/spec/fixtures/profile/failure.yml +26 -0
  35. data/spec/fixtures/profile/reactivate/failure.yml +26 -0
  36. data/spec/fixtures/profile/reactivate/success.yml +26 -0
  37. data/spec/fixtures/profile/success.yml +26 -0
  38. data/spec/fixtures/profile/suspend/failure.yml +26 -0
  39. data/spec/fixtures/profile/suspend/success.yml +26 -0
  40. data/spec/paypal/recurring_spec.rb +87 -0
  41. data/spec/paypal/request_spec.rb +102 -0
  42. data/spec/paypal/response/checkout_details_spec.rb +51 -0
  43. data/spec/paypal/response/checkout_spec.rb +32 -0
  44. data/spec/paypal/response/create_recurring_profile_spec.rb +39 -0
  45. data/spec/paypal/response/manage_profile_spec.rb +62 -0
  46. data/spec/paypal/response/profile_spec.rb +41 -0
  47. data/spec/paypal/response/request_payment_spec.rb +35 -0
  48. data/spec/spec_helper.rb +24 -0
  49. metadata +187 -0
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
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
@@ -0,0 +1,5 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
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