payoneer-client 0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3403735dba6cf4fdebc3909ea215bbc5a3c49058
4
+ data.tar.gz: e85cc201eee353b81693000785003e79cc31445d
5
+ SHA512:
6
+ metadata.gz: bcaf96cb747a67d9952a9263257ea6c0de6d65b9890f18293f79762369bf8a911666c65b63499b28c58c9062e27465c69844ca4d3ffa9662c5209d9c928ae120
7
+ data.tar.gz: 2107242700e6d088bf73596310f8142a6a10635ee6a254a6af64e8cf38940ddded833a75d46a015997e1b3282867e3283a1962a29fb3e5422d3d9b0add884c63
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ /Gemfile.lock
3
+ /.approvals
4
+ /.bundle
5
+ /coverage
6
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,38 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.2
3
+
4
+ Metrics/AbcSize:
5
+ Enabled: false
6
+ Metrics/CyclomaticComplexity:
7
+ Enabled: false
8
+ Metrics/PerceivedComplexity:
9
+ Enabled: false
10
+
11
+ Metrics/LineLength:
12
+ Enabled: false
13
+ Metrics/ClassLength:
14
+ Enabled: false
15
+ Metrics/MethodLength:
16
+ Enabled: false
17
+ Metrics/BlockLength:
18
+ Enabled: false
19
+ Metrics/ParameterLists:
20
+ Enabled: false
21
+
22
+ Lint/EndAlignment:
23
+ Enabled: false
24
+
25
+ Style/Documentation:
26
+ Enabled: false
27
+ Style/IndentationWidth:
28
+ Enabled: false
29
+ Style/ElseAlignment:
30
+ Enabled: false
31
+ Style/GuardClause:
32
+ Enabled: false
33
+ Style/NumericLiterals:
34
+ Enabled: false
35
+
36
+ # This is temporary - it can be remove after updating rubocop to the latest.
37
+ Style/PercentLiteralDelimiters:
38
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :development, :test do
5
+ gem 'awesome_print'
6
+ gem 'pry'
7
+ gem 'rake'
8
+ gem 'rubocop'
9
+ end
10
+
11
+ group :test do
12
+ gem 'coveralls', require: false
13
+ gem 'rspec'
14
+ gem 'webmock'
15
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Tophatter
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,65 @@
1
+ ### Install
2
+
3
+ ```
4
+ gem install payoneer-client
5
+ ```
6
+
7
+ ### Usage
8
+
9
+ ```ruby
10
+ client = Payoneer::Client.new(
11
+ Payoneer::Configuration.new(
12
+ username: 'fake-username',
13
+ api_password: 'fake-api-password',
14
+ partner_id: 'fake-partner-id'
15
+ )
16
+ )
17
+ => <Payoneer::Client @configuration=<Payoneer::Configuration @partner_id="fake-partner-id", @username="fake-username", @api_password="fake-api-password", @host="api.sandbox.payoneer.com", @auto_approve_sandbox_accounts=true>>
18
+
19
+ response = client.status
20
+ response.ok?
21
+ => true
22
+
23
+ response.body
24
+ => {
25
+ "Status" => "000",
26
+ "Description" => "Echo Ok - All systems are up."
27
+ }
28
+
29
+ client.version.body
30
+ => {
31
+ "Version" => "4.15"
32
+ }
33
+
34
+ client.payee_signup_url('test').body
35
+ => "https://payouts.sandbox.payoneer.com/partners/lp.aspx?token=fake-token"
36
+
37
+ client.payee_details('fake-payee-id').body
38
+ => {"FirstName"=>"Foo",
39
+ "LastName"=>"Bar",
40
+ "Email"=>"foo@bar.com",
41
+ "Address1"=>"123 Main Street",
42
+ "Address2"=>nil,
43
+ "City"=>"Palo Alto",
44
+ "State"=>"CA",
45
+ "Zip"=>"94306",
46
+ "Country"=>"US",
47
+ "Phone"=>"555-867-5309",
48
+ "Mobile"=>nil,
49
+ "PayeeStatus"=>"InActive",
50
+ "PayOutMethod"=>"Direct Deposit",
51
+ "RegDate"=>"12/21/2015 8:03:19 PM",
52
+ "PayoutMethodDetails"=>
53
+ {"Currency"=>"USD",
54
+ "Country"=>"US",
55
+ "BankAccountType"=>"Individual",
56
+ "BankName"=>"Wells Fargo",
57
+ "AccountName"=>"Foo Bar",
58
+ "AccountNumber"=>"123456789",
59
+ "RoutingNumber"=>"121042882",
60
+ "AccountType"=>"S"}}
61
+ ```
62
+
63
+ ### Development
64
+
65
+ After checking out the repo, run `bin/payoneer-console` for an interactive prompt that will allow you to experiment.
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require 'rspec/core/rake_task'
2
+ RSpec::Core::RakeTask.new(:spec)
3
+ task default: :spec
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup' # Otherwise "require 'payoneer'" won't work.
4
+ require 'payoneer'
5
+ require 'awesome_print'
6
+ require 'pry'
7
+
8
+ # Payoneer.logger = Logger.new(STDOUT)
9
+ # Payoneer.logger.level = Logger::DEBUG
10
+
11
+ AwesomePrint.pry!
12
+ Pry.start
data/lib/payoneer.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rest-client'
2
+ require 'active_support/core_ext/hash' # For Hash.to_xml.
3
+
4
+ require File.dirname(__FILE__) + '/payoneer/configuration'
5
+ require File.dirname(__FILE__) + '/payoneer/client'
6
+ require File.dirname(__FILE__) + '/payoneer/response'
7
+ require File.dirname(__FILE__) + '/payoneer/response_error'
@@ -0,0 +1,74 @@
1
+ module Payoneer
2
+ class Client
3
+ attr_reader :configuration
4
+
5
+ def initialize(configuration)
6
+ @configuration = configuration
7
+ end
8
+
9
+ def status
10
+ post('Echo')
11
+ end
12
+
13
+ def version
14
+ post('GetVersion')
15
+ end
16
+
17
+ def payee_signup_url(payee_id, redirect_url: nil, redirect_time: nil)
18
+ post('GetToken', p4: payee_id, p6: redirect_url, p8: redirect_time, p9: configuration.auto_approve_sandbox_accounts, p10: true) do |response|
19
+ response['Token']
20
+ end
21
+ end
22
+
23
+ def payee_details(payee_id)
24
+ post('GetPayeeDetails', p4: payee_id, p10: true) do |response|
25
+ response['CompanyDetails'].present? ? response['Payee'].merge(response['CompanyDetails']) : response['Payee']
26
+ end
27
+ end
28
+
29
+ def payout(program_id:, payment_id:, payee_id:, amount:, description:, payment_date: Time.now, currency: 'USD')
30
+ post(
31
+ 'PerformPayoutPayment',
32
+ p4: program_id,
33
+ p5: payment_id,
34
+ p6: payee_id,
35
+ p7: format('%.2f', amount),
36
+ p8: description,
37
+ p9: payment_date.strftime('%m/%d/%Y %H:%M:%S'),
38
+ Currency: currency
39
+ )
40
+ end
41
+
42
+ def payout_details(payee_id:, payment_id:)
43
+ post('GetPaymentStatus', p4: payee_id, p5: payment_id)
44
+ end
45
+
46
+ private
47
+
48
+ def post(method_name, params = {})
49
+ response = RestClient.post(configuration.base_uri, {
50
+ mname: method_name,
51
+ p1: configuration.username,
52
+ p2: configuration.api_password,
53
+ p3: configuration.partner_id
54
+ }.merge(params))
55
+
56
+ raise ResponseError.new(code: response.code, body: response.body) if response.code != 200
57
+
58
+ # @TODO: Validate that the response is XML?
59
+ hash = Hash.from_xml(response.body).values.first
60
+
61
+ if hash.key?('Code')
62
+ Response.new(hash['Code'], hash['Description'])
63
+ else
64
+ hash = if block_given?
65
+ yield(hash)
66
+ else
67
+ hash
68
+ end
69
+
70
+ Response.new(Response::OK_STATUS_CODE, hash)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,25 @@
1
+ module Payoneer
2
+ class Configuration
3
+ attr_reader :partner_id, :username, :api_password, :auto_approve_sandbox_accounts
4
+
5
+ def initialize(partner_id:, username:, api_password:, environment: 'development', auto_approve_sandbox_accounts: true)
6
+ @partner_id = partner_id
7
+ @username = username
8
+ @api_password = api_password
9
+ @host = 'api.sandbox.payoneer.com' if environment != 'production'
10
+ @auto_approve_sandbox_accounts = auto_approve_sandbox_accounts && environment != 'production'
11
+ end
12
+
13
+ def protocol
14
+ @protocol || 'https'
15
+ end
16
+
17
+ def host
18
+ @host || 'api.payoneer.com'
19
+ end
20
+
21
+ def base_uri
22
+ @base_uri || "#{protocol}://#{host}/Payouts/HttpApi/API.aspx"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ module Payoneer
2
+ class Response
3
+ OK_STATUS_CODE = '000'.freeze
4
+
5
+ attr_reader :code, :body
6
+
7
+ def initialize(code, body)
8
+ @code = code
9
+ @body = body
10
+ end
11
+
12
+ def ok?
13
+ code == OK_STATUS_CODE
14
+ end
15
+
16
+ def ==(other)
17
+ code == other.code && body == other.body
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Payoneer
2
+ class ResponseError < StandardError
3
+ attr_reader :code, :body
4
+
5
+ def initialize(code:, body:)
6
+ @code = code
7
+ @body = body
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # To publish the next version:
2
+ # gem build payoneer-client.gemspec
3
+ # gem push payoneer-client-{VERSION}.gem
4
+ Gem::Specification.new do |s|
5
+ s.name = 'payoneer-client'
6
+ s.version = '0.3'
7
+ s.platform = Gem::Platform::RUBY
8
+ s.licenses = ['MIT']
9
+ s.authors = ['Chris Estreich']
10
+ s.email = ['chris@tophatter.com']
11
+ s.homepage = 'https://github.com/tophatter/payoneer-api-ruby'
12
+ s.summary = 'Payoneer SDK for ruby.'
13
+ s.description = 'Payoneer SDK for ruby.'
14
+
15
+ s.extra_rdoc_files = ['README.md']
16
+
17
+ s.required_ruby_version = '~> 2.0'
18
+
19
+ s.add_dependency 'rest-client', '~> 1.6'
20
+ s.add_dependency 'activesupport', '~> 4.2'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
25
+ s.require_paths = ['lib']
26
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ # rspec spec/client_spec.rb
4
+ describe Payoneer::Client do
5
+ let(:response) do
6
+ mock = double
7
+ allow(mock).to receive(:code).and_return(200)
8
+ allow(mock).to receive(:body).and_return(xml)
9
+ mock
10
+ end
11
+
12
+ let(:endpoint) { 'https://api.payoneer.com/Payouts/HttpApi/API.aspx' }
13
+ let(:configuration) { Payoneer::Configuration.new(username: 'fake-username', api_password: 'fake-password', partner_id: 'fake-partner-id', environment: 'production') }
14
+ let(:client) { Payoneer::Client.new(configuration) }
15
+
16
+ describe '#status' do
17
+ context 'when the response is valid' do
18
+ let(:xml) { "<?xml version='1.0' encoding='ISO-8859-1' ?><PayoneerResponse><Status>000</Status><Description>Echo Ok - All systems are up.</Description></PayoneerResponse>" }
19
+
20
+ it 'returns a successful response' do
21
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'Echo')).and_return(response)
22
+ response = client.status
23
+ expect(response.ok?).to be_truthy
24
+ expect(response.body['Description']).to eq('Echo Ok - All systems are up.')
25
+ end
26
+ end
27
+
28
+ context 'when the response specifies a non-200 code' do
29
+ let(:xml) { "<?xml version='1.0' encoding='ISO-8859-1' ?><PayoneerResponse><Code>999</Code><Description>Echo Failure - All systems are down.</Description></PayoneerResponse>" }
30
+
31
+ it 'returns a failure response' do
32
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'Echo')).and_return(response)
33
+ response = client.status
34
+ expect(response.ok?).to be_falsey
35
+ expect(response.body).to eq('Echo Failure - All systems are down.')
36
+ end
37
+ end
38
+
39
+ context 'when the response is invalid' do
40
+ let(:response) do
41
+ mock = double
42
+ allow(mock).to receive(:code).and_return(500)
43
+ allow(mock).to receive(:body).and_return('Server Error')
44
+ mock
45
+ end
46
+
47
+ it 'raises an error' do
48
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'Echo')).and_return(response)
49
+ expect { client.status }.to raise_error(Payoneer::ResponseError)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe '#version' do
55
+ let(:xml) { "<?xml version='1.0' encoding='ISO-8859-1' ?><PayoneerResponse><Version>4.15</Version></PayoneerResponse>" }
56
+
57
+ it 'generates the correct request' do
58
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'GetVersion')).and_return(response)
59
+ response = client.version
60
+ expect(response.ok?).to be_truthy
61
+ expect(response.body['Version']).to eq('4.15')
62
+ end
63
+ end
64
+
65
+ describe '#payee_signup_url' do
66
+ let(:xml) { '<?xml version="1.0" encoding="UTF-8" ?><PayoneerToken><Token>https://payouts.sandbox.payoneer.com/partners/lp.aspx?token=fake-token</Token></PayoneerToken>' }
67
+
68
+ it 'generates the correct request' do
69
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'GetToken')).and_return(response)
70
+ response = client.payee_signup_url('test')
71
+ expect(response.ok?).to be_truthy
72
+ expect(response.body).to eq('https://payouts.sandbox.payoneer.com/partners/lp.aspx?token=fake-token')
73
+ end
74
+ end
75
+
76
+ describe '#payee_details' do
77
+ let(:xml) { '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?><GetPayeeDetails><Payee><FirstName>Foo</FirstName><LastName>Bar</LastName><Email>foo@bar.com</Email><Address1>185 Berry Street</Address1><Address2>Suite 2400</Address2><City>San Francisco</City><State>CA</State><Zip>94107</Zip><Country>US</Country><Phone></Phone><Mobile>15552223333</Mobile><PayeeStatus>Active</PayeeStatus><PayOutMethod>Prepaid Card</PayOutMethod><Cards><Card><CardID>123456789</CardID><Currency>USD</Currency><ActivationStatus>Card Issued, Not Activated</ActivationStatus><CardShipDate>11/25/2015</CardShipDate><CardStatus>Active</CardStatus></Card></Cards><RegDate>10/9/2017 7:58:44 PM</RegDate></Payee><CompanyDetails><CompanyName></CompanyName></CompanyDetails></GetPayeeDetails>' }
78
+
79
+ it 'generates the correct request' do
80
+ expect(RestClient).to receive(:post).exactly(1).times.with(endpoint, hash_including(mname: 'GetPayeeDetails')).and_return(response)
81
+ response = client.payee_details('fake-payee-id')
82
+ expect(response.ok?).to be_truthy
83
+ expect(response.body).to include('FirstName' => 'Foo', 'LastName' => 'Bar')
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,8 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'payoneer'
5
+ require 'awesome_print'
6
+
7
+ gemspec = Gem::Specification.find_by_name('payoneer')
8
+ Dir["#{gemspec.gem_dir}/spec/support/**/*.rb"].each { |f| require f }
@@ -0,0 +1,3 @@
1
+ require 'webmock/rspec'
2
+
3
+ WebMock.disable_net_connect!(allow_localhost: true)
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: payoneer-client
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.3'
5
+ platform: ruby
6
+ authors:
7
+ - Chris Estreich
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.2'
41
+ description: Payoneer SDK for ruby.
42
+ email:
43
+ - chris@tophatter.com
44
+ executables:
45
+ - payoneer-console
46
+ extensions: []
47
+ extra_rdoc_files:
48
+ - README.md
49
+ files:
50
+ - ".coveralls.yml"
51
+ - ".gitignore"
52
+ - ".rspec"
53
+ - ".rubocop.yml"
54
+ - Gemfile
55
+ - LICENSE.md
56
+ - README.md
57
+ - Rakefile
58
+ - bin/payoneer-console
59
+ - lib/payoneer.rb
60
+ - lib/payoneer/client.rb
61
+ - lib/payoneer/configuration.rb
62
+ - lib/payoneer/response.rb
63
+ - lib/payoneer/response_error.rb
64
+ - payoneer-client.gemspec
65
+ - spec/client_spec.rb
66
+ - spec/spec_helper.rb
67
+ - spec/support/webmock.rb
68
+ homepage: https://github.com/tophatter/payoneer-api-ruby
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '2.0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project:
88
+ rubygems_version: 2.6.12
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Payoneer SDK for ruby.
92
+ test_files:
93
+ - spec/client_spec.rb
94
+ - spec/spec_helper.rb
95
+ - spec/support/webmock.rb