Class: RockBooks::ChartOfAccounts

Inherits:
Object
  • Object
show all
Defined in:
lib/rock_books/documents/chart_of_accounts.rb

Constant Summary collapse

REQUIRED_FIELDS =
%i(doc_type  title  accounts  entity  start_date  end_date)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_lines, filespec = nil) ⇒ ChartOfAccounts

Returns a new instance of ChartOfAccounts.



24
25
26
27
28
29
30
# 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

Class Method Details

.from_file(filespec) ⇒ Object



14
15
16
# 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) ⇒ Object



19
20
21
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 19

def self.from_string(string)
  self.new(string.split("\n"))
end

Instance Method Details

#==(other) ⇒ Object



173
174
175
176
177
178
179
180
# 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) ⇒ Object



109
110
111
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 109

def (type)
  accounts_of_type(type).map(&:code)
end

#account_for_code(code) ⇒ Object



139
140
141
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 139

def (code)
  accounts.detect { |a| a.code == code }
end

#accounts_of_type(type) ⇒ Object



104
105
106
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 104

def accounts_of_type(type)
  accounts.select { || .type == type }
end

#check_for_missing_fieldsObject



33
34
35
36
37
38
39
40
41
# 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) ⇒ Object



161
162
163
164
165
166
167
168
169
170
# 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) ⇒ Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 114

def include?(candidate_code)
  accounts.any? { || .code == candidate_code }
end

#included_in_period?(date) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
# 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_lengthObject



156
157
158
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 156

def 
  @max_account_code_length ||= accounts.map { |a| a.code.length }.max
end

#name_for_code(code) ⇒ Object



150
151
152
153
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 150

def name_for_code(code)
  found = (code)
  found ? found.name : nil
end

#parse_date(date_string) ⇒ Object



57
58
59
60
61
62
63
64
# 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) ⇒ Object



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
# 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+(.*)$/)

       = matcher[1]
       = AccountType.letter_to_type()

      name = matcher[2]

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

end

#parse_lines(input_lines) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
# 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_stringObject



124
125
126
127
128
129
130
131
132
133
134
135
136
# 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) ⇒ Object



144
145
146
147
# File 'lib/rock_books/documents/chart_of_accounts.rb', line 144

def type_for_code(code)
  found = (code)
  found ? found.type : nil
end