paypal_api 0.3.0 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +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
|