slidepay 0.0.12 → 0.0.13
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.
- checksums.yaml +4 -4
- data/README.md +71 -0
- data/TODO.md +8 -6
- data/lib/slidepay.rb +5 -0
- data/lib/slidepay/ach/balance.rb +31 -0
- data/lib/slidepay/ach/resource.rb +17 -0
- data/lib/slidepay/ach/retrieval.rb +111 -0
- data/lib/slidepay/ach/settlement.rb +68 -0
- data/lib/slidepay/resources/api_resource.rb +18 -16
- data/lib/slidepay/resources/payment.rb +17 -0
- data/lib/slidepay/version.rb +1 -1
- data/scenarios/ach/balance.rb +18 -0
- data/scenarios/ach/fetch_retrieval.rb +19 -0
- data/scenarios/ach/retrieval_create_with_bank_account_info.rb +39 -0
- data/scenarios/ach/retrieval_create_with_id_fields.rb +25 -0
- data/scenarios/ach/retrieval_fetch_with_settlement_token_class_method.rb +17 -0
- data/scenarios/ach/retrieval_settlement_token_fetch.rb +19 -0
- data/scenarios/ach/settlement.rb +28 -0
- data/scenarios/create_simple_payment.rb +33 -0
- data/spec/ach/balance_spec.rb +38 -0
- data/spec/ach/resource_spec.rb +17 -0
- data/spec/ach/retrieval_spec.rb +170 -0
- data/spec/ach/settlement_spec.rb +121 -0
- data/spec/payment_spec.rb +26 -1
- data/spec/spec_helper.rb +524 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b65de9b4a73dbbcf304c9a88b93e9a03fcee70b4
|
4
|
+
data.tar.gz: cc564d6baeeec3e2ffbed1662ba04c5c82afcec1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ca65bf127f9c5e96dfb5436ce8ec413e97c95b562ae9ebea81fb65a4e8bb53f1e4b357026387825e37997d3fa483dfba150d23579ae4b0e2b270a8f9b01cb92
|
7
|
+
data.tar.gz: 39dd5940961c5a0642e9a6c9f409d7a7eec33e9a468bccddab6aeec87461a4e0284c51d2da2a934a261dc3bb110cbf935404e8d688a6ab0f10167d7ac59b162b
|
data/README.md
CHANGED
@@ -253,6 +253,77 @@ payment_report.retrieve()
|
|
253
253
|
|
254
254
|
```
|
255
255
|
|
256
|
+
## ACH
|
257
|
+
|
258
|
+
SlidePay supports ACH retrievals, programmatic settlements via ACH, and checking the balance of unsettled funds for an account.
|
259
|
+
|
260
|
+
### Balance
|
261
|
+
|
262
|
+
To check the balance of a settlement ledger, just provide a location_id to the ```Balance.retrieve``` class method.
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
location_id = 18
|
266
|
+
balance = SlidePay::ACH::Balance.retrieve(location_id)
|
267
|
+
```
|
268
|
+
|
269
|
+
### ACH Retrieval
|
270
|
+
|
271
|
+
To initiate an ACH retrieval from a bank account, supply a hash with bank account details to the
|
272
|
+
```Retrieval.create_with_bank_account``` class method, or create an instance of the Retrieval class and
|
273
|
+
use the instance method of the same name.
|
274
|
+
|
275
|
+
A retrieval can be initiated using either a stored bank account or explicit bank account details. A full
|
276
|
+
explanation of the differences can be found on the
|
277
|
+
[ACH retrieval documentation page](https://getcube.atlassian.net/wiki/display/CDP/Processing+Manual+ACH+Retrievals).
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
retrieval_info = {
|
281
|
+
location_id: 12,
|
282
|
+
company_id: 10,
|
283
|
+
bank_account_id: 3,
|
284
|
+
user_master_id: 20,
|
285
|
+
retrieval_amount: 1.02
|
286
|
+
}
|
287
|
+
|
288
|
+
# class method
|
289
|
+
r = ACH::Retrieval.create_with_bank_account(retrieval_info)
|
290
|
+
|
291
|
+
# instance method - the retrieval instance will be populated with the
|
292
|
+
# retrieval response data from the server.
|
293
|
+
r = ACH::Retrieval.new()
|
294
|
+
r.create_with_bank_account(retrieval_info)
|
295
|
+
```
|
296
|
+
|
297
|
+
### ACH Settlement
|
298
|
+
|
299
|
+
SlidePay users can settle funds from an account ledger to one or more bank accounts programmatically
|
300
|
+
via ACH. Note: To do this, an account must have manual settlement enabled. Complete documentation for
|
301
|
+
ACH settlements lives on the [documentation page](https://getcube.atlassian.net/wiki/display/CDP/Processing+Manual+ACH+Settlements).
|
302
|
+
|
303
|
+
To initiate an ACH settlement to one or more bank accounts, supply a settlement
|
304
|
+
descriptor Hash to the ```Settlement.process``` method in the following format:
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
settlement_descriptor = {
|
308
|
+
location_id: YOUR_LOCATION_ID,
|
309
|
+
company_id: YOUR_COMPANY_ID,
|
310
|
+
settlement_list:[
|
311
|
+
{ bank_account_id: FIRST_SETTLEMENT_BANK_ACCOUNT_ID, amount: 0.25 },
|
312
|
+
{ bank_account_id: SECOND_SETTLEMENT_BANK_ACCOUNT_ID, amount: 0.25 }
|
313
|
+
],
|
314
|
+
notes:'Really important notes about this settlement. '
|
315
|
+
}
|
316
|
+
```
|
317
|
+
|
318
|
+
The Settlement.process class method will return an array of [transaction processor responses](https://getcube.atlassian.net/wiki/display/CDP/processor_ach_txn_response)
|
319
|
+
corresponding to the list of settlements requested.
|
320
|
+
|
321
|
+
```ruby
|
322
|
+
|
323
|
+
# Process the settlement
|
324
|
+
settlment_result = SlidePay::ACH::Settlement.process(settlement_descriptor)
|
325
|
+
```
|
326
|
+
|
256
327
|
## Testing
|
257
328
|
|
258
329
|
### Basics
|
data/TODO.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
[
|
1
|
+
[x] Reports
|
2
2
|
---------------
|
3
|
-
[
|
4
|
-
[
|
3
|
+
[x] Account
|
4
|
+
[x] Payment
|
5
5
|
|
6
6
|
[ ] ACH
|
7
7
|
---------------
|
8
|
-
[
|
8
|
+
[x] Retrieval
|
9
9
|
[ ] Settlement
|
10
|
-
[
|
10
|
+
[x] Balance
|
11
11
|
-- Speculative
|
12
|
-
[
|
12
|
+
[x] Credit
|
13
|
+
-- Payments
|
14
|
+
[x] is_settled? method
|
data/lib/slidepay.rb
CHANGED
@@ -28,6 +28,11 @@ require "slidepay/reports/post_report"
|
|
28
28
|
require "slidepay/reports/account_report"
|
29
29
|
require "slidepay/reports/payment_report"
|
30
30
|
|
31
|
+
# ACH
|
32
|
+
require "slidepay/ach/resource"
|
33
|
+
require "slidepay/ach/retrieval"
|
34
|
+
require "slidepay/ach/balance"
|
35
|
+
require "slidepay/ach/settlement"
|
31
36
|
|
32
37
|
module SlidePay
|
33
38
|
class << self
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SlidePay
|
2
|
+
module ACH
|
3
|
+
class Balance
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def retrieve(location_id, options={})
|
8
|
+
token = options[:token]
|
9
|
+
api_key = options[:api_key]
|
10
|
+
endpoint = options[:endpoint]
|
11
|
+
|
12
|
+
path = "settlement/balance/#{location_id}"
|
13
|
+
|
14
|
+
response = SlidePay.post(path: path, data: {}.to_json, token: token, api_key: api_key, endpoint: endpoint)
|
15
|
+
|
16
|
+
if response.was_successful?
|
17
|
+
return response.data
|
18
|
+
else
|
19
|
+
error_text = response.error_text unless response.error == false
|
20
|
+
|
21
|
+
if error_text != nil
|
22
|
+
raise "Could not get settlement balance: #{error_text}"
|
23
|
+
else
|
24
|
+
raise "Could not get settlement balance."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SlidePay
|
2
|
+
module ACH
|
3
|
+
class Resource < ApiResource
|
4
|
+
def initialize(values_hash={})
|
5
|
+
super(values_hash)
|
6
|
+
end
|
7
|
+
|
8
|
+
def save
|
9
|
+
raise "ACH Resources cannot be saved"
|
10
|
+
end
|
11
|
+
|
12
|
+
def destroy
|
13
|
+
raise "ACH Resources cannot be destroyed"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module SlidePay
|
2
|
+
module ACH
|
3
|
+
class Retrieval < Resource
|
4
|
+
attr_accessor :retrieval_bank_account
|
5
|
+
|
6
|
+
@url_root = "retrieval"
|
7
|
+
@id_attribute = "retrieval_id"
|
8
|
+
|
9
|
+
def initialize(values_hash={})
|
10
|
+
@url_root = "retrieval"
|
11
|
+
@id_attribute = "retrieval_id"
|
12
|
+
|
13
|
+
# if values_hash[:retrieval_bank_account] is present and a hash, then we should probably pull
|
14
|
+
# that out and set the instance attribute for bank account
|
15
|
+
# @retrieval_bank_account = values_hash[:retrieval_bank_account]
|
16
|
+
# values_hash.remove(:retrieval_bank_account)
|
17
|
+
|
18
|
+
super(values_hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
# url should allow retrieving by settlement_transaction_token
|
22
|
+
def url
|
23
|
+
if is_new?
|
24
|
+
@url_root
|
25
|
+
elsif self.settlement_transaction_token != nil
|
26
|
+
"#{@url_root}?settlement_transaction_token=#{self['settlement_transaction_token']}"
|
27
|
+
else
|
28
|
+
"#{@url_root}/#{self.id()}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def settlement_transaction_token
|
33
|
+
self['settlement_transaction_token']
|
34
|
+
end
|
35
|
+
|
36
|
+
def is_new?
|
37
|
+
if id() == nil && self.settlement_transaction_token == nil
|
38
|
+
true
|
39
|
+
else
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_with_bank_account(bank_account, options={})
|
45
|
+
options[:token] = options[:token] || @token
|
46
|
+
options[:api_key] = options[:api_key] || @api_key
|
47
|
+
options[:endpoint] = options[:endpoint] || @endpoint
|
48
|
+
|
49
|
+
r = self.class.create_with_bank_account(bank_account, options)
|
50
|
+
merge! r
|
51
|
+
end
|
52
|
+
|
53
|
+
def retrieve_by_settlement_token(settlement_transaction_token, options={})
|
54
|
+
options[:token] = options[:token] || @token
|
55
|
+
options[:api_key] = options[:api_key] || @api_key
|
56
|
+
options[:endpoint] = options[:endpoint] || @endpoint
|
57
|
+
|
58
|
+
r = self.class.retrieve_by_settlement_token(settlement_transaction_token, options)
|
59
|
+
merge! r
|
60
|
+
end
|
61
|
+
|
62
|
+
def is_ledgered?
|
63
|
+
return self['ledgered'] == 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def ledger_after
|
67
|
+
return self['ledger_after']
|
68
|
+
end
|
69
|
+
|
70
|
+
def retrieval_amount
|
71
|
+
return self['retrieval_amount']
|
72
|
+
end
|
73
|
+
|
74
|
+
def provider_status
|
75
|
+
return self['provider_status']
|
76
|
+
end
|
77
|
+
|
78
|
+
class << self
|
79
|
+
def create_with_bank_account(bank_account, options={})
|
80
|
+
token = options[:token]
|
81
|
+
api_key = options[:api_key]
|
82
|
+
endpoint = options[:endpoint]
|
83
|
+
|
84
|
+
response = SlidePay.post(path: "#{@url_root}/manual", data: bank_account.to_json, token: token, api_key: api_key, endpoint: endpoint)
|
85
|
+
if response.was_successful?
|
86
|
+
r = self.new()
|
87
|
+
r.populate_from_response(response)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def retrieve_by_settlement_token(settlement_transaction_token, options={})
|
92
|
+
if ! settlement_transaction_token.is_a? String
|
93
|
+
raise "settlement_transaction_token must be a String"
|
94
|
+
end
|
95
|
+
|
96
|
+
token = options[:token]
|
97
|
+
api_key = options[:api_key]
|
98
|
+
endpoint = options[:endpoint]
|
99
|
+
|
100
|
+
url_suffix = "?settlement_transaction_token=#{settlement_transaction_token}"
|
101
|
+
|
102
|
+
response = SlidePay.get(path: "#{@url_root}#{url_suffix}", token: token, api_key: api_key, endpoint: endpoint)
|
103
|
+
if response.was_successful?
|
104
|
+
r = self.new()
|
105
|
+
r.populate_from_response(response)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module SlidePay
|
2
|
+
module ACH
|
3
|
+
class Settlement < Resource
|
4
|
+
@url_root = "settlement"
|
5
|
+
@id_attribute = "settlement_id"
|
6
|
+
|
7
|
+
def initialize(values_hash={})
|
8
|
+
@url_root = "settlement"
|
9
|
+
@id_attribute = "settlement_id"
|
10
|
+
|
11
|
+
super(values_hash)
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def process(settlement_order, options={})
|
17
|
+
validate_settlement_order(settlement_order)
|
18
|
+
|
19
|
+
token = @token || options[:token]
|
20
|
+
api_key = @api_key || options[:api_key]
|
21
|
+
endpoint = @endpoint || options[:endpoint]
|
22
|
+
|
23
|
+
response = SlidePay.post(path: "settlement/manual", api_key: api_key, token: token, endpoint: endpoint, data: settlement_order.to_json)
|
24
|
+
|
25
|
+
if response.was_successful?
|
26
|
+
return response.data
|
27
|
+
elsif response.error_text
|
28
|
+
raise Exception.new(response.error_text)
|
29
|
+
elsif response.data["status_message"]
|
30
|
+
raise Exception.new(response.data["status_message"])
|
31
|
+
else
|
32
|
+
raise Exception.new("Settlement(s) could not be processed.")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def validate_single_settlement_descriptor(descriptor)
|
39
|
+
puts "Descriptor: #{descriptor}\n\n"
|
40
|
+
if ! descriptor.is_a? Hash
|
41
|
+
raise "Cannot validate a settlement descriptor that is not a hash."
|
42
|
+
elsif ! descriptor.include?(:bank_account_id) && ! descriptor.include?("bank_account_id")
|
43
|
+
raise "A bank_account_id is required for each settlement being processed."
|
44
|
+
elsif ! descriptor.include?(:amount) && ! descriptor.include?("amount")
|
45
|
+
raise "An amount is required for each settlement being processed."
|
46
|
+
else
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_settlement_order(settlement_order)
|
52
|
+
raise "A settlement must be a Hash object." unless settlement_order.is_a? Hash
|
53
|
+
raise "company_id is required for a settlement." unless (settlement_order['company_id'] || settlement_order[:company_id])
|
54
|
+
raise "location_id is required for a settlement." unless (settlement_order['location_id'] || settlement_order[:location_id])
|
55
|
+
raise "settlement_list is required for a settlement." unless (settlement_order['settlement_list'] || settlement_order[:settlement_list])
|
56
|
+
|
57
|
+
descriptor_list = settlement_order['settlement_list'] || settlement_order[:settlement_list]
|
58
|
+
descriptor_list.each do |descriptor|
|
59
|
+
validate_single_settlement_descriptor(descriptor)
|
60
|
+
end
|
61
|
+
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -3,32 +3,34 @@ module SlidePay
|
|
3
3
|
attr_accessor :url_root, :id_attribute, :token, :api_key, :endpoint
|
4
4
|
|
5
5
|
def initialize(values_hash={})
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
values_clone = values_hash.clone()
|
7
|
+
|
8
|
+
if values_clone[:url_root]
|
9
|
+
@url_root = values_clone[:url_root]
|
10
|
+
values_clone.delete(:url_root)
|
9
11
|
end
|
10
12
|
|
11
|
-
if
|
12
|
-
@id_attribute =
|
13
|
-
|
13
|
+
if values_clone[:id_attribute]
|
14
|
+
@id_attribute = values_clone[:id_attribute]
|
15
|
+
values_clone.delete(:id_attribute)
|
14
16
|
end
|
15
17
|
|
16
|
-
if
|
17
|
-
@token =
|
18
|
-
|
18
|
+
if values_clone[:token]
|
19
|
+
@token = values_clone[:token]
|
20
|
+
values_clone.delete(:token)
|
19
21
|
end
|
20
22
|
|
21
|
-
if
|
22
|
-
@api_key =
|
23
|
-
|
23
|
+
if values_clone[:api_key]
|
24
|
+
@api_key = values_clone[:api_key]
|
25
|
+
values_clone.delete(:api_key)
|
24
26
|
end
|
25
27
|
|
26
|
-
if
|
27
|
-
@endpoint =
|
28
|
-
|
28
|
+
if values_clone[:endpoint]
|
29
|
+
@endpoint = values_clone[:endpoint]
|
30
|
+
values_clone.delete(:endpoint)
|
29
31
|
end
|
30
32
|
|
31
|
-
merge!
|
33
|
+
merge! values_clone
|
32
34
|
end
|
33
35
|
|
34
36
|
def url
|
@@ -18,6 +18,23 @@ module SlidePay
|
|
18
18
|
refund(options_hash)
|
19
19
|
end
|
20
20
|
|
21
|
+
def is_settled?
|
22
|
+
raise "Cannot check settlement status for a payment with no ID." unless is_new? == false
|
23
|
+
|
24
|
+
if ! self['provider_capture_state'].eql? "Captured"
|
25
|
+
# puts "#{self['provider_capture_state']}. \"Captured\" has evaluated to false"
|
26
|
+
return false
|
27
|
+
elsif self['settlement_transaction_token'] == nil
|
28
|
+
# puts 'self[\settlement_transaction_token\] == nil has evaluated to false'
|
29
|
+
return false
|
30
|
+
elsif self['settlement_transaction_token'].is_a?(String) && self['settlement_transaction_token'].empty?
|
31
|
+
# puts 'self[\'settlement_transaction_token\'].kind_of? String && self[\'settlement_transaction_token\'].empty? has evaluated to false'
|
32
|
+
return false
|
33
|
+
else
|
34
|
+
return true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
21
38
|
def process(options_hash={})
|
22
39
|
token = @token || options_hash[:token]
|
23
40
|
api_key = @api_key || options_hash[:api_key]
|
data/lib/slidepay/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), 'spec'))
|
3
|
+
|
4
|
+
require 'multi_json'
|
5
|
+
require 'slidepay'
|
6
|
+
require 'spec_helper'
|
7
|
+
|
8
|
+
include SlidePay
|
9
|
+
|
10
|
+
SlidePay.configure(development: true)
|
11
|
+
SlidePay.api_key = ENV["ach_api_key"]
|
12
|
+
|
13
|
+
RestClient.proxy = "http://127.0.0.1:8888"
|
14
|
+
|
15
|
+
location_id = 18
|
16
|
+
balance = SlidePay::ACH::Balance.retrieve(location_id)
|
17
|
+
|
18
|
+
puts "Balance for location_id #{location_id}: #{balance}"
|