paypal-recurring 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/paypal/recurring.rb +8 -5
- data/lib/paypal/recurring/base.rb +8 -8
- data/lib/paypal/recurring/notification.rb +75 -0
- data/lib/paypal/recurring/request.rb +20 -6
- data/lib/paypal/recurring/version.rb +1 -1
- data/spec/fixtures/notification/failure.yml +32 -0
- data/spec/fixtures/notification/success.yml +32 -0
- data/spec/paypal/notification_spec.rb +23 -0
- data/spec/paypal/recurring_spec.rb +0 -6
- data/spec/paypal/request_spec.rb +1 -1
- metadata +11 -4
data/Gemfile.lock
CHANGED
data/lib/paypal/recurring.rb
CHANGED
@@ -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
|
47
|
+
# Set seller id. Will be used to verify IPN.
|
48
48
|
#
|
49
|
-
|
50
|
-
|
49
|
+
#
|
50
|
+
attr_accessor :seller_id
|
51
51
|
|
52
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
75
|
+
def run(method, params = {})
|
74
76
|
params = prepare_params(params.merge(:method => METHODS.fetch(method, method.to_s)))
|
75
|
-
|
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:
|
@@ -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¬ify_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)
|
data/spec/paypal/request_spec.rb
CHANGED
@@ -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.
|
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.
|
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-
|
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: -
|
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: -
|
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
|