class SimplefinAccount::Processor attr_reader :simplefin_account def initialize(simplefin_account) @simplefin_account = simplefin_account end def process ensure_account_exists process_transactions end private def ensure_account_exists return if simplefin_account.account.present? account = Account.create_from_simplefin_account(simplefin_account) simplefin_account.update!(account: account) end def process_transactions return unless simplefin_account.raw_transactions_payload.present? account = simplefin_account.account transactions_data = simplefin_account.raw_transactions_payload transactions_data.each do |transaction_data| process_transaction(account, transaction_data) end end def process_transaction(account, transaction_data) # Convert SimpleFin transaction to internal Transaction format amount_cents = parse_amount(transaction_data[:amount], account.currency) posted_date = parse_date(transaction_data[:posted]) transaction_attributes = { account: account, name: transaction_data[:description] || "Unknown transaction", amount: Money.new(amount_cents, account.currency), date: posted_date, currency: account.currency, raw_data: transaction_data } # Use external ID to prevent duplicates external_id = "simplefin_#{transaction_data[:id]}" Transaction.find_or_create_by(external_id: external_id) do |transaction| transaction.assign_attributes(transaction_attributes) end rescue => e Rails.logger.error("Failed to process SimpleFin transaction #{transaction_data[:id]}: #{e.message}") # Don't fail the entire sync for one bad transaction end def parse_amount(amount_value, currency) case amount_value when String (BigDecimal(amount_value) * 100).to_i when Numeric (amount_value * 100).to_i else 0 end rescue ArgumentError 0 end def parse_date(date_value) case date_value when String Date.parse(date_value) when Integer # Unix timestamp Time.at(date_value).to_date else Date.current end rescue ArgumentError, TypeError Date.current end end