Module: MercuryBanking::CLI::Transactions
- Included in:
- Main
- Defined in:
- lib/mercury_banking/cli/transactions.rb
Overview
Module for transaction-related commands
Class Method Summary collapse
-
.included(base) ⇒ Object
Add transaction-related commands to the CLI class.
Class Method Details
.included(base) ⇒ Object
Add transaction-related commands to the CLI class
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/mercury_banking/cli/transactions.rb', line 8 def self.included(base) base.class_eval do include MercuryBanking::Formatters::ExportFormatter desc 'transactions_download', 'Download all Mercury transactions as CSV files' method_option :output_dir, type: :string, default: 'transactions', desc: 'Directory to save transaction files' method_option :start_date, type: :string, default: '2020-01-01', desc: 'Start date for transactions (YYYY-MM-DD)' method_option :end_date, type: :string, desc: 'End date for transactions (YYYY-MM-DD)' method_option :format, type: :string, default: 'csv', enum: %w[csv beancount ledger all], desc: 'Output format (csv, beancount, ledger, or all)' method_option :verbose, type: :boolean, default: false, desc: 'Show detailed debug information' def transactions_download with_api_client do |client| # Create output directory if it doesn't exist output_dir = [:output_dir] FileUtils.mkdir_p(output_dir) # Get all accounts accounts = client.accounts # Get start and end dates start_date = [:start_date] end_date = [:end_date] # Get format format = [:format] || 'all' # Get verbose option verbose = [:verbose] # For each account, get transactions and save to file accounts.each do |account| account_id = account["id"] account_name = account["name"] account_number = account["accountNumber"] puts "Fetching transactions for #{account_name} (#{account_id})..." # Get all transactions for this account transactions = client.get_transactions(account_id, start_date) # Add account information to each transaction transactions.each do |transaction| transaction["accountName"] = account_name transaction["accountId"] = account_id transaction["accountNumber"] = account_number end # 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 #{account_name}." next end # Group transactions by month transactions_by_month = {} transactions.each do |t| # Get the month from the transaction date date = Date.parse(t["postedAt"] || t["createdAt"]) month_key = "#{date.year}-#{date.month.to_s.rjust(2, '0')}" # Initialize the month array if it doesn't exist transactions_by_month[month_key] ||= [] # Add the transaction to the month array transactions_by_month[month_key] << t end # For each month, save transactions to file transactions_by_month.each do |month, month_transactions| # Use the full account number for the filename account_number = account["accountNumber"] # Create filenames for different formats csv_filename = File.join(output_dir, "#{month}-Mercury-#{account_number}.csv") beancount_filename = File.join(output_dir, "#{month}-Mercury-#{account_number}.beancount") ledger_filename = File.join(output_dir, "#{month}-Mercury-#{account_number}.ledger") # Export transactions in the requested format case format when 'csv' export_to_csv(month_transactions, csv_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{csv_filename}" when 'beancount' export_to_beancount(month_transactions, beancount_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{beancount_filename}" when 'ledger' export_to_ledger(month_transactions, ledger_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{ledger_filename}" when 'all' export_to_csv(month_transactions, csv_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{csv_filename}" export_to_beancount(month_transactions, beancount_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{beancount_filename}" export_to_ledger(month_transactions, ledger_filename, [], verbose) puts "Exported #{month_transactions.size} transactions to #{ledger_filename}" end end end puts "\nTransaction export complete. Files saved to #{output_dir}/ directory." end end desc "transactions ACCOUNT_ID_OR_NUMBER", "List transactions for an account with their status" method_option :limit, type: :numeric, default: 10, desc: "Number of transactions to show" method_option :start, type: :string, desc: "Start date (YYYY-MM-DD)" method_option :end, type: :string, desc: "End date (YYYY-MM-DD)" method_option :status, type: :string, desc: "Filter by status (pending, sent, complete, failed)" method_option :json, type: :boolean, default: false, desc: "Output in JSON format" method_option :csv, type: :string, desc: "Export to CSV file" def transactions(account_id_or_number) with_api_client do |client| # Find the account by ID or account number account = find_account(client, account_id_or_number) if account.nil? puts "Account not found: #{account_id_or_number}" return end account_id = account["id"] # Get transactions with optional date filters start_date = [:start] end_date = [:end] puts "Fetching transactions for #{account['name']}..." transactions = client.get_transactions(account_id, start_date) # Add account information to each transaction transactions.each do |transaction| transaction["accountName"] = account["name"] transaction["accountId"] = account["id"] transaction["accountNumber"] = account["accountNumber"] end # 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 # Filter by status if specified transactions = transactions.select { |t| t["status"] == [:status] } if [:status] # Limit the number of transactions limit = [:limit] transactions = transactions.take(limit) if limit.positive? # Export to CSV if requested if [:csv] export_to_csv(transactions, [:csv]) puts "Exported #{transactions.size} transactions to #{[:csv]}" return end # Output in JSON format if requested if [:json] puts JSON.pretty_generate(transactions) return end # Create a table for display table = Terminal::Table.new table.title = "Transactions for #{account['name']}" table.headings = %w[Date Description Amount Status] transactions.each do |t| date = Date.parse(t["postedAt"] || t["createdAt"]) description = t["bankDescription"] || t["externalMemo"] || "Unknown" amount = t["amount"] status = t["status"] table.add_row [date, description, "$#{amount}", status] end puts table end end # Helper methods that should not be exposed as commands no_commands do # Helper method to sort transactions chronologically def sort_transactions_chronologically(transactions) transactions.sort_by do |t| # Use postedAt if available, otherwise fall back to createdAt = t["postedAt"] || t["createdAt"] Time.parse() end end # Helper method to find an account by ID or account number def find_account(client, account_id_or_number) accounts = client.accounts # Try to find by ID first account = accounts.find { |a| a["id"] == account_id_or_number } # If not found by ID, try by account number account = accounts.find { |a| a["accountNumber"] == account_id_or_number } if account.nil? # If still not found, try by the last 4 digits of the account number account = accounts.find { |a| a["accountNumber"]&.end_with?(account_id_or_number) } if account.nil? account end end end end |