module Gnucash class Account attr_accessor :name attr_accessor :type attr_accessor :id attr_accessor :transactions def initialize(book, node) @book = book @node = node @name = node.xpath('act:name').text @type = node.xpath('act:type').text @id = node.xpath('act:id').text @parent_id = node.xpath('act:parent').text @parent_id = nil if @parent_id == "" @transactions = [] @balances = [] end def full_name prefix = "" if @parent_id parent = @book.find_account_by_id(@parent_id) if parent and parent.type != 'ROOT' prefix = parent.full_name + "::" end end prefix + name end def add_transaction(txn, value) @transactions << { txn: txn, value: value, } end def finalize @transactions.sort! do |a, b| a[:txn].date <=> b[:txn].date end balance = Value.new(0) @balances = @transactions.map do |txn_hash| balance += txn_hash[:value] { date: txn_hash[:txn].date, value: balance, } end end def final_balance return Value.new(0) unless @balances.size > 0 @balances.last[:value] end def balance_on(date) return Value.new(0) unless @balances.size > 0 return Value.new(0) if @balances.first[:date] > date return @balances.last[:value] if date >= @balances.last[:date] imin = 0 imax = @balances.size - 2 idx = imax / 2 until @balances[idx][:date] <= date and @balances[idx + 1][:date] > date if @balances[idx][:date] <= date imin = idx + 1 else imax = idx end idx = (imin + imax) / 2 end @balances[idx][:value] end end end