mercury_banking 0.6.0 → 0.7.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/CHANGELOG.md +16 -0
- data/Gemfile.lock +1 -1
- data/lib/mercury_banking/cli/base.rb +38 -1
- data/lib/mercury_banking/cli/financials.rb +162 -289
- data/lib/mercury_banking/cli.rb +5 -2
- data/lib/mercury_banking/version.rb +1 -1
- data/lib/mercury_banking.rb +0 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c388af3fd079eacd9a2ba3fbc78a137ecb57352bd7deda55bcebbb372149126
|
4
|
+
data.tar.gz: 5665853a81cb64eb76128d70a60a3d830b732fa9ae9096ab2f6bae2d5ea858fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8161c1c7afb40e33bb6dd29dbd843d01b969616be1ef4ed45983c2ea65dc2047344ca204e3043085351f8da86822e11ab015d56c4fa077400dd0982047186f75
|
7
|
+
data.tar.gz: 97f6fa41b322f94b53a4b69ee9255ceeb9083f3ec5934f35fc1b3952166aa9b0e16767a6460c688d0d7e4cd9aa6f43d65b1eeb3bac0eedb9f519c6679c11aab9
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.7.0] - 2025-03-11
|
4
|
+
### Changed
|
5
|
+
- Simplified gem functionality to focus on core features
|
6
|
+
- Removed balance sheet generation and only kept balance checking functionality
|
7
|
+
- Removed all reconciliation functionality (reconcile, reconcile_all, reconciliation_status, unreconcile)
|
8
|
+
- Added new `balancecheck` command that checks ledger balances against Mercury account balances
|
9
|
+
- Reduced dependencies by removing unnecessary modules and imports
|
10
|
+
|
11
|
+
## [0.6.0] - 2025-03-10
|
12
|
+
### Changed
|
13
|
+
- Major code refactoring to improve code quality and maintainability
|
14
|
+
- Extracted helper methods into separate modules
|
15
|
+
- Reduced method complexity and size
|
16
|
+
- Fixed various RuboCop issues
|
17
|
+
- Improved code organization by separating concerns
|
18
|
+
|
3
19
|
## [0.5.34] - 2025-03-10
|
4
20
|
### Fixed
|
5
21
|
- Added missing `thor` gem dependency to fix LoadError when running CLI commands
|
data/Gemfile.lock
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'logger'
|
4
|
+
require 'symmetric-encryption'
|
5
|
+
require 'json'
|
6
|
+
require 'base64'
|
7
|
+
require 'fileutils'
|
8
|
+
|
3
9
|
module MercuryBanking
|
4
10
|
module CLI
|
5
11
|
# Base module for CLI functionality
|
@@ -20,7 +26,38 @@ module MercuryBanking
|
|
20
26
|
exit 1
|
21
27
|
end
|
22
28
|
|
23
|
-
# Get
|
29
|
+
# Get API key by decrypting the stored encrypted key
|
30
|
+
def get_api_key
|
31
|
+
config_dir = File.join(Dir.home, '.mercury-banking')
|
32
|
+
key_config_path = File.join(config_dir, 'key_config.json')
|
33
|
+
api_key_path = File.join(config_dir, 'api_key.enc')
|
34
|
+
|
35
|
+
unless File.exist?(key_config_path) && File.exist?(api_key_path)
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Load the cipher configuration
|
40
|
+
cipher_config = JSON.parse(File.read(key_config_path))
|
41
|
+
|
42
|
+
# Recreate the cipher
|
43
|
+
cipher = SymmetricEncryption::Cipher.new(
|
44
|
+
key: Base64.strict_decode64(cipher_config['key']),
|
45
|
+
iv: Base64.strict_decode64(cipher_config['iv']),
|
46
|
+
cipher_name: cipher_config['cipher_name']
|
47
|
+
)
|
48
|
+
|
49
|
+
# Set the cipher as the primary one
|
50
|
+
SymmetricEncryption.cipher = cipher
|
51
|
+
|
52
|
+
# Load and decrypt the API key
|
53
|
+
encrypted_key = File.read(api_key_path)
|
54
|
+
cipher.decrypt(encrypted_key)
|
55
|
+
rescue StandardError => e
|
56
|
+
puts "Error decrypting API key: #{e.message}" unless options[:json]
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the API key from the configuration file (legacy method)
|
24
61
|
def api_key
|
25
62
|
config_path = File.join(Dir.home, '.mercury', 'config')
|
26
63
|
key_path = File.join(Dir.home, '.mercury', 'key')
|
@@ -2,278 +2,28 @@
|
|
2
2
|
|
3
3
|
require 'mercury_banking/cli/base'
|
4
4
|
require 'mercury_banking/formatters/export_formatter'
|
5
|
-
require 'mercury_banking/reports/balance_sheet'
|
6
5
|
|
7
6
|
module MercuryBanking
|
8
7
|
module CLI
|
9
|
-
# Module for
|
10
|
-
module Financials
|
11
|
-
# Define the financials command class
|
12
|
-
class FinancialsCommand < Thor
|
13
|
-
include MercuryBanking::CLI::Base
|
14
|
-
include MercuryBanking::Formatters::ExportFormatter
|
15
|
-
include MercuryBanking::Reports::BalanceSheet
|
16
|
-
# BalanceSheetHelper will be included after it's defined
|
17
|
-
|
18
|
-
desc "balancesheet", "Generate a balance sheet report and cross-check with Mercury account balances"
|
19
|
-
method_option :format, type: :string, default: 'ledger', desc: 'Accounting format to use (ledger or beancount)'
|
20
|
-
method_option :start, type: :string, default: '2020-01-01', desc: 'Start date for transactions (YYYY-MM-DD)'
|
21
|
-
method_option :end, type: :string, desc: 'End date for transactions (YYYY-MM-DD)'
|
22
|
-
method_option :save_report, type: :string, desc: 'Save report output to specified file'
|
23
|
-
method_option :verbose, type: :boolean, default: false, desc: 'Show detailed debug information'
|
24
|
-
method_option :ledger_file, type: :string,
|
25
|
-
desc: 'Use an existing ledger file instead of fetching transactions from Mercury'
|
26
|
-
def balancesheet
|
27
|
-
# Call the balance_sheet method directly
|
28
|
-
balance_sheet
|
29
|
-
end
|
30
|
-
|
31
|
-
# Methods that should not be exposed as commands
|
32
|
-
no_commands do
|
33
|
-
# Implementation of the balance sheet functionality
|
34
|
-
def balance_sheet
|
35
|
-
client = MercuryBanking::Client.new
|
36
|
-
accounts = client.get_accounts
|
37
|
-
|
38
|
-
if options[:ledger_file] && File.exist?(options[:ledger_file])
|
39
|
-
process_existing_ledger_file(options[:ledger_file], options[:format], options[:save_report], options[:verbose])
|
40
|
-
return
|
41
|
-
end
|
42
|
-
|
43
|
-
# Fetch all transactions from all accounts
|
44
|
-
transactions = fetch_all_transactions(client, accounts, options[:end])
|
45
|
-
puts "Found #{transactions.length} transactions across #{accounts.length} accounts."
|
46
|
-
|
47
|
-
# Get current balances for all Mercury accounts
|
48
|
-
mercury_balances = get_mercury_balances(accounts)
|
49
|
-
|
50
|
-
# Create a temporary file for exporting transactions
|
51
|
-
temp_file, output_file = create_temp_file(options[:format])
|
52
|
-
|
53
|
-
# Export transactions and generate balance sheet
|
54
|
-
balance_sheet_output = export_and_generate_balance_sheet(
|
55
|
-
transactions,
|
56
|
-
output_file,
|
57
|
-
options[:format],
|
58
|
-
options[:end],
|
59
|
-
options[:verbose]
|
60
|
-
)
|
61
|
-
|
62
|
-
# If balance sheet generation failed, exit
|
63
|
-
unless balance_sheet_output
|
64
|
-
temp_file.close
|
65
|
-
temp_file.unlink
|
66
|
-
return
|
67
|
-
end
|
68
|
-
|
69
|
-
# Parse the balance sheet output to get account balances
|
70
|
-
ledger_balances = {}
|
71
|
-
balance_sheet_output.each_line do |line|
|
72
|
-
next unless line.strip.start_with?('Assets:')
|
73
|
-
|
74
|
-
parts = line.strip.split(/\s+/)
|
75
|
-
account = parts.first
|
76
|
-
amount = parts.last.gsub(/[$,]/, '').to_f
|
77
|
-
ledger_balances[account] = amount
|
78
|
-
end
|
79
|
-
|
80
|
-
# Display cross-check between Mercury and ledger balances
|
81
|
-
display_balance_cross_check(mercury_balances, ledger_balances, options[:verbose])
|
82
|
-
|
83
|
-
# Save full report to file if requested
|
84
|
-
save_full_report(balance_sheet_output, mercury_balances, ledger_balances, options[:save_report]) if options[:save_report]
|
85
|
-
|
86
|
-
# Clean up temporary file
|
87
|
-
temp_file.close
|
88
|
-
temp_file.unlink
|
89
|
-
end
|
90
|
-
|
91
|
-
# Process an existing ledger file
|
92
|
-
def process_existing_ledger_file(ledger_file, format, save_path, _verbose)
|
93
|
-
puts "Using existing ledger file: #{ledger_file}"
|
94
|
-
|
95
|
-
# Determine the format based on file extension if not specified
|
96
|
-
unless format
|
97
|
-
format = File.extname(ledger_file).delete('.').downcase
|
98
|
-
puts "Detected format: #{format}"
|
99
|
-
end
|
100
|
-
|
101
|
-
# Generate balance sheet based on format
|
102
|
-
balance_sheet_output = process_ledger_format(ledger_file, format)
|
103
|
-
|
104
|
-
# If balance sheet generation failed, exit
|
105
|
-
return unless balance_sheet_output
|
106
|
-
|
107
|
-
# Save report to file if requested
|
108
|
-
return unless save_path
|
109
|
-
|
110
|
-
File.write(save_path, balance_sheet_output)
|
111
|
-
puts "\nReport saved to #{save_path}"
|
112
|
-
end
|
113
|
-
|
114
|
-
# Process ledger format file
|
115
|
-
def process_ledger_format(ledger_file, format)
|
116
|
-
case format
|
117
|
-
when 'ledger'
|
118
|
-
generate_ledger_balance_sheet(ledger_file)
|
119
|
-
when 'beancount'
|
120
|
-
generate_beancount_balance_sheet(ledger_file)
|
121
|
-
else
|
122
|
-
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
123
|
-
nil
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Helper method to save a report to a file
|
128
|
-
def save_report_to_file(content, file_path)
|
129
|
-
File.write(file_path, content)
|
130
|
-
puts "\nReport saved to #{file_path}"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
desc "incomestatement", "Generate an income statement report"
|
135
|
-
method_option :format, type: :string, default: 'ledger', desc: 'Accounting format to use (ledger or beancount)'
|
136
|
-
method_option :start, type: :string, default: '2020-01-01', desc: 'Start date for transactions (YYYY-MM-DD)'
|
137
|
-
method_option :end, type: :string, desc: 'End date for transactions (YYYY-MM-DD)'
|
138
|
-
method_option :save_report, type: :string, desc: 'Save report output to specified file'
|
139
|
-
method_option :verbose, type: :boolean, default: false, desc: 'Show detailed debug information'
|
140
|
-
def incomestatement
|
141
|
-
# Access the parent class to call with_api_client
|
142
|
-
parent_class = self.class.parent_class
|
143
|
-
parent_instance = parent_class.new
|
144
|
-
|
145
|
-
parent_instance.with_api_client do |client|
|
146
|
-
# Get all transactions for the income statement
|
147
|
-
start_date = options[:start]
|
148
|
-
end_date = options[:end]
|
149
|
-
format = options[:format]
|
150
|
-
verbose = options[:verbose]
|
151
|
-
|
152
|
-
date_range = "since #{start_date}"
|
153
|
-
date_range += " until #{end_date}" if end_date
|
154
|
-
|
155
|
-
puts "Fetching transactions for all accounts #{date_range}..."
|
156
|
-
|
157
|
-
transactions = client.get_all_transactions(start_date)
|
158
|
-
|
159
|
-
# Filter by end date if specified
|
160
|
-
if end_date
|
161
|
-
end_date_obj = Date.parse(end_date)
|
162
|
-
transactions = transactions.select do |t|
|
163
|
-
transaction_date = Date.parse(t["postedAt"] || t["createdAt"])
|
164
|
-
transaction_date <= end_date_obj
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Create a temporary file
|
169
|
-
require 'tempfile'
|
170
|
-
temp_file = Tempfile.new(['mercury_transactions', ".#{format}"])
|
171
|
-
output_file = temp_file.path
|
172
|
-
|
173
|
-
# Export transactions in the specified format
|
174
|
-
case format
|
175
|
-
when 'ledger'
|
176
|
-
parent_instance.export_to_ledger(transactions, output_file, [], verbose)
|
177
|
-
income_statement_output = parent_instance.generate_ledger_reports(output_file, 'income', nil, end_date)
|
178
|
-
when 'beancount'
|
179
|
-
parent_instance.export_to_beancount(transactions, output_file, [], verbose)
|
180
|
-
income_statement_output = parent_instance.generate_beancount_reports(output_file, 'income', nil, end_date)
|
181
|
-
else
|
182
|
-
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
183
|
-
temp_file.unlink
|
184
|
-
income_statement_output = nil
|
185
|
-
break # Use break instead of return to exit the loop
|
186
|
-
end
|
187
|
-
|
188
|
-
# Display the income statement if it exists
|
189
|
-
puts income_statement_output if income_statement_output
|
190
|
-
|
191
|
-
# Save the report to a file if requested
|
192
|
-
if options[:save_report]
|
193
|
-
File.open(options[:save_report], 'w') do |file|
|
194
|
-
file.puts income_statement_output
|
195
|
-
end
|
196
|
-
puts "\nReport saved to #{options[:save_report]}"
|
197
|
-
end
|
198
|
-
|
199
|
-
# Clean up the temporary file
|
200
|
-
temp_file.unlink
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# Store reference to parent class
|
205
|
-
class << self
|
206
|
-
attr_accessor :parent_class
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
# Add financial report commands to the CLI class
|
211
|
-
def self.included(base)
|
212
|
-
base.class_eval do
|
213
|
-
# Register the financials command
|
214
|
-
desc "financials SUBCOMMAND", "Financial reporting commands"
|
215
|
-
subcommand "financials", FinancialsCommand
|
216
|
-
|
217
|
-
# Set the parent class for the subcommand
|
218
|
-
FinancialsCommand.parent_class = base
|
219
|
-
|
220
|
-
# Remove the old methods with underscores if they exist
|
221
|
-
remove_method :financials_balancesheet if method_defined?(:financials_balancesheet)
|
222
|
-
remove_method :financials_incomestatement if method_defined?(:financials_incomestatement)
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
# Module for balance sheet related functionality
|
8
|
+
# Module for balance check related functionality
|
228
9
|
module BalanceSheetHelper
|
229
|
-
# Fetch all transactions from all accounts
|
230
|
-
def fetch_all_transactions(client, accounts, end_date)
|
231
|
-
transactions = []
|
232
|
-
accounts.each do |account|
|
233
|
-
account_id = account['id']
|
234
|
-
account_transactions = client.get_transactions(account_id)
|
235
|
-
|
236
|
-
# Filter by end date if provided
|
237
|
-
if end_date
|
238
|
-
account_transactions = account_transactions.select do |t|
|
239
|
-
t['postedAt'] && Date.parse(t['postedAt']) <= Date.parse(end_date)
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
transactions.concat(account_transactions)
|
244
|
-
end
|
245
|
-
transactions
|
246
|
-
end
|
247
|
-
|
248
10
|
# Get current balances for all Mercury accounts
|
249
11
|
def get_mercury_balances(accounts)
|
250
12
|
mercury_balances = {}
|
251
13
|
accounts.each do |account|
|
252
|
-
|
14
|
+
# Use the simplified account name for easier matching with ledger accounts
|
15
|
+
account_name = account['name'].gsub(/•+\d+/, '').strip
|
16
|
+
mercury_balances[account_name] = account['currentBalance'].to_f
|
253
17
|
end
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
temp_file = Tempfile.new(['mercury_transactions', ".#{format}"])
|
261
|
-
[temp_file, temp_file.path]
|
262
|
-
end
|
263
|
-
|
264
|
-
# Export transactions and generate balance sheet
|
265
|
-
def export_and_generate_balance_sheet(transactions, output_file, format, end_date, verbose)
|
266
|
-
case format
|
267
|
-
when 'ledger'
|
268
|
-
export_to_ledger(transactions, output_file, [], verbose)
|
269
|
-
generate_ledger_balance_sheet(output_file, end_date)
|
270
|
-
when 'beancount'
|
271
|
-
export_to_beancount(transactions, output_file, [], verbose)
|
272
|
-
generate_beancount_balance_sheet(output_file, end_date)
|
273
|
-
else
|
274
|
-
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
275
|
-
nil
|
18
|
+
|
19
|
+
if options[:verbose]
|
20
|
+
puts "\nMercury account balances:"
|
21
|
+
mercury_balances.each do |name, balance|
|
22
|
+
puts " #{name}: $#{format('%.2f', balance)}"
|
23
|
+
end
|
276
24
|
end
|
25
|
+
|
26
|
+
mercury_balances
|
277
27
|
end
|
278
28
|
|
279
29
|
# Display cross-check between Mercury and ledger balances
|
@@ -283,19 +33,45 @@ module MercuryBanking
|
|
283
33
|
puts "-" * 75
|
284
34
|
|
285
35
|
total_diff = 0
|
36
|
+
|
37
|
+
if verbose
|
38
|
+
puts "\nMatching accounts:"
|
39
|
+
puts "Mercury accounts: #{mercury_balances.keys.join(', ')}"
|
40
|
+
puts "Ledger accounts: #{ledger_balances.keys.join(', ')}"
|
41
|
+
end
|
42
|
+
|
286
43
|
mercury_balances.each do |account_name, mercury_balance|
|
287
|
-
# Find the corresponding ledger account
|
288
|
-
ledger_account_key =
|
289
|
-
|
44
|
+
# Find the corresponding ledger account
|
45
|
+
ledger_account_key = nil
|
46
|
+
ledger_balance = 0
|
47
|
+
|
48
|
+
# Try different matching strategies
|
49
|
+
if ledger_balances.key?("Assets:Mercury:#{account_name.split.first}")
|
50
|
+
# Direct match with first word (e.g., "Checking" or "Savings")
|
51
|
+
ledger_account_key = "Assets:Mercury:#{account_name.split.first}"
|
52
|
+
ledger_balance = ledger_balances[ledger_account_key]
|
53
|
+
elsif account_name.include?("Checking") && ledger_balances.keys.any? { |k| k.include?("Checking") }
|
54
|
+
# Match by account type
|
55
|
+
ledger_account_key = ledger_balances.keys.find { |k| k.include?("Checking") }
|
56
|
+
ledger_balance = ledger_balances[ledger_account_key]
|
57
|
+
elsif account_name.include?("Savings") && ledger_balances.keys.any? { |k| k.include?("Savings") }
|
58
|
+
# Match by account type
|
59
|
+
ledger_account_key = ledger_balances.keys.find { |k| k.include?("Savings") }
|
60
|
+
ledger_balance = ledger_balances[ledger_account_key]
|
61
|
+
end
|
62
|
+
|
290
63
|
# Debug information
|
291
64
|
if verbose
|
292
|
-
puts "
|
293
|
-
|
294
|
-
|
295
|
-
|
65
|
+
puts "\nMatching for Mercury account '#{account_name}':"
|
66
|
+
puts " Found match: #{ledger_account_key || 'None'}"
|
67
|
+
puts " Mercury balance: $#{format('%.2f', mercury_balance)}"
|
68
|
+
puts " Ledger balance: $#{format('%.2f', ledger_balance)}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# Skip zero-balance accounts unless in verbose mode
|
72
|
+
if mercury_balance == 0 && ledger_balance == 0
|
73
|
+
next unless verbose
|
296
74
|
end
|
297
|
-
|
298
|
-
ledger_balance = ledger_account_key ? ledger_balances[ledger_account_key] : 0
|
299
75
|
|
300
76
|
# Calculate difference
|
301
77
|
diff = mercury_balance - ledger_balance
|
@@ -325,30 +101,127 @@ module MercuryBanking
|
|
325
101
|
puts "\n✓ Balance sheet matches Mercury account balances."
|
326
102
|
end
|
327
103
|
end
|
104
|
+
end
|
328
105
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
106
|
+
# Module for financial report commands
|
107
|
+
module Financials
|
108
|
+
# Define the financials command class
|
109
|
+
class FinancialsCommand < Thor
|
110
|
+
include MercuryBanking::CLI::Base
|
111
|
+
include MercuryBanking::Formatters::ExportFormatter
|
112
|
+
include MercuryBanking::CLI::BalanceSheetHelper
|
336
113
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
114
|
+
desc "balancecheck", "Check that transactions match the bank balance shown in Mercury"
|
115
|
+
method_option :format, type: :string, default: 'ledger', desc: 'Accounting format to use (ledger or beancount)'
|
116
|
+
method_option :ledger_file, type: :string, desc: 'Ledger file to check against Mercury balances'
|
117
|
+
method_option :verbose, type: :boolean, default: false, desc: 'Show detailed debug information'
|
118
|
+
def balancecheck
|
119
|
+
with_api_client do |client|
|
120
|
+
accounts = client.accounts
|
342
121
|
|
343
|
-
|
122
|
+
unless options[:ledger_file] && File.exist?(options[:ledger_file])
|
123
|
+
puts "Error: You must provide a valid ledger file to check. Use --ledger-file option."
|
124
|
+
return
|
125
|
+
end
|
126
|
+
|
127
|
+
# Get balances from the ledger file
|
128
|
+
ledger_file = options[:ledger_file]
|
129
|
+
format = options[:format] || File.extname(ledger_file).delete('.').downcase
|
130
|
+
|
131
|
+
# Get ledger balances
|
132
|
+
ledger_balances = get_ledger_balances(ledger_file, format)
|
133
|
+
|
134
|
+
if ledger_balances.empty?
|
135
|
+
puts "No account balances found in the ledger file."
|
136
|
+
return
|
137
|
+
end
|
138
|
+
|
139
|
+
# Get current balances for all Mercury accounts
|
140
|
+
mercury_balances = get_mercury_balances(accounts)
|
141
|
+
|
142
|
+
# Display cross-check between Mercury and ledger balances
|
143
|
+
display_balance_cross_check(mercury_balances, ledger_balances, options[:verbose])
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Methods that should not be exposed as commands
|
148
|
+
no_commands do
|
149
|
+
# Get balances from ledger file
|
150
|
+
def get_ledger_balances(ledger_file, format)
|
151
|
+
ledger_balances = {}
|
152
|
+
|
153
|
+
# Get balance sheet output from the ledger file
|
154
|
+
balance_sheet_output = case format
|
155
|
+
when 'ledger'
|
156
|
+
`ledger -f #{ledger_file} balance Assets:Mercury`
|
157
|
+
when 'beancount'
|
158
|
+
`bean-report #{ledger_file} balances`
|
159
|
+
else
|
160
|
+
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
161
|
+
return {}
|
162
|
+
end
|
163
|
+
|
164
|
+
puts "Raw ledger output:" if options[:verbose]
|
165
|
+
puts balance_sheet_output if options[:verbose]
|
166
|
+
|
167
|
+
# Directly parse the specific format we know ledger outputs
|
168
|
+
balance_sheet_output.each_line do |line|
|
169
|
+
line = line.strip
|
170
|
+
# Skip empty lines
|
171
|
+
next if line.empty?
|
172
|
+
|
173
|
+
# Split the line on whitespace but preserve the account path
|
174
|
+
parts = line.split(/\s+/, 2) # Split on first whitespace
|
175
|
+
if parts.length == 2
|
176
|
+
amount_part = parts[0]
|
177
|
+
account_part = parts[1]
|
178
|
+
|
179
|
+
# Parse amount - remove $ and , characters
|
180
|
+
amount = amount_part.gsub(/[$,]/, '').to_f
|
181
|
+
|
182
|
+
# Store in the hash
|
183
|
+
ledger_balances[account_part] = amount
|
184
|
+
|
185
|
+
puts "Matched: #{account_part} = $#{amount}" if options[:verbose]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
if options[:verbose]
|
190
|
+
puts "Parsed ledger balances:"
|
191
|
+
if ledger_balances.empty?
|
192
|
+
puts " No account balances found in the ledger file."
|
193
|
+
else
|
194
|
+
ledger_balances.each do |account, amount|
|
195
|
+
puts " #{account}: $#{format('%.2f', amount)}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
ledger_balances
|
201
|
+
end
|
344
202
|
end
|
345
203
|
|
346
|
-
|
347
|
-
|
204
|
+
# Store reference to parent class
|
205
|
+
class << self
|
206
|
+
attr_accessor :parent_class
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Add financial report commands to the CLI class
|
211
|
+
def self.included(base)
|
212
|
+
base.class_eval do
|
213
|
+
# Register the financials command
|
214
|
+
desc "financials SUBCOMMAND", "Financial reporting commands"
|
215
|
+
subcommand "financials", FinancialsCommand
|
216
|
+
|
217
|
+
# Set the parent class for the subcommand
|
218
|
+
FinancialsCommand.parent_class = base
|
219
|
+
|
220
|
+
# Remove the old methods with underscores if they exist
|
221
|
+
remove_method :financials_balancesheet if method_defined?(:financials_balancesheet)
|
222
|
+
remove_method :financials_incomestatement if method_defined?(:financials_incomestatement)
|
223
|
+
end
|
348
224
|
end
|
349
225
|
end
|
350
226
|
end
|
351
227
|
end
|
352
|
-
|
353
|
-
# Include the BalanceSheetHelper module in the FinancialsCommand class
|
354
|
-
MercuryBanking::CLI::Financials::FinancialsCommand.include(MercuryBanking::CLI::BalanceSheetHelper)
|
data/lib/mercury_banking/cli.rb
CHANGED
@@ -7,7 +7,11 @@ require 'mercury_banking/cli/transactions'
|
|
7
7
|
require 'mercury_banking/cli/financials'
|
8
8
|
require 'mercury_banking/formatters/table_formatter'
|
9
9
|
require 'mercury_banking/formatters/export_formatter'
|
10
|
-
require '
|
10
|
+
require 'symmetric-encryption'
|
11
|
+
require 'json'
|
12
|
+
require 'base64'
|
13
|
+
require 'fileutils'
|
14
|
+
require 'securerandom'
|
11
15
|
|
12
16
|
module MercuryBanking
|
13
17
|
# CLI module for Mercury Banking
|
@@ -21,7 +25,6 @@ module MercuryBanking
|
|
21
25
|
include MercuryBanking::CLI::Financials
|
22
26
|
include MercuryBanking::Formatters::TableFormatter
|
23
27
|
include MercuryBanking::Formatters::ExportFormatter
|
24
|
-
include MercuryBanking::Reports::BalanceSheet
|
25
28
|
|
26
29
|
# Add global option for JSON output
|
27
30
|
class_option :json, type: :boolean, default: false, desc: 'Output in JSON format'
|
data/lib/mercury_banking.rb
CHANGED
@@ -11,10 +11,7 @@ require 'csv'
|
|
11
11
|
require 'mercury_banking/api'
|
12
12
|
require 'mercury_banking/recipient'
|
13
13
|
require 'mercury_banking/multi'
|
14
|
-
require 'mercury_banking/reconciliation'
|
15
14
|
require 'mercury_banking/utils/command_utils'
|
16
|
-
require 'mercury_banking/reports/balance_sheet'
|
17
|
-
require 'mercury_banking/reports/reconciliation'
|
18
15
|
|
19
16
|
module MercuryBanking
|
20
17
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mercury_banking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Siegel
|
8
8
|
- Yusuke Ishida
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|