balanced 0.3.11 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +6 -0
- data/examples/examples.rb +37 -7
- data/lib/balanced.rb +2 -1
- data/lib/balanced/client.rb +25 -7
- data/lib/balanced/error.rb +19 -4
- data/lib/balanced/resources/account.rb +13 -15
- data/lib/balanced/resources/bank_account.rb +33 -6
- data/lib/balanced/resources/card.rb +17 -4
- data/lib/balanced/resources/credit.rb +32 -5
- data/lib/balanced/resources/debit.rb +2 -0
- data/lib/balanced/resources/hold.rb +9 -1
- data/lib/balanced/resources/marketplace.rb +119 -3
- data/lib/balanced/resources/merchant.rb +1 -1
- data/lib/balanced/resources/resource.rb +35 -10
- data/lib/balanced/version.rb +1 -1
- data/spec/balanced/error_spec.rb +42 -0
- data/spec/balanced/resources/account_spec.rb +75 -102
- data/spec/balanced/resources/bank_account_spec.rb +91 -0
- data/spec/balanced/resources/credit_spec.rb +60 -0
- data/spec/balanced/resources/hold_spec.rb +6 -5
- data/spec/balanced/resources/marketplace_spec.rb +115 -6
- data/spec/balanced/resources/merchant_spec.rb +6 -0
- data/spec/balanced/resources/resource_spec.rb +43 -0
- data/spec/balanced/resources/transactions_spec.rb +8 -5
- data/spec/balanced_spec.rb +20 -1
- data/spec/spec_helper.rb +18 -0
- metadata +14 -5
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -55,6 +55,12 @@ spec/cassettes. To clear them and regenerate:
|
|
55
55
|
$ rm -rf spec/cassettes
|
56
56
|
|
57
57
|
|
58
|
+
### Issues
|
59
|
+
|
60
|
+
All issues should be documented at
|
61
|
+
[balanced-ruby/issues](https://github.com/balanced/balanced-ruby/issues)
|
62
|
+
|
63
|
+
|
58
64
|
### Building Documentation
|
59
65
|
|
60
66
|
Documentation is built using YARD - http://rubydoc.info/docs/yard
|
data/examples/examples.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
cwd = File.dirname(File.dirname(File.absolute_path(__FILE__)))
|
2
|
+
$:.unshift(cwd + "/lib")
|
2
3
|
require 'balanced'
|
3
4
|
|
4
5
|
begin
|
@@ -7,9 +8,9 @@ rescue NameError
|
|
7
8
|
raise "wtf"
|
8
9
|
end
|
9
10
|
|
10
|
-
host = ENV
|
11
|
+
host = ENV.fetch('BALANCED_HOST') { nil }
|
11
12
|
options = {}
|
12
|
-
if host
|
13
|
+
if host
|
13
14
|
options[:scheme] = 'http'
|
14
15
|
options[:host] = host
|
15
16
|
options[:port] = 5000
|
@@ -79,11 +80,11 @@ refund = debit.refund() # the full amount!
|
|
79
80
|
puts "ok, we have a merchant that's signing up, let's create an account for them " \
|
80
81
|
"first, lets create their bank account."
|
81
82
|
|
82
|
-
bank_account =
|
83
|
+
bank_account = marketplace.create_bank_account(
|
83
84
|
:account_number => "1234567890",
|
84
85
|
:bank_code => "12",
|
85
86
|
:name => "Jack Q Merchant",
|
86
|
-
)
|
87
|
+
)
|
87
88
|
|
88
89
|
merchant = marketplace.create_merchant(
|
89
90
|
:email_address => "merchant@example.org",
|
@@ -100,9 +101,9 @@ merchant = marketplace.create_merchant(
|
|
100
101
|
:name => "Jack Q Merchant",
|
101
102
|
)
|
102
103
|
|
103
|
-
puts "oh our buyer is interested in buying something for
|
104
|
+
puts "oh our buyer is interested in buying something for 530.00$"
|
104
105
|
another_debit = buyer.debit(
|
105
|
-
:amount =>
|
106
|
+
:amount => 53000,
|
106
107
|
:appears_on_statement_as => "MARKETPLACE.COM"
|
107
108
|
)
|
108
109
|
|
@@ -127,3 +128,32 @@ puts "invalidating a bank account"
|
|
127
128
|
bank_account.invalidate
|
128
129
|
|
129
130
|
raise "This card is INCORRECTLY VALID" if bank_account.is_valid
|
131
|
+
|
132
|
+
puts "let's create a bank account not associated to an account"
|
133
|
+
bank_account = Balanced::BankAccount.new(
|
134
|
+
:account_number => "9876543210",
|
135
|
+
:routing_number => "021000021",
|
136
|
+
:name => "Jake Skellington",
|
137
|
+
:type => "checking"
|
138
|
+
).save
|
139
|
+
|
140
|
+
puts "now let's credit it, the super-simple way"
|
141
|
+
credit = bank_account.credit(
|
142
|
+
:amount => 500
|
143
|
+
)
|
144
|
+
|
145
|
+
raise "Incorrect value for credit" if credit.amount != 500
|
146
|
+
|
147
|
+
puts "That was still too hard -- let's credit without creating a bank account first"
|
148
|
+
credit = Balanced::Credit.new(
|
149
|
+
:amount => 700,
|
150
|
+
:description => "Amazing",
|
151
|
+
:bank_account => {
|
152
|
+
:account_number => "55555555",
|
153
|
+
:bank_code => "021000021",
|
154
|
+
:name => "Wanda Wandy",
|
155
|
+
:type => "checking"
|
156
|
+
}
|
157
|
+
).save
|
158
|
+
raise "OOPS -- that was hard after all" if (credit.amount != 700 or
|
159
|
+
credit.created_at.nil?)
|
data/lib/balanced.rb
CHANGED
@@ -25,7 +25,8 @@ module Balanced
|
|
25
25
|
attr_accessor :config
|
26
26
|
|
27
27
|
def configure(api_key=nil, options={})
|
28
|
-
@
|
28
|
+
@config = @config.merge(options)
|
29
|
+
@client = Balanced::Client.new(api_key, @config)
|
29
30
|
end
|
30
31
|
|
31
32
|
def is_configured_with_api_key?
|
data/lib/balanced/client.rb
CHANGED
@@ -16,7 +16,8 @@ module Balanced
|
|
16
16
|
:logging_level => 'WARN',
|
17
17
|
:connection_timeout => 2,
|
18
18
|
:read_timeout => 5,
|
19
|
-
:logger => nil
|
19
|
+
:logger => nil,
|
20
|
+
:ssl_verify => true
|
20
21
|
}
|
21
22
|
|
22
23
|
attr_reader :conn
|
@@ -43,6 +44,9 @@ module Balanced
|
|
43
44
|
:request => {
|
44
45
|
:open_timeout => config[:connection_timeout],
|
45
46
|
:timeout => config[:read_timeout]
|
47
|
+
},
|
48
|
+
:ssl => {
|
49
|
+
:verify => @config[:ssl_verify] # Only set this to false for testing
|
46
50
|
}
|
47
51
|
}
|
48
52
|
@conn = Faraday.new(url, options) do |cxn|
|
@@ -63,20 +67,34 @@ module Balanced
|
|
63
67
|
#end
|
64
68
|
|
65
69
|
def url
|
66
|
-
|
67
|
-
end
|
70
|
+
builder = (config[:scheme] == 'http') ? URI::HTTP : URI::HTTPS
|
68
71
|
|
69
|
-
|
72
|
+
builder.build ({:host => config[:host],
|
73
|
+
:port => config[:port],
|
74
|
+
:scheme => config[:scheme]})
|
75
|
+
end
|
70
76
|
|
71
77
|
def method_missing(method, *args, &block)
|
72
|
-
|
73
|
-
when :get, :post, :put, :delete
|
78
|
+
if is_http_method? method
|
74
79
|
conn.basic_auth(api_key, '') unless api_key.nil?
|
75
80
|
conn.send method, *args
|
76
81
|
else
|
77
|
-
super
|
82
|
+
super method, *args, &block
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
86
|
+
private
|
87
|
+
|
88
|
+
def is_http_method? method
|
89
|
+
[:get, :post, :put, :delete].include? method
|
90
|
+
end
|
91
|
+
|
92
|
+
def respond_to?(method, include_private = false)
|
93
|
+
if is_http_method? method
|
94
|
+
true
|
95
|
+
else
|
96
|
+
super method, include_private
|
97
|
+
end
|
98
|
+
end
|
81
99
|
end
|
82
100
|
end
|
data/lib/balanced/error.rb
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
module Balanced
|
2
2
|
|
3
|
-
# Custom error class for rescuing from all Balanced errors
|
4
|
-
class Error < StandardError
|
3
|
+
# Custom error class for rescuing from all API response-related Balanced errors
|
4
|
+
class Error < ::StandardError
|
5
5
|
attr_reader :response
|
6
6
|
|
7
|
+
# @param [Hash] response the decoded json response body
|
7
8
|
def initialize(response)
|
8
9
|
@response = response
|
9
10
|
super error_message
|
10
11
|
end
|
11
12
|
|
13
|
+
# @return [Hash]
|
12
14
|
def body
|
13
|
-
|
15
|
+
@body ||= begin
|
16
|
+
return {} unless response[:body]
|
17
|
+
Utils.hash_with_indifferent_read_access(response[:body])
|
18
|
+
end
|
14
19
|
end
|
15
20
|
|
16
21
|
def error_message
|
@@ -26,12 +31,22 @@ module Balanced
|
|
26
31
|
body.keys.each do |name|
|
27
32
|
self.class.instance_eval {
|
28
33
|
define_method(name) { body[name] } # Get.
|
29
|
-
define_method("#{name}?") { !!body[name]
|
34
|
+
define_method("#{name}?") { !!body[name] } # Present.
|
30
35
|
}
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
34
39
|
|
40
|
+
# General error class for non API response exceptions
|
41
|
+
class StandardError < Error
|
42
|
+
attr_reader :message
|
43
|
+
alias :error_message :message
|
44
|
+
|
45
|
+
def initialize(message)
|
46
|
+
@message = message
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
35
50
|
class MoreInformationRequired < Error
|
36
51
|
def redirect_uri
|
37
52
|
response.headers['Location']
|
@@ -29,9 +29,11 @@ module Balanced
|
|
29
29
|
#
|
30
30
|
# @return [Debit]
|
31
31
|
def debit *args
|
32
|
+
warn_on_positional args
|
33
|
+
|
32
34
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
33
35
|
amount = args[0] || options.fetch(:amount) { nil }
|
34
|
-
|
36
|
+
appears_on_statement_as = args[1] || options.fetch(:appears_on_statement_as) { nil }
|
35
37
|
hold_uri = args[2] || options.fetch(:hold_uri) { nil }
|
36
38
|
meta = args[3] || options.fetch(:meta) { nil }
|
37
39
|
description = args[4] || options.fetch(:description) { nil }
|
@@ -40,7 +42,7 @@ module Balanced
|
|
40
42
|
debit = Debit.new(
|
41
43
|
:uri => self.debits_uri,
|
42
44
|
:amount => amount,
|
43
|
-
:appears_on_statement_as =>
|
45
|
+
:appears_on_statement_as => appears_on_statement_as,
|
44
46
|
:hold_uri => hold_uri,
|
45
47
|
:meta => meta,
|
46
48
|
:description => description,
|
@@ -59,6 +61,8 @@ module Balanced
|
|
59
61
|
# @return [Hold] A Hold representing the reservation of funds from
|
60
62
|
# this Account to your Marketplace.
|
61
63
|
def hold *args
|
64
|
+
warn_on_positional args
|
65
|
+
|
62
66
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
63
67
|
amount = args[0] || options.fetch(:amount) { }
|
64
68
|
meta = args[1] || options.fetch(:meta) { nil }
|
@@ -81,20 +85,14 @@ module Balanced
|
|
81
85
|
# @return [Credit] A Credit representing the transfer of funds from
|
82
86
|
# your Marketplace to this Account.
|
83
87
|
def credit *args
|
84
|
-
|
85
|
-
amount = args[0] || options.fetch(:amount) { }
|
86
|
-
description = args[1] || options.fetch(:description) { nil }
|
87
|
-
meta = args[2] || options.fetch(:meta) { nil }
|
88
|
-
destination_uri = args[3] || options.fetch(:destination_uri) { nil }
|
88
|
+
warn_on_positional args
|
89
89
|
|
90
|
-
|
91
|
-
:
|
92
|
-
|
93
|
-
:
|
94
|
-
|
95
|
-
|
96
|
-
)
|
97
|
-
credit.save
|
90
|
+
if args.last.is_a? Hash
|
91
|
+
args.last.merge! uri: self.credits_uri
|
92
|
+
else
|
93
|
+
args << { uri: self.credits_uri }
|
94
|
+
end
|
95
|
+
Credit.new(*args).save
|
98
96
|
end
|
99
97
|
|
100
98
|
# Associates the Card represented by +card_uri+ with this Account.
|
@@ -7,6 +7,19 @@ module Balanced
|
|
7
7
|
class BankAccount
|
8
8
|
include Balanced::Resource
|
9
9
|
|
10
|
+
def self.has_account?
|
11
|
+
self.respond_to?('account') && !self.account.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.uri
|
15
|
+
# Override the default nesting -- bank accounts can be toplevel now
|
16
|
+
if !self.has_account?
|
17
|
+
self.collection_path
|
18
|
+
else
|
19
|
+
self.class.uri
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
10
23
|
def initialize attributes = {}
|
11
24
|
Balanced::Utils.stringify_keys! attributes
|
12
25
|
unless attributes.has_key? 'uri'
|
@@ -21,25 +34,39 @@ module Balanced
|
|
21
34
|
# the +domain_name+ property from your Marketplace.
|
22
35
|
# @return [Debit]
|
23
36
|
def debit *args
|
37
|
+
warn_on_positional args
|
38
|
+
|
24
39
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
25
40
|
amount = args[0] || options.fetch(:amount) { nil }
|
26
|
-
|
41
|
+
appears_on_statement_as = args[1] || options.fetch(:appears_on_statement_as) { nil }
|
27
42
|
meta = args[2] || options.fetch(:meta) { nil }
|
28
43
|
description = args[3] || options.fetch(:description) { nil }
|
29
44
|
|
30
|
-
self.account.debit(amount,
|
45
|
+
self.account.debit(amount, appears_on_statement_as, meta, description, self.uri)
|
31
46
|
end
|
32
47
|
|
33
|
-
# Creates a Credit of funds from your Marketplace's escrow account to this
|
48
|
+
# Creates a Credit of funds from your Marketplace's escrow account to this
|
49
|
+
# Account.
|
34
50
|
#
|
35
51
|
# @return [Credit]
|
36
52
|
def credit *args
|
53
|
+
warn_on_positional args
|
54
|
+
|
37
55
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
38
56
|
amount = args[0] || options.fetch(:amount) { nil }
|
39
57
|
description = args[1] || options.fetch(:description) { nil }
|
40
|
-
|
41
|
-
|
42
|
-
|
58
|
+
if !self.class.has_account?
|
59
|
+
Credit.new(
|
60
|
+
:amount => amount,
|
61
|
+
:description => description,
|
62
|
+
:uri => self.credits_uri,
|
63
|
+
).save
|
64
|
+
else
|
65
|
+
meta = args[2] || options.fetch(:meta) { nil }
|
66
|
+
appears_on_statement_as = args[3] || options.fetch(:appears_on_statement_as) { nil }
|
67
|
+
destination_url = args[4] || options.fetch(:destination_uri) { self.uri }
|
68
|
+
self.account.credit(amount, meta, description, destination_uri, appears_on_statement_as)
|
69
|
+
end
|
43
70
|
end
|
44
71
|
|
45
72
|
def invalidate
|
@@ -20,25 +20,38 @@ module Balanced
|
|
20
20
|
#
|
21
21
|
# @return [Debit]
|
22
22
|
def debit *args
|
23
|
+
warn_on_positional args
|
23
24
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
24
25
|
amount = args[0] || options.fetch(:amount) { nil }
|
25
26
|
appears_on_statement_as = args[1] || options.fetch(:appears_on_statement_as) { nil }
|
26
|
-
|
27
|
+
hold_uri = args[2] || options.fetch(:hold_uri) { nil }
|
27
28
|
meta = args[3] || options.fetch(:meta) { nil }
|
28
29
|
description = args[3] || options.fetch(:description) { nil }
|
29
30
|
|
30
|
-
self.account.debit(
|
31
|
+
self.account.debit(
|
32
|
+
:amount => amount,
|
33
|
+
:appears_on_statement_as => appears_on_statement_as,
|
34
|
+
:hold_uri => hold_uri,
|
35
|
+
:meta => meta,
|
36
|
+
:description => description,
|
37
|
+
:source_uri => self.uri
|
38
|
+
)
|
31
39
|
end
|
32
40
|
|
33
41
|
# Creates a Hold of funds from this Card to your Marketplace.
|
34
42
|
#
|
35
43
|
# @return [Hold]
|
36
44
|
def hold *args
|
45
|
+
warn_on_positional args
|
37
46
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
38
47
|
amount = args[0] || options.fetch(:amount) { nil }
|
39
|
-
meta = args[
|
48
|
+
meta = args[1] || options.fetch(:meta) { nil }
|
40
49
|
|
41
|
-
self.account.hold(
|
50
|
+
self.account.hold(
|
51
|
+
:amount => amount,
|
52
|
+
:meta => meta,
|
53
|
+
:source_uri => self.uri
|
54
|
+
)
|
42
55
|
end
|
43
56
|
|
44
57
|
def invalidate
|
@@ -8,13 +8,40 @@ module Balanced
|
|
8
8
|
#
|
9
9
|
class Credit
|
10
10
|
include Balanced::Resource
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
|
12
|
+
def initialize *args
|
13
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
14
|
+
uri = options.fetch(:uri) { self.class.uri }
|
15
|
+
bank_account = options.fetch(:bank_account) {}
|
16
|
+
amount = args[0] || options.fetch(:amount) { }
|
17
|
+
description = args[1] || options.fetch(:description) { nil }
|
18
|
+
|
19
|
+
unless bank_account.nil?
|
20
|
+
# Accountless bank account
|
21
|
+
attributes = {
|
22
|
+
uri: uri,
|
23
|
+
amount: amount,
|
24
|
+
description: description,
|
25
|
+
bank_account: bank_account,
|
26
|
+
meta: nil
|
27
|
+
}
|
28
|
+
else
|
29
|
+
meta = args[2] || options.fetch(:meta) { nil }
|
30
|
+
destination_uri = args[3] || options.fetch(:destination_uri) { nil }
|
31
|
+
appears_on_statement_as = args[4] || options.fetch(:appears_on_statement_as) { nil }
|
32
|
+
attributes = {
|
33
|
+
uri: uri,
|
34
|
+
amount: amount,
|
35
|
+
meta: meta,
|
36
|
+
description: description,
|
37
|
+
destination_uri: destination_uri,
|
38
|
+
appears_on_statement_as: appears_on_statement_as
|
39
|
+
}
|
15
40
|
end
|
41
|
+
|
42
|
+
Balanced::Utils.stringify_keys! attributes
|
43
|
+
|
16
44
|
super attributes
|
17
45
|
end
|
18
46
|
end
|
19
47
|
end
|
20
|
-
|
@@ -28,6 +28,8 @@ module Balanced
|
|
28
28
|
#
|
29
29
|
# @return [Refund]
|
30
30
|
def refund *args
|
31
|
+
warn_on_positional args
|
32
|
+
|
31
33
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
32
34
|
amount = args[0] || options.fetch(:amount) { nil }
|
33
35
|
description = args[1] || options.fetch(:description) { nil }
|
@@ -38,6 +38,8 @@ module Balanced
|
|
38
38
|
#
|
39
39
|
# @return [Debit]
|
40
40
|
def capture *args
|
41
|
+
warn_on_positional args
|
42
|
+
|
41
43
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
42
44
|
amount = args[0] || options.fetch(:amount) { nil }
|
43
45
|
appears_on_statement_as = args[1] || options.fetch(:appears_on_statement_as) { nil }
|
@@ -45,7 +47,13 @@ module Balanced
|
|
45
47
|
description = args[3] || options.fetch(:description) { nil }
|
46
48
|
|
47
49
|
amount ||= self.amount
|
48
|
-
self.account.debit(
|
50
|
+
self.account.debit(
|
51
|
+
:amount => amount,
|
52
|
+
:appears_on_statement_as => appears_on_statement_as,
|
53
|
+
:hold_uri => self.uri,
|
54
|
+
:meta => meta,
|
55
|
+
:description => description
|
56
|
+
)
|
49
57
|
end
|
50
58
|
|
51
59
|
end
|