mercury_banking 0.5.37 → 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 -22
- 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 +74 -61
- 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
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'mercury_banking/cli/base'
|
2
4
|
require 'mercury_banking/formatters/export_formatter'
|
3
5
|
require 'mercury_banking/reports/balance_sheet'
|
@@ -11,202 +13,124 @@ module MercuryBanking
|
|
11
13
|
include MercuryBanking::CLI::Base
|
12
14
|
include MercuryBanking::Formatters::ExportFormatter
|
13
15
|
include MercuryBanking::Reports::BalanceSheet
|
14
|
-
|
16
|
+
# BalanceSheetHelper will be included after it's defined
|
17
|
+
|
15
18
|
desc "balancesheet", "Generate a balance sheet report and cross-check with Mercury account balances"
|
16
19
|
method_option :format, type: :string, default: 'ledger', desc: 'Accounting format to use (ledger or beancount)'
|
17
20
|
method_option :start, type: :string, default: '2020-01-01', desc: 'Start date for transactions (YYYY-MM-DD)'
|
18
21
|
method_option :end, type: :string, desc: 'End date for transactions (YYYY-MM-DD)'
|
19
22
|
method_option :save_report, type: :string, desc: 'Save report output to specified file'
|
20
23
|
method_option :verbose, type: :boolean, default: false, desc: 'Show detailed debug information'
|
21
|
-
method_option :ledger_file, type: :string,
|
24
|
+
method_option :ledger_file, type: :string,
|
25
|
+
desc: 'Use an existing ledger file instead of fetching transactions from Mercury'
|
22
26
|
def balancesheet
|
23
27
|
# Call the balance_sheet method directly
|
24
28
|
balance_sheet
|
25
29
|
end
|
26
|
-
|
30
|
+
|
27
31
|
# Methods that should not be exposed as commands
|
28
32
|
no_commands do
|
29
33
|
# Implementation of the balance sheet functionality
|
30
34
|
def balance_sheet
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
verbose = options[:verbose]
|
37
|
-
|
38
|
-
puts "Using existing ledger file: #{ledger_file}"
|
39
|
-
|
40
|
-
if !File.exist?(ledger_file)
|
41
|
-
puts "Error: Ledger file not found at #{ledger_file}"
|
42
|
-
return
|
43
|
-
end
|
44
|
-
|
45
|
-
# Generate balance sheet from the ledger file
|
46
|
-
case format
|
47
|
-
when 'ledger'
|
48
|
-
balance_sheet_output = generate_ledger_balance_sheet(ledger_file, end_date)
|
49
|
-
if balance_sheet_output
|
50
|
-
puts "\n=== Balance Sheet ===\n"
|
51
|
-
puts balance_sheet_output
|
52
|
-
|
53
|
-
# Save report to file if requested
|
54
|
-
if options[:save_report]
|
55
|
-
File.write(options[:save_report], balance_sheet_output)
|
56
|
-
puts "\nReport saved to #{options[:save_report]}"
|
57
|
-
end
|
58
|
-
else
|
59
|
-
puts "Failed to generate balance sheet from ledger file."
|
60
|
-
end
|
61
|
-
when 'beancount'
|
62
|
-
balance_sheet_output = generate_beancount_balance_sheet(ledger_file, end_date)
|
63
|
-
if balance_sheet_output
|
64
|
-
puts "\n=== Balance Sheet ===\n"
|
65
|
-
puts balance_sheet_output
|
66
|
-
|
67
|
-
# Save report to file if requested
|
68
|
-
if options[:save_report]
|
69
|
-
File.write(options[:save_report], balance_sheet_output)
|
70
|
-
puts "\nReport saved to #{options[:save_report]}"
|
71
|
-
end
|
72
|
-
else
|
73
|
-
puts "Failed to generate balance sheet from beancount file."
|
74
|
-
end
|
75
|
-
else
|
76
|
-
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
77
|
-
end
|
78
|
-
|
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])
|
79
40
|
return
|
80
41
|
end
|
81
|
-
|
82
|
-
#
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
transactions = client.get_all_transactions(start_date)
|
105
|
-
|
106
|
-
# Filter by end date if specified
|
107
|
-
if end_date
|
108
|
-
end_date_obj = Date.parse(end_date)
|
109
|
-
transactions = transactions.select do |t|
|
110
|
-
transaction_date = t["postedAt"] ? Date.parse(t["postedAt"]) : Date.parse(t["createdAt"])
|
111
|
-
transaction_date <= end_date_obj
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
if transactions.empty?
|
116
|
-
puts "No transactions found to generate balance sheet."
|
117
|
-
return
|
118
|
-
end
|
119
|
-
|
120
|
-
# Create a temporary file
|
121
|
-
require 'tempfile'
|
122
|
-
temp_file = Tempfile.new(['mercury_transactions', ".#{format}"])
|
123
|
-
output_file = temp_file.path
|
124
|
-
|
125
|
-
# Export transactions in the specified format
|
126
|
-
case format
|
127
|
-
when 'ledger'
|
128
|
-
export_to_ledger(transactions, output_file, [], verbose)
|
129
|
-
balance_sheet_output = generate_ledger_balance_sheet(output_file, end_date)
|
130
|
-
when 'beancount'
|
131
|
-
export_to_beancount(transactions, output_file, [], verbose)
|
132
|
-
balance_sheet_output = generate_beancount_balance_sheet(output_file, end_date)
|
133
|
-
else
|
134
|
-
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
135
|
-
temp_file.unlink
|
136
|
-
return
|
137
|
-
end
|
138
|
-
|
139
|
-
# Parse the balance sheet output to extract account balances
|
140
|
-
ledger_balances = parse_balance_sheet_output(balance_sheet_output, format, verbose)
|
141
|
-
|
142
|
-
# Cross-check Mercury balances with ledger balances
|
143
|
-
puts "\n=== Balance Sheet Cross-Check ==="
|
144
|
-
puts "Mercury Account".ljust(30) + "Mercury Balance".ljust(15) + "Ledger Balance".ljust(15) + "Difference"
|
145
|
-
puts "-" * 75
|
146
|
-
|
147
|
-
total_diff = 0
|
148
|
-
mercury_balances.each do |account_name, mercury_balance|
|
149
|
-
# Find the corresponding ledger account (might be prefixed with Assets:)
|
150
|
-
ledger_account_key = ledger_balances.keys.find { |k| k.include?(account_name) }
|
151
|
-
|
152
|
-
# Debug information
|
153
|
-
if verbose
|
154
|
-
puts "Looking for Mercury account '#{account_name}' in ledger accounts:"
|
155
|
-
ledger_balances.keys.each do |k|
|
156
|
-
puts " - #{k} (match: #{k.include?(account_name) ? 'Yes' : 'No'})"
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
ledger_balance = ledger_account_key ? ledger_balances[ledger_account_key] : 0
|
161
|
-
|
162
|
-
# Calculate difference
|
163
|
-
diff = mercury_balance - ledger_balance
|
164
|
-
total_diff += diff.abs
|
165
|
-
|
166
|
-
# Format for display
|
167
|
-
mercury_balance_str = format("$%.2f", mercury_balance)
|
168
|
-
ledger_balance_str = format("$%.2f", ledger_balance)
|
169
|
-
diff_str = format("$%.2f", diff)
|
170
|
-
|
171
|
-
# Add warning marker for differences
|
172
|
-
diff_marker = diff.abs > 0.01 ? " ⚠️" : ""
|
173
|
-
|
174
|
-
puts account_name.ljust(30) + mercury_balance_str.ljust(15) + ledger_balance_str.ljust(15) + diff_str + diff_marker
|
175
|
-
end
|
176
|
-
|
177
|
-
puts "-" * 75
|
178
|
-
puts "Total Discrepancy: #{format("$%.2f", total_diff)}"
|
179
|
-
|
180
|
-
if total_diff > 0.01
|
181
|
-
puts "\n⚠️ Warning: There are discrepancies between Mercury account balances and the ledger balance sheet."
|
182
|
-
puts "This could be due to:"
|
183
|
-
puts " - Transactions not yet recorded in the ledger"
|
184
|
-
puts " - Incorrect categorization of transactions"
|
185
|
-
puts " - Timing differences between when transactions were recorded"
|
186
|
-
else
|
187
|
-
puts "\n✓ Balance sheet matches Mercury account balances."
|
188
|
-
end
|
189
|
-
|
190
|
-
# Save report to file if requested
|
191
|
-
if options[:save_report] && balance_sheet_output
|
192
|
-
full_report = balance_sheet_output + "\n\n" + "=== Balance Sheet Cross-Check ===\n"
|
193
|
-
mercury_balances.each do |account_name, mercury_balance|
|
194
|
-
ledger_account_key = ledger_balances.keys.find { |k| k.include?(account_name) }
|
195
|
-
ledger_balance = ledger_account_key ? ledger_balances[ledger_account_key] : 0
|
196
|
-
diff = mercury_balance - ledger_balance
|
197
|
-
full_report += "#{account_name}: Mercury $#{format("%.2f", mercury_balance)} vs Ledger $#{format("%.2f", ledger_balance)} (Diff: $#{format("%.2f", diff)})\n"
|
198
|
-
end
|
199
|
-
|
200
|
-
File.write(options[:save_report], full_report)
|
201
|
-
puts "\nReport saved to #{options[:save_report]}"
|
202
|
-
end
|
203
|
-
|
204
|
-
# Clean up temporary file
|
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
|
205
65
|
temp_file.unlink
|
66
|
+
return
|
206
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}"
|
207
131
|
end
|
208
132
|
end
|
209
|
-
|
133
|
+
|
210
134
|
desc "incomestatement", "Generate an income statement report"
|
211
135
|
method_option :format, type: :string, default: 'ledger', desc: 'Accounting format to use (ledger or beancount)'
|
212
136
|
method_option :start, type: :string, default: '2020-01-01', desc: 'Start date for transactions (YYYY-MM-DD)'
|
@@ -217,35 +141,35 @@ module MercuryBanking
|
|
217
141
|
# Access the parent class to call with_api_client
|
218
142
|
parent_class = self.class.parent_class
|
219
143
|
parent_instance = parent_class.new
|
220
|
-
|
144
|
+
|
221
145
|
parent_instance.with_api_client do |client|
|
222
146
|
# Get all transactions for the income statement
|
223
147
|
start_date = options[:start]
|
224
148
|
end_date = options[:end]
|
225
149
|
format = options[:format]
|
226
150
|
verbose = options[:verbose]
|
227
|
-
|
151
|
+
|
228
152
|
date_range = "since #{start_date}"
|
229
153
|
date_range += " until #{end_date}" if end_date
|
230
|
-
|
154
|
+
|
231
155
|
puts "Fetching transactions for all accounts #{date_range}..."
|
232
|
-
|
156
|
+
|
233
157
|
transactions = client.get_all_transactions(start_date)
|
234
|
-
|
158
|
+
|
235
159
|
# Filter by end date if specified
|
236
160
|
if end_date
|
237
161
|
end_date_obj = Date.parse(end_date)
|
238
162
|
transactions = transactions.select do |t|
|
239
|
-
transaction_date =
|
163
|
+
transaction_date = Date.parse(t["postedAt"] || t["createdAt"])
|
240
164
|
transaction_date <= end_date_obj
|
241
165
|
end
|
242
166
|
end
|
243
|
-
|
167
|
+
|
244
168
|
# Create a temporary file
|
245
169
|
require 'tempfile'
|
246
170
|
temp_file = Tempfile.new(['mercury_transactions', ".#{format}"])
|
247
171
|
output_file = temp_file.path
|
248
|
-
|
172
|
+
|
249
173
|
# Export transactions in the specified format
|
250
174
|
case format
|
251
175
|
when 'ledger'
|
@@ -257,12 +181,13 @@ module MercuryBanking
|
|
257
181
|
else
|
258
182
|
puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'."
|
259
183
|
temp_file.unlink
|
260
|
-
|
184
|
+
income_statement_output = nil
|
185
|
+
break # Use break instead of return to exit the loop
|
261
186
|
end
|
262
|
-
|
263
|
-
# Display the income statement
|
264
|
-
puts income_statement_output
|
265
|
-
|
187
|
+
|
188
|
+
# Display the income statement if it exists
|
189
|
+
puts income_statement_output if income_statement_output
|
190
|
+
|
266
191
|
# Save the report to a file if requested
|
267
192
|
if options[:save_report]
|
268
193
|
File.open(options[:save_report], 'w') do |file|
|
@@ -270,33 +195,160 @@ module MercuryBanking
|
|
270
195
|
end
|
271
196
|
puts "\nReport saved to #{options[:save_report]}"
|
272
197
|
end
|
273
|
-
|
198
|
+
|
274
199
|
# Clean up the temporary file
|
275
200
|
temp_file.unlink
|
276
201
|
end
|
277
202
|
end
|
278
|
-
|
203
|
+
|
279
204
|
# Store reference to parent class
|
280
205
|
class << self
|
281
206
|
attr_accessor :parent_class
|
282
207
|
end
|
283
208
|
end
|
284
|
-
|
209
|
+
|
285
210
|
# Add financial report commands to the CLI class
|
286
211
|
def self.included(base)
|
287
212
|
base.class_eval do
|
288
213
|
# Register the financials command
|
289
214
|
desc "financials SUBCOMMAND", "Financial reporting commands"
|
290
215
|
subcommand "financials", FinancialsCommand
|
291
|
-
|
216
|
+
|
292
217
|
# Set the parent class for the subcommand
|
293
218
|
FinancialsCommand.parent_class = base
|
294
|
-
|
219
|
+
|
295
220
|
# Remove the old methods with underscores if they exist
|
296
221
|
remove_method :financials_balancesheet if method_defined?(:financials_balancesheet)
|
297
222
|
remove_method :financials_incomestatement if method_defined?(:financials_incomestatement)
|
298
223
|
end
|
299
224
|
end
|
300
225
|
end
|
226
|
+
|
227
|
+
# Module for balance sheet related functionality
|
228
|
+
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
|
+
# Get current balances for all Mercury accounts
|
249
|
+
def get_mercury_balances(accounts)
|
250
|
+
mercury_balances = {}
|
251
|
+
accounts.each do |account|
|
252
|
+
mercury_balances[account['name']] = account['currentBalance']
|
253
|
+
end
|
254
|
+
mercury_balances
|
255
|
+
end
|
256
|
+
|
257
|
+
# Create a temporary file for exporting transactions
|
258
|
+
def create_temp_file(format)
|
259
|
+
require 'tempfile'
|
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
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Display cross-check between Mercury and ledger balances
|
280
|
+
def display_balance_cross_check(mercury_balances, ledger_balances, verbose)
|
281
|
+
puts "\n=== Balance Sheet Cross-Check ==="
|
282
|
+
puts "#{'Mercury Account'.ljust(30)}#{'Mercury Balance'.ljust(15)}#{'Ledger Balance'.ljust(15)}Difference"
|
283
|
+
puts "-" * 75
|
284
|
+
|
285
|
+
total_diff = 0
|
286
|
+
mercury_balances.each do |account_name, mercury_balance|
|
287
|
+
# Find the corresponding ledger account (might be prefixed with Assets:)
|
288
|
+
ledger_account_key = ledger_balances.keys.find { |k| k.include?(account_name) }
|
289
|
+
|
290
|
+
# Debug information
|
291
|
+
if verbose
|
292
|
+
puts "Looking for Mercury account '#{account_name}' in ledger accounts:"
|
293
|
+
ledger_balances.each_key do |k|
|
294
|
+
puts " - #{k} (match: #{k.include?(account_name) ? 'Yes' : 'No'})"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
ledger_balance = ledger_account_key ? ledger_balances[ledger_account_key] : 0
|
299
|
+
|
300
|
+
# Calculate difference
|
301
|
+
diff = mercury_balance - ledger_balance
|
302
|
+
total_diff += diff.abs
|
303
|
+
|
304
|
+
# Format for display
|
305
|
+
mercury_balance_str = format("$%.2f", mercury_balance)
|
306
|
+
ledger_balance_str = format("$%.2f", ledger_balance)
|
307
|
+
diff_str = format("$%.2f", diff)
|
308
|
+
|
309
|
+
# Add warning marker for differences
|
310
|
+
diff_marker = diff.abs > 0.01 ? " ⚠️" : ""
|
311
|
+
|
312
|
+
puts account_name.ljust(30) + mercury_balance_str.ljust(15) + ledger_balance_str.ljust(15) + diff_str + diff_marker
|
313
|
+
end
|
314
|
+
|
315
|
+
puts "-" * 75
|
316
|
+
puts "Total Discrepancy: #{format('$%.2f', total_diff)}"
|
317
|
+
|
318
|
+
if total_diff > 0.01
|
319
|
+
puts "\n⚠️ Warning: There are discrepancies between Mercury account balances and the ledger balance sheet."
|
320
|
+
puts "This could be due to:"
|
321
|
+
puts " - Transactions not yet recorded in the ledger"
|
322
|
+
puts " - Incorrect categorization of transactions"
|
323
|
+
puts " - Timing differences between when transactions were recorded"
|
324
|
+
else
|
325
|
+
puts "\n✓ Balance sheet matches Mercury account balances."
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# Save full report to file
|
330
|
+
def save_full_report(balance_sheet_output, mercury_balances, ledger_balances, save_path)
|
331
|
+
full_report = "#{balance_sheet_output}\n\n=== Balance Sheet Cross-Check ===\n"
|
332
|
+
mercury_balances.each do |account_name, mercury_balance|
|
333
|
+
ledger_account_key = ledger_balances.keys.find { |k| k.include?(account_name) }
|
334
|
+
ledger_balance = ledger_account_key ? ledger_balances[ledger_account_key] : 0
|
335
|
+
diff = mercury_balance - ledger_balance
|
336
|
+
|
337
|
+
# Format the report line with proper line breaks
|
338
|
+
report_line = "#{account_name}: "
|
339
|
+
report_line += "Mercury $#{format('%.2f', mercury_balance)} "
|
340
|
+
report_line += "vs Ledger $#{format('%.2f', ledger_balance)} "
|
341
|
+
report_line += "(Diff: $#{format('%.2f', diff)})\n"
|
342
|
+
|
343
|
+
full_report += report_line
|
344
|
+
end
|
345
|
+
|
346
|
+
File.write(save_path, full_report)
|
347
|
+
puts "\nReport saved to #{save_path}"
|
348
|
+
end
|
349
|
+
end
|
301
350
|
end
|
302
|
-
end
|
351
|
+
end
|
352
|
+
|
353
|
+
# Include the BalanceSheetHelper module in the FinancialsCommand class
|
354
|
+
MercuryBanking::CLI::Financials::FinancialsCommand.include(MercuryBanking::CLI::BalanceSheetHelper)
|