rock_books 0.4.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -2
  3. data/RELEASE_NOTES.md +33 -0
  4. data/assets/fonts/JetBrainsMono-Medium.ttf +0 -0
  5. data/lib/rock_books/cmd_line/command_line_interface.rb +6 -6
  6. data/lib/rock_books/cmd_line/main.rb +1 -9
  7. data/lib/rock_books/documents/book_set.rb +4 -136
  8. data/lib/rock_books/documents/chart_of_accounts.rb +29 -12
  9. data/lib/rock_books/documents/journal.rb +2 -6
  10. data/lib/rock_books/documents/journal_entry.rb +7 -2
  11. data/lib/rock_books/documents/journal_entry_builder.rb +4 -0
  12. data/lib/rock_books/helpers/book_set_loader.rb +3 -3
  13. data/lib/rock_books/reports/balance_sheet.rb +9 -43
  14. data/lib/rock_books/reports/book_set_reporter.rb +207 -0
  15. data/lib/rock_books/reports/data/bs_is_data.rb +61 -0
  16. data/lib/rock_books/reports/data/bs_is_section_data.rb +28 -0
  17. data/lib/rock_books/reports/data/journal_data.rb +37 -0
  18. data/lib/rock_books/reports/data/multidoc_txn_by_account_data.rb +40 -0
  19. data/lib/rock_books/reports/data/multidoc_txn_report_data.rb +39 -0
  20. data/lib/rock_books/reports/data/receipts_report_data.rb +47 -0
  21. data/lib/rock_books/reports/data/tx_one_account_data.rb +37 -0
  22. data/lib/rock_books/reports/helpers/erb_helper.rb +21 -0
  23. data/lib/rock_books/reports/helpers/html_report_helper.rb +35 -0
  24. data/lib/rock_books/reports/helpers/text_report_helper.rb +134 -0
  25. data/lib/rock_books/reports/income_statement.rb +9 -47
  26. data/lib/rock_books/reports/journal_report.rb +72 -0
  27. data/lib/rock_books/reports/multidoc_txn_by_account_report.rb +32 -0
  28. data/lib/rock_books/reports/multidoc_txn_report.rb +25 -0
  29. data/lib/rock_books/reports/receipts_report.rb +6 -55
  30. data/lib/rock_books/reports/templates/html/index.html.erb +141 -0
  31. data/lib/rock_books/reports/templates/html/report_page.html.erb +12 -0
  32. data/lib/rock_books/reports/templates/text/_receipt_section.txt.erb +17 -0
  33. data/lib/rock_books/reports/templates/text/_totals.txt.erb +8 -0
  34. data/lib/rock_books/reports/templates/text/balance_sheet.txt.erb +21 -0
  35. data/lib/rock_books/reports/templates/text/income_statement.txt.erb +21 -0
  36. data/lib/rock_books/reports/templates/text/journal.txt.erb +20 -0
  37. data/lib/rock_books/reports/templates/text/multidoc_txn_by_account_report.txt.erb +28 -0
  38. data/lib/rock_books/reports/templates/text/multidoc_txn_report.txt.erb +22 -0
  39. data/lib/rock_books/reports/templates/text/receipts_report.txt.erb +13 -0
  40. data/lib/rock_books/reports/templates/text/tx_one_account.txt.erb +18 -0
  41. data/lib/rock_books/reports/tx_one_account.rb +10 -45
  42. data/lib/rock_books/types/account.rb +13 -1
  43. data/lib/rock_books/types/account_type.rb +18 -7
  44. data/lib/rock_books/version.rb +1 -1
  45. data/rock_books.gemspec +5 -3
  46. metadata +64 -16
  47. data/lib/rock_books/documents/index.html.erb +0 -156
  48. data/lib/rock_books/documents/receipts.html.erb +0 -54
  49. data/lib/rock_books/reports/multidoc_transaction_report.rb +0 -66
  50. data/lib/rock_books/reports/reporter.rb +0 -118
  51. data/lib/rock_books/reports/transaction_report.rb +0 -105
  52. data/lib/rock_books/reports/tx_by_account.rb +0 -82
@@ -1,54 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <body>
4
-
5
- <h1><%= chart_of_accounts.entity %> -- Receipts</h1>
6
- <p>Reports Generated at <%= DateTime.now.strftime('%Y-%m-%d_%H-%M-%S') %> by RockBooks version <%=RockBooks::VERSION %></p>
7
- <br />
8
-
9
- <% receipts.each %>
10
- <h2>Financial Statements</h2>
11
- <ul>
12
- <li><a href='balance_sheet.html'>Balance Sheet</a></li>
13
- <li><a href='income_statement.html'>Income Statement</a></li>
14
- </ul>
15
-
16
- <h2>All Transactions</h2>
17
- <ul>
18
- <li><a href="all_txns_by_acct.html">By Account</a></li>
19
- <li><a href="all_txns_by_amount.html">By Amount</a></li>
20
- <li><a href="all_txns_by_date.html">By Date</a></li>
21
- </ul>
22
-
23
- <h2>Journals</h2>
24
- <ul>
25
- <% journals.each do |journal|
26
- filespec = journal.short_name + '.html'
27
- caption = "#{journal.title} -- #{journal.short_name} -- #{journal.account_code}"
28
- %>
29
- <li><a href="<%= filespec %>"><%= caption %></a></li>
30
- <% end %>
31
- </ul>
32
-
33
- <h2>Individual Accounts</h2>
34
- <ul>
35
-
36
- <%
37
- chart_of_accounts.accounts.each do |account|
38
- filespec = File.join('single-account', "acct_#{account.code}.html")
39
- caption = "#{account.name} (#{account.code})"
40
- %>
41
- <li><a href="<%= filespec %>"><%= caption %></a></li>
42
- <% end %>
43
- </ul>
44
-
45
-
46
- <h2>Receipts</h2>
47
- <ul>
48
- <% if run_options.do_receipts %>
49
- <li><a href="receipts.html">Missing and Existing Receipts</a></li>
50
- <% end %>
51
- </ul>
52
-
53
- </body>
54
- </html>
@@ -1,66 +0,0 @@
1
- require_relative '../documents/journal'
2
- require_relative 'reporter'
3
- require_relative 'report_context'
4
-
5
- module RockBooks
6
-
7
- class MultidocTransactionReport
8
-
9
- include Reporter
10
-
11
- attr_accessor :context
12
-
13
- SORT_BY_VALID_OPTIONS = %i(date_and_account amount)
14
-
15
- def initialize(report_context)
16
- @context = report_context
17
- end
18
-
19
-
20
- def generate_header(sort_by)
21
- lines = [banner_line]
22
- lines << center(context.entity || 'Unspecified Entity')
23
- lines << center('Multi Document Transaction Report')
24
- lines << center('Sorted by Amount Descending') if sort_by == :amount
25
- lines << ''
26
- lines << center('Source Documents:')
27
- lines << ''
28
- context.journals.each do |document|
29
- short_name = SHORT_NAME_FORMAT_STRING % document.short_name
30
- lines << center("#{short_name} -- #{document.title}")
31
- end
32
- lines << banner_line
33
- lines << ''
34
- lines << ' Date Document Amount Account'
35
- lines << ' ---- -------- ------ -------'
36
- lines.join("\n") << "\n\n"
37
- end
38
-
39
-
40
- def generate_report(filter = nil, sort_by = :date_and_account)
41
- unless SORT_BY_VALID_OPTIONS.include?(sort_by)
42
- raise Error.new("sort_by option '#{sort_by}' not in valid choices of #{SORT_BY_VALID_OPTIONS}.")
43
- end
44
-
45
- entries = Journal.entries_in_documents(context.journals, filter)
46
-
47
- if sort_by == :amount
48
- JournalEntry.sort_entries_by_amount_descending!(entries)
49
- end
50
-
51
- sio = StringIO.new
52
- sio << generate_header(sort_by)
53
- entries.each { |entry| sio << format_multidoc_entry(entry) << "\n" }
54
-
55
- totals = AcctAmount.aggregate_amounts_by_account(JournalEntry.entries_acct_amounts(entries))
56
- sio << generate_and_format_totals('Totals', totals)
57
-
58
- sio << "\n"
59
- sio.string
60
- end
61
-
62
-
63
- alias_method :to_s, :generate_report
64
- alias_method :call, :generate_report
65
- end
66
- end
@@ -1,118 +0,0 @@
1
- require_relative '../documents/journal_entry'
2
-
3
- module RockBooks
4
- module Reporter
5
-
6
- module_function
7
-
8
- SHORT_NAME_MAX_LENGTH = 16
9
-
10
- SHORT_NAME_FORMAT_STRING = "%#{SHORT_NAME_MAX_LENGTH}.#{SHORT_NAME_MAX_LENGTH}s"
11
-
12
-
13
- def page_width
14
- context.page_width || 80
15
- end
16
-
17
-
18
- def format_account_code(code)
19
- "%*.*s" % [max_account_code_length, max_account_code_length, code]
20
- end
21
-
22
-
23
- def account_code_name_type_string(account)
24
- "#{account.code} -- #{account.name} (#{account.type.to_s.capitalize})"
25
- end
26
-
27
-
28
- def format_amount(amount)
29
- "%9.2f" % amount
30
- end
31
-
32
-
33
- # e.g. " 117.70 tr.mileage Travel - Mileage Allowance"
34
- def format_acct_amount(acct_amount)
35
- "%s %s %s" % [
36
- format_amount(acct_amount.amount),
37
- format_account_code(acct_amount.code),
38
- context.chart_of_accounts.name_for_code(acct_amount.code)
39
- ]
40
- end
41
-
42
-
43
- def banner_line
44
- @banner_line ||= '-' * page_width
45
- end
46
-
47
-
48
- def center(string)
49
- indent = (page_width - string.length) / 2
50
- indent = 0 if indent < 0
51
- (' ' * indent) + string
52
- end
53
-
54
-
55
- def max_account_code_length
56
- @max_account_code_length ||= context.chart_of_accounts.max_account_code_length
57
- end
58
-
59
-
60
- def generate_and_format_totals(section_caption, totals)
61
- output = section_caption
62
- output << "\n#{'-' * section_caption.length}\n\n"
63
- format_string = "%12.2f %-#{context.chart_of_accounts.max_account_code_length}s %s\n"
64
- totals.keys.sort.each do |account_code|
65
- account_name = context.chart_of_accounts.name_for_code(account_code)
66
- account_total = totals[account_code]
67
- output << format_string % [account_total, account_code, account_name]
68
- end
69
-
70
- output << "------------\n"
71
- output << "%12.2f\n" % totals.values.sum.round(2)
72
- output
73
- end
74
-
75
-
76
- def generate_account_type_section(section_caption, totals, section_type, need_to_reverse_sign)
77
- account_codes_this_section = context.chart_of_accounts.account_codes_of_type(section_type)
78
-
79
- totals_this_section = totals.select do |account_code, _amount|
80
- account_codes_this_section.include?(account_code)
81
- end
82
-
83
- if need_to_reverse_sign
84
- totals_this_section.each { |code, amount| totals_this_section[code] = -amount }
85
- end
86
-
87
- section_total_amount = totals_this_section.map { |aa| aa.last }.sum
88
-
89
- output = generate_and_format_totals(section_caption, totals_this_section)
90
- [ output, section_total_amount ]
91
- end
92
-
93
-
94
- def format_multidoc_entry(entry)
95
- acct_amounts = entry.acct_amounts
96
-
97
- # "2017-10-29 hsbc_visa":
98
- output = entry.date.to_s << ' ' << (SHORT_NAME_FORMAT_STRING % entry.doc_short_name) << ' '
99
-
100
- indent = ' ' * output.length
101
-
102
- output << format_acct_amount(acct_amounts.first) << "\n"
103
-
104
- acct_amounts[1..-1].each do |acct_amount|
105
- output << indent << format_acct_amount(acct_amount) << "\n"
106
- end
107
-
108
- if entry.description && entry.description.length > 0
109
- output << entry.description
110
- end
111
-
112
- output
113
- end
114
-
115
- end
116
- end
117
-
118
-
@@ -1,105 +0,0 @@
1
- require_relative 'reporter'
2
- require_relative 'report_context'
3
-
4
- module RockBooks
5
-
6
- class TransactionReport
7
-
8
- include Reporter
9
-
10
- attr_accessor :journal, :context
11
-
12
-
13
- def initialize(journal, report_context)
14
- @journal = journal
15
- @context = report_context
16
- end
17
-
18
-
19
- def generate_header
20
-
21
- code = journal.account_code
22
- name = journal.chart_of_accounts.name_for_code(code)
23
- title = "Transactions for Account ##{code} -- #{name}"
24
-
25
- lines = [banner_line]
26
- lines << center(context.entity || 'Unspecified Entity')
27
- lines << center(journal.title) if journal.title && journal.title.length > 0
28
- lines << center(title)
29
- lines << banner_line
30
- lines << ''
31
- lines << ''
32
- lines << ''
33
- lines.join("\n")
34
- end
35
-
36
-
37
- def format_entry_first_acct_amount(entry)
38
- entry.date.to_s \
39
- << ' ' \
40
- << format_acct_amount(entry.acct_amounts.last) \
41
- << "\n"
42
- end
43
-
44
-
45
- # Formats an entry like this, with entry description added on additional line(s) if it exists:
46
- # 2018-05-21 $120.00 701 Office Supplies
47
- def format_entry_no_split(entry)
48
- output = format_entry_first_acct_amount(entry)
49
-
50
- if entry.description && entry.description.length > 0
51
- output << entry.description
52
- end
53
- output
54
- end
55
-
56
-
57
- # Formats an entry like this, with entry description added on additional line(s) if it exists::
58
- # 2018-05-21 $120.00 95.00 701 Office Supplies
59
- # 25.00 751 Gift to Customer
60
- def format_entry_with_split(entry)
61
- output = format_entry_first_acct_amount(entry)
62
- indent = ' ' * 12
63
-
64
- entry.acct_amounts[1..-1].each do |acct_amount|
65
- output << indent << format_acct_amount(acct_amount) << "\n"
66
- end
67
-
68
- if entry.description && entry.description.length > 0
69
- output << entry.description
70
- end
71
- end
72
-
73
-
74
- def format_entry(entry)
75
- if entry.acct_amounts.size > 2
76
- format_entry_with_split(entry)
77
- else
78
- format_entry_no_split(entry)
79
- end
80
- end
81
-
82
-
83
- def generate_report(filter = nil)
84
- sio = StringIO.new
85
- sio << generate_header
86
-
87
- entries = journal.entries
88
- if filter
89
- entries = entries.select { |entry| filter.(entry) }
90
- end
91
-
92
- entries.each do |entry|
93
- sio << format_entry(entry) << "\n"
94
- end
95
- totals = AcctAmount.aggregate_amounts_by_account(JournalEntry.entries_acct_amounts(entries))
96
- sio << generate_and_format_totals('Totals', totals)
97
- sio.string
98
- end
99
-
100
-
101
- alias_method :to_s, :generate_report
102
- alias_method :call, :generate_report
103
- end
104
-
105
- end
@@ -1,82 +0,0 @@
1
- require_relative '../documents/chart_of_accounts'
2
- require_relative '../documents/journal'
3
- require_relative 'reporter'
4
- require_relative 'report_context'
5
-
6
- module RockBooks
7
-
8
- class TxByAccount
9
-
10
- include Reporter
11
-
12
- attr_accessor :context
13
-
14
-
15
- def initialize(report_context)
16
- @context = report_context
17
- end
18
-
19
-
20
- def generate_header
21
- lines = [banner_line]
22
- lines << center(context.entity || 'Unspecified Entity')
23
- lines << center("Transactions by Account")
24
- lines << banner_line
25
- lines << ''
26
- lines << ''
27
- lines << ''
28
- lines.join("\n")
29
- end
30
-
31
-
32
- def account_header(account, account_total)
33
- total_string = "%.2f" % account_total
34
- title = "Total: #{total_string} -- #{account_code_name_type_string(account)}"
35
-
36
- <<~HEREDOC
37
- #{banner_line}
38
- #{center(title)}
39
- #{banner_line}
40
-
41
- HEREDOC
42
- end
43
-
44
-
45
- def account_total_line(account_code, account_total)
46
- account_name = context.chart_of_accounts.name_for_code(account_code)
47
- "%.2f Total for account: %s - %s" % [account_total, account_code, account_name]
48
- end
49
-
50
-
51
- def generate_report
52
- output = generate_header
53
-
54
- all_entries = Journal.entries_in_documents(context.journals)
55
-
56
- context.chart_of_accounts.accounts.each do |account|
57
- code = account.code
58
- account_entries = JournalEntry.entries_containing_account_code(all_entries, code)
59
- account_total = JournalEntry.total_for_code(account_entries, code)
60
- output << account_header(account, account_total)
61
-
62
- account_entries.each do |entry|
63
- output << format_multidoc_entry(entry) << "\n"
64
- output << "\n" if entry.description && entry.description.length > 0
65
- end
66
- output << account_total_line(code, account_total) << "\n"
67
- output << "\n\n\n"
68
- end
69
-
70
- totals = AcctAmount.aggregate_amounts_by_account(JournalEntry.entries_acct_amounts(all_entries))
71
- output << generate_and_format_totals('Totals', totals)
72
-
73
- output
74
- end
75
-
76
- alias_method :to_s, :generate_report
77
- alias_method :call, :generate_report
78
-
79
-
80
- end
81
-
82
- end