paypal-masspay 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +22 -0
- data/.rspec +1 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +85 -0
- data/Rakefile +19 -0
- data/lib/paypal/masspay.rb +131 -0
- data/lib/paypal/masspay/configuration.rb +13 -0
- data/lib/paypal/masspay/error.rb +12 -0
- data/lib/paypal/masspay/length_validator.rb +11 -0
- data/lib/paypal/masspay/recipient.rb +23 -0
- data/lib/paypal/masspay/response_parser.rb +62 -0
- data/lib/paypal/masspay/version.rb +5 -0
- data/paypal-masspay.gemspec +26 -0
- data/spec/lib/integration/masspay_spec.rb +92 -0
- data/spec/lib/paypal/masspay/error_spec.rb +34 -0
- data/spec/lib/paypal/masspay/length_validator_spec.rb +17 -0
- data/spec/lib/paypal/masspay/recipient_spec.rb +27 -0
- data/spec/lib/paypal/masspay/response_parser_spec.rb +44 -0
- data/spec/lib/paypal/masspay_spec.rb +101 -0
- data/spec/spec_helper.rb +6 -0
- metadata +161 -0
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Envato
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Paypal::Masspay
|
2
|
+
|
3
|
+
Paypal::Masspay is a Ruby library that uses PayPals MassPay API to send Mass Payments.
|
4
|
+
|
5
|
+
The MassPay API provides a SOAP and NVP (Name-Value Pair) interface, however this library uses the NVP interface exclusively.
|
6
|
+
|
7
|
+
You can read more about PayPals MassPay API at the following link: [PayPal MassPay API Documentationn](https://developer.paypal.com/docs/classic/mass-pay/integration-guide/MassPayUsingAPI/)
|
8
|
+
|
9
|
+
A introduction about PayPals NVP interface in general can be found here: [PayPal NVP API Overview](https://developer.paypal.com/docs/classic/api/NVPAPIOverview/)
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
In a nutshell the Paypal::Masspay library lets you send multiple payments at once using the following schema:
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
Paypal::Masspay::Configuration.configure do |config|
|
17
|
+
config.environment = :production
|
18
|
+
config.username = 'your_paypal_username'
|
19
|
+
config.password = 'your_paypal_password'
|
20
|
+
config.signature = 'your_paypal_signature'
|
21
|
+
end
|
22
|
+
|
23
|
+
masspay = Paypal::Masspay.new(:currency => 'USD') do |bucket|
|
24
|
+
bucket.add_recipient(Paypal::Masspay::Recipient.new(:recipient_email => 'chunky@example.com', :amount => 10.00, :unique_id => 1234, :note => 'hello'))
|
25
|
+
bucket.add_recipient(Paypal::Masspay::Recipient.new(:recipient_email => 'bacon@example.com', :amount => 2.95, :unique_id => 222))
|
26
|
+
end
|
27
|
+
|
28
|
+
masspay.deliver
|
29
|
+
```
|
30
|
+
|
31
|
+
It also supports being used like this:
|
32
|
+
``` ruby
|
33
|
+
Paypal::Masspay::Configuration.configure do |config|
|
34
|
+
config.environment = :production
|
35
|
+
config.username = 'your_paypal_username'
|
36
|
+
config.password = 'your_paypal_password'
|
37
|
+
config.signature = 'your_paypal_signature'
|
38
|
+
end
|
39
|
+
|
40
|
+
recipients = [
|
41
|
+
Paypal::Masspay::Recipient.new(
|
42
|
+
:recipient_email => 'chunky@example.com',
|
43
|
+
:amount => 10.00,
|
44
|
+
:unique_id => 1234,
|
45
|
+
:note => 'hello'),
|
46
|
+
Paypal::Masspay::Recipient.new(
|
47
|
+
:recipient_email => 'bacon@example.com',
|
48
|
+
:amount => 2.95,
|
49
|
+
:unique_id => 222)
|
50
|
+
]
|
51
|
+
|
52
|
+
masspay = Paypal::Masspay.new(:currency => 'USD', :recipients => recipients)
|
53
|
+
|
54
|
+
masspay.deliver
|
55
|
+
```
|
56
|
+
|
57
|
+
This sends a post request to the PayPal NVP API endpoint containing the following data:
|
58
|
+
|
59
|
+
```
|
60
|
+
USER=your_paypal_username&
|
61
|
+
PWD=your_paypal_password&
|
62
|
+
SIGNATURE=your_paypal_signature&
|
63
|
+
VERSION=2.3&
|
64
|
+
METHOD=MassPay&
|
65
|
+
RECEIVERTYPE=EmailAddress&
|
66
|
+
L_EMAIL0=chunky@example.com&
|
67
|
+
L_AMT0=10.00&
|
68
|
+
L_UNIQUEID0=1234&
|
69
|
+
L_NOTE0=hello&
|
70
|
+
L_EMAIL1=bacon@example.com&
|
71
|
+
L_AMT1=2.95&
|
72
|
+
L_UNIQUEID1=222&
|
73
|
+
CURRENCYCODE=USD
|
74
|
+
```
|
75
|
+
|
76
|
+
You are also able to check whether or not the request was successfully sent to paypal, and can check any returned error/warnings using the following code:
|
77
|
+
|
78
|
+
``` ruby
|
79
|
+
masspay.successful? # ===> true/false
|
80
|
+
|
81
|
+
masspay.errors # ===> [ <Paypal::Masspay::Error>, <Paypal::Masspay::Error>, ... ]
|
82
|
+
masspay.errors[0].methods # ===> [ :code, :short_message, :long_message, :severity ]
|
83
|
+
masspay.errors[0].code # ===> 10000
|
84
|
+
masspay.errors[0].short_message # ===> "insufficient funds"
|
85
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
RSpec::Core::RakeTask.new(:spec)
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'cane'
|
8
|
+
require 'cane/rake_task'
|
9
|
+
|
10
|
+
desc "Run cane to check quality metrics"
|
11
|
+
Cane::RakeTask.new(:quality) do |cane|
|
12
|
+
cane.no_style = true
|
13
|
+
cane.no_doc = true
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
warn "cane not available, quality task not provided."
|
17
|
+
end
|
18
|
+
|
19
|
+
task :default => [ :quality, :spec ]
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'paypal/masspay/version'
|
2
|
+
require 'paypal/masspay/response_parser'
|
3
|
+
require 'paypal/masspay/recipient'
|
4
|
+
require 'paypal/masspay/length_validator'
|
5
|
+
require 'paypal/masspay/configuration'
|
6
|
+
|
7
|
+
require 'faraday'
|
8
|
+
require 'ostruct'
|
9
|
+
|
10
|
+
module Paypal
|
11
|
+
class Masspay
|
12
|
+
SANDBOX_API_URL = 'https://api-3t.sandbox.paypal.com'
|
13
|
+
PRODUCTION_API_URL = 'https://api-3t.paypal.com'
|
14
|
+
API_PATH = '/nvp'
|
15
|
+
API_VERSION = '2.3'
|
16
|
+
IDENTIFIER = 'EmailAddress'
|
17
|
+
METHOD = 'MassPay'
|
18
|
+
MAX_PER_REQUEST = 250
|
19
|
+
|
20
|
+
DEFAULT_CURRENCY = 'USD'
|
21
|
+
DEFAULT_SUBJECT = 'Paypal Masspay'
|
22
|
+
|
23
|
+
CURRENCY_MAX_LENGTH = 3
|
24
|
+
SUBJECT_MAX_LENGTH = 255
|
25
|
+
|
26
|
+
attr_reader :errors
|
27
|
+
|
28
|
+
def initialize(options = {}, &block)
|
29
|
+
build_options(options)
|
30
|
+
|
31
|
+
@success = true
|
32
|
+
@delivered = false
|
33
|
+
@errors = []
|
34
|
+
|
35
|
+
yield(self) if block_given?
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_recipient(recipient)
|
39
|
+
@recipients << recipient
|
40
|
+
end
|
41
|
+
|
42
|
+
def deliver
|
43
|
+
validate
|
44
|
+
|
45
|
+
connection = create_connection
|
46
|
+
|
47
|
+
@recipients.each_slice(MAX_PER_REQUEST) do |recipients_slice|
|
48
|
+
response = connection.post(API_PATH, request_data(recipients_slice))
|
49
|
+
check_response(response)
|
50
|
+
end
|
51
|
+
|
52
|
+
@delivered = true
|
53
|
+
end
|
54
|
+
|
55
|
+
def successful?
|
56
|
+
@success
|
57
|
+
end
|
58
|
+
|
59
|
+
def delivered?
|
60
|
+
@delivered
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def validate
|
66
|
+
Paypal::Masspay::LengthValidator.validate(@currency, CURRENCY_MAX_LENGTH, :currency)
|
67
|
+
Paypal::Masspay::LengthValidator.validate(@subject, SUBJECT_MAX_LENGTH, :subject)
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_connection
|
71
|
+
Faraday.new(:url => api_url) do |con|
|
72
|
+
con.use(Faraday::Request::UrlEncoded)
|
73
|
+
con.use(Faraday::Adapter::NetHttp)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def api_url
|
78
|
+
if Paypal::Masspay::Configuration.environment == :production
|
79
|
+
PRODUCTION_API_URL
|
80
|
+
else
|
81
|
+
SANDBOX_API_URL
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def check_response(response)
|
86
|
+
response = Paypal::Masspay::ResponseParser.new(response.body)
|
87
|
+
if response.successful?
|
88
|
+
@success = true && @success
|
89
|
+
else
|
90
|
+
@success = false
|
91
|
+
@errors.concat(response.errors)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def request_data(recipients)
|
96
|
+
(default_options.merge(credentials).merge(build_payments(recipients))).delete_if { |k, v| v.nil? }
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_options(options)
|
100
|
+
@recipients = options[:recipients] || []
|
101
|
+
@currency = options[:currency] || DEFAULT_CURRENCY
|
102
|
+
@subject = options[:subject] || DEFAULT_SUBJECT
|
103
|
+
end
|
104
|
+
|
105
|
+
def build_payments(recipients)
|
106
|
+
Hash.new({}).tap do |output|
|
107
|
+
recipients.each_with_index do |payment, index|
|
108
|
+
output.merge!(payment.get_params(index))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def credentials
|
114
|
+
{
|
115
|
+
'USER' => Paypal::Masspay::Configuration.username,
|
116
|
+
'PWD' => Paypal::Masspay::Configuration.password,
|
117
|
+
'SIGNATURE' => Paypal::Masspay::Configuration.signature
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def default_options
|
122
|
+
{
|
123
|
+
'VERSION' => API_VERSION,
|
124
|
+
'METHOD' => METHOD,
|
125
|
+
'RECEIVERTYPE' => IDENTIFIER,
|
126
|
+
'CURRENCYCODE' => @currency,
|
127
|
+
'EMAILSUBJECT' => @subject
|
128
|
+
}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Paypal
|
2
|
+
class Masspay::Configuration
|
3
|
+
class << self
|
4
|
+
attr_accessor :environment, :username, :password, :signature
|
5
|
+
|
6
|
+
def configure
|
7
|
+
@configuration ||= Paypal::Masspay::Configuration.tap do |config|
|
8
|
+
yield config
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Paypal
|
2
|
+
class Masspay::Error
|
3
|
+
attr_reader :code, :short_message, :long_message, :severity
|
4
|
+
|
5
|
+
def initialize(params = {})
|
6
|
+
@code = params[:code]
|
7
|
+
@short_message = params[:short_message]
|
8
|
+
@long_message = params[:long_message]
|
9
|
+
@severity = params[:severity]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Paypal
|
2
|
+
class Masspay::LengthValidator
|
3
|
+
class FieldLengthTooLarge < StandardError; end
|
4
|
+
|
5
|
+
def self.validate(string, length, field_name)
|
6
|
+
string.tap do |output|
|
7
|
+
raise FieldLengthTooLarge.new("#{output} is longer than the paypal max char limit of #{length} for field #{field_name}") if !output.nil? && output.length > length
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Paypal
|
2
|
+
class Masspay::Recipient
|
3
|
+
RECIPIENT_EMAIL_MAX_LENGTH = 127
|
4
|
+
RECIPIENT_NOTE_MAX_LENGTH = 4000
|
5
|
+
RECIPIENT_UNIQUE_ID_MAX_LENGTH = 30
|
6
|
+
|
7
|
+
def initialize(args = {})
|
8
|
+
@recipient_email = Paypal::Masspay::LengthValidator.validate(args[:recipient_email], RECIPIENT_EMAIL_MAX_LENGTH, :recipient_email)
|
9
|
+
@note = Paypal::Masspay::LengthValidator.validate(args[:note], RECIPIENT_NOTE_MAX_LENGTH, :note)
|
10
|
+
@unique_id = Paypal::Masspay::LengthValidator.validate(args[:unique_id], RECIPIENT_UNIQUE_ID_MAX_LENGTH, :unique_id)
|
11
|
+
@amount = args[:amount]
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_params(index)
|
15
|
+
{
|
16
|
+
"L_EMAIL#{index}" => @recipient_email,
|
17
|
+
"L_AMT#{index}" => @amount,
|
18
|
+
"L_NOTE#{index}" => @note,
|
19
|
+
"L_UNIQUEID#{index}" => @unique_id
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'paypal/masspay/error'
|
3
|
+
|
4
|
+
module Paypal
|
5
|
+
class Masspay::ResponseParser
|
6
|
+
SUCCESS_ACK = 'Success'
|
7
|
+
SUCCESS_WITH_WARN_ACK = 'SuccessWithWarning'
|
8
|
+
SUCCESSFUL_ACKS = [ SUCCESS_ACK, SUCCESS_WITH_WARN_ACK ]
|
9
|
+
|
10
|
+
def initialize(response_body)
|
11
|
+
@response_body = response_body
|
12
|
+
@errors = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def successful?
|
16
|
+
SUCCESSFUL_ACKS.include?(ack)
|
17
|
+
end
|
18
|
+
|
19
|
+
def errors
|
20
|
+
@errors.tap do |errors|
|
21
|
+
parsed_response.select { |k, v| k.match(/^L_ERRORCODE\d+$/) }.keys.count.times do |i|
|
22
|
+
errors << Paypal::Masspay::Error.new(
|
23
|
+
:code => error_code_for(i),
|
24
|
+
:short_message => short_message_for(i),
|
25
|
+
:long_message => long_message_for(i),
|
26
|
+
:severity => severity_for(i))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parsed_response
|
34
|
+
if @parsed_response.nil?
|
35
|
+
@parsed_response = CGI::parse(@response_body)
|
36
|
+
@parsed_response.each { |key, value| @parsed_response[key] = value.first }
|
37
|
+
end
|
38
|
+
|
39
|
+
@parsed_response
|
40
|
+
end
|
41
|
+
|
42
|
+
def ack
|
43
|
+
parsed_response["ACK"]
|
44
|
+
end
|
45
|
+
|
46
|
+
def error_code_for(index)
|
47
|
+
parsed_response["L_ERRORCODE#{index}"].to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
def short_message_for(index)
|
51
|
+
parsed_response["L_SHORTMESSAGE#{index}"]
|
52
|
+
end
|
53
|
+
|
54
|
+
def long_message_for(index)
|
55
|
+
parsed_response["L_LONGMESSAGE#{index}"]
|
56
|
+
end
|
57
|
+
|
58
|
+
def severity_for(index)
|
59
|
+
parsed_response["L_SEVERITYCODE#{index}"]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'paypal/masspay/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'paypal-masspay'
|
8
|
+
gem.version = Paypal::Masspay::VERSION
|
9
|
+
gem.authors = ['Martin Jagusch', 'Shervin Aflatooni']
|
10
|
+
gem.email = ['shervinaflatooni@gmail.com']
|
11
|
+
gem.description = 'Performing multiple payments to PayPal using the MassPay API'
|
12
|
+
gem.summary = "paypal-masspay-#{Paypal::Masspay::VERSION}"
|
13
|
+
gem.homepage = 'https://github.com/envato/paypal-masspay'
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
16
|
+
gem.files = `git ls-files -z`.split("\x0")
|
17
|
+
gem.test_files = gem.files.grep(%r{^spec/})
|
18
|
+
gem.require_paths = ['lib']
|
19
|
+
|
20
|
+
gem.add_dependency 'faraday', '~> 0.9', '>= 0.9.0'
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rake', '~> 10.3'
|
23
|
+
gem.add_development_dependency 'rspec', '~> 3.0.0.beta1'
|
24
|
+
gem.add_development_dependency 'cane', '~> 2.6'
|
25
|
+
gem.add_development_dependency 'webmock', '~> 1.17'
|
26
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'performing a masspay' do
|
4
|
+
let(:success_body) { 'ACK=Success' }
|
5
|
+
let(:fail_body) { 'ACK=Failure&L_ERRORCODE0=10000&L_SHORTMESSAGE0=short_error_message&L_LONGMESSAGE0=long_error_message&L_SEVERITYCODE0=Error&L_ERRORCODE1=20000&L_SHORTMESSAGE1=short_error_message2&L_LONGMESSAGE1=long_error_message2&L_SEVERITYCODE1=Error' }
|
6
|
+
let(:response_body) { success_body }
|
7
|
+
|
8
|
+
let(:recipient_one) { Paypal::Masspay::Recipient.new(:recipient_email => 'chunky@example.com', :amount => 10.00) }
|
9
|
+
let(:recipient_two) { Paypal::Masspay::Recipient.new(:recipient_email => 'bacon@example.com', :amount => 2.95) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
stub_request(:post, "https://api-3t.sandbox.paypal.com/nvp").with(
|
13
|
+
:body => {
|
14
|
+
"USER" => "your_paypal_username",
|
15
|
+
"PWD" => "your_paypal_password",
|
16
|
+
"SIGNATURE" => "your_paypal_signature",
|
17
|
+
"CURRENCYCODE" => "USD",
|
18
|
+
"EMAILSUBJECT" => "Paypal Masspay",
|
19
|
+
"L_AMT0" => "10.0",
|
20
|
+
"L_AMT1" => "2.95",
|
21
|
+
"L_EMAIL0" => "chunky@example.com",
|
22
|
+
"L_EMAIL1" => "bacon@example.com",
|
23
|
+
"METHOD" => "MassPay",
|
24
|
+
"RECEIVERTYPE" => "EmailAddress",
|
25
|
+
"VERSION" => "2.3"
|
26
|
+
}).to_return(:body => response_body)
|
27
|
+
|
28
|
+
Paypal::Masspay::Configuration.configure do |config|
|
29
|
+
config.environment = :sandbox
|
30
|
+
config.username = 'your_paypal_username'
|
31
|
+
config.password = 'your_paypal_password'
|
32
|
+
config.signature = 'your_paypal_signature'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'adding recipients one at a time' do
|
37
|
+
before do
|
38
|
+
@masspay = Paypal::Masspay.new(:currency => 'USD', :subject => 'Paypal Masspay') do |bucket|
|
39
|
+
bucket.add_recipient(recipient_one)
|
40
|
+
bucket.add_recipient(recipient_two)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when the response was successful' do
|
45
|
+
let(:response_body) { success_body }
|
46
|
+
|
47
|
+
it 'sends the correct request to the paypal api and is successful' do
|
48
|
+
expect(@masspay).to_not be_delivered
|
49
|
+
@masspay.deliver
|
50
|
+
expect(@masspay).to be_successful
|
51
|
+
expect(@masspay).to be_delivered
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the response was not successful' do
|
56
|
+
let(:response_body) { fail_body }
|
57
|
+
|
58
|
+
it 'sends the correct request to the paypal api and is successful' do
|
59
|
+
@masspay.deliver
|
60
|
+
expect(@masspay).to_not be_successful
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'has 2 errors' do
|
64
|
+
@masspay.deliver
|
65
|
+
expect(@masspay.errors.count).to eq(2)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'has the correct error codes' do
|
69
|
+
@masspay.deliver
|
70
|
+
expect(@masspay.errors[0].code).to eq(10000)
|
71
|
+
expect(@masspay.errors[1].code).to eq(20000)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'adding recipients in a hash' do
|
77
|
+
let(:recipients) { [recipient_one, recipient_two] }
|
78
|
+
|
79
|
+
before do
|
80
|
+
@masspay = Paypal::Masspay.new(:currency => 'USD', :subject => 'Paypal Masspay', :recipients => recipients)
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the response was successful' do
|
84
|
+
let(:response_body) { success_body }
|
85
|
+
|
86
|
+
it 'sends the correct request to the paypal api and is successful' do
|
87
|
+
@masspay.deliver
|
88
|
+
expect(@masspay).to be_successful
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paypal::Masspay::Error do
|
4
|
+
let(:code) { double }
|
5
|
+
let(:short_message) { double }
|
6
|
+
let(:long_message) { double }
|
7
|
+
let(:severity) { double }
|
8
|
+
let(:arguments) { { :code => code, :short_message => short_message, :long_message => long_message, :severity => severity } }
|
9
|
+
subject(:error) { Paypal::Masspay::Error.new(arguments) }
|
10
|
+
|
11
|
+
describe '#code' do
|
12
|
+
it 'returns the error code' do
|
13
|
+
expect(error.code).to eq(code)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#short_message' do
|
18
|
+
it 'returns the error short_message' do
|
19
|
+
expect(error.short_message).to eq(short_message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#long_message' do
|
24
|
+
it 'returns the error long_message' do
|
25
|
+
expect(error.long_message).to eq(long_message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#severity' do
|
30
|
+
it 'returns the error severity' do
|
31
|
+
expect(error.severity).to eq(severity)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paypal::Masspay::LengthValidator do
|
4
|
+
describe '.validate' do
|
5
|
+
context 'the string is valid' do
|
6
|
+
it 'returns the string' do
|
7
|
+
expect(Paypal::Masspay::LengthValidator.validate("hello", 5, :test)).to eq("hello")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'the string is not valid' do
|
12
|
+
it 'raises a field too large exception' do
|
13
|
+
expect { Paypal::Masspay::LengthValidator.validate("hello", 4, :test) }.to raise_error(Paypal::Masspay::LengthValidator::FieldLengthTooLarge)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paypal::Masspay::Recipient do
|
4
|
+
let(:recipient_email) { double }
|
5
|
+
let(:amount) { double }
|
6
|
+
let(:note) { double }
|
7
|
+
let(:unique_id) { double }
|
8
|
+
let(:arguments) { { :recipient_email => recipient_email, :amount => amount, :note => note, :unique_id => unique_id } }
|
9
|
+
subject(:recipient) { Paypal::Masspay::Recipient.new(arguments) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(Paypal::Masspay::LengthValidator).to receive(:validate).with(recipient_email, 127, :recipient_email).and_return(recipient_email)
|
13
|
+
allow(Paypal::Masspay::LengthValidator).to receive(:validate).with(note, 4000, :note).and_return(note)
|
14
|
+
allow(Paypal::Masspay::LengthValidator).to receive(:validate).with(unique_id, 30, :unique_id).and_return(unique_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#get_params' do
|
18
|
+
it 'returns the arguments in the correct format' do
|
19
|
+
expect(recipient.get_params(5)).to eq({
|
20
|
+
"L_EMAIL5" => recipient_email,
|
21
|
+
"L_AMT5" => amount,
|
22
|
+
"L_NOTE5" => note,
|
23
|
+
"L_UNIQUEID5" => unique_id
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paypal::Masspay::ResponseParser do
|
4
|
+
let(:success_body) { 'ACK=Success' }
|
5
|
+
let(:fail_body) { 'ACK=Failure&L_ERRORCODE0=10000&L_SHORTMESSAGE0=short_error_message&L_LONGMESSAGE0=long_error_message&L_SEVERITYCODE0=Error&L_ERRORCODE1=20000&L_SHORTMESSAGE1=short_error_message2&L_LONGMESSAGE1=long_error_message2&L_SEVERITYCODE1=Error' }
|
6
|
+
let(:response_body) { success_body }
|
7
|
+
subject(:response_parser) { Paypal::Masspay::ResponseParser.new(response_body) }
|
8
|
+
|
9
|
+
describe '#successful?' do
|
10
|
+
context 'the response was successful' do
|
11
|
+
let(:response_body) { success_body }
|
12
|
+
|
13
|
+
it 'returns true' do
|
14
|
+
expect(response_parser).to be_successful
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'the response was not successful' do
|
19
|
+
let(:response_body) { fail_body }
|
20
|
+
|
21
|
+
it 'returns false' do
|
22
|
+
expect(response_parser).to_not be_successful
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#errors' do
|
28
|
+
context 'the response was successful' do
|
29
|
+
let(:response_body) { success_body }
|
30
|
+
|
31
|
+
it 'has no errors' do
|
32
|
+
expect(response_parser.errors.count).to eq(0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'the response was not successful' do
|
37
|
+
let(:response_body) { fail_body }
|
38
|
+
|
39
|
+
it 'has errors' do
|
40
|
+
expect(response_parser.errors.count).to eq(2)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Paypal::Masspay do
|
4
|
+
let(:recipient_one) { double }
|
5
|
+
let(:recipient_two) { double }
|
6
|
+
let(:response) { double(:successful? => successful, :errors => errors) }
|
7
|
+
let(:errors) { [] }
|
8
|
+
|
9
|
+
let(:successful) { true }
|
10
|
+
let(:success_body) { 'ACK=Success' }
|
11
|
+
let(:fail_body) { 'ACK=Failure&L_ERRORCODE0=10000&L_SHORTMESSAGE0=short_error_message&L_LONGMESSAGE0=long_error_message&L_SEVERITYCODE0=Error&L_ERRORCODE1=20000&L_SHORTMESSAGE1=short_error_message2&L_LONGMESSAGE1=long_error_message2&L_SEVERITYCODE1=Error' }
|
12
|
+
let(:response_body) { success_body }
|
13
|
+
|
14
|
+
before do
|
15
|
+
allow(Paypal::Masspay::Configuration).to receive(:environment).and_return(:sandbox)
|
16
|
+
allow(Paypal::Masspay::Configuration).to receive(:username).and_return("user1")
|
17
|
+
allow(Paypal::Masspay::Configuration).to receive(:password).and_return("password1")
|
18
|
+
allow(Paypal::Masspay::Configuration).to receive(:signature).and_return("sig1")
|
19
|
+
|
20
|
+
allow(recipient_one).to receive(:get_params).with(0).and_return({"L_EMAIL0" => 'chunky@example.com', "L_AMT0" => 10.0})
|
21
|
+
allow(recipient_two).to receive(:get_params).with(1).and_return({"L_EMAIL1" => 'bacon@example.com', "L_AMT1" => 2.95})
|
22
|
+
allow(Paypal::Masspay::ResponseParser).to receive(:new).with(response_body).and_return(response)
|
23
|
+
|
24
|
+
allow(Paypal::Masspay::LengthValidator).to receive(:validate).with('USD', 3, :currency).and_return('USD')
|
25
|
+
allow(Paypal::Masspay::LengthValidator).to receive(:validate).with('Paypal Masspay', 255, :subject).and_return('Paypal Masspay')
|
26
|
+
|
27
|
+
stub_request(:post, "https://api-3t.sandbox.paypal.com/nvp").with(
|
28
|
+
:body => {
|
29
|
+
"USER" => "user1",
|
30
|
+
"PWD" => "password1",
|
31
|
+
"SIGNATURE" => "sig1",
|
32
|
+
"CURRENCYCODE" => "USD",
|
33
|
+
"EMAILSUBJECT" => "Paypal Masspay",
|
34
|
+
"L_AMT0" => "10.0",
|
35
|
+
"L_AMT1" => "2.95",
|
36
|
+
"L_EMAIL0" => "chunky@example.com",
|
37
|
+
"L_EMAIL1" => "bacon@example.com",
|
38
|
+
"METHOD" => "MassPay",
|
39
|
+
"RECEIVERTYPE" => "EmailAddress",
|
40
|
+
"VERSION" => "2.3"
|
41
|
+
}).to_return(:body => response_body)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'adding recipients one at a time' do
|
45
|
+
before do
|
46
|
+
|
47
|
+
@masspay = Paypal::Masspay.new(:currency => 'USD', :subject => 'Paypal Masspay') do |bucket|
|
48
|
+
bucket.add_recipient(recipient_one)
|
49
|
+
bucket.add_recipient(recipient_two)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when the response was successful' do
|
54
|
+
let(:response_body) { success_body }
|
55
|
+
let(:successful) { true }
|
56
|
+
let(:errors) { [] }
|
57
|
+
|
58
|
+
it 'sends the correct request to the paypal api and is successful' do
|
59
|
+
expect(@masspay).to_not be_delivered
|
60
|
+
@masspay.deliver
|
61
|
+
expect(@masspay).to be_successful
|
62
|
+
expect(@masspay).to be_delivered
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the response was not successful' do
|
67
|
+
let(:response_body) { fail_body }
|
68
|
+
let(:successful) { false }
|
69
|
+
let(:errors) { [ double, double ] }
|
70
|
+
|
71
|
+
it 'sends the correct request to the paypal api and is successful' do
|
72
|
+
@masspay.deliver
|
73
|
+
expect(@masspay).to_not be_successful
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'has 2 errors' do
|
77
|
+
@masspay.deliver
|
78
|
+
expect(@masspay.errors.count).to eq(2)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'adding recipients in a hash' do
|
84
|
+
let(:recipients) { [recipient_one, recipient_two] }
|
85
|
+
|
86
|
+
before do
|
87
|
+
@masspay = Paypal::Masspay.new(:currency => 'USD', :subject => 'Paypal Masspay', :recipients => recipients)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when the response was successful' do
|
91
|
+
let(:response_body) { success_body }
|
92
|
+
let(:successful) { true }
|
93
|
+
let(:errors) { [] }
|
94
|
+
|
95
|
+
it 'sends the correct request to the paypal api and is successful' do
|
96
|
+
@masspay.deliver
|
97
|
+
expect(@masspay).to be_successful
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paypal-masspay
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Martin Jagusch
|
9
|
+
- Shervin Aflatooni
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2014-09-09 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: faraday
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ~>
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0.9'
|
23
|
+
- - ! '>='
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.9.0
|
26
|
+
type: :runtime
|
27
|
+
prerelease: false
|
28
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.9'
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 0.9.0
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rake
|
39
|
+
requirement: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '10.3'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ~>
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '10.3'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.0.0.beta1
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.0.0.beta1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: cane
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.6'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ~>
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '2.6'
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: webmock
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
89
|
+
requirements:
|
90
|
+
- - ~>
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '1.17'
|
93
|
+
type: :development
|
94
|
+
prerelease: false
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ~>
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '1.17'
|
101
|
+
description: Performing multiple payments to PayPal using the MassPay API
|
102
|
+
email:
|
103
|
+
- shervinaflatooni@gmail.com
|
104
|
+
executables: []
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- .gitignore
|
109
|
+
- .rspec
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE.txt
|
112
|
+
- README.md
|
113
|
+
- Rakefile
|
114
|
+
- lib/paypal/masspay.rb
|
115
|
+
- lib/paypal/masspay/configuration.rb
|
116
|
+
- lib/paypal/masspay/error.rb
|
117
|
+
- lib/paypal/masspay/length_validator.rb
|
118
|
+
- lib/paypal/masspay/recipient.rb
|
119
|
+
- lib/paypal/masspay/response_parser.rb
|
120
|
+
- lib/paypal/masspay/version.rb
|
121
|
+
- paypal-masspay.gemspec
|
122
|
+
- spec/lib/integration/masspay_spec.rb
|
123
|
+
- spec/lib/paypal/masspay/error_spec.rb
|
124
|
+
- spec/lib/paypal/masspay/length_validator_spec.rb
|
125
|
+
- spec/lib/paypal/masspay/recipient_spec.rb
|
126
|
+
- spec/lib/paypal/masspay/response_parser_spec.rb
|
127
|
+
- spec/lib/paypal/masspay_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: https://github.com/envato/paypal-masspay
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ! '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubyforge_project:
|
150
|
+
rubygems_version: 1.8.21
|
151
|
+
signing_key:
|
152
|
+
specification_version: 3
|
153
|
+
summary: paypal-masspay-1.1.0
|
154
|
+
test_files:
|
155
|
+
- spec/lib/integration/masspay_spec.rb
|
156
|
+
- spec/lib/paypal/masspay/error_spec.rb
|
157
|
+
- spec/lib/paypal/masspay/length_validator_spec.rb
|
158
|
+
- spec/lib/paypal/masspay/recipient_spec.rb
|
159
|
+
- spec/lib/paypal/masspay/response_parser_spec.rb
|
160
|
+
- spec/lib/paypal/masspay_spec.rb
|
161
|
+
- spec/spec_helper.rb
|