fintoc 0.1.0 → 1.1.0

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.github/pull_request_template.md +46 -0
  3. data/.github/workflows/ci.yml +46 -0
  4. data/.rubocop.yml +14 -7
  5. data/CHANGELOG.md +53 -1
  6. data/Gemfile +20 -1
  7. data/Gemfile.lock +237 -61
  8. data/README.md +404 -42
  9. data/Rakefile +3 -3
  10. data/fintoc.gemspec +3 -7
  11. data/lib/config/initializers/money.rb +5 -0
  12. data/lib/fintoc/base_client.rb +161 -0
  13. data/lib/fintoc/client.rb +14 -123
  14. data/lib/fintoc/constants.rb +4 -3
  15. data/lib/fintoc/errors.rb +139 -15
  16. data/lib/fintoc/jws.rb +83 -0
  17. data/lib/fintoc/utils.rb +2 -2
  18. data/lib/fintoc/v1/client/client.rb +12 -0
  19. data/lib/fintoc/v1/managers/links_manager.rb +46 -0
  20. data/lib/fintoc/v1/resources/account.rb +95 -0
  21. data/lib/fintoc/v1/resources/balance.rb +27 -0
  22. data/lib/fintoc/v1/resources/institution.rb +21 -0
  23. data/lib/fintoc/v1/resources/link.rb +85 -0
  24. data/lib/fintoc/v1/resources/movement.rb +62 -0
  25. data/lib/fintoc/v1/resources/transfer_account.rb +24 -0
  26. data/lib/fintoc/v2/client/client.rb +37 -0
  27. data/lib/fintoc/v2/managers/account_numbers_manager.rb +64 -0
  28. data/lib/fintoc/v2/managers/account_verifications_manager.rb +46 -0
  29. data/lib/fintoc/v2/managers/accounts_manager.rb +55 -0
  30. data/lib/fintoc/v2/managers/entities_manager.rb +36 -0
  31. data/lib/fintoc/v2/managers/simulate_manager.rb +32 -0
  32. data/lib/fintoc/v2/managers/transfers_manager.rb +61 -0
  33. data/lib/fintoc/v2/resources/account.rb +106 -0
  34. data/lib/fintoc/v2/resources/account_number.rb +106 -0
  35. data/lib/fintoc/v2/resources/account_verification.rb +73 -0
  36. data/lib/fintoc/v2/resources/entity.rb +51 -0
  37. data/lib/fintoc/v2/resources/transfer.rb +131 -0
  38. data/lib/fintoc/version.rb +1 -1
  39. data/lib/fintoc/webhook_signature.rb +73 -0
  40. data/lib/fintoc.rb +3 -0
  41. data/lib/tasks/simplecov_config.rb +19 -0
  42. metadata +35 -83
  43. data/lib/fintoc/resources/account.rb +0 -84
  44. data/lib/fintoc/resources/balance.rb +0 -24
  45. data/lib/fintoc/resources/institution.rb +0 -18
  46. data/lib/fintoc/resources/link.rb +0 -83
  47. data/lib/fintoc/resources/movement.rb +0 -55
  48. data/lib/fintoc/resources/transfer_account.rb +0 -22
@@ -0,0 +1,95 @@
1
+ require 'tabulate'
2
+ require 'fintoc/utils'
3
+ require 'fintoc/v1/resources/movement'
4
+ require 'fintoc/v1/resources/balance'
5
+
6
+ module Fintoc
7
+ module V1
8
+ class Account
9
+ include Utils
10
+
11
+ attr_reader :id, :name, :holder_name, :currency, :type, :refreshed_at,
12
+ :official_name, :number, :holder_id, :balance, :movements
13
+
14
+ HEADERS = ['#', 'Amount', 'Currency', 'Description', 'Date'].freeze
15
+
16
+ def initialize(
17
+ id:,
18
+ name:,
19
+ official_name:,
20
+ number:,
21
+ holder_id:,
22
+ holder_name:,
23
+ type:,
24
+ currency:,
25
+ refreshed_at: nil,
26
+ balance: nil,
27
+ movements: nil,
28
+ client: nil,
29
+ **
30
+ )
31
+ @id = id
32
+ @name = name
33
+ @official_name = official_name
34
+ @number = number
35
+ @holder_id = holder_id
36
+ @holder_name = holder_name
37
+ @type = type
38
+ @currency = currency
39
+ @refreshed_at = DateTime.iso8601(refreshed_at) if refreshed_at
40
+ @balance = Fintoc::V1::Balance.new(**balance)
41
+ @movements = movements || []
42
+ @client = client
43
+ end
44
+
45
+ def update_balance
46
+ @balance = Fintoc::V1::Balance.new(**get_account[:balance])
47
+ end
48
+
49
+ def get_movements(**params)
50
+ _get_movements(**params).lazy.map do
51
+ |movement| Fintoc::V1::Movement.new(**movement, client: @client)
52
+ end
53
+ end
54
+
55
+ def update_movements(**params)
56
+ @movements += get_movements(**params).to_a
57
+ @movements = @movements.uniq.sort_by(&:post_date)
58
+ end
59
+
60
+ def show_movements(rows = 5)
61
+ puts("This account has #{Utils.pluralize(@movements.size, 'movement')}.")
62
+
63
+ return unless @movements.any?
64
+
65
+ movements =
66
+ @movements
67
+ .to_a
68
+ .slice(0, rows)
69
+ .map.with_index do |mov, index|
70
+ [index + 1, mov.amount, mov.currency, mov.description, mov.locale_date]
71
+ end
72
+
73
+ puts
74
+ puts tabulate(HEADERS, movements, indent: 4, style: 'fancy')
75
+ end
76
+
77
+ def to_s
78
+ "💰 #{@holder_name}’s #{@name} #{@balance}"
79
+ end
80
+
81
+ private
82
+
83
+ def get_account
84
+ @client.get(version: :v1).call("accounts/#{@id}")
85
+ end
86
+
87
+ def _get_movements(**params)
88
+ first = @client.get(version: :v1).call("accounts/#{@id}/movements", **params)
89
+ return first if params.empty?
90
+
91
+ first + Utils.flatten(@client.fetch_next)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fintoc
4
+ module V1
5
+ class Balance
6
+ attr_reader :available, :current, :limit
7
+
8
+ def initialize(available:, current:, limit:)
9
+ @available = available
10
+ @current = current
11
+ @limit = limit
12
+ end
13
+
14
+ def id
15
+ object_id
16
+ end
17
+
18
+ def to_s
19
+ "#{@available} (#{@current})"
20
+ end
21
+
22
+ def inspect
23
+ "<Fintoc::V1::Balance #{@available} (#{@current})>"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Fintoc
2
+ module V1
3
+ class Institution
4
+ attr_reader :id, :name, :country
5
+
6
+ def initialize(id:, name:, country:, **)
7
+ @id = id
8
+ @name = name
9
+ @country = country
10
+ end
11
+
12
+ def to_s
13
+ "🏦 #{@name}"
14
+ end
15
+
16
+ def inspect
17
+ "<Fintoc::V1::Institution #{@name}>"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,85 @@
1
+ require 'date'
2
+ require 'tabulate'
3
+ require 'fintoc/utils'
4
+ require 'fintoc/v1/resources/account'
5
+ require 'fintoc/v1/resources/institution'
6
+
7
+ module Fintoc
8
+ module V1
9
+ class Link
10
+ attr_reader :id, :username, :holder_type, :institution, :created_at, :mode,
11
+ :accounts, :link_token
12
+
13
+ include Utils
14
+
15
+ def initialize(
16
+ id:,
17
+ username:,
18
+ holder_type:,
19
+ institution:,
20
+ created_at:,
21
+ mode:,
22
+ accounts: nil,
23
+ link_token: nil,
24
+ client: nil,
25
+ **
26
+ )
27
+ @id = id
28
+ @username = username
29
+ @holder_type = holder_type
30
+ @institution = Fintoc::V1::Institution.new(**institution)
31
+ @created_at = Date.iso8601(created_at)
32
+ @mode = mode
33
+ @accounts = if accounts.nil?
34
+ []
35
+ else
36
+ accounts.map { |data| Fintoc::V1::Account.new(**data, client:) }
37
+ end
38
+ @token = link_token
39
+ @client = client
40
+ end
41
+
42
+ def find_all(**kwargs)
43
+ raise 'You must provide *exactly one* account field.' if kwargs.size != 1
44
+
45
+ field, value = kwargs.to_a.first
46
+ @accounts.select do |account|
47
+ account.send(field.to_sym) == value
48
+ end
49
+ end
50
+
51
+ def find(**)
52
+ results = find_all(**)
53
+ results.any? ? results.first : nil
54
+ end
55
+
56
+ def show_accounts(rows = 5)
57
+ puts "This links has #{Utils.pluralize(@accounts.size, 'account')}"
58
+ return unless @accounts.any?
59
+
60
+ accounts = @accounts.to_a.slice(0, rows)
61
+ .map.with_index do |acc, index|
62
+ [index + 1, acc.name, acc.holder_name, acc.currency]
63
+ end
64
+ headers = ['#', 'Name', 'Holder', 'Currency']
65
+ puts
66
+ puts tabulate(headers, accounts, indent: 4, style: 'fancy')
67
+ end
68
+
69
+ def update_accounts
70
+ @accounts.each do |account|
71
+ account.update_balance
72
+ account.update_movements
73
+ end
74
+ end
75
+
76
+ def delete
77
+ @client.links.delete(@id)
78
+ end
79
+
80
+ def to_s
81
+ "<#{@username}@#{@institution.name}> 🔗 <Fintoc>"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,62 @@
1
+ require 'date'
2
+ require 'fintoc/v1/resources/transfer_account'
3
+
4
+ module Fintoc
5
+ module V1
6
+ class Movement
7
+ attr_reader :id, :amount, :currency, :description, :reference_id,
8
+ :post_date, :transaction_date, :type, :recipient_account,
9
+ :sender_account, :account, :comment
10
+
11
+ def initialize(
12
+ id:,
13
+ amount:,
14
+ currency:,
15
+ description:,
16
+ post_date:,
17
+ transaction_date:,
18
+ type:,
19
+ reference_id:,
20
+ recipient_account:,
21
+ sender_account:,
22
+ comment:,
23
+ client: nil,
24
+ **
25
+ )
26
+ @id = id
27
+ @amount = amount
28
+ @currency = currency
29
+ @description = description
30
+ @post_date = DateTime.iso8601(post_date)
31
+ @transaction_date = DateTime.iso8601(transaction_date) if transaction_date
32
+ @type = type
33
+ @reference_id = reference_id
34
+ @recipient_account =
35
+ if recipient_account
36
+ Fintoc::V1::TransferAccount.new(**recipient_account)
37
+ end
38
+ @sender_account = Fintoc::V1::TransferAccount.new(**sender_account) if sender_account
39
+ @comment = comment
40
+ @client = client
41
+ end
42
+
43
+ def ==(other)
44
+ @id == other.id
45
+ end
46
+
47
+ alias eql? ==
48
+
49
+ def hash
50
+ @id.hash
51
+ end
52
+
53
+ def locale_date
54
+ @post_date.strftime('%x')
55
+ end
56
+
57
+ def to_s
58
+ "#{@amount} (#{@description} @ #{locale_date})"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,24 @@
1
+ require 'fintoc/v1/resources/institution'
2
+
3
+ module Fintoc
4
+ module V1
5
+ class TransferAccount
6
+ attr_reader :holder_id, :holder_name, :number, :institution
7
+
8
+ def initialize(holder_id:, holder_name:, number:, institution:, **)
9
+ @holder_id = holder_id
10
+ @holder_name = holder_name
11
+ @number = number
12
+ @institution = institution && Fintoc::V1::Institution.new(**institution)
13
+ end
14
+
15
+ def id
16
+ object_id
17
+ end
18
+
19
+ def to_s
20
+ @holder_id.to_s
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ require 'fintoc/base_client'
2
+ require 'fintoc/v2/managers/entities_manager'
3
+ require 'fintoc/v2/managers/accounts_manager'
4
+ require 'fintoc/v2/managers/account_numbers_manager'
5
+ require 'fintoc/v2/managers/transfers_manager'
6
+ require 'fintoc/v2/managers/simulate_manager'
7
+ require 'fintoc/v2/managers/account_verifications_manager'
8
+
9
+ module Fintoc
10
+ module V2
11
+ class Client < BaseClient
12
+ def entities
13
+ @entities ||= Managers::EntitiesManager.new(self)
14
+ end
15
+
16
+ def accounts
17
+ @accounts ||= Managers::AccountsManager.new(self)
18
+ end
19
+
20
+ def account_numbers
21
+ @account_numbers ||= Managers::AccountNumbersManager.new(self)
22
+ end
23
+
24
+ def transfers
25
+ @transfers ||= Managers::TransfersManager.new(self)
26
+ end
27
+
28
+ def simulate
29
+ @simulate ||= Managers::SimulateManager.new(self)
30
+ end
31
+
32
+ def account_verifications
33
+ @account_verifications ||= Managers::AccountVerificationsManager.new(self)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ require 'fintoc/v2/resources/account_number'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class AccountNumbersManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def create(account_id:, description: nil, metadata: nil, idempotency_key: nil, **params)
12
+ data = _create_account_number(
13
+ account_id:, description:, metadata:, idempotency_key:, **params
14
+ )
15
+ build_account_number(data)
16
+ end
17
+
18
+ def get(account_number_id)
19
+ data = _get_account_number(account_number_id)
20
+ build_account_number(data)
21
+ end
22
+
23
+ def list(**params)
24
+ _list_account_numbers(**params).map { |data| build_account_number(data) }
25
+ end
26
+
27
+ def update(account_number_id, idempotency_key: nil, **params)
28
+ data = _update_account_number(account_number_id, idempotency_key:, **params)
29
+ build_account_number(data)
30
+ end
31
+
32
+ private
33
+
34
+ def _create_account_number(
35
+ account_id:, description: nil, metadata: nil, idempotency_key: nil, **params
36
+ )
37
+ request_params = { account_id: }
38
+ request_params[:description] = description if description
39
+ request_params[:metadata] = metadata if metadata
40
+ request_params.merge!(params)
41
+
42
+ @client.post(version: :v2, idempotency_key:).call('account_numbers', **request_params)
43
+ end
44
+
45
+ def _get_account_number(account_number_id)
46
+ @client.get(version: :v2).call("account_numbers/#{account_number_id}")
47
+ end
48
+
49
+ def _list_account_numbers(**params)
50
+ @client.get(version: :v2).call('account_numbers', **params)
51
+ end
52
+
53
+ def _update_account_number(account_number_id, idempotency_key: nil, **params)
54
+ @client.patch(version: :v2, idempotency_key:)
55
+ .call("account_numbers/#{account_number_id}", **params)
56
+ end
57
+
58
+ def build_account_number(data)
59
+ Fintoc::V2::AccountNumber.new(**data, client: @client)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ require 'fintoc/v2/resources/account_verification'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class AccountVerificationsManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def create(account_number:, idempotency_key: nil)
12
+ data = _create_account_verification(account_number:, idempotency_key:)
13
+ build_account_verification(data)
14
+ end
15
+
16
+ def get(account_verification_id)
17
+ data = _get_account_verification(account_verification_id)
18
+ build_account_verification(data)
19
+ end
20
+
21
+ def list(**params)
22
+ _list_account_verifications(**params).map { |data| build_account_verification(data) }
23
+ end
24
+
25
+ private
26
+
27
+ def _create_account_verification(account_number:, idempotency_key: nil)
28
+ @client.post(version: :v2, use_jws: true, idempotency_key:)
29
+ .call('account_verifications', account_number:)
30
+ end
31
+
32
+ def _get_account_verification(account_verification_id)
33
+ @client.get(version: :v2).call("account_verifications/#{account_verification_id}")
34
+ end
35
+
36
+ def _list_account_verifications(**params)
37
+ @client.get(version: :v2).call('account_verifications', **params)
38
+ end
39
+
40
+ def build_account_verification(data)
41
+ Fintoc::V2::AccountVerification.new(**data, client: @client)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,55 @@
1
+ require 'fintoc/v2/resources/account'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class AccountsManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def create(entity_id:, description:, idempotency_key: nil, **params)
12
+ data = _create_account(entity_id:, description:, idempotency_key:, **params)
13
+ build_account(data)
14
+ end
15
+
16
+ def get(account_id)
17
+ data = _get_account(account_id)
18
+ build_account(data)
19
+ end
20
+
21
+ def list(**params)
22
+ _list_accounts(**params).map { |data| build_account(data) }
23
+ end
24
+
25
+ def update(account_id, idempotency_key: nil, **params)
26
+ data = _update_account(account_id, idempotency_key:, **params)
27
+ build_account(data)
28
+ end
29
+
30
+ private
31
+
32
+ def _create_account(entity_id:, description:, idempotency_key: nil, **params)
33
+ @client.post(version: :v2, idempotency_key:)
34
+ .call('accounts', entity_id:, description:, **params)
35
+ end
36
+
37
+ def _get_account(account_id)
38
+ @client.get(version: :v2).call("accounts/#{account_id}")
39
+ end
40
+
41
+ def _list_accounts(**params)
42
+ @client.get(version: :v2).call('accounts', **params)
43
+ end
44
+
45
+ def _update_account(account_id, idempotency_key: nil, **params)
46
+ @client.patch(version: :v2, idempotency_key:).call("accounts/#{account_id}", **params)
47
+ end
48
+
49
+ def build_account(data)
50
+ Fintoc::V2::Account.new(**data, client: @client)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,36 @@
1
+ require 'fintoc/v2/resources/entity'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class EntitiesManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def get(entity_id)
12
+ data = _get_entity(entity_id)
13
+ build_entity(data)
14
+ end
15
+
16
+ def list(**params)
17
+ _list_entities(**params).map { |data| build_entity(data) }
18
+ end
19
+
20
+ private
21
+
22
+ def _get_entity(entity_id)
23
+ @client.get(version: :v2).call("entities/#{entity_id}")
24
+ end
25
+
26
+ def _list_entities(**params)
27
+ @client.get(version: :v2).call('entities', **params)
28
+ end
29
+
30
+ def build_entity(data)
31
+ Fintoc::V2::Entity.new(**data, client: @client)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ require 'fintoc/v2/resources/transfer'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class SimulateManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def receive_transfer(account_number_id:, amount:, currency:, idempotency_key: nil)
12
+ data = _simulate_receive_transfer(
13
+ account_number_id:, amount:, currency:, idempotency_key:
14
+ )
15
+ build_transfer(data)
16
+ end
17
+
18
+ private
19
+
20
+ def _simulate_receive_transfer(account_number_id:, amount:, currency:, idempotency_key: nil)
21
+ @client
22
+ .post(version: :v2, idempotency_key:)
23
+ .call('simulate/receive_transfer', account_number_id:, amount:, currency:)
24
+ end
25
+
26
+ def build_transfer(data)
27
+ Fintoc::V2::Transfer.new(**data, client: @client)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,61 @@
1
+ require 'fintoc/v2/resources/transfer'
2
+
3
+ module Fintoc
4
+ module V2
5
+ module Managers
6
+ class TransfersManager
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def create(amount:, currency:, account_id:, counterparty:, idempotency_key: nil, **params)
12
+ data = _create_transfer(
13
+ amount:, currency:, account_id:, counterparty:, idempotency_key:, **params
14
+ )
15
+ build_transfer(data)
16
+ end
17
+
18
+ def get(transfer_id)
19
+ data = _get_transfer(transfer_id)
20
+ build_transfer(data)
21
+ end
22
+
23
+ def list(**params)
24
+ _list_transfers(**params).map { |data| build_transfer(data) }
25
+ end
26
+
27
+ def return(transfer_id, idempotency_key: nil)
28
+ data = _return_transfer(transfer_id, idempotency_key:)
29
+ build_transfer(data)
30
+ end
31
+
32
+ private
33
+
34
+ def _create_transfer(
35
+ amount:, currency:, account_id:, counterparty:, idempotency_key: nil, **params
36
+ )
37
+ @client
38
+ .post(version: :v2, use_jws: true, idempotency_key:)
39
+ .call('transfers', amount:, currency:, account_id:, counterparty:, **params)
40
+ end
41
+
42
+ def _get_transfer(transfer_id)
43
+ @client.get(version: :v2).call("transfers/#{transfer_id}")
44
+ end
45
+
46
+ def _list_transfers(**params)
47
+ @client.get(version: :v2).call('transfers', **params)
48
+ end
49
+
50
+ def _return_transfer(transfer_id, idempotency_key: nil)
51
+ @client.post(version: :v2, use_jws: true, idempotency_key:)
52
+ .call('transfers/return', transfer_id:)
53
+ end
54
+
55
+ def build_transfer(data)
56
+ Fintoc::V2::Transfer.new(**data, client: @client)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end