paypal-recurring 0.1.0 → 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/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paypal-recurring (0.1.0)
4
+ paypal-recurring (0.1.1)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
@@ -1,13 +1,13 @@
1
1
  require "net/https"
2
2
  require "cgi"
3
3
  require "uri"
4
- require "logger"
5
4
  require "ostruct"
6
5
  require "time"
7
6
 
8
7
  module PayPal
9
8
  module Recurring
10
9
  autoload :Base, "paypal/recurring/base"
10
+ autoload :Notification, "paypal/recurring/notification"
11
11
  autoload :Request, "paypal/recurring/request"
12
12
  autoload :Response, "paypal/recurring/response"
13
13
  autoload :Version, "paypal/recurring/version"
@@ -44,12 +44,15 @@ module PayPal
44
44
  #
45
45
  attr_accessor :signature
46
46
 
47
- # Set application logger. By default, will send output to +STDOUT+.
47
+ # Set seller id. Will be used to verify IPN.
48
48
  #
49
- attr_accessor :logger
50
- end
49
+ #
50
+ attr_accessor :seller_id
51
51
 
52
- self.logger = Logger.new(STDOUT)
52
+ # The seller e-mail. Will be used to verify IPN.
53
+ #
54
+ attr_accessor :email
55
+ end
53
56
 
54
57
  # Just a shortcut for <tt>PayPal::Recurring::Base.new</tt>.
55
58
  #
@@ -44,7 +44,7 @@ module PayPal
44
44
  #
45
45
  def checkout
46
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)
47
+ request.run(:checkout, params)
48
48
  end
49
49
 
50
50
  # Suspend a recurring profile.
@@ -54,7 +54,7 @@ module PayPal
54
54
  # response = ppr.suspend
55
55
  #
56
56
  def suspend
57
- request.post(:manage_profile, :action => :suspend, :profile_id => profile_id)
57
+ request.run(:manage_profile, :action => :suspend, :profile_id => profile_id)
58
58
  end
59
59
 
60
60
  # Reactivate a suspended recurring profile.
@@ -63,7 +63,7 @@ module PayPal
63
63
  # response = ppr.reactivate
64
64
  #
65
65
  def reactivate
66
- request.post(:manage_profile, :action => :reactivate, :profile_id => profile_id)
66
+ request.run(:manage_profile, :action => :reactivate, :profile_id => profile_id)
67
67
  end
68
68
 
69
69
  # Cancel a recurring profile.
@@ -73,7 +73,7 @@ module PayPal
73
73
  # response = ppr.cancel
74
74
  #
75
75
  def cancel
76
- request.post(:manage_profile, :action => :cancel, :profile_id => profile_id)
76
+ request.run(:manage_profile, :action => :cancel, :profile_id => profile_id)
77
77
  end
78
78
 
79
79
  # Return checkout details.
@@ -82,7 +82,7 @@ module PayPal
82
82
  # response = ppr.checkout_details
83
83
  #
84
84
  def checkout_details
85
- request.post(:details, :token => token)
85
+ request.run(:details, :token => token)
86
86
  end
87
87
 
88
88
  # Request payment.
@@ -98,7 +98,7 @@ module PayPal
98
98
  #
99
99
  def request_payment
100
100
  params = collect(:amount, :return_url, :cancel_url, :ipn_url, :currency, :description, :payer_id, :token).merge(:payment_action => "Sale")
101
- request.post(:payment, params)
101
+ request.run(:payment, params)
102
102
  end
103
103
 
104
104
  # Create a recurring billing profile.
@@ -122,7 +122,7 @@ module PayPal
122
122
  #
123
123
  def create_recurring_profile
124
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)
125
+ request.run(:create_profile, params)
126
126
  end
127
127
 
128
128
  # Retrieve information about existing recurring profile.
@@ -131,7 +131,7 @@ module PayPal
131
131
  # response = ppr.profile
132
132
  #
133
133
  def profile
134
- request.post(:profile, :profile_id => profile_id)
134
+ request.run(:profile, :profile_id => profile_id)
135
135
  end
136
136
 
137
137
  private
@@ -0,0 +1,75 @@
1
+ module PayPal
2
+ module Recurring
3
+ class Notification
4
+ attr_reader :params
5
+
6
+ def initialize(params = {})
7
+ self.params = params
8
+ end
9
+
10
+ def params=(params)
11
+ @params = params.inject({}) do |buffer, (name,value)|
12
+ buffer.merge(name.to_sym => value)
13
+ end
14
+ end
15
+
16
+ def request
17
+ @request ||= PayPal::Recurring::Request.new.tap do |request|
18
+ request.uri = URI.parse("#{PayPal::Recurring.site_endpoint}?cmd=_notify-validate")
19
+ end
20
+ end
21
+
22
+ def response
23
+ @response ||= request.post(params.merge(:cmd => "_notify-validate"))
24
+ end
25
+
26
+ def valid?
27
+ completed? && verified? && params[:receiver_email] == PayPal::Recurring.email && params[:receiver_id] == PayPal::Recurring.seller_id && params[:txn_type] == "recurring_payment"
28
+ end
29
+
30
+ def completed?
31
+ status == "Completed"
32
+ end
33
+
34
+ def transaction_id
35
+ params[:txn_id]
36
+ end
37
+
38
+ def fee
39
+ params[:mc_currency]
40
+ end
41
+
42
+ def reference
43
+ params[:rp_invoice_id]
44
+ end
45
+
46
+ def payment_id
47
+ params[:recurring_payment_id]
48
+ end
49
+
50
+ def next_payment_date
51
+ Time.parse(params[:next_payment_date]) if params[:next_payment_date]
52
+ end
53
+
54
+ def paid_at
55
+ Time.parse params[:time_created] if params[:time_created]
56
+ end
57
+
58
+ def amount
59
+ params[:amount]
60
+ end
61
+
62
+ def currency
63
+ params[:mc_currency]
64
+ end
65
+
66
+ def status
67
+ params[:payment_status]
68
+ end
69
+
70
+ def verified?
71
+ response.body == "VERIFIED"
72
+ end
73
+ end
74
+ end
75
+ end
@@ -57,12 +57,14 @@ module PayPal
57
57
 
58
58
  CA_FILE = File.dirname(__FILE__) + "/cacert.pem"
59
59
 
60
+ attr_accessor :uri
61
+
60
62
  # Do a POST request to PayPal API.
61
63
  # The +method+ argument is the name of the API method you want to invoke.
62
64
  # For instance, if you want to request a new checkout token, you may want
63
65
  # to do something like:
64
66
  #
65
- # response = request.post(:express_checkout)
67
+ # response = request.run(:express_checkout)
66
68
  #
67
69
  # We normalize the methods name. For a list of what's being covered, refer to
68
70
  # PayPal::Recurring::Request::METHODS constant.
@@ -70,15 +72,27 @@ module PayPal
70
72
  # The params hash can use normalized names. For a list, check the
71
73
  # PayPal::Recurring::Request::ATTRIBUTES constant.
72
74
  #
73
- def post(method, params = {})
75
+ def run(method, params = {})
74
76
  params = prepare_params(params.merge(:method => METHODS.fetch(method, method.to_s)))
75
- request = Net::HTTP::Post.new(uri.request_uri)
76
- request["User-Agent"] = "PayPal::Recurring/#{PayPal::Recurring::Version::STRING}"
77
- request.form_data = params
78
- response = client.request(request)
77
+ response = post(params)
79
78
  Response.process(method, response)
80
79
  end
81
80
 
81
+ #
82
+ #
83
+ def request
84
+ @request ||= Net::HTTP::Post.new(uri.request_uri).tap do |http|
85
+ http["User-Agent"] = "PayPal::Recurring/#{PayPal::Recurring::Version::STRING}"
86
+ end
87
+ end
88
+
89
+ #
90
+ #
91
+ def post(params = {})
92
+ request.form_data = params
93
+ client.request(request)
94
+ end
95
+
82
96
  # Join params and normalize attribute names.
83
97
  #
84
98
  def prepare_params(params) # :nodoc:
@@ -3,7 +3,7 @@ module PayPal
3
3
  module Version
4
4
  MAJOR = 0
5
5
  MINOR = 1
6
- PATCH = 0
6
+ PATCH = 1
7
7
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
8
8
  end
9
9
  end
@@ -0,0 +1,32 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :post
5
+ uri: https://www.sandbox.paypal.com:443/cgi-bin/webscr?cmd=_notify-validate
6
+ body: cmd=_notify-validate
7
+ headers:
8
+ user-agent:
9
+ - PayPal::Recurring/0.1.0
10
+ content-type:
11
+ - application/x-www-form-urlencoded
12
+ response: !ruby/struct:VCR::Response
13
+ status: !ruby/struct:VCR::ResponseStatus
14
+ code: 200
15
+ message: OK
16
+ headers:
17
+ date:
18
+ - Mon, 27 Jun 2011 17:39:42 GMT
19
+ server:
20
+ - Apache
21
+ set-cookie:
22
+ - c9MWDuvPtT9GIMyPc3jwol1VSlO=FYMA2gxaecqXl8Q9SSeevuaQcqfcQcwNGw_shFaqV4wYiWT3ZUcQ4O8NLvXqevPJfliR0yse8Z4bzZ8A37MQKM6Q_ci6wnYOkfGZSxZYa_hNLMvR6QHnGyW6u94YxhYQpgu0VG%7cySXso7WZVjU8pXiTJS488DAO3YqW5S6DsAZMY8TN22H5J8gW1As5DlqX1pm60R5dWee5wm%7cdMLFsFZz_xjN2U4nbQ71pdvMUEch5_rqq4NReBSNMz7j3ry9JJhQ1J0X6pqjinKs-kO5NG%7c1309196387; domain=.paypal.com; path=/; Secure; HttpOnly
23
+ - cookie_check=yes; expires=Thu, 24-Jun-2021 17:39:47 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
24
+ - navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
25
+ - navlns=0.0; expires=Sun, 22-Jun-2031 17:39:47 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
26
+ - Apache=10.72.109.11.1309196382543853; path=/; expires=Wed, 19-Jun-41 17:39:42 GMT
27
+ transfer-encoding:
28
+ - chunked
29
+ content-type:
30
+ - text/html; charset=UTF-8
31
+ body: INVALID
32
+ http_version: "1.1"
@@ -0,0 +1,32 @@
1
+ ---
2
+ - !ruby/struct:VCR::HTTPInteraction
3
+ request: !ruby/struct:VCR::Request
4
+ method: :post
5
+ uri: https://www.sandbox.paypal.com:443/cgi-bin/webscr?cmd=_notify-validate
6
+ body: test_ipn=1&payment_type=echeck&payment_date=06%3a16%3a11%20Jun%2027%2c%202011%20PDT&payment_status=Completed&pending_reason=echeck&address_status=confirmed&payer_status=verified&first_name=John&last_name=Smith&payer_email=buyer%40paypalsandbox.com&payer_id=TESTBUYERID01&address_name=John%20Smith&address_country=United%20States&address_country_code=US&address_zip=95131&address_state=CA&address_city=San%20Jose&address_street=123%2c%20any%20street&business=seller%40paypalsandbox.com&receiver_email=seller%40paypalsandbox.com&receiver_id=TESTSELLERID1&residence_country=US&item_name=something&item_number=AK-1234&quantity=1&shipping=3.04&tax=2.02&mc_currency=USD&mc_fee=0.44&mc_gross=12.34&txn_type=web_accept&txn_id=116271316&notify_version=2.1&custom=xyz123&invoice=abc1234&charset=windows-1252&verify_sign=AvgHA1TpBJYQMa-x3XsZYuQd7MkKAMUFy7f2a9G4UNFmNHHXGnfAFi3l&cmd=_notify-validate
7
+ headers:
8
+ user-agent:
9
+ - PayPal::Recurring/0.1.0
10
+ content-type:
11
+ - application/x-www-form-urlencoded
12
+ response: !ruby/struct:VCR::Response
13
+ status: !ruby/struct:VCR::ResponseStatus
14
+ code: 200
15
+ message: OK
16
+ headers:
17
+ date:
18
+ - Mon, 27 Jun 2011 17:37:09 GMT
19
+ server:
20
+ - Apache
21
+ set-cookie:
22
+ - c9MWDuvPtT9GIMyPc3jwol1VSlO=EShGvdSJTkQTmhIi4jIAvW9REPYfLjRSo3BqPdRvBymVBvHIai4jnMHE9UzQDrz7FgAtLCUw0V0VroudhtcfoaNLca2TZq61mMSzEHPHgwAj5ON8rmHCr_IjY_AkKI885AFFLW%7c-PiLEQg9LK_E6xg7biKrMLHv97B5cP5yT2R1l6g_ZNq-3SDSCAm-9VQdvpJSnrGNtfsrrG%7cvdBU3UXz8sDrfFIOKP_zwmNkSm8nNcKCATxNvMpGb4VOdGI4Sjia0YCorXMBWxpjKuAip0%7c1309196230; domain=.paypal.com; path=/; Secure; HttpOnly
23
+ - cookie_check=yes; expires=Thu, 24-Jun-2021 17:37:10 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
24
+ - navcmd=_notify-validate; domain=.paypal.com; path=/; Secure; HttpOnly
25
+ - navlns=0.0; expires=Sun, 22-Jun-2031 17:37:10 GMT; domain=.paypal.com; path=/; Secure; HttpOnly
26
+ - Apache=10.72.109.11.1309196229102128; path=/; expires=Wed, 19-Jun-41 17:37:09 GMT
27
+ transfer-encoding:
28
+ - chunked
29
+ content-type:
30
+ - text/html; charset=UTF-8
31
+ body: VERIFIED
32
+ http_version: "1.1"
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ describe PayPal::Recurring::Notification do
4
+ context "when successful" do
5
+ use_vcr_cassette "notification/success"
6
+
7
+ it "verifies notification" do
8
+ subject.params = {"test_ipn"=>"1", "payment_type"=>"echeck", "payment_date"=>"06:16:11 Jun 27, 2011 PDT", "payment_status"=>"Completed", "pending_reason"=>"echeck", "address_status"=>"confirmed", "payer_status"=>"verified", "first_name"=>"John", "last_name"=>"Smith", "payer_email"=>"buyer@paypalsandbox.com", "payer_id"=>"TESTBUYERID01", "address_name"=>"John Smith", "address_country"=>"United States", "address_country_code"=>"US", "address_zip"=>"95131", "address_state"=>"CA", "address_city"=>"San Jose", "address_street"=>"123, any street", "business"=>"seller@paypalsandbox.com", "receiver_email"=>"seller@paypalsandbox.com", "receiver_id"=>"TESTSELLERID1", "residence_country"=>"US", "item_name"=>"something", "item_number"=>"AK-1234", "quantity"=>"1", "shipping"=>"3.04", "tax"=>"2.02", "mc_currency"=>"USD", "mc_fee"=>"0.44", "mc_gross"=>"12.34", "txn_type"=>"web_accept", "txn_id"=>"116271316", "notify_version"=>"2.1", "custom"=>"xyz123", "invoice"=>"abc1234", "charset"=>"windows-1252", "verify_sign"=>"A12AYqq6LElPcpXaQx48GiroLHnMAoQPnK0Z7aRwXUOpg1GfDaE15mFN"}
9
+ subject.should be_verified
10
+ subject.should be_completed
11
+ end
12
+ end
13
+
14
+ context "when failure" do
15
+ use_vcr_cassette "notification/failure"
16
+
17
+ it "verifies notification" do
18
+ subject.params = {}
19
+ subject.should_not be_verified
20
+ subject.should_not be_completed
21
+ end
22
+ end
23
+ end
@@ -1,12 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe PayPal::Recurring do
4
- describe ".logger" do
5
- it "has a default logging" do
6
- PayPal::Recurring.logger.should be_a(Logger)
7
- end
8
- end
9
-
10
4
  describe ".new" do
11
5
  it "instantiates PayPal::Recurring::Base" do
12
6
  PayPal::Recurring.new.should be_a(PayPal::Recurring::Base)
@@ -19,7 +19,7 @@ describe PayPal::Recurring::Request do
19
19
  describe "#post" do
20
20
  let(:request) {
21
21
  FakeWeb.register_uri :post, "https://api-3t.sandbox.paypal.com/nvp", :status => 200
22
- subject.post(:checkout)
22
+ subject.run(:checkout)
23
23
  CGI.parse(FakeWeb.last_request.body)
24
24
  }
25
25
 
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: paypal-recurring
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.1.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nando Vieira
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-27 00:00:00 Z
13
+ date: 2011-06-28 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rspec
@@ -89,6 +89,7 @@ files:
89
89
  - lib/paypal/recurring.rb
90
90
  - lib/paypal/recurring/base.rb
91
91
  - lib/paypal/recurring/cacert.pem
92
+ - lib/paypal/recurring/notification.rb
92
93
  - lib/paypal/recurring/request.rb
93
94
  - lib/paypal/recurring/response.rb
94
95
  - lib/paypal/recurring/response/base.rb
@@ -106,6 +107,8 @@ files:
106
107
  - spec/fixtures/details/cancelled.yml
107
108
  - spec/fixtures/details/failure.yml
108
109
  - spec/fixtures/details/success.yml
110
+ - spec/fixtures/notification/failure.yml
111
+ - spec/fixtures/notification/success.yml
109
112
  - spec/fixtures/payment/failure.yml
110
113
  - spec/fixtures/payment/success.yml
111
114
  - spec/fixtures/profile/cancel/failure.yml
@@ -116,6 +119,7 @@ files:
116
119
  - spec/fixtures/profile/success.yml
117
120
  - spec/fixtures/profile/suspend/failure.yml
118
121
  - spec/fixtures/profile/suspend/success.yml
122
+ - spec/paypal/notification_spec.rb
119
123
  - spec/paypal/recurring_spec.rb
120
124
  - spec/paypal/request_spec.rb
121
125
  - spec/paypal/response/checkout_details_spec.rb
@@ -138,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
142
  requirements:
139
143
  - - ">="
140
144
  - !ruby/object:Gem::Version
141
- hash: -1993102493723648975
145
+ hash: -1456604981268972750
142
146
  segments:
143
147
  - 0
144
148
  version: "0"
@@ -147,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
147
151
  requirements:
148
152
  - - ">="
149
153
  - !ruby/object:Gem::Version
150
- hash: -1993102493723648975
154
+ hash: -1456604981268972750
151
155
  segments:
152
156
  - 0
153
157
  version: "0"
@@ -166,6 +170,8 @@ test_files:
166
170
  - spec/fixtures/details/cancelled.yml
167
171
  - spec/fixtures/details/failure.yml
168
172
  - spec/fixtures/details/success.yml
173
+ - spec/fixtures/notification/failure.yml
174
+ - spec/fixtures/notification/success.yml
169
175
  - spec/fixtures/payment/failure.yml
170
176
  - spec/fixtures/payment/success.yml
171
177
  - spec/fixtures/profile/cancel/failure.yml
@@ -176,6 +182,7 @@ test_files:
176
182
  - spec/fixtures/profile/success.yml
177
183
  - spec/fixtures/profile/suspend/failure.yml
178
184
  - spec/fixtures/profile/suspend/success.yml
185
+ - spec/paypal/notification_spec.rb
179
186
  - spec/paypal/recurring_spec.rb
180
187
  - spec/paypal/request_spec.rb
181
188
  - spec/paypal/response/checkout_details_spec.rb