class RockBooks::ChartOfAccounts

Constants

REQUIRED_FIELDS

Public Class Methods

from_file(filespec) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 14
def self.from_file(filespec)
  self.new(File.readlines(filespec).map(&:chomp), filespec)
end
from_string(string) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 19
def self.from_string(string)
  self.new(string.split("\n"))
end
new(input_lines, filespec = nil) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 24
def initialize(input_lines, filespec = nil)
  @filespec = filespec
  @accounts = []
  parse_lines(input_lines)
  # TODO: Add validation for required fields.
  check_for_missing_fields
end

Public Instance Methods

==(other) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 173
def ==(other)
  doc_type   == other.doc_type   && \
  title      == other.title      && \
  accounts   == other.accounts   && \
  entity     == other.entity     && \
  start_date == other.start_date && \
  end_date   == other.end_date
end
account_codes_of_type(type) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 109
def account_codes_of_type(type)
  accounts_of_type(type).map(&:code)
end
account_for_code(code) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 139
def account_for_code(code)
  accounts.detect { |a| a.code == code }
end
accounts_of_type(type) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 104
def accounts_of_type(type)
  accounts.select { |account| account.type == type }
end
check_for_missing_fields() click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 33
def check_for_missing_fields
  missing_fields = REQUIRED_FIELDS.select do |field|
    instance_variable_get("@#{field}").nil?
  end

  unless missing_fields.empty?
    raise Error.new("Chart of accounts lacks required fields: #{missing_fields.join(', ')}")
  end
end
debit_or_credit_for_code(code) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 161
def debit_or_credit_for_code(code)
  type = type_for_code(code)
  if %i(asset  expense).include?(type)
    :debit
  elsif %i(liability  equity  income).include?(type)
    :credit
  else
    raise "Unexpected type #{type} for code #{code}."
  end
end
include?(candidate_code) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 114
def include?(candidate_code)
  accounts.any? { |account| account.code == candidate_code }
end
included_in_period?(date) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 119
def included_in_period?(date)
  (start_date..end_date).include?(date)
end
max_account_code_length() click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 156
def max_account_code_length
  @max_account_code_length ||= accounts.map { |a| a.code.length }.max
end
name_for_code(code) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 150
def name_for_code(code)
  found = account_for_code(code)
  found ? found.name : nil
end
parse_date(date_string) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 57
def parse_date(date_string)
  # TODO: Add better handling for this error.
  # begin
    date = Date.iso8601(date_string)
  # rescue ArgumentError
  #  ..
  # end
end
parse_line(line) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 66
def parse_line(line)
  begin
    case line.strip
    when /^@doc_type:/
      @doc_type = line.split('@doc_type:').last.strip
    when /^@entity:/
      @entity ||= line.split('@entity:').last.strip
    when /^@title:/
      @title = line.split('@title:').last.strip
    when /^@start_date:/
      @start_date = parse_date(line.split('@start_date:').last.strip)
    when /^@end_date:/
      @end_date = parse_date(line.split('@end_date:').last.strip)
    when /^$/
      # ignore empty line
    when /^#/
      # ignore comment line
    else
      # this is an account line in the form: 101 Asset First National City Bank
      # The regex below gets everything before the first whitespace in token 1, and the rest in token 2.
      matcher = line.match(/^(\S+)\s+(.*)$/)
      code = matcher[1]
      rest = matcher[2]

      matcher = rest.match(/^(\S+)\s+(.*)$/)

      account_type_token = matcher[1]
      account_type = AccountType.letter_to_type(account_type_token)

      name = matcher[2]

      accounts << Account.new(code, account_type.symbol, name)
    end
  end

end
parse_lines(input_lines) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 44
def parse_lines(input_lines)
  input_lines.each_with_index do |line, line_num|
    begin
      parse_line(line)
    rescue => e
      file_message_fragment = (@filespec ? " in file '#{@filespec}'" : '')
      puts "Error parsing chart of accounts#{file_message_fragment}. Bad line is line ##{line_num}, text is:\n#{line}\n\n"
      raise
    end
  end
end
report_string() click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 124
def report_string
  result = StringIO.new

  if title
    result << title << "\n\n"
  end

  code_width = @accounts.inject(0) { |width, a| width = [width, a.code.length].max }
  format_string = "%-#{code_width}s  %-10.10s  %s\n"
  accounts.each { |a| result << sprintf(format_string, a.code, a.type.to_s, a.name) }

  result.string
end
type_for_code(code) click to toggle source
# File lib/rock_books/documents/chart_of_accounts.rb, line 144
def type_for_code(code)
  found = account_for_code(code)
  found ? found.type : nil
end