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 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}"