paypal_api 0.3.0 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/MIT-LICENSE +20 -0
- data/README.markdown +53 -2
- data/lib/generators/paypal/ipn_message_generator.rb +32 -0
- data/lib/generators/templates/ipn_message.rb +28 -0
- data/lib/generators/templates/migration.rb +13 -0
- data/lib/paypal_api/apis/adaptive_accounts.rb +4 -0
- data/lib/paypal_api/apis/adaptive_payments.rb +183 -0
- data/lib/paypal_api/apis/api.rb +29 -6
- data/lib/paypal_api/apis/button_manager.rb +5 -0
- data/lib/paypal_api/apis/express_checkout.rb +5 -0
- data/lib/paypal_api/apis/invoicing.rb +5 -0
- data/lib/paypal_api/apis/mass_pay.rb +12 -11
- data/lib/paypal_api/apis/payments_pro.rb +76 -0
- data/lib/paypal_api/apis/permissions.rb +5 -0
- data/lib/paypal_api/support/request.rb +105 -26
- data/lib/paypal_api/support/response.rb +3 -3
- data/lib/paypal_api/version.rb +1 -1
- data/lib/paypal_api.rb +12 -1
- data/paypal_api.gemspec +6 -4
- data/spec/generators/ipn_message_generator_spec.rb +43 -0
- data/spec/support/parameter_spec.rb +3 -2
- data/spec/support/request_spec.rb +3 -2
- data/spec/unit/adaptive_payments_spec.rb +122 -0
- data/spec/unit/api_spec.rb +12 -12
- data/spec/unit/mass_pay_spec.rb +2 -2
- metadata +33 -19
data/.gitignore
CHANGED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Matt Handler
|
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.markdown
CHANGED
@@ -20,8 +20,8 @@ request.amt = 10.00
|
|
20
20
|
|
21
21
|
# Add a list type field
|
22
22
|
request.item.push {
|
23
|
-
:
|
24
|
-
:
|
23
|
+
:email => "bro@dudeman.com",
|
24
|
+
:amt => 23.0
|
25
25
|
}
|
26
26
|
|
27
27
|
response = request.make
|
@@ -56,14 +56,55 @@ test:
|
|
56
56
|
username: "user_api1.something.com"
|
57
57
|
password: "some_password_they_gave_you"
|
58
58
|
signature: "some_signature"
|
59
|
+
application_id: "APP-80W284485P519543T" # only necessary for adaptive payments api
|
59
60
|
|
60
61
|
production:
|
61
62
|
environment: "production"
|
62
63
|
username: <%= ENV["PAYPAL_USERNAME"] %>
|
63
64
|
password: <%= ENV["PAYPAL_PASSWORD"] %>
|
64
65
|
signature: <%= ENV["PAYPAL_SIGNATURE"] %>
|
66
|
+
application_id <%= ENV["PAYPAL_APP_ID"] %>
|
65
67
|
```
|
66
68
|
|
69
|
+
## Ipn Messages
|
70
|
+
|
71
|
+
there is an ipn message model generator: `rails generate paypal:ipn_message`, it will create
|
72
|
+
a migration and the IpnMessage model.
|
73
|
+
|
74
|
+
you must edit the route and add a handler like so:
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
# config/routes
|
78
|
+
MyApp::Application.routes.draw do
|
79
|
+
|
80
|
+
match '/ipn_message', to: 'handlers#handle_ipn', as: 'ipn_message'
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
# app/controllers/handlers_controller.rb
|
85
|
+
class HandlersController < ApplicationController
|
86
|
+
|
87
|
+
def handle_ipn
|
88
|
+
@ipn_message = IpnMessage.create_from_message(params) # provided by generator
|
89
|
+
|
90
|
+
@ipn_message.success?
|
91
|
+
@ipn_message.correlation_id
|
92
|
+
@ipn_message.transaction_id # not always provided
|
93
|
+
@ipn_message.message # raw text of the message
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
## Testing
|
100
|
+
|
101
|
+
i'm an rspec kinda guy. note that i have test for actual requests against the paypal
|
102
|
+
sandbox server, but they are off by default. remove the line about `:slow_paypal` in
|
103
|
+
`spec/spec_helper.rb` to turn these back on.
|
104
|
+
|
105
|
+
also note that, for the Adaptive Payments api, an application id is required, for testing,
|
106
|
+
you can use this: "APP-80W284485P519543T" ([https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_APGettingStarted](https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_APGettingStarted))
|
107
|
+
|
67
108
|
# Current Status
|
68
109
|
|
69
110
|
alpha
|
@@ -92,6 +133,11 @@ like to contribute, i've made it pretty easy to add compatibility for a new api
|
|
92
133
|
|
93
134
|
## Payments Pro
|
94
135
|
|
136
|
+
note that paypal has a strict policy about who they approve for
|
137
|
+
payments pro. you can sign up for it, and start testing it, but as soon as your first
|
138
|
+
real charge goes through, they will vet your website and many people have gotten burned
|
139
|
+
by this (including me, sad sad me...).
|
140
|
+
|
95
141
|
* do_direct_payment - ✓
|
96
142
|
|
97
143
|
* do_reference_transaction - ✓
|
@@ -152,6 +198,11 @@ note that you need to request that paypal enable mass pay for your account befor
|
|
152
198
|
|
153
199
|
## Adaptive Payments
|
154
200
|
|
201
|
+
this api is very different from the others... getting it to work with the way i built things already
|
202
|
+
required some ugly stuff, but it helps keep the gem consistent from the outside.
|
203
|
+
|
204
|
+
* pay - ✓
|
205
|
+
|
155
206
|
## Adaptive Accounts
|
156
207
|
|
157
208
|
## Invoicing
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
require "rails/generators/migration"
|
3
|
+
|
4
|
+
module Paypal
|
5
|
+
module Generators
|
6
|
+
class IpnMessageGenerator < Rails::Generators::Base
|
7
|
+
# include Rails::Generators::ResourceHelpers
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
|
10
|
+
source_root File.expand_path("../../templates", __FILE__)
|
11
|
+
|
12
|
+
desc "creates a migration to store ipn messages, adds some model helpers, adds a route"
|
13
|
+
|
14
|
+
def create_ipn_message_migration
|
15
|
+
migration_template "migration.rb", "db/migrate/add_ipn_messages.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.next_migration_number(path)
|
19
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_to_ipn_message_handling_model
|
23
|
+
copy_file "ipn_message.rb", "app/models/ipn_message.rb"
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_route
|
27
|
+
route %Q{match "ipn_message", :to => "callback_controller#handle_ipn", :as => :ipn_message} if FileTest.exists?("config/routes.rb")
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class IpnMessage < ActiveRecord::Base
|
2
|
+
|
3
|
+
alias_method :success?, :success
|
4
|
+
|
5
|
+
def self.create_from_message(hash)
|
6
|
+
ipn_message = IpnMessage.new
|
7
|
+
|
8
|
+
ipn_message.body = hash.to_yaml
|
9
|
+
ipn_message.success = hash["ACK"] == "Success"
|
10
|
+
ipn_message.correlation_id = hash["correlation_id"]
|
11
|
+
ipn_message.transaction_id = hash["transaction_id"]
|
12
|
+
|
13
|
+
ipn_message.save
|
14
|
+
return ipn_message
|
15
|
+
end
|
16
|
+
|
17
|
+
# returns hash of unique_id:string => status:bool
|
18
|
+
def unique_ids
|
19
|
+
hash = YAML.load(self.body)
|
20
|
+
|
21
|
+
return hash.inject({}){|acc, (k,v)|
|
22
|
+
k.to_s =~ /unique_id_(\d+)/
|
23
|
+
acc[v] = hash["status_#{$1}"] == "Completed" if $1
|
24
|
+
acc
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# note: things got a little weird here because the paypal apis
|
2
|
+
# are so different, but i tried to make it work smoothly... at least
|
3
|
+
# it is from outside interaction... wahhh
|
4
|
+
|
5
|
+
module Paypal
|
6
|
+
|
7
|
+
class AdaptivePaymentsResponse < Response
|
8
|
+
def initialize(stringio)
|
9
|
+
@raw_response = stringio.class == StringIO ? stringio.read : stringio
|
10
|
+
@parsed_response = CGI.parse(@raw_response)
|
11
|
+
|
12
|
+
@success = @parsed_response["responseEnvelope.ack"] == ["Success"]
|
13
|
+
|
14
|
+
unless @success
|
15
|
+
# "responseEnvelope.timestamp"=>["2012-02-29T13:35:28.528-08:00"],
|
16
|
+
# "responseEnvelope.ack"=>["Failure"],
|
17
|
+
# "responseEnvelope.correlationId"=>["ca0befbd1fe0b"],
|
18
|
+
# "responseEnvelope.build"=>["2486531"],
|
19
|
+
# "error(0).errorId"=>["560022"],
|
20
|
+
# "error(0).domain"=>["PLATFORM"],
|
21
|
+
# "error(0).subdomain"=>["Application"],
|
22
|
+
# "error(0).severity"=>["Error"],
|
23
|
+
# "error(0).category"=>["Application"],
|
24
|
+
# "error(0).message"=>["The X-PAYPAL-APPLICATION-ID header contains an invalid value"],
|
25
|
+
# "error(0).parameter(0)"=>["X-PAYPAL-APPLICATION-ID"]
|
26
|
+
|
27
|
+
@error_message = @parsed_response["error(0).message"][0]
|
28
|
+
@error_code = @parsed_response["error(0).errorId"][0]
|
29
|
+
@paypal_error_field = @parsed_response["error(0).parameter(0)"][0]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def symbol_to_key(symbol)
|
36
|
+
case symbol
|
37
|
+
when :correlation_id
|
38
|
+
return "responseEnvelope.correlationId"
|
39
|
+
else
|
40
|
+
return Paypal::Api.symbol_to_lower_camel(symbol)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class AdaptivePaymentsRequest < Request
|
46
|
+
# customize validation here
|
47
|
+
attr_accessor :ip_address
|
48
|
+
|
49
|
+
def self.api_endpoint
|
50
|
+
"https://svcs.paypal.com/AdaptivePayments/#{api_method.capitalize}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.api_sandbox_endpoint
|
54
|
+
"https://svcs.sandbox.paypal.com/AdaptivePayments/#{api_method.capitalize}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def headers
|
58
|
+
{
|
59
|
+
"X-PAYPAL-SECURITY-USERID" => user,
|
60
|
+
"X-PAYPAL-SECURITY-PASSWORD" => password,
|
61
|
+
"X-PAYPAL-SECURITY-SIGNATURE" => signature,
|
62
|
+
"X-PAYPAL-DEVICE-IPADDRESS" => @ip_address,
|
63
|
+
"X-PAYPAL-REQUEST-DATA-FORMAT" => "NV",
|
64
|
+
"X-PAYPAL-RESPONSE-DATA-FORMAT" => "NV",
|
65
|
+
"X-PAYPAL-APPLICATION-ID" => application_id
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def process_response(response)
|
70
|
+
return AdaptivePaymentsResponse.new(response)
|
71
|
+
end
|
72
|
+
|
73
|
+
def make_request
|
74
|
+
if @ip_address.nil?
|
75
|
+
throw Paypal::InvalidRequest, "need an ip address"
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_key(symbol)
|
82
|
+
if symbol.is_a?(String)
|
83
|
+
return symbol
|
84
|
+
else
|
85
|
+
case symbol
|
86
|
+
when :request_envelope_error_language then
|
87
|
+
return "requestEnvelope.errorLanguage"
|
88
|
+
# when :reverse_all_parallel_payments_on_error then
|
89
|
+
# return "reverseAllParallelPaymentsonError" # may just be a typo in docs, need to test
|
90
|
+
when :request_envelope_detail_level then
|
91
|
+
return "requestEnvelope.detailLevel"
|
92
|
+
when :sender_use_credentials
|
93
|
+
return "sender.useCredentials"
|
94
|
+
when :method
|
95
|
+
return "METHOD"
|
96
|
+
else
|
97
|
+
#camelcaps but first letter is lowercase
|
98
|
+
return Paypal::Api.symbol_to_lower_camel(symbol)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class AdaptivePayments < Paypal::Api
|
105
|
+
|
106
|
+
set_request_signature :pay, {
|
107
|
+
# standard params
|
108
|
+
:action_type => Enum.new({:pay => "PAY", :create => "CREATE", :pay_primary => "PAY_PRIMARY"}),
|
109
|
+
:receiver => Sequential.new({
|
110
|
+
:email => String,
|
111
|
+
:amount => Float,
|
112
|
+
:primary => Optional.new(bool_class),
|
113
|
+
:invoice_id => Optional.new(String), # max 127 char
|
114
|
+
:payment_type => Optional.new(Enum.new({
|
115
|
+
:goods => "GOODS",
|
116
|
+
:service => "SERVICE",
|
117
|
+
:personal => "PERSONAL",
|
118
|
+
:cash_advance => "CASHADVANCE",
|
119
|
+
:digital_goods => "DIGITALGOODS"
|
120
|
+
})),
|
121
|
+
:payment_sub_type => Optional.new(String),
|
122
|
+
:phone => Optional.new({
|
123
|
+
:country_code => String,
|
124
|
+
:phone_number => String,
|
125
|
+
:extension => Optional.new(String)
|
126
|
+
})
|
127
|
+
}, 6, lambda {|key, i| "receiverList.receiver(#{i}).#{Paypal::AdaptivePaymentsRequest.new.to_key(key)}" }),
|
128
|
+
:currency_code => Default.new("USD", String),
|
129
|
+
:cancel_url => String,
|
130
|
+
:return_url => String,
|
131
|
+
|
132
|
+
# parallel payments
|
133
|
+
# request is considered parallel if more than one receiver is added
|
134
|
+
:reverse_all_parallel_payments_on_error => Optional.new(bool_class),
|
135
|
+
|
136
|
+
# chained payments
|
137
|
+
# choose one of your receivers to be primary = true and the rest false to initiate a chained payment
|
138
|
+
|
139
|
+
# implicit payments
|
140
|
+
# if you are the api caller and you put in your own email address here, it is automatically approved
|
141
|
+
:sender_email => Optional.new(String),
|
142
|
+
|
143
|
+
# preapproval payments
|
144
|
+
# if you provide the following, and it is accurate, the payment will automatically be approved
|
145
|
+
:preapproval_key => Optional.new(String),
|
146
|
+
:pin => Optional.new(String),
|
147
|
+
|
148
|
+
|
149
|
+
:client_details => Optional.new({
|
150
|
+
:application_id => String,
|
151
|
+
:customer_id => String,
|
152
|
+
:customer_type => String,
|
153
|
+
:device_id => String,
|
154
|
+
:geo_location => String,
|
155
|
+
:ip_address => String,
|
156
|
+
:model => String,
|
157
|
+
:partner_name => String
|
158
|
+
}),
|
159
|
+
:fees_payer => Optional.new(Enum.new({
|
160
|
+
:sender => "SENDER",
|
161
|
+
:primary_receiver => "PRIMARYRECEIVER",
|
162
|
+
:each_receiver => "EACHRECEIVER",
|
163
|
+
:secondary_only => "SECONDARYONLY"
|
164
|
+
})),
|
165
|
+
# note: FundingConstraint is unavailable to API callers with standard permission levels; for more information, refer to the section Adaptive Payments Permission Levels.
|
166
|
+
# maybe collapse into a sequential w proc
|
167
|
+
:funding_constraint => Sequential.new({
|
168
|
+
:funding_type => Enum.new({:e_check => "ECHECK", :balance => "BALANCE", :credit_card => "CREDITCARD"})
|
169
|
+
}, nil, lambda {|key, i| "fundingConstraint.allowedFundingType(#{i}).fundingTypeInfo.#{Paypal::PaymentsPro.to_key(key)}"}),
|
170
|
+
:ipn_notification_url => Optional.new(String),
|
171
|
+
:memo => Optional.new(String), # max 1000 char
|
172
|
+
|
173
|
+
:request_envelope_error_language => "en_US",
|
174
|
+
:request_envelope_detail_level => Default.new("ReturnAll", Optional.new(String)),
|
175
|
+
|
176
|
+
:sender_user_credentials => Optional.new(bool_class),
|
177
|
+
|
178
|
+
:tracking_id => Optional.new(String)
|
179
|
+
|
180
|
+
}
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
data/lib/paypal_api/apis/api.rb
CHANGED
@@ -4,10 +4,6 @@ module Paypal
|
|
4
4
|
string = string.to_s
|
5
5
|
return URI.escape(string, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
6
6
|
end
|
7
|
-
|
8
|
-
def to_key(symbol)
|
9
|
-
return symbol.to_s.gsub(/[^a-z0-9]/i, "").upcase
|
10
|
-
end
|
11
7
|
end
|
12
8
|
|
13
9
|
class Api
|
@@ -102,11 +98,33 @@ module Paypal
|
|
102
98
|
return symbol.to_s.downcase.split("_").map(&:capitalize).join
|
103
99
|
end
|
104
100
|
|
101
|
+
def self.symbol_to_lower_camel(symbol)
|
102
|
+
cameled = symbol_to_camel(symbol)
|
103
|
+
return cameled[0].downcase + cameled.split(/./, 2).join
|
104
|
+
end
|
105
|
+
|
105
106
|
def self.set_request_signature(name, hash)
|
107
|
+
|
108
|
+
# create Request subclass if not already created
|
109
|
+
subname = self.to_s.split("::")[1]
|
110
|
+
if !Paypal.const_defined?("#{subname}Request")
|
111
|
+
Paypal.class_eval <<-EOS
|
112
|
+
class #{subname}Request < Request
|
113
|
+
def self.parent_api
|
114
|
+
return #{self}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
EOS
|
118
|
+
end
|
119
|
+
|
106
120
|
# create request object
|
107
121
|
class_name = "#{self.symbol_to_camel name}Request"
|
108
|
-
|
109
|
-
class
|
122
|
+
Paypal.class_eval <<-EOS
|
123
|
+
class #{class_name} < #{subname}Request
|
124
|
+
def self.api_method
|
125
|
+
return "#{name}"
|
126
|
+
end
|
127
|
+
end
|
110
128
|
EOS
|
111
129
|
klass = Kernel.const_get("Paypal").const_get(class_name)
|
112
130
|
|
@@ -138,6 +156,11 @@ module Paypal
|
|
138
156
|
EOS
|
139
157
|
end
|
140
158
|
|
159
|
+
# hack for no Bool class :'(
|
160
|
+
def self.bool_class
|
161
|
+
return Enum.new("true", "false")
|
162
|
+
end
|
163
|
+
|
141
164
|
# TODO: make this useful :'(
|
142
165
|
# def set_response_signature(hash)
|
143
166
|
# hash.each do |k,v|
|
@@ -1,5 +1,16 @@
|
|
1
1
|
module Paypal
|
2
|
-
class
|
2
|
+
class MassPayApiRequest < Request
|
3
|
+
|
4
|
+
protected
|
5
|
+
def validate!
|
6
|
+
if @payee.length == 0
|
7
|
+
raise Paypal::InvalidRequest, "you pust provide at least one payee"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# named with api because of method overlap
|
13
|
+
class MassPayApi < Paypal::Api
|
3
14
|
set_request_signature :mass_pay, {
|
4
15
|
:method => "MassPay",
|
5
16
|
:email_subject => Optional.new(String), # max 255 char
|
@@ -12,14 +23,4 @@ module Paypal
|
|
12
23
|
}, 250, lambda {|key, i| "L_#{key.to_s.gsub("_","").upcase}#{i}"})
|
13
24
|
}
|
14
25
|
end
|
15
|
-
|
16
|
-
class MassPayRequest
|
17
|
-
|
18
|
-
protected
|
19
|
-
def validate!
|
20
|
-
if @payee.length == 0
|
21
|
-
raise Paypal::InvalidRequest, "you pust provide at least one payee"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
26
|
end
|
@@ -151,5 +151,81 @@ module Paypal
|
|
151
151
|
:profile_id => String # max 19 char
|
152
152
|
}
|
153
153
|
|
154
|
+
set_request_signature :address_verify, {
|
155
|
+
|
156
|
+
}
|
157
|
+
|
158
|
+
set_request_signature :bill_outstanding_amount, {
|
159
|
+
|
160
|
+
}
|
161
|
+
|
162
|
+
set_request_signature :callback, {
|
163
|
+
|
164
|
+
}
|
165
|
+
|
166
|
+
set_request_signature :create_recurring_payments_profile, {
|
167
|
+
|
168
|
+
}
|
169
|
+
|
170
|
+
set_request_signature :do_authorization, {
|
171
|
+
|
172
|
+
}
|
173
|
+
|
174
|
+
set_request_signature :do_express_checkout_payment, {
|
175
|
+
|
176
|
+
}
|
177
|
+
|
178
|
+
set_request_signature :do_nonreferenced_credit, {
|
179
|
+
|
180
|
+
}
|
181
|
+
|
182
|
+
set_request_signature :do_reauthorization, {
|
183
|
+
|
184
|
+
}
|
185
|
+
|
186
|
+
set_request_signature :get_balance, {
|
187
|
+
|
188
|
+
}
|
189
|
+
|
190
|
+
set_request_signature :get_billing_agreement_customer_details, {
|
191
|
+
|
192
|
+
}
|
193
|
+
|
194
|
+
set_request_signature :get_express_checkout_details, {
|
195
|
+
|
196
|
+
}
|
197
|
+
|
198
|
+
set_request_signature :get_transaction_details, {
|
199
|
+
|
200
|
+
}
|
201
|
+
|
202
|
+
set_request_signature :manage_pending_transaction_status, {
|
203
|
+
|
204
|
+
}
|
205
|
+
|
206
|
+
set_request_signature :manage_recurring_payments_profile_status, {
|
207
|
+
|
208
|
+
}
|
209
|
+
|
210
|
+
set_request_signature :refund_transaction, {
|
211
|
+
|
212
|
+
}
|
213
|
+
|
214
|
+
set_request_signature :set_customer_billing_agreement, {
|
215
|
+
|
216
|
+
}
|
217
|
+
|
218
|
+
set_request_signature :set_express_checkout, {
|
219
|
+
|
220
|
+
}
|
221
|
+
|
222
|
+
set_request_signature :transaction_search, {
|
223
|
+
|
224
|
+
}
|
225
|
+
|
226
|
+
set_request_signature :update_recurring_payments_profile, {
|
227
|
+
|
228
|
+
}
|
229
|
+
|
154
230
|
end
|
155
231
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Paypal
|
2
2
|
class Request
|
3
3
|
|
4
|
-
cattr_accessor :environment, :user, :pwd, :signature, :version
|
4
|
+
cattr_accessor :environment, :user, :pwd, :signature, :version, :application_id
|
5
5
|
|
6
6
|
PAYPAL_VERSION = "84.0"
|
7
7
|
@@paypal_info = nil
|
@@ -12,7 +12,7 @@ module Paypal
|
|
12
12
|
@required = []
|
13
13
|
@sequential = []
|
14
14
|
|
15
|
-
attr_accessor :payload, :error_message
|
15
|
+
attr_accessor :payload, :error_message, :test_request
|
16
16
|
|
17
17
|
def initialize(payload = {})
|
18
18
|
config
|
@@ -42,17 +42,25 @@ module Paypal
|
|
42
42
|
@sequential
|
43
43
|
end
|
44
44
|
|
45
|
+
def request_host
|
46
|
+
URI.parse(@@paypal_endpoint).host
|
47
|
+
end
|
48
|
+
|
45
49
|
def paypal_endpoint_with_defaults
|
46
|
-
return "#{@@paypal_endpoint}?PWD=#{
|
47
|
-
"&USER=#{
|
48
|
-
"&SIGNATURE=#{
|
49
|
-
"&VERSION=#{
|
50
|
+
return "#{@@paypal_endpoint}?PWD=#{password}" +
|
51
|
+
"&USER=#{user}" +
|
52
|
+
"&SIGNATURE=#{signature}" +
|
53
|
+
"&VERSION=#{version}"
|
50
54
|
end
|
51
55
|
|
52
56
|
def sequentials_string
|
53
57
|
self.class.sequential_keys.map{|k| self.send(k).to_query_string }.join
|
54
58
|
end
|
55
59
|
|
60
|
+
def to_key(symbol)
|
61
|
+
return symbol.to_s.gsub(/[^a-z0-9]/i, "").upcase
|
62
|
+
end
|
63
|
+
|
56
64
|
def request_string
|
57
65
|
(@payload.keys | self.class.required_keys).inject(paypal_endpoint_with_defaults + sequentials_string) do |acc, key|
|
58
66
|
# if key signature is hash or optional...
|
@@ -62,32 +70,66 @@ module Paypal
|
|
62
70
|
|
63
71
|
# separated out so as not to stub Kernel.open in tests
|
64
72
|
def make_request
|
65
|
-
response =
|
66
|
-
|
73
|
+
response = nil
|
74
|
+
if self.respond_to? :headers
|
75
|
+
uri = URI.parse(request_string)
|
76
|
+
|
77
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
78
|
+
http.set_debug_output $stderr if @test_request
|
79
|
+
http.use_ssl = true
|
80
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
81
|
+
|
82
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
83
|
+
headers.each do |k,v|
|
84
|
+
request[k] = v
|
85
|
+
end
|
86
|
+
|
87
|
+
response = http.request(request).body
|
88
|
+
else
|
89
|
+
$stderr.puts(request_string) if @test_request
|
90
|
+
|
91
|
+
response = open(request_string)
|
92
|
+
end
|
93
|
+
|
94
|
+
return process_response(response)
|
95
|
+
end
|
96
|
+
|
97
|
+
def process_response(response)
|
98
|
+
Paypal::Response.new(response)
|
67
99
|
end
|
68
100
|
|
69
101
|
def make(&block)
|
70
102
|
params_fulfilled?
|
71
103
|
validate!
|
72
104
|
|
73
|
-
|
74
|
-
response = make_request
|
105
|
+
response = make_request
|
75
106
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
107
|
+
if block
|
108
|
+
yield response
|
109
|
+
else
|
110
|
+
return response
|
111
|
+
end
|
112
|
+
|
113
|
+
do_request = lambda {
|
114
|
+
|
115
|
+
}
|
116
|
+
|
117
|
+
if @test_request
|
118
|
+
do_request.call
|
119
|
+
else
|
120
|
+
begin
|
121
|
+
do_request.call
|
122
|
+
rescue OpenURI::HTTPError => error
|
123
|
+
# status_code = error.io.status[0]
|
124
|
+
# Rails.logger.info "[ERROR][Paypal] #{error.message } : #{error.backtrace} " if @@rails
|
125
|
+
raise $!
|
126
|
+
# rescue Timeout::Error => time_out_error
|
127
|
+
# Rails.logger.info "[ERROR][Timeout Error] #{time_out_error.message} : #{time_out_error.backtrace}" if @@rails
|
128
|
+
# raise $!
|
129
|
+
rescue => err
|
130
|
+
# Rails.logger.info "[ERROR][Something went wrong] #{err.message} : #{err.backtrace}" if @@rails
|
131
|
+
raise $!
|
80
132
|
end
|
81
|
-
rescue OpenURI::HTTPError => error
|
82
|
-
status_code = error.io.status[0]
|
83
|
-
# Rails.logger.info "[ERROR][Paypal] #{error.message } : #{error.backtrace} " if @@rails
|
84
|
-
raise $!
|
85
|
-
# rescue Timeout::Error => time_out_error
|
86
|
-
# Rails.logger.info "[ERROR][Timeout Error] #{time_out_error.message} : #{time_out_error.backtrace}" if @@rails
|
87
|
-
# raise $!
|
88
|
-
rescue => err
|
89
|
-
# Rails.logger.info "[ERROR][Something went wrong] #{err.message} : #{err.backtrace}" if @@rails
|
90
|
-
raise $!
|
91
133
|
end
|
92
134
|
end
|
93
135
|
|
@@ -95,18 +137,55 @@ module Paypal
|
|
95
137
|
|
96
138
|
include Paypal::Formatters
|
97
139
|
|
140
|
+
def user
|
141
|
+
@@paypal_info["username"] || self.class.user
|
142
|
+
end
|
143
|
+
|
144
|
+
def signature
|
145
|
+
@@paypal_info["signature"] || self.class.signature
|
146
|
+
end
|
147
|
+
|
148
|
+
def password
|
149
|
+
@@paypal_info["password"] || self.class.pwd
|
150
|
+
end
|
151
|
+
|
152
|
+
def application_id
|
153
|
+
@@paypal_info["application_id"] || self.class.application_id
|
154
|
+
end
|
155
|
+
|
156
|
+
def version
|
157
|
+
self.class.version || PAYPAL_VERSION
|
158
|
+
end
|
159
|
+
|
98
160
|
# override for custom request validation
|
99
161
|
def validate!
|
100
162
|
return true
|
101
163
|
end
|
102
164
|
|
165
|
+
# for completeness
|
166
|
+
def self.parent_api
|
167
|
+
return nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.api_method
|
171
|
+
""
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.api_endpoint
|
175
|
+
"https://api-3t.paypal.com/nvp"
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.api_sandbox_endpoint
|
179
|
+
"https://api-3t.sandbox.paypal.com/nvp"
|
180
|
+
end
|
181
|
+
|
103
182
|
def config
|
104
183
|
|
105
184
|
@@paypal_info = {}
|
106
185
|
|
107
|
-
@@paypal_info = get_info if Module.const_defined?("Rails")
|
186
|
+
@@paypal_info = get_info if Module.const_defined?("Rails") && (Module.const_get("Rails").respond_to?(:root) && !Module.const_get("Rails").root.nil?)
|
108
187
|
|
109
|
-
@@paypal_endpoint = (@@paypal_info["environment"] == "production" || Paypal::Request.environment == "production") ?
|
188
|
+
@@paypal_endpoint = (@@paypal_info["environment"] == "production" || Paypal::Request.environment == "production") ? self.class.api_endpoint : self.class.api_sandbox_endpoint
|
110
189
|
|
111
190
|
end
|
112
191
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Paypal
|
2
2
|
class Response
|
3
3
|
|
4
|
-
attr_accessor :raw_response, :parsed_response, :error_code
|
4
|
+
attr_accessor :raw_response, :parsed_response, :error_code, :paypal_error_field
|
5
5
|
|
6
6
|
def initialize(stringio)
|
7
7
|
@raw_response = stringio.class == StringIO ? stringio.read : stringio
|
@@ -36,14 +36,14 @@ module Paypal
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def error_field
|
39
|
-
@@error_codes[@error_code] ? @@human_readable[@@error_codes[@error_code]] : nil
|
39
|
+
@paypal_error_field || (@@error_codes[@error_code] ? @@human_readable[@@error_codes[@error_code]] : nil)
|
40
40
|
end
|
41
41
|
|
42
42
|
def error_message
|
43
43
|
@error_message + "[#{@error_code}]"
|
44
44
|
end
|
45
45
|
|
46
|
-
|
46
|
+
protected
|
47
47
|
|
48
48
|
def symbol_to_key(symbol)
|
49
49
|
return symbol.to_s.gsub(/[^0-9a-z]/i, "").upcase
|
data/lib/paypal_api/version.rb
CHANGED
data/lib/paypal_api.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "cgi"
|
2
2
|
require "open-uri"
|
3
3
|
require 'active_support/core_ext/class/attribute_accessors'
|
4
|
+
require "net/http"
|
4
5
|
|
5
6
|
module Paypal
|
6
7
|
class InvalidRequest < StandardError; end
|
@@ -14,8 +15,18 @@ $:.push File.expand_path("../../lib", __FILE__)
|
|
14
15
|
|
15
16
|
require "paypal_api/version"
|
16
17
|
require "paypal_api/apis/api"
|
18
|
+
|
17
19
|
require "paypal_api/support/parameter"
|
18
20
|
require "paypal_api/support/response"
|
19
21
|
require "paypal_api/support/request"
|
22
|
+
|
23
|
+
require "generators/paypal/ipn_message_generator"
|
24
|
+
|
20
25
|
require "paypal_api/apis/payments_pro"
|
21
|
-
require "paypal_api/apis/
|
26
|
+
require "paypal_api/apis/express_checkout"
|
27
|
+
require "paypal_api/apis/adaptive_payments"
|
28
|
+
require "paypal_api/apis/adaptive_accounts"
|
29
|
+
require "paypal_api/apis/invoicing"
|
30
|
+
require "paypal_api/apis/mass_pay"
|
31
|
+
require "paypal_api/apis/button_manager"
|
32
|
+
require "paypal_api/apis/permissions"
|
data/paypal_api.gemspec
CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
-
s.add_dependency "activesupport", "3.
|
21
|
+
# s.add_dependency "activesupport", "~> 3.1"
|
22
|
+
s.add_dependency "rails", "~> 3.1"
|
22
23
|
|
23
|
-
s.add_development_dependency "
|
24
|
-
s.add_development_dependency "rspec-
|
25
|
-
s.add_development_dependency "
|
24
|
+
s.add_development_dependency "ruby-debug19"
|
25
|
+
s.add_development_dependency "rspec-rails", "~> 2.6"
|
26
|
+
s.add_development_dependency "generator_spec", "0.8.5"
|
27
|
+
# s.add_development_dependency "rake", "0.8.7"
|
26
28
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "rails/all"
|
2
|
+
require "spec_helper"
|
3
|
+
require "generator_spec/test_case"
|
4
|
+
|
5
|
+
describe Paypal::Generators::IpnMessageGenerator do
|
6
|
+
include GeneratorSpec::TestCase
|
7
|
+
destination File.expand_path("../../tmp", __FILE__)
|
8
|
+
|
9
|
+
before(:all) do
|
10
|
+
prepare_destination
|
11
|
+
run_generator
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should add model file" do
|
15
|
+
assert_file "app/models/ipn_message.rb"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify do
|
19
|
+
destination_root.should have_structure {
|
20
|
+
no_file "test.rb"
|
21
|
+
directory "app" do
|
22
|
+
directory "models" do
|
23
|
+
file "ipn_message.rb" do
|
24
|
+
contains "def self.create_from_message"
|
25
|
+
contains "def unique_ids"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
directory "db" do
|
30
|
+
directory "migrate" do
|
31
|
+
migration "add_ipn_messages" do
|
32
|
+
contains "class CreateIpnMessages"
|
33
|
+
contains ":message"
|
34
|
+
contains ":correlation_id"
|
35
|
+
contains ":transaction_id"
|
36
|
+
contains ":tracking_id"
|
37
|
+
contains ":success"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require "rails/all"
|
1
2
|
require "spec_helper"
|
2
3
|
|
3
4
|
describe Paypal::Api::Parameter do
|
@@ -67,13 +68,13 @@ describe Paypal::Api::Parameter do
|
|
67
68
|
|
68
69
|
describe Paypal::Api::Sequential do
|
69
70
|
before do
|
70
|
-
class
|
71
|
+
class Testical < @api
|
71
72
|
set_request_signature :tester, {
|
72
73
|
:sequential => @api::Sequential.new({:l_string => String, :l_fixnum => Fixnum, :l_set_category => Optional.new(String)})
|
73
74
|
}
|
74
75
|
end
|
75
76
|
|
76
|
-
@request =
|
77
|
+
@request = Testical.tester
|
77
78
|
@request.sequential.push({:l_string => "sasdf", :l_fixnum => 23, :l_set_category => "asdfasdf"})
|
78
79
|
|
79
80
|
|
@@ -44,6 +44,7 @@ describe Paypal::Request do
|
|
44
44
|
describe "for production" do
|
45
45
|
before do
|
46
46
|
Module.should_receive(:const_defined?).and_return(true)
|
47
|
+
Module.should_receive(:const_get).twice.and_return(stub(:root => true))
|
47
48
|
|
48
49
|
Paypal::Request.any_instance.should_receive(:get_info).and_return({"environment" => "production" })
|
49
50
|
end
|
@@ -72,7 +73,7 @@ describe Paypal::Request do
|
|
72
73
|
before do
|
73
74
|
@api = Paypal::Api
|
74
75
|
|
75
|
-
class
|
76
|
+
class Testical < @api
|
76
77
|
set_request_signature :tester, {
|
77
78
|
:test_field => "something",
|
78
79
|
:optional => @api::Optional.new(String),
|
@@ -84,7 +85,7 @@ describe Paypal::Request do
|
|
84
85
|
}
|
85
86
|
end
|
86
87
|
|
87
|
-
@request =
|
88
|
+
@request = Testical.tester({
|
88
89
|
:string => "adsafasdf",
|
89
90
|
:fixnum => 23,
|
90
91
|
:enum => :one
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Paypal::AdaptivePayments do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
Paypal::Request.application_id = "APP-80W284485P519543T"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe :to_key do
|
10
|
+
it "should camel but not first letter" do
|
11
|
+
string = Paypal::AdaptivePaymentsRequest.new.to_key(:som_symbole_here)
|
12
|
+
string.should eq("somSymboleHere")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :pay do
|
17
|
+
before(:each) do
|
18
|
+
@request = Paypal::AdaptivePayments.pay
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be a PayRequest" do
|
22
|
+
@request.should be_a(Paypal::PayRequest)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be invalid without a lot of stuff" do
|
26
|
+
@request.valid?.should be_false
|
27
|
+
@request.error_message.should_not be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with some information filled in" do
|
31
|
+
before(:each) do
|
32
|
+
@request.receiver.push({
|
33
|
+
:email => "test@dude.com",
|
34
|
+
:amount => 10.22
|
35
|
+
})
|
36
|
+
@request.cancel_url = "http://www.test.com/cancel"
|
37
|
+
@request.return_url = "http://www.test.com/return"
|
38
|
+
@request.ip_address = "168.212.226.204"
|
39
|
+
end
|
40
|
+
|
41
|
+
shared_examples_for "a good pay request" do
|
42
|
+
it "should look like a successful request" do
|
43
|
+
@request.request_string.should include("&receiverList.receiver(0).email=test%40dude.com&receiverList.receiver(0).amount=10.22&actionType=")
|
44
|
+
@request.request_string.should include("¤cyCode=USD&cancelUrl=http%3A%2F%2Fwww.test.com%2Fcancel&returnUrl=http%3A%2F%2Fwww.test.com%2Freturn&requestEnvelope.errorLanguage=en_US&requestEnvelope.detailLevel=ReturnAll")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not raise exception, response should be success" do
|
48
|
+
Paypal::PayRequest.any_instance.stub(:make_request).and_return("")
|
49
|
+
expect {
|
50
|
+
response = @request.make
|
51
|
+
}.to_not raise_exception(Paypal::InvalidRequest)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should get a response from paypal", :slow_paypal => true do
|
55
|
+
# @request.test_request = true
|
56
|
+
response = @request.make
|
57
|
+
response.success?.should be_true
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "with stubbed response" do
|
61
|
+
before(:each) do
|
62
|
+
Paypal::PayRequest.any_instance.stub(:make_request).and_return(Paypal::AdaptivePaymentsResponse.new("responseEnvelope.timestamp=2012-02-29T13%3A40%3A17.074-08%3A00&responseEnvelope.ack=Success&responseEnvelope.correlationId=722689b427b7c&responseEnvelope.build=2486531&payKey=AP-1W763567RM6393227&paymentExecStatus=CREATED"))
|
63
|
+
@response = @request.make
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should be an adative payments response" do
|
67
|
+
@response.should be_a(Paypal::AdaptivePaymentsResponse)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should have a correlation_id" do
|
71
|
+
@response[:correlation_id].should eq("722689b427b7c")
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have a pay key and exec status" do
|
75
|
+
@response[:pay_key].should eq("AP-1W763567RM6393227")
|
76
|
+
@response[:payment_exec_status].should eq("CREATED")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "with stubbed failure" do
|
81
|
+
before(:each) do
|
82
|
+
Paypal::PayRequest.any_instance.stub(:make_request).and_return(Paypal::AdaptivePaymentsResponse.new("responseEnvelope.timestamp=2012-02-29T13%3A35%3A28.528-08%3A00&responseEnvelope.ack=Failure&responseEnvelope.correlationId=ca0befbd1fe0b&responseEnvelope.build=2486531&error(0).errorId=560022&error(0).domain=PLATFORM&error(0).subdomain=Application&error(0).severity=Error&error(0).category=Application&error(0).message=The+X-PAYPAL-APPLICATION-ID+header+contains+an+invalid+value&error(0).parameter(0)=X-PAYPAL-APPLICATION-ID"))
|
83
|
+
@response = @request.make
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should have a correlation id" do
|
87
|
+
@response[:correlation_id].should eq("ca0befbd1fe0b")
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have an error message" do
|
91
|
+
@response.error_message.should_not be_nil
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should not be success" do
|
95
|
+
@response.success?.should be_false
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should have an error field and code" do
|
99
|
+
@response.error_code.should eq("560022")
|
100
|
+
@response.error_field.should eq("X-PAYPAL-APPLICATION-ID")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "when creating" do
|
106
|
+
before(:each) do
|
107
|
+
@request.action_type = :create
|
108
|
+
end
|
109
|
+
|
110
|
+
it_behaves_like "a good pay request"
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "when paying" do
|
114
|
+
before(:each) do
|
115
|
+
@request.action_type = :pay
|
116
|
+
end
|
117
|
+
|
118
|
+
it_behaves_like "a good pay request"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/spec/unit/api_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Paypal::Api do
|
|
8
8
|
describe :set_request_signature do
|
9
9
|
it "should be callable from a class body definition" do
|
10
10
|
expect {
|
11
|
-
class
|
11
|
+
class Testical < @api
|
12
12
|
set_request_signature :test, {}
|
13
13
|
end
|
14
14
|
}.to_not raise_exception
|
@@ -16,7 +16,7 @@ describe Paypal::Api do
|
|
16
16
|
|
17
17
|
context "with field descriptions" do
|
18
18
|
before do
|
19
|
-
class
|
19
|
+
class Testical < @api
|
20
20
|
set_request_signature :tester, {
|
21
21
|
:test_field => "something",
|
22
22
|
:optional => @api::Optional.new(String),
|
@@ -30,27 +30,27 @@ describe Paypal::Api do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should add getters for all keys" do
|
33
|
-
|
34
|
-
|
33
|
+
Testical.tester.payload.each do |k,v|
|
34
|
+
Testical.tester.respond_to?(k).should be_true
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
it "should return a dynamic request object" do
|
39
|
-
|
39
|
+
Testical.tester.class.should eq(Paypal::TesterRequest)
|
40
40
|
end
|
41
41
|
|
42
42
|
it "should make the class respond to class method" do
|
43
|
-
|
43
|
+
Testical.respond_to?(:tester).should be_true
|
44
44
|
end
|
45
45
|
|
46
46
|
it "should add constant getters and not setters for value types" do
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
Testical.tester.respond_to?(:test_field).should be_true
|
48
|
+
Testical.tester.send(:test_field).should eq("something")
|
49
|
+
Testical.tester.respond_to?(:test_field=).should be_false
|
50
50
|
end
|
51
51
|
|
52
52
|
it "should add setters for all non-constant types" do
|
53
|
-
request =
|
53
|
+
request = Testical.tester
|
54
54
|
request.payload.each do |k,v|
|
55
55
|
if [String, Fixnum, Float].include?(v.class)
|
56
56
|
request.respond_to?(k).should be_false
|
@@ -61,7 +61,7 @@ describe Paypal::Api do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should raise an InvalidRequest error when missing required fields" do
|
64
|
-
request =
|
64
|
+
request = Testical.tester
|
65
65
|
expect {
|
66
66
|
request.make
|
67
67
|
}.to raise_exception(Paypal::InvalidRequest)
|
@@ -69,7 +69,7 @@ describe Paypal::Api do
|
|
69
69
|
|
70
70
|
describe "setters" do
|
71
71
|
before do
|
72
|
-
@request =
|
72
|
+
@request = Testical.tester
|
73
73
|
end
|
74
74
|
|
75
75
|
it "should handle sequential types" do
|
data/spec/unit/mass_pay_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Paypal::
|
3
|
+
describe Paypal::MassPayApi do
|
4
4
|
|
5
5
|
describe :mass_pay do
|
6
6
|
before(:each) do
|
7
|
-
@request = Paypal::
|
7
|
+
@request = Paypal::MassPayApi.mass_pay
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should be invalid without a payee" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paypal_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,33 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-01 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: rails
|
16
|
+
requirement: &70244225979560 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 3.
|
21
|
+
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70244225979560
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement: &
|
26
|
+
name: ruby-debug19
|
27
|
+
requirement: &70244225978140 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
|
-
- -
|
30
|
+
- - ! '>='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70244225978140
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name: rspec-
|
38
|
-
requirement: &
|
37
|
+
name: rspec-rails
|
38
|
+
requirement: &70244225976180 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,18 +43,18 @@ dependencies:
|
|
43
43
|
version: '2.6'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70244225976180
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
49
|
-
requirement: &
|
48
|
+
name: generator_spec
|
49
|
+
requirement: &70244225974780 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - =
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0.8.
|
54
|
+
version: 0.8.5
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70244225974780
|
58
58
|
description: alpha - currently covers part of payments pro and all of mass pay
|
59
59
|
email:
|
60
60
|
- matt.handler@gmail.com
|
@@ -65,22 +65,34 @@ files:
|
|
65
65
|
- .gitignore
|
66
66
|
- .rspec
|
67
67
|
- Gemfile
|
68
|
+
- MIT-LICENSE
|
68
69
|
- README.markdown
|
69
70
|
- Rakefile
|
70
71
|
- init.rb
|
72
|
+
- lib/generators/paypal/ipn_message_generator.rb
|
73
|
+
- lib/generators/templates/ipn_message.rb
|
74
|
+
- lib/generators/templates/migration.rb
|
71
75
|
- lib/paypal_api.rb
|
76
|
+
- lib/paypal_api/apis/adaptive_accounts.rb
|
77
|
+
- lib/paypal_api/apis/adaptive_payments.rb
|
72
78
|
- lib/paypal_api/apis/api.rb
|
79
|
+
- lib/paypal_api/apis/button_manager.rb
|
80
|
+
- lib/paypal_api/apis/express_checkout.rb
|
81
|
+
- lib/paypal_api/apis/invoicing.rb
|
73
82
|
- lib/paypal_api/apis/mass_pay.rb
|
74
83
|
- lib/paypal_api/apis/payments_pro.rb
|
84
|
+
- lib/paypal_api/apis/permissions.rb
|
75
85
|
- lib/paypal_api/support/parameter.rb
|
76
86
|
- lib/paypal_api/support/request.rb
|
77
87
|
- lib/paypal_api/support/response.rb
|
78
88
|
- lib/paypal_api/version.rb
|
79
89
|
- paypal_api.gemspec
|
90
|
+
- spec/generators/ipn_message_generator_spec.rb
|
80
91
|
- spec/spec_helper.rb
|
81
92
|
- spec/support/parameter_spec.rb
|
82
93
|
- spec/support/request_spec.rb
|
83
94
|
- spec/support/response_spec.rb
|
95
|
+
- spec/unit/adaptive_payments_spec.rb
|
84
96
|
- spec/unit/api_spec.rb
|
85
97
|
- spec/unit/mass_pay_spec.rb
|
86
98
|
- spec/unit/payments_pro_spec.rb
|
@@ -109,10 +121,12 @@ signing_key:
|
|
109
121
|
specification_version: 3
|
110
122
|
summary: an interface to paypals api
|
111
123
|
test_files:
|
124
|
+
- spec/generators/ipn_message_generator_spec.rb
|
112
125
|
- spec/spec_helper.rb
|
113
126
|
- spec/support/parameter_spec.rb
|
114
127
|
- spec/support/request_spec.rb
|
115
128
|
- spec/support/response_spec.rb
|
129
|
+
- spec/unit/adaptive_payments_spec.rb
|
116
130
|
- spec/unit/api_spec.rb
|
117
131
|
- spec/unit/mass_pay_spec.rb
|
118
132
|
- spec/unit/payments_pro_spec.rb
|