mercury_banking 0.5.38 → 0.6.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +46 -2
- data/Gemfile +13 -12
- data/Gemfile.lock +1 -1
- data/Rakefile +3 -1
- data/bin/console +1 -0
- data/bin/mercury +2 -1
- data/lib/mercury_banking/api.rb +26 -23
- data/lib/mercury_banking/cli/accounts.rb +24 -24
- data/lib/mercury_banking/cli/base.rb +13 -28
- data/lib/mercury_banking/cli/financials.rb +247 -195
- data/lib/mercury_banking/cli/reconciliation.rb +284 -371
- data/lib/mercury_banking/cli/reports.rb +82 -74
- data/lib/mercury_banking/cli/transactions.rb +60 -62
- data/lib/mercury_banking/cli.rb +51 -49
- data/lib/mercury_banking/formatters/export_formatter.rb +99 -97
- data/lib/mercury_banking/formatters/table_formatter.rb +32 -30
- data/lib/mercury_banking/multi.rb +43 -37
- data/lib/mercury_banking/recipient.rb +17 -9
- data/lib/mercury_banking/reconciliation.rb +57 -58
- data/lib/mercury_banking/reports/balance_sheet.rb +210 -218
- data/lib/mercury_banking/reports/reconciliation.rb +114 -100
- data/lib/mercury_banking/utils/command_utils.rb +3 -1
- data/lib/mercury_banking/version.rb +3 -1
- data/lib/mercury_banking.rb +2 -0
- data/mercury_banking.gemspec +15 -12
- metadata +39 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d958cfcc9d23e6dada51282855c5ee4a3bdee31c75ec8651d0f91abc1de1d52
|
4
|
+
data.tar.gz: 7e4da144d5e945c181bdd523956907ed52ec4cb4e58956b3d8dfc959abbf4b7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aeb81d99cda287f2c8fc890604338af74a5b2ea9077ba0a73909fdc0284aa6a2b84d2b19f2d07e7aea76c8f2c5914c221aa438697b7fabe3d96cb806468b2ad5
|
7
|
+
data.tar.gz: 9bbd04395ed06195a618ed0e33b7899d3c56ce1a4fcac1e1c013673120e2900382ca4e800f20b4382092d0fb65fb556b564e1ba8e99aae19aff129e4f96837a8
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion:
|
2
|
+
TargetRubyVersion: 3.0
|
3
3
|
NewCops: enable
|
4
|
+
SuggestExtensions: false
|
4
5
|
|
5
6
|
# Disable the rule that changes $? to $CHILD_STATUS
|
6
7
|
Style/GlobalVars:
|
@@ -14,4 +15,47 @@ Style/SpecialGlobalVars:
|
|
14
15
|
|
15
16
|
# Allow slightly longer methods since we've already done significant refactoring
|
16
17
|
Metrics/MethodLength:
|
17
|
-
Max:
|
18
|
+
Max: 50 # Default is 10, we're increasing it to 50
|
19
|
+
Exclude:
|
20
|
+
- 'spec/**/*'
|
21
|
+
|
22
|
+
# Disable enforcement of single quotes over double quotes
|
23
|
+
Style/StringLiterals:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
# Increase line length limit
|
27
|
+
Layout/LineLength:
|
28
|
+
Max: 150
|
29
|
+
Exclude:
|
30
|
+
- 'spec/**/*'
|
31
|
+
|
32
|
+
# Increase block length limit for specs and complex methods
|
33
|
+
Metrics/BlockLength:
|
34
|
+
Max: 100
|
35
|
+
Exclude:
|
36
|
+
- 'spec/**/*'
|
37
|
+
|
38
|
+
# Increase class and module length limits
|
39
|
+
Metrics/ClassLength:
|
40
|
+
Max: 150
|
41
|
+
|
42
|
+
Metrics/ModuleLength:
|
43
|
+
Max: 500
|
44
|
+
|
45
|
+
# Increase complexity limits
|
46
|
+
Metrics/AbcSize:
|
47
|
+
Max: 75
|
48
|
+
|
49
|
+
Metrics/CyclomaticComplexity:
|
50
|
+
Max: 30
|
51
|
+
|
52
|
+
Metrics/PerceivedComplexity:
|
53
|
+
Max: 30
|
54
|
+
|
55
|
+
# Increase parameter list limit
|
56
|
+
Metrics/ParameterLists:
|
57
|
+
Max: 12
|
58
|
+
|
59
|
+
# Allow optional boolean parameters
|
60
|
+
Style/OptionalBooleanParameter:
|
61
|
+
Enabled: false
|
data/Gemfile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
source 'https://rubygems.org'
|
2
4
|
|
3
5
|
ruby '3.3.5'
|
@@ -5,22 +7,21 @@ ruby '3.3.5'
|
|
5
7
|
# Specify your gem's dependencies in mercury_banking.gemspec
|
6
8
|
gemspec
|
7
9
|
|
8
|
-
gem 'dotenv'
|
9
10
|
gem 'activesupport'
|
10
|
-
gem '
|
11
|
-
gem '
|
12
|
-
gem '
|
13
|
-
gem '
|
14
|
-
gem '
|
11
|
+
gem 'base64'
|
12
|
+
gem 'csv'
|
13
|
+
gem 'dead_end', require: false # Helps find syntax errors
|
14
|
+
gem 'debride', require: false # Finds unused code
|
15
|
+
gem 'dotenv'
|
15
16
|
gem 'lockbox'
|
17
|
+
gem 'pry'
|
16
18
|
gem 'rake', '~> 13.0'
|
17
19
|
gem 'rspec', '~> 3.0'
|
18
20
|
gem 'rubocop', require: false
|
19
21
|
gem 'rubocop-performance', require: false
|
20
|
-
gem 'rubocop-rspec', require: false
|
21
22
|
gem 'rubocop-rake', require: false
|
22
|
-
gem '
|
23
|
-
gem '
|
24
|
-
gem '
|
25
|
-
gem '
|
26
|
-
|
23
|
+
gem 'rubocop-rspec', require: false
|
24
|
+
gem 'symmetric-encryption'
|
25
|
+
gem 'terminal-table'
|
26
|
+
gem 'thor'
|
27
|
+
gem 'webmock', '~> 3.18'
|
data/Gemfile.lock
CHANGED
data/Rakefile
CHANGED
data/bin/console
CHANGED
data/bin/mercury
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'thor'
|
4
5
|
require 'mercury_banking'
|
@@ -14,4 +15,4 @@ require 'mercury_banking/cli'
|
|
14
15
|
require 'symmetric-encryption'
|
15
16
|
|
16
17
|
# Start the CLI
|
17
|
-
MercuryBanking::CLI::Main.start(ARGV)
|
18
|
+
MercuryBanking::CLI::Main.start(ARGV)
|
data/lib/mercury_banking/api.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MercuryBanking
|
4
|
+
# API client for Mercury Banking
|
5
|
+
# Handles all API requests to the Mercury Banking API
|
2
6
|
class API
|
3
7
|
def initialize(secret)
|
4
8
|
@api_key = secret
|
@@ -40,10 +44,8 @@ module MercuryBanking
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def validate_body(body, path)
|
43
|
-
if body["errors"]
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
+
raise "#{@api_key} access to #{path} errored with #{body['errors']['message']}" if body["errors"]
|
48
|
+
|
47
49
|
body
|
48
50
|
end
|
49
51
|
|
@@ -86,6 +88,7 @@ module MercuryBanking
|
|
86
88
|
def find_account_by_number(account_number)
|
87
89
|
account = accounts.find { |a| a["accountNumber"] == account_number.to_s }
|
88
90
|
raise "Account with number #{account_number} not found" unless account
|
91
|
+
|
89
92
|
account
|
90
93
|
end
|
91
94
|
|
@@ -93,37 +96,35 @@ module MercuryBanking
|
|
93
96
|
account = get_account(account_id)
|
94
97
|
account['currentBalance']
|
95
98
|
end
|
96
|
-
|
99
|
+
|
97
100
|
# /account/:id/transactions
|
98
101
|
def get_transactions(account_id, start_date = nil)
|
99
102
|
path = "account/#{account_id}/transactions"
|
100
103
|
path += "?start=#{start_date}" if start_date
|
101
104
|
get(path)["transactions"]
|
102
105
|
end
|
103
|
-
|
106
|
+
|
104
107
|
# Get transactions from all accounts
|
105
108
|
def get_all_transactions(start_date = nil)
|
106
109
|
all_transactions = []
|
107
|
-
|
110
|
+
|
108
111
|
accounts.each do |account|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
transaction["accountNumber"] = account["accountNumber"]
|
116
|
-
end
|
117
|
-
all_transactions.concat(account_transactions)
|
118
|
-
rescue StandardError => e
|
119
|
-
puts "Warning: Could not fetch transactions for account #{account["name"]}: #{e.message}" unless ENV['MERCURY_SILENT']
|
112
|
+
account_transactions = get_transactions(account["id"], start_date)
|
113
|
+
# Add account information to each transaction
|
114
|
+
account_transactions.each do |transaction|
|
115
|
+
transaction["accountName"] = account["name"]
|
116
|
+
transaction["accountId"] = account["id"]
|
117
|
+
transaction["accountNumber"] = account["accountNumber"]
|
120
118
|
end
|
119
|
+
all_transactions.concat(account_transactions)
|
120
|
+
rescue StandardError => e
|
121
|
+
puts "Warning: Could not fetch transactions for account #{account['name']}: #{e.message}" unless ENV['MERCURY_SILENT']
|
121
122
|
end
|
122
|
-
|
123
|
+
|
123
124
|
# Sort all transactions by date (newest first)
|
124
125
|
all_transactions.sort_by { |t| t["createdAt"] || "" }.reverse
|
125
126
|
end
|
126
|
-
|
127
|
+
|
127
128
|
# /account/:id/transactions/:id
|
128
129
|
def transaction(account_id, transaction_id)
|
129
130
|
path = "account/#{account_id}/transaction/#{transaction_id}"
|
@@ -158,10 +159,12 @@ module MercuryBanking
|
|
158
159
|
post(rec.json, 'recipients')
|
159
160
|
new_recipient = find_recipient(name: name)
|
160
161
|
raise "Couldn't add account #{name}" unless new_recipient
|
162
|
+
|
161
163
|
puts "Successfully added #{new_recipient['name']}" if new_recipient
|
162
164
|
end
|
163
165
|
|
164
|
-
def update_recipient(name:, address:, email:, city:, region:, postal_code:, country:, account_number:,
|
166
|
+
def update_recipient(name:, address:, email:, city:, region:, postal_code:, country:, account_number:,
|
167
|
+
routing_number:, recipient_id:)
|
165
168
|
rec = MercuryBanking::Recipient.new(
|
166
169
|
name: name,
|
167
170
|
address: address,
|
@@ -179,7 +182,7 @@ module MercuryBanking
|
|
179
182
|
def transfer(recipient_id:, amount:, account_id:, note: nil, external: nil)
|
180
183
|
payload = { recipientId: recipient_id, amount: amount, paymentMethod: 'ach',
|
181
184
|
note: note, externalMemo: external, idempotencyKey: "#{recipient_id}-#{amount}-#{note}-#{external}" }
|
182
|
-
|
185
|
+
post(payload, "account/#{account_id}/transactions")
|
183
186
|
end
|
184
187
|
end
|
185
|
-
end
|
188
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MercuryBanking
|
2
4
|
module CLI
|
3
5
|
# Module for account-related commands
|
@@ -6,51 +8,49 @@ module MercuryBanking
|
|
6
8
|
def self.included(base)
|
7
9
|
base.class_eval do
|
8
10
|
desc 'accounts', 'Display all accounts'
|
9
|
-
method_option :format, type: :string, default: 'table', enum: [
|
11
|
+
method_option :format, type: :string, default: 'table', enum: %w[table json],
|
12
|
+
desc: 'Output format (table or json)'
|
10
13
|
def accounts
|
11
14
|
with_api_client do |client|
|
12
15
|
accounts = client.accounts
|
13
|
-
|
16
|
+
|
14
17
|
if options[:json] || options[:format] == 'json'
|
15
18
|
puts JSON.pretty_generate(accounts)
|
16
19
|
else
|
17
20
|
display_accounts_table(accounts)
|
18
21
|
end
|
19
|
-
|
22
|
+
|
20
23
|
puts "You have #{accounts.count} account/s" unless options[:json]
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
desc 'balance ACCOUNT_ID_OR_NUMBER',
|
27
|
+
desc 'balance ACCOUNT_ID_OR_NUMBER',
|
28
|
+
"Display the current balance of an account (using account number from accounts table)"
|
25
29
|
def balance(account_identifier)
|
26
30
|
with_api_client do |client|
|
27
31
|
# Determine if we're dealing with an account ID or account number
|
28
32
|
account_id = nil
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
# If not found by number, assume it's an ID
|
35
|
-
account_id = account_identifier
|
36
|
-
account = client.get_account(account_id)
|
37
|
-
end
|
38
|
-
else
|
33
|
+
begin
|
34
|
+
account = client.find_account_by_number(account_identifier)
|
35
|
+
account_id = account['id']
|
36
|
+
rescue StandardError
|
37
|
+
# If not found by number, assume it's an ID
|
39
38
|
account_id = account_identifier
|
40
|
-
account = client.get_account(account_id)
|
41
39
|
end
|
42
|
-
|
40
|
+
|
41
|
+
account = client.get_account(account_id)
|
42
|
+
|
43
43
|
balance = client.balance(account_id)
|
44
|
-
|
44
|
+
|
45
45
|
if options[:json]
|
46
46
|
puts JSON.pretty_generate({
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
'account_id' => account_id,
|
48
|
+
'account_number' => account['accountNumber'],
|
49
|
+
'name' => account['name'],
|
50
|
+
'balance' => balance
|
51
|
+
})
|
52
52
|
else
|
53
|
-
puts "#{account['name']} (#{account['accountNumber']}): $#{format(
|
53
|
+
puts "#{account['name']} (#{account['accountNumber']}): $#{format('%.2f', balance)}"
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -58,4 +58,4 @@ module MercuryBanking
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
61
|
-
end
|
61
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module MercuryBanking
|
2
4
|
module CLI
|
3
5
|
# Base module for CLI functionality
|
@@ -6,7 +8,7 @@ module MercuryBanking
|
|
6
8
|
def with_api_client
|
7
9
|
api_key = get_api_key
|
8
10
|
raise "API key not found. Please run 'mercury set_key' first." unless api_key
|
9
|
-
|
11
|
+
|
10
12
|
client = MercuryBanking::API.new(api_key)
|
11
13
|
yield client
|
12
14
|
rescue StandardError => e
|
@@ -18,41 +20,24 @@ module MercuryBanking
|
|
18
20
|
exit 1
|
19
21
|
end
|
20
22
|
|
21
|
-
# Get the API key from the
|
22
|
-
def
|
23
|
-
config_path = File.join(Dir.home, '.mercury
|
24
|
-
key_path = File.join(Dir.home, '.mercury
|
25
|
-
|
23
|
+
# Get the API key from the configuration file
|
24
|
+
def api_key
|
25
|
+
config_path = File.join(Dir.home, '.mercury', 'config')
|
26
|
+
key_path = File.join(Dir.home, '.mercury', 'key')
|
27
|
+
|
26
28
|
unless File.exist?(config_path) && File.exist?(key_path)
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
begin
|
31
|
-
key_config = JSON.parse(File.read(key_path))
|
32
|
-
|
33
|
-
# Initialize the SymmetricEncryption with the loaded cipher
|
34
|
-
cipher = SymmetricEncryption::Cipher.new(
|
35
|
-
key: Base64.strict_decode64(key_config['key']),
|
36
|
-
iv: Base64.strict_decode64(key_config['iv']),
|
37
|
-
cipher_name: key_config['cipher_name'] || 'aes-256-cbc'
|
38
|
-
)
|
39
|
-
|
40
|
-
# Set the cipher as the primary one
|
41
|
-
SymmetricEncryption.cipher = cipher
|
42
|
-
|
43
|
-
encrypted_key = File.read(config_path)
|
44
|
-
cipher.decrypt(encrypted_key)
|
45
|
-
rescue => e
|
46
|
-
puts "Error decrypting API key: #{e.message}"
|
29
|
+
puts "Error: Mercury API key not found. Please run 'mercury configure' first."
|
47
30
|
exit 1
|
48
31
|
end
|
32
|
+
|
33
|
+
File.read(key_path).strip
|
49
34
|
end
|
50
35
|
|
51
36
|
# Log transfer details
|
52
37
|
def log_transfer(from, to, amount, note, status)
|
53
38
|
log_dir = File.join(Dir.home, '.mercury-banking', 'logs')
|
54
39
|
FileUtils.mkdir_p(log_dir)
|
55
|
-
|
40
|
+
|
56
41
|
log_file = File.join(log_dir, 'transfers.log')
|
57
42
|
File.open(log_file, 'a') do |f|
|
58
43
|
f.puts "#{Time.now.iso8601},\"#{from}\",\"#{to}\",\"#{amount}\",\"#{note}\",\"#{status}\""
|
@@ -65,4 +50,4 @@ module MercuryBanking
|
|
65
50
|
end
|
66
51
|
end
|
67
52
|
end
|
68
|
-
end
|
53
|
+
end
|