paypal-masspay 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -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.
@@ -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
+ ```
@@ -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,5 @@
1
+ module Paypal
2
+ class Masspay
3
+ VERSION = '1.1.0'
4
+ end
5
+ 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
@@ -0,0 +1,6 @@
1
+ lib = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'paypal/masspay'
5
+ require 'rspec'
6
+ require 'webmock/rspec'
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