Module: MercuryBanking::Reports::Reconciliation
- Defined in:
- lib/mercury_banking/reports/reconciliation.rb
Overview
Module for reconciliation between ledger and Mercury balances
Instance Method Summary collapse
-
#generate_reconciliation_report(client, account_name, start_date, end_date = nil, format = 'ledger') ⇒ Object
Generate a reconciliation report to identify when balances diverged.
Instance Method Details
#generate_reconciliation_report(client, account_name, start_date, end_date = nil, format = 'ledger') ⇒ Object
Generate a reconciliation report to identify when balances diverged
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/mercury_banking/reports/reconciliation.rb', line 8 def generate_reconciliation_report(client, account_name, start_date, end_date = nil, format = 'ledger') puts "Generating reconciliation report for #{account_name} from #{start_date} to #{end_date || 'present'}..." # Find the account by name account = find_account_by_name(client, account_name) return unless account # Get current balance from Mercury current_mercury_balance = account['currentBalance'] # Get all transactions for the account transactions = get_account_transactions(client, account['id'], start_date) # Filter by end date if specified if end_date end_date_obj = Date.parse(end_date) transactions = transactions.select do |t| transaction_date = Date.parse(t["postedAt"] || t["createdAt"]) transaction_date <= end_date_obj end end if transactions.empty? puts "No transactions found for reconciliation." return end # Sort transactions by date transactions = sort_transactions_by_date(transactions) # Group transactions by month for easier analysis monthly_transactions = group_transactions_by_month(transactions) # Create a temporary file for ledger export require 'tempfile' temp_file = Tempfile.new(['mercury_reconciliation', ".#{format}"]) output_file = temp_file.path # Export all transactions to the ledger file case format when 'ledger' export_to_ledger(transactions, output_file, [], false) when 'beancount' export_to_beancount(transactions, output_file, [], false) else puts "Unsupported format: #{format}. Please use 'ledger' or 'beancount'." temp_file.unlink return end # Analyze each month to find when divergence occurred puts "\n=== Monthly Reconciliation Analysis ===" puts "#{'Period'.ljust(15)}#{'Mercury Balance'.ljust(20)}#{'Ledger Balance'.ljust(20)}#{'Difference'.ljust(15)}Status" puts "-" * 80 # Initialize variables for tracking divergence_point = nil monthly_data = [] monthly_transactions.each do |month, month_transactions| # Calculate the Mercury balance at the end of this month last_transaction = month_transactions.last last_date = Date.parse(last_transaction["postedAt"] || last_transaction["createdAt"]) # Get ledger balance for this month month_end_date = last_date.strftime("%Y-%m-%d") ledger_balance = get_ledger_balance_at_date(output_file, month_end_date, account_name, format) # Calculate Mercury balance at this point in time # This is an approximation based on current balance and subsequent transactions mercury_balance_at_month_end = calculate_mercury_balance_at_date(current_mercury_balance, transactions, last_date) # Calculate difference difference = mercury_balance_at_month_end - ledger_balance # Determine status status = difference.abs < 0.01 ? "✓ Balanced" : "⚠️ Diverged" # Record the first divergence point divergence_point = month if difference.abs >= 0.01 && divergence_point.nil? # Format for display month_str = month mercury_balance_str = format("$%.2f", mercury_balance_at_month_end) ledger_balance_str = format("$%.2f", ledger_balance) difference_str = format("$%.2f", difference) puts month_str.ljust(15) + mercury_balance_str.ljust(20) + ledger_balance_str.ljust(20) + difference_str.ljust(15) + status monthly_data << { period: month, mercury_balance: mercury_balance_at_month_end, ledger_balance: ledger_balance, difference: difference, status: status } end puts "-" * 80 # If divergence was found, analyze the specific month in more detail if divergence_point puts "\n=== Detailed Analysis of Divergence Point: #{divergence_point} ===" # Get transactions for the divergence month divergence_month_transactions = monthly_transactions[divergence_point] # Check for pending or failed transactions pending_transactions = divergence_month_transactions.reject { |t| t["status"] == "posted" } if pending_transactions.any? puts "\nPotential issues found: #{pending_transactions.count} transactions with non-posted status" puts "\nTransactions with non-posted status:" pending_transactions.each do |t| date = t["postedAt"] ? Time.parse(t["postedAt"]).strftime("%Y-%m-%d") : Time.parse(t["createdAt"]).strftime("%Y-%m-%d") amount = format("$%.2f", t["amount"]) description = t["bankDescription"] || t["externalMemo"] || "Unknown transaction" status = t["status"] puts "#{date} | #{amount} | #{status.upcase} | #{description}" end end # Check for transactions on the same day with opposite amounts (potential duplicates or corrections) potential_corrections = find_potential_corrections(divergence_month_transactions) if potential_corrections.any? puts "\nPotential corrections or duplicates found:" potential_corrections.each do |pair| t1, t2 = pair date1 = t1["postedAt"] ? Time.parse(t1["postedAt"]).strftime("%Y-%m-%d") : Time.parse(t1["createdAt"]).strftime("%Y-%m-%d") date2 = t2["postedAt"] ? Time.parse(t2["postedAt"]).strftime("%Y-%m-%d") : Time.parse(t2["createdAt"]).strftime("%Y-%m-%d") puts "#{date1} | #{format('$%.2f', t1['amount'])} | #{t1['bankDescription'] || t1['externalMemo'] || 'Unknown'}" puts "#{date2} | #{format('$%.2f', t2['amount'])} | #{t2['bankDescription'] || t2['externalMemo'] || 'Unknown'}" puts "-" * 50 end end end # Clean up temporary file temp_file.unlink monthly_data end |