blnk 0.1.1 → 0.1.3

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
  SHA256:
3
- metadata.gz: 05e768b805f7c2e8f061d334fd923afcf82fcc3945bf0c5a3ac844815403fd3f
4
- data.tar.gz: 2edddcd8e0227f1183f05d488a7aec58b22cdef9d157e4479fb7e8ca9026aad7
3
+ metadata.gz: 5c5fd560be10539e1da9ac8d3d47685a4070b2723432ef1b2580ae5e57760a82
4
+ data.tar.gz: d90db62cdd4fbea9c633cdbe579df1e3242188b520b9e4de17e095b201a598fc
5
5
  SHA512:
6
- metadata.gz: d8084904b5d4210b9c4e0c8b5a7f7bc8d107fca56ff3669e0d01376cbe5360a644e52b490c677b86baa9672ddb04ba417f4fc4c5ab6c7a6170f381d133558b3b
7
- data.tar.gz: 54bf131a6080c1af282d581c24395cf99ec28c7a26fab84cc09c77d1337f19e1be5600907454470edff6017ac6dd3d1a7b4234da8def6c3700ecd527feee0370
6
+ metadata.gz: f8e50a2169fe30914d20bd8bab234202900e23d336215c93e643edb34ced8a0565996aa7fe873b10a90862ed5b17e1915191b92367bc616c6ff42560b63acd81
7
+ data.tar.gz: 81c7c8d09fcaf7312e3fb256a5d7a991c59e0c1355141ff8487df32544a40716a11f33ea72909c964a1a3fb437d2aaf6510ef7ededf6481b8c4cc75917dafbb6
data/README.md CHANGED
@@ -1,5 +1,3 @@
1
- # This gem is under development, don't use in production
2
-
3
1
  # Blnk
4
2
 
5
3
  Easy way to use the blnkfinance.com API in ruby
@@ -14,23 +12,40 @@ If bundler is not being used to manage dependencies, install the gem by executin
14
12
 
15
13
  $ gem install blnk
16
14
 
17
- ## Usage
15
+ ## TODO
18
16
 
19
- TODO:
20
17
  - [x] Create Ledger
21
18
  - [x] Find Ledger
22
19
  - [x] List Ledgers
23
- - [ ] Search Ledgers
20
+ - [x] Search Ledgers
24
21
  - [x] Create Balances
25
22
  - [x] Find Balance
26
- - [ ] Search Balances
27
- - [ ] Create Transaction
28
- - [ ] Find Transaction
29
- - [ ] Search Transactions
23
+ - [x] Search Balances
24
+ - [x] Create Transaction
25
+ - [x] Multiple sources / destinations Transaction
26
+ - [x] Refund Transaction
27
+ - [x] Commit inflight Transaction
28
+ - [x] Void inflight Transaction
29
+ - [x] Find Transaction
30
+ - [x] Search Transactions
31
+ - [ ] Handler notifications
32
+ - [ ] Create Balance Monitor
33
+ - [ ] Find Balance Monitor
34
+ - [ ] Update Balance Monitor
35
+ - [ ] Backup endpoint
36
+ - [ ] Backup to S3 endpoint
37
+ - [ ] Add Search Contract schema for each resource using they own search attributes
38
+ - [ ] Search Result should convert document resul into resource class
39
+ - [x] Use Dry Monads to get success / failure output
40
+ - [x] Use Dry Validation to validate inputs
41
+ - [ ] Use Dry Schema instead OpenStruct to handle with resource attributes
42
+ - [ ] Use Dry Configuration to better config DSL
30
43
 
31
44
  ## Usage
32
45
 
33
46
  ```ruby
47
+ transaction = Blnk::Transaction.find 'transaction_id'
48
+
34
49
  require 'blnk'
35
50
 
36
51
  # client config
@@ -39,28 +54,40 @@ Blnk.address = '192.168.2.7:5001'
39
54
  Blnk.secret_token = 'your_strong_secret_key'
40
55
  Blnk.search_api_key = Blnk.secret_token
41
56
 
42
- # ledgers integration
57
+ # Ledgers
43
58
 
44
59
  ledger = Blnk::Ledger.create(name: 'foobar')
45
60
  ledger = Blnk::Ledger.find 'ledger_id'
46
61
  ledgers = Blnk::Ledger.all
47
62
 
48
- # search not implemented yet
49
- ledgers = Blnk::Ledger.search(
50
- q: 'USD',
51
- filter_by: 'balances > 1400',
52
- sort_by: 'created_at:desc',
53
- page: 1,
54
- per_page: 50
55
- )
56
-
63
+ ledgers = Blnk::Ledger.search(q: '*')
57
64
 
58
- # Balance integrations
65
+ # Balances
59
66
  balance = Blnk::Balance.find 'balance_id'
60
67
  balance = Blnk::Balance.create(ledger_id: 'ledger_id', currency: 'USD')
61
68
 
69
+ balances = Blnk::Balance.search(q: '*')
70
+
71
+ # Transactions
72
+ transaction = Blnk::Transaction.find 'transaction_id'
73
+ transaction = Blnk::Transaction.create(
74
+ amount: 75,
75
+ reference: 'ref_005',
76
+ currency: 'BRLX',
77
+ precision: 100,
78
+ source: '@world',
79
+ destination: 'bln_469f93bc-40e9-4e0e-b6ab-d11c3638c15d',
80
+ description: 'For fees',
81
+ allow_overdraft: true
82
+ )
83
+
84
+ transaction = Blnk::Transaction.search q: '*'
62
85
  ```
63
86
 
87
+ ## Result
88
+
89
+ All methods return a Dry::Monad::Result, so you can use ```.failure?``` to check if method was executed and returned a failure (can be validation or a server error). ```.success?``` to check if method was executed with successful and access the data from the failure or successful result using ```.value!```. You can check on the dry-monad gem to see other options on Result.
90
+
64
91
 
65
92
  ## Development
66
93
 
data/lib/blnk/balance.rb CHANGED
@@ -3,9 +3,15 @@
3
3
  module Blnk
4
4
  # Balance representation
5
5
  class Balance < Resourceable
6
- def self.resource_name = :balances
6
+ class CreateContract < Dry::Validation::Contract
7
+ schema do
8
+ required(:ledger_id).value(:string)
9
+ required(:currency).value(:string)
10
+ end
11
+ end
7
12
 
8
- def persisted? = !balance_id.nil?
9
- def body_data = { ledger_id:, currency: }
13
+ self.resource_name = :balances
14
+ self.id_field = :balance_id
15
+ self.create_contract = CreateContract
10
16
  end
11
17
  end
data/lib/blnk/ledger.rb CHANGED
@@ -3,9 +3,15 @@
3
3
  module Blnk
4
4
  # Ledger representation
5
5
  class Ledger < Resourceable
6
- def self.resource_name = :ledgers
6
+ class CreateContract < Dry::Validation::Contract
7
+ schema do
8
+ required(:name).value(:string)
9
+ optional(:meta_data).value(:hash)
10
+ end
11
+ end
7
12
 
8
- def persisted? = !ledger_id.nil?
9
- def body_data = { name:, meta_data: }
13
+ self.resource_name = :ledgers
14
+ self.id_field = :ledger_id
15
+ self.create_contract = CreateContract
10
16
  end
11
17
  end
@@ -3,37 +3,127 @@
3
3
  module Blnk
4
4
  # Resoureable module that bring some tweaks for basic REST api integration
5
5
  class Resourceable < OpenStruct
6
- include Client
6
+ extend Client
7
+ extend Forwardable
7
8
 
8
- def self.resource_name = raise NotImplementedError
9
+ def_delegators :'self.class', :put_request, :post_request, :get_request, :with_handler
9
10
 
10
- def self.find(id)
11
- response = new.get_request(path: "/#{resource_name}/#{id}")
12
- return response unless response.status.success?
11
+ class SearchResult < OpenStruct; end
13
12
 
14
- new response.parse
13
+ class DefaultSearchContract < Dry::Validation::Contract
14
+ schema do
15
+ required(:q).value(:string)
16
+ end
15
17
  end
16
18
 
17
- def self.all
18
- response = new.get_request(path: "/#{resource_name}")
19
- return response unless response.status.success?
19
+ class << self
20
+ include Dry::Monads[:result]
21
+
22
+ attr_accessor :resource_name, :id_field, :create_contract, :search_contract
23
+
24
+ def resources_path = "/#{resource_name}"
25
+ def resource_path(id) = "/#{resource_name}/#{id}"
26
+ def search_path = "/search/#{resource_name}"
27
+
28
+ def find(id) = with_handler resp: find_request(id)
29
+ def find_request(id) = get_request(path: resource_path(id))
30
+
31
+ def all
32
+ check_vars
33
+ resp = get_request(path: resources_path)
34
+ with_handler(resp:, block: method(:all_handler))
35
+ end
36
+
37
+ def create(**args)
38
+ wrap_call(create_contract_new, args) do |contract|
39
+ with_handler(resp: post_request(path: resources_path, body: contract.to_h))
40
+ end
41
+ end
42
+
43
+ def search(**args)
44
+ wrap_call(search_contract_new, args) do |contract|
45
+ with_handler(resp: post_request(path: search_path, body: contract.to_h),
46
+ block: method(:search_handler))
47
+ end
48
+ end
49
+
50
+ def check_vars
51
+ raise NotImplementedError, 'missing self.resource_name' unless resource_name
52
+ raise NotImplementedError, 'missing self.id_field' unless id_field
53
+ raise NotImplementedError, 'missing self.create_contract' unless create_contract
54
+ end
55
+
56
+ def wrap_call(contract, args)
57
+ check_vars
58
+ ccall = contract.call(args)
59
+ return Failure(ccall.errors.to_h) if ccall.failure?
60
+
61
+ return yield ccall if block_given?
62
+
63
+ ccall
64
+ end
65
+
66
+ def create_contract_new
67
+ return create_contract.new if create_contract
20
68
 
21
- response.parse.map do |r|
22
- new r
69
+ raise NotImplementedError, 'missing self.create_contract'
70
+ end
71
+
72
+ def search_contract_new = (search_contract || DefaultSearchContract).new
73
+
74
+ def search_handler(parsed, status)
75
+ success = status.success?
76
+ result = SearchResult.new(parsed) if success
77
+
78
+ inj_handler(result:, success:, error: parsed)
79
+ end
80
+
81
+ def all_handler(parsed, status)
82
+ success = status.success?
83
+ result = parsed.map { |r| new(r) } if success
84
+ inj_handler(success:, result:, error: parsed)
85
+ end
86
+
87
+ def handler(parsed, status)
88
+ inj_handler(
89
+ result: new(parsed),
90
+ error: parsed,
91
+ success: status.success?
92
+ )
93
+ end
94
+
95
+ def inj_handler(result:, error:, success:)
96
+ (success ? Success(result) : Failure(error))
97
+ end
98
+
99
+ def with_handler(resp:, kself: nil, block: method(:handler))
100
+ using_resp(resp:, kself:, &block)
101
+ end
102
+
103
+ def using_resp(resp:, kself: nil, &block)
104
+ check_vars
105
+ parsed = resp.parse
106
+ parsed = parsed.transform_keys(&:to_sym) unless parsed.is_a?(Array)
107
+
108
+ kself&.reload
109
+
110
+ block.call(parsed, resp.status)
23
111
  end
24
112
  end
25
113
 
26
- def self.create(*)
27
- response = new.post_request(
28
- path: "/#{resource_name}",
29
- body: new(*).body_data
30
- )
31
- return response unless response.status.success?
114
+ def reload
115
+ self.class.find_request(_id).tap do |res|
116
+ next unless res.status.success?
32
117
 
33
- new(response.parse)
118
+ res.parse.each_pair do |k, v|
119
+ self[k] = v
120
+ end
121
+ end
122
+ self
34
123
  end
35
124
 
36
- def persisted? = raise NotImplementedError
37
- def body_data = raise NotImplementedError
125
+ # table[self.class.id_field]
126
+ def persisted? = !_id.nil?
127
+ def _id = public_send(self.class.id_field)
38
128
  end
39
129
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blnk
4
+ # Transaction representation
5
+ class Transaction < Resourceable
6
+ class CreateContract < Dry::Validation::Contract
7
+ schema do
8
+ required(:amount).value(:integer)
9
+ required(:precision).value(:integer)
10
+ required(:currency).value(:string)
11
+ required(:reference).value(:string)
12
+ optional(:source).value(:string)
13
+ optional(:sources).array(:hash) do
14
+ required(:identifier).value(:string)
15
+ required(:distribution).value(:string)
16
+ required(:narration).value(:string)
17
+ end
18
+ optional(:destination).value(:string)
19
+ optional(:destinations).array(:hash) do
20
+ required(:identifier).value(:string)
21
+ required(:distribution).value(:string)
22
+ required(:narration).value(:string)
23
+ end
24
+ required(:description).value(:string)
25
+ required(:allow_overdraft).value(:bool)
26
+ optional(:inflight).value(:bool)
27
+ optional(:rate).value(:integer)
28
+ optional(:scheduled_for).value(:string)
29
+ end
30
+
31
+ rule do
32
+ base.failure('must only contain one of source, sources') if key?(:source) && key?(:sources)
33
+
34
+ if key?(:destination) && key?(:destinations)
35
+ base.failure('must only contain one of destination, destinations')
36
+ end
37
+
38
+ if values[:source].to_s.empty? && values[:sources].to_s.empty?
39
+ key(:source).failure('missing source')
40
+ end
41
+
42
+ if values[:destination].to_s.empty? && values[:destinations].to_s.empty?
43
+ key(:destination).failure('missing destination')
44
+ end
45
+ end
46
+ end
47
+
48
+ self.resource_name = :transactions
49
+ self.id_field = :transaction_id
50
+ self.create_contract = CreateContract
51
+
52
+ def refund = short_hander(resp: req_refund)
53
+ def void = short_hander(resp: req_inflight(body: { status: 'void' }))
54
+ def commit = short_hander(resp: req_inflight(body: { status: 'commit' }))
55
+
56
+ private
57
+
58
+ def short_hander(resp:) = with_handler(resp:, kself: self)
59
+ def inflight_path = "/transactions/inflight/#{_id}"
60
+ def refund_path = "/refund-transaction/#{_id}"
61
+ def req_inflight(body:) = put_request(path: inflight_path, body:)
62
+ def req_refund = post_request(path: refund_path, body: nil)
63
+ end
64
+ end
data/lib/blnk/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Blnk
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.3'
5
5
  end
data/lib/blnk.rb CHANGED
@@ -2,11 +2,14 @@
2
2
 
3
3
  require 'http'
4
4
  require 'ostruct'
5
+ require 'dry-validation'
6
+ require 'dry/monads'
5
7
  require_relative 'blnk/version'
6
8
  require_relative 'blnk/client'
7
9
  require_relative 'blnk/resourceable'
8
10
  require_relative 'blnk/ledger'
9
11
  require_relative 'blnk/balance'
12
+ require_relative 'blnk/transaction'
10
13
 
11
14
  module Blnk
12
15
  class Error < StandardError; end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blnk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Roberto Silva
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-27 00:00:00.000000000 Z
11
+ date: 2024-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-configurable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-monads
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-validation
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.10.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.10.0
13
55
  - !ruby/object:Gem::Dependency
14
56
  name: http
15
57
  requirement: !ruby/object:Gem::Requirement
@@ -41,6 +83,7 @@ files:
41
83
  - lib/blnk/client.rb
42
84
  - lib/blnk/ledger.rb
43
85
  - lib/blnk/resourceable.rb
86
+ - lib/blnk/transaction.rb
44
87
  - lib/blnk/version.rb
45
88
  - sig/blnk.rbs
46
89
  homepage: https://blnkledger.com/