slidepay 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4fd5c93874d452c096489e21fc5e21299a402b6d
4
- data.tar.gz: 831e67be3a2080f47b5d3bac38ca22c5989ddea7
3
+ metadata.gz: b65de9b4a73dbbcf304c9a88b93e9a03fcee70b4
4
+ data.tar.gz: cc564d6baeeec3e2ffbed1662ba04c5c82afcec1
5
5
  SHA512:
6
- metadata.gz: 6c58e8724d17eb29812939567f60abcffea199e703842dfe3edfd61ba7761eb2da8a5fe748ab845ead0d48b77cf915e329303a829cc6c23b8fd75ad0b8664c89
7
- data.tar.gz: 80276a5604efaa119532f372e4bcad0f6b4efd4cf557ccf03c0f81e9e79c257daf1f723891a5d0e9da5d7879fb6cff7eed6c9361875377076c172638139cc853
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
- [ ] Reports
1
+ [x] Reports
2
2
  ---------------
3
- [ ] Account
4
- [ ] Payment
3
+ [x] Account
4
+ [x] Payment
5
5
 
6
6
  [ ] ACH
7
7
  ---------------
8
- [ ] Retrieval
8
+ [x] Retrieval
9
9
  [ ] Settlement
10
- [ ] Balance
10
+ [x] Balance
11
11
  -- Speculative
12
- [ ] Credit
12
+ [x] Credit
13
+ -- Payments
14
+ [x] is_settled? method
@@ -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
- if values_hash[:url_root]
7
- @url_root = values_hash[:url_root]
8
- values_hash.delete(:url_root)
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 values_hash[:id_attribute]
12
- @id_attribute = values_hash[:id_attribute]
13
- values_hash.delete(:id_attribute)
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 values_hash[:token]
17
- @token = values_hash[:token]
18
- values_hash.delete(:token)
18
+ if values_clone[:token]
19
+ @token = values_clone[:token]
20
+ values_clone.delete(:token)
19
21
  end
20
22
 
21
- if values_hash[:api_key]
22
- @api_key = values_hash[:api_key]
23
- values_hash.delete(:api_key)
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 values_hash[:endpoint]
27
- @endpoint = values_hash[:endpoint]
28
- values_hash.delete(:endpoint)
28
+ if values_clone[:endpoint]
29
+ @endpoint = values_clone[:endpoint]
30
+ values_clone.delete(:endpoint)
29
31
  end
30
32
 
31
- merge! values_hash
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]
@@ -1,3 +1,3 @@
1
1
  module SlidePay
2
- VERSION = "0.0.12"
2
+ VERSION = "0.0.13"
3
3
  end
@@ -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}"