rock_books 0.4.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/RELEASE_NOTES.md +33 -0
- data/assets/fonts/JetBrainsMono-Medium.ttf +0 -0
- data/lib/rock_books/cmd_line/command_line_interface.rb +6 -6
- data/lib/rock_books/cmd_line/main.rb +1 -9
- data/lib/rock_books/documents/book_set.rb +4 -136
- data/lib/rock_books/documents/chart_of_accounts.rb +29 -12
- data/lib/rock_books/documents/journal.rb +2 -6
- data/lib/rock_books/documents/journal_entry.rb +7 -2
- data/lib/rock_books/documents/journal_entry_builder.rb +4 -0
- data/lib/rock_books/helpers/book_set_loader.rb +3 -3
- data/lib/rock_books/reports/balance_sheet.rb +9 -43
- data/lib/rock_books/reports/book_set_reporter.rb +207 -0
- data/lib/rock_books/reports/data/bs_is_data.rb +61 -0
- data/lib/rock_books/reports/data/bs_is_section_data.rb +28 -0
- data/lib/rock_books/reports/data/journal_data.rb +37 -0
- data/lib/rock_books/reports/data/multidoc_txn_by_account_data.rb +40 -0
- data/lib/rock_books/reports/data/multidoc_txn_report_data.rb +39 -0
- data/lib/rock_books/reports/data/receipts_report_data.rb +47 -0
- data/lib/rock_books/reports/data/tx_one_account_data.rb +37 -0
- data/lib/rock_books/reports/helpers/erb_helper.rb +21 -0
- data/lib/rock_books/reports/helpers/html_report_helper.rb +35 -0
- data/lib/rock_books/reports/helpers/text_report_helper.rb +134 -0
- data/lib/rock_books/reports/income_statement.rb +9 -47
- data/lib/rock_books/reports/journal_report.rb +72 -0
- data/lib/rock_books/reports/multidoc_txn_by_account_report.rb +32 -0
- data/lib/rock_books/reports/multidoc_txn_report.rb +25 -0
- data/lib/rock_books/reports/receipts_report.rb +6 -55
- data/lib/rock_books/reports/templates/html/index.html.erb +141 -0
- data/lib/rock_books/reports/templates/html/report_page.html.erb +12 -0
- data/lib/rock_books/reports/templates/text/_receipt_section.txt.erb +17 -0
- data/lib/rock_books/reports/templates/text/_totals.txt.erb +8 -0
- data/lib/rock_books/reports/templates/text/balance_sheet.txt.erb +21 -0
- data/lib/rock_books/reports/templates/text/income_statement.txt.erb +21 -0
- data/lib/rock_books/reports/templates/text/journal.txt.erb +20 -0
- data/lib/rock_books/reports/templates/text/multidoc_txn_by_account_report.txt.erb +28 -0
- data/lib/rock_books/reports/templates/text/multidoc_txn_report.txt.erb +22 -0
- data/lib/rock_books/reports/templates/text/receipts_report.txt.erb +13 -0
- data/lib/rock_books/reports/templates/text/tx_one_account.txt.erb +18 -0
- data/lib/rock_books/reports/tx_one_account.rb +10 -45
- data/lib/rock_books/types/account.rb +13 -1
- data/lib/rock_books/types/account_type.rb +18 -7
- data/lib/rock_books/version.rb +1 -1
- data/rock_books.gemspec +5 -3
- metadata +64 -16
- data/lib/rock_books/documents/index.html.erb +0 -156
- data/lib/rock_books/documents/receipts.html.erb +0 -54
- data/lib/rock_books/reports/multidoc_transaction_report.rb +0 -66
- data/lib/rock_books/reports/reporter.rb +0 -118
- data/lib/rock_books/reports/transaction_report.rb +0 -105
- data/lib/rock_books/reports/tx_by_account.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d37feeb3b20b730f06340d5e026dca81b564dc7cd6cb174a2d8bd0ffcbcb6441
|
4
|
+
data.tar.gz: 41a1e166136c536fde00512d8e624ce49c894766cd5f18ed673f8f67fdaf8908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41e4511367107b2be92ff53eb28c42635884413c3fa91c010eee41a53da6ac94b3b9a8f7eccf3522610eee287008944d318f3250dcdc349544491dcb13dd515c
|
7
|
+
data.tar.gz: 45239916850fd6102b50c8ca719a2d336b0704a116c0c4f2af5014c5a061c8b6a6147f95811a88fe13f51e23f345baeb3eda16b0e789b9682596945b92ddabb4
|
data/README.md
CHANGED
@@ -31,7 +31,10 @@ To simplify its implementation, RockBooks assumes some conventions:
|
|
31
31
|
* `statements` - statements from banks, etc.
|
32
32
|
* `worksheets` - spreadsheets, etc., e.g. mileage and per diem calculations
|
33
33
|
|
34
|
-
|
34
|
+
#### Supported Operating Systems
|
35
|
+
|
36
|
+
At this time, RockBooks is tested only on Mac OS and Linux. However, it will probably work fine on Windows.
|
37
|
+
|
35
38
|
#### Text Files as Input
|
36
39
|
|
37
40
|
Instead of a web interface, data input is done in plain text files. This isn't as fancy but has the following advantages:
|
@@ -91,7 +94,6 @@ As a product written by a single developer in his spare time, RockBooks lacks so
|
|
91
94
|
* On the fly data validation
|
92
95
|
* Data entry conveniences such as drop down selection lists for data such as accounts
|
93
96
|
* Fancy reporting and graphing -- however, RockBooks' bringing links to all the entity's documentation and output into a single web page may well be more useful
|
94
|
-
* At this time, RockBooks is only tested on Macs. The input files are plain text files and could be created on any OS, but the validation and report generation might not work. Get in touch with me if you are using a different OS and want to use RockBooks, and are willing and available to test my changes. Linux in particular should be an easy port.
|
95
97
|
|
96
98
|
|
97
99
|
## Installation
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
### v0.7.1
|
2
|
+
|
3
|
+
* Refactor report helpers.
|
4
|
+
* Improve/reduce text output during reporting.
|
5
|
+
* Add title to HTML reports.
|
6
|
+
* Minor fixes.
|
7
|
+
|
8
|
+
|
9
|
+
### v0.7.0
|
10
|
+
|
11
|
+
* Dependencies on external commands in Linux and Mac OS for generating PDF and HTML files has been eliminated,
|
12
|
+
using the prawn gem for PDF and simple ERB templating for HTML.
|
13
|
+
* Massive refactoring of reports to separate data generation from presentation.
|
14
|
+
* Reports are now computed and then written one at a time. Previously they were all computed, then all written.
|
15
|
+
* ERB is now used for generating text reports.
|
16
|
+
* Fix receipt hyperlinks in HTML output.
|
17
|
+
* Improve some error output.
|
18
|
+
* Various minor improvements and bug fixes.
|
19
|
+
|
20
|
+
|
21
|
+
### v0.6.1
|
22
|
+
|
23
|
+
* Linux PDF generation fixed by using wkhtmltopdf instead of cupsfilter.
|
24
|
+
|
25
|
+
### v0.6.0
|
26
|
+
|
27
|
+
* Linux support added!
|
28
|
+
|
29
|
+
### v0.5.0
|
30
|
+
|
31
|
+
* Add receipt hyperlinks to HTML output.
|
32
|
+
|
33
|
+
|
1
34
|
## v0.4.0
|
2
35
|
|
3
36
|
* Sort unused receipts alphanumerically.
|
Binary file
|
@@ -4,7 +4,7 @@ require 'ostruct'
|
|
4
4
|
|
5
5
|
require_relative '../../rock_books'
|
6
6
|
require_relative '../version'
|
7
|
-
require_relative '../reports/
|
7
|
+
require_relative '../reports/helpers/text_report_helper'
|
8
8
|
require_relative '../helpers/book_set_loader'
|
9
9
|
|
10
10
|
module RockBooks
|
@@ -105,7 +105,7 @@ When in interactive shell mode:
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
-
|
108
|
+
validate_receipt_dir = -> do
|
109
109
|
File.directory?(options.receipt_dir) ? nil : \
|
110
110
|
"Receipts directory '#{options.receipt_dir}' does not exist. "
|
111
111
|
end
|
@@ -114,7 +114,7 @@ When in interactive shell mode:
|
|
114
114
|
output << validate_input_dir.()
|
115
115
|
output << validate_output_dir.()
|
116
116
|
if run_options.do_receipts
|
117
|
-
output <<
|
117
|
+
output << validate_receipt_dir.()
|
118
118
|
end
|
119
119
|
|
120
120
|
output.compact!
|
@@ -298,9 +298,9 @@ When in interactive shell mode:
|
|
298
298
|
|
299
299
|
|
300
300
|
def cmd_d
|
301
|
-
book_set.all_reports($filter).each do |short_name,
|
301
|
+
book_set.all_reports($filter).each do |short_name, text_report|
|
302
302
|
puts "#{short_name}:\n\n"
|
303
|
-
puts
|
303
|
+
puts text_report
|
304
304
|
puts "\n\n\n"
|
305
305
|
end
|
306
306
|
nil
|
@@ -358,7 +358,7 @@ When in interactive shell mode:
|
|
358
358
|
end
|
359
359
|
|
360
360
|
def cmd_w
|
361
|
-
|
361
|
+
BookSetReporter.new(book_set, run_options.output_dir, $filter).generate
|
362
362
|
nil
|
363
363
|
end
|
364
364
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'amazing_print'
|
2
2
|
require 'optparse'
|
3
3
|
require 'pry'
|
4
4
|
require 'shellwords'
|
@@ -67,10 +67,6 @@ class Main
|
|
67
67
|
options.verbose_mode = v
|
68
68
|
end
|
69
69
|
|
70
|
-
parser.on('-y', '--[no-]say', 'Say error messages.') do |v|
|
71
|
-
options.say = v
|
72
|
-
end
|
73
|
-
|
74
70
|
parser.on('', '--[no-]receipts', 'Include report on existing and missing receipts.') do |v|
|
75
71
|
options.do_receipts = v
|
76
72
|
end
|
@@ -101,10 +97,6 @@ class Main
|
|
101
97
|
|
102
98
|
HEREDOC
|
103
99
|
|
104
|
-
if run_options.say
|
105
|
-
`say #{error}`
|
106
|
-
end
|
107
|
-
|
108
100
|
exit(-1)
|
109
101
|
binding.pry
|
110
102
|
raise error
|
@@ -1,17 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'amazing_print'
|
2
|
+
require 'os'
|
2
3
|
|
3
4
|
require_relative 'chart_of_accounts'
|
4
5
|
require_relative 'journal'
|
5
6
|
require_relative '../filters/journal_entry_filters' # for shell mode
|
6
7
|
require_relative '../helpers/parse_helper'
|
7
|
-
require_relative '../reports/
|
8
|
-
require_relative '../reports/income_statement'
|
9
|
-
require_relative '../reports/multidoc_transaction_report'
|
10
|
-
require_relative '../reports/receipts_report'
|
11
|
-
require_relative '../reports/report_context'
|
12
|
-
require_relative '../reports/transaction_report'
|
13
|
-
require_relative '../reports/tx_by_account'
|
14
|
-
require_relative '../reports/tx_one_account'
|
8
|
+
require_relative '../reports/book_set_reporter'
|
15
9
|
|
16
10
|
require 'erb'
|
17
11
|
require 'open3'
|
@@ -28,101 +22,6 @@ module RockBooks
|
|
28
22
|
end
|
29
23
|
|
30
24
|
|
31
|
-
def report_context
|
32
|
-
@report_context ||= ReportContext.new(chart_of_accounts, journals, 80)
|
33
|
-
end
|
34
|
-
|
35
|
-
|
36
|
-
def all_reports(filter = nil)
|
37
|
-
|
38
|
-
context = report_context
|
39
|
-
report_hash = context.journals.each_with_object({}) do |journal, report_hash|
|
40
|
-
key = journal.short_name.to_sym
|
41
|
-
report_hash[key] = TransactionReport.new(journal, context).call(filter)
|
42
|
-
end
|
43
|
-
report_hash[:all_txns_by_date] = MultidocTransactionReport.new(context).call(filter)
|
44
|
-
report_hash[:all_txns_by_amount] = MultidocTransactionReport.new(context).call(filter, :amount)
|
45
|
-
report_hash[:all_txns_by_acct] = TxByAccount.new(context).call
|
46
|
-
report_hash[:balance_sheet] = BalanceSheet.new(context).call
|
47
|
-
report_hash[:income_statement] = IncomeStatement.new(context).call
|
48
|
-
|
49
|
-
if run_options.do_receipts
|
50
|
-
report_hash[:receipts] = ReceiptsReport.new(context, *missing_existing_unused_receipts).call
|
51
|
-
end
|
52
|
-
|
53
|
-
chart_of_accounts.accounts.each do |account|
|
54
|
-
key = ('acct_' + account.code).to_sym
|
55
|
-
report = TxOneAccount.new(context, account.code).call
|
56
|
-
report_hash[key] = report
|
57
|
-
end
|
58
|
-
|
59
|
-
report_hash
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
def run_command(command)
|
64
|
-
puts "\n----\nRunning command: #{command}"
|
65
|
-
stdout, stderr, status = Open3.capture3(command)
|
66
|
-
puts "Status was #{status}."
|
67
|
-
unless stdout.size == 0
|
68
|
-
puts "\nStdout was:\n\n#{stdout}"
|
69
|
-
end
|
70
|
-
unless stderr.size == 0
|
71
|
-
puts "\nStderr was:\n\n#{stderr}"
|
72
|
-
end
|
73
|
-
puts
|
74
|
-
stdout
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
def all_reports_to_files(directory = '.', filter = nil)
|
79
|
-
reports = all_reports(filter)
|
80
|
-
|
81
|
-
create_directories = -> do
|
82
|
-
%w(txt pdf html).each do |format|
|
83
|
-
dir = File.join(directory, format, SINGLE_ACCT_SUBDIR)
|
84
|
-
FileUtils.mkdir_p(dir)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# "./pdf/short_name.pdf" or "./pdf/single_account/short_name.pdf"
|
89
|
-
build_filespec = ->(directory, short_name, file_format) do
|
90
|
-
fragments = [directory, file_format, "#{short_name}.#{file_format}"]
|
91
|
-
is_acct_report = /^acct_/.match(short_name)
|
92
|
-
if is_acct_report
|
93
|
-
fragments.insert(2, SINGLE_ACCT_SUBDIR)
|
94
|
-
end
|
95
|
-
File.join(*fragments)
|
96
|
-
end
|
97
|
-
|
98
|
-
create_index_html = -> do
|
99
|
-
filespec = build_filespec.(directory, 'index', 'html')
|
100
|
-
File.write(filespec, index_html_content)
|
101
|
-
puts "Created index.html"
|
102
|
-
end
|
103
|
-
|
104
|
-
write_reports = ->do
|
105
|
-
|
106
|
-
reports.each do |short_name, report_text|
|
107
|
-
txt_filespec = build_filespec.(directory, short_name, 'txt')
|
108
|
-
html_filespec = build_filespec.(directory, short_name, 'html')
|
109
|
-
pdf_filespec = build_filespec.(directory, short_name, 'pdf')
|
110
|
-
|
111
|
-
File.write(txt_filespec, report_text)
|
112
|
-
# Use smaller size for the PDF but larger size for the web pages:
|
113
|
-
run_command("textutil -convert html -font 'Courier New Bold' -fontsize 11 #{txt_filespec} -output #{html_filespec}")
|
114
|
-
run_command("cupsfilter #{html_filespec} > #{pdf_filespec}")
|
115
|
-
run_command("textutil -convert html -font 'Courier New Bold' -fontsize 14 #{txt_filespec} -output #{html_filespec}")
|
116
|
-
puts "Created reports in txt, html, and pdf for #{"%-20s" % short_name} at #{File.dirname(txt_filespec)}.\n\n\n"
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
create_directories.()
|
121
|
-
create_index_html.()
|
122
|
-
write_reports.()
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
25
|
def journal_names
|
127
26
|
journals.map(&:short_name)
|
128
27
|
end
|
@@ -139,37 +38,6 @@ module RockBooks
|
|
139
38
|
@all_entries ||= Journal.entries_in_documents(journals)
|
140
39
|
end
|
141
40
|
|
142
|
-
|
143
|
-
def receipt_full_filespec(receipt_filespec)
|
144
|
-
File.join(run_options.receipt_dir, receipt_filespec)
|
145
|
-
end
|
146
|
-
|
147
|
-
|
148
|
-
def missing_existing_unused_receipts
|
149
|
-
missing = []
|
150
|
-
existing = []
|
151
|
-
unused = Dir['receipts/**/*'].select { |s| File.file?(s) }.sort # Remove files as they are found
|
152
|
-
unused.map! { |s| "./" + s } # Prepend './' to match the data
|
153
|
-
|
154
|
-
all_entries.each do |entry|
|
155
|
-
entry.receipts.each do |receipt|
|
156
|
-
filespec = receipt_full_filespec(receipt)
|
157
|
-
unused.delete(filespec)
|
158
|
-
file_exists = File.file?(filespec)
|
159
|
-
list = (file_exists ? existing : missing)
|
160
|
-
list << { receipt: receipt, journal: entry.doc_short_name }
|
161
|
-
end
|
162
|
-
end
|
163
|
-
[missing, existing, unused]
|
164
|
-
end
|
165
|
-
|
166
|
-
def index_html_content
|
167
|
-
erb_filespec = File.join(File.dirname(__FILE__), 'index.html.erb')
|
168
|
-
erb = ERB.new(File.read(erb_filespec))
|
169
|
-
erb.result_with_hash(
|
170
|
-
journals: journals,
|
171
|
-
chart_of_accounts: chart_of_accounts,
|
172
|
-
run_options: run_options)
|
173
|
-
end
|
174
41
|
end
|
175
42
|
end
|
43
|
+
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'stringio'
|
1
2
|
require_relative '../types/account'
|
2
3
|
require_relative '../types/account_type'
|
3
4
|
require_relative '../errors/error'
|
@@ -10,8 +11,8 @@ class ChartOfAccounts
|
|
10
11
|
REQUIRED_FIELDS.each { |field| attr_reader(field) }
|
11
12
|
|
12
13
|
|
13
|
-
def self.from_file(
|
14
|
-
self.new(File.readlines(
|
14
|
+
def self.from_file(filespec)
|
15
|
+
self.new(File.readlines(filespec).map(&:chomp), filespec)
|
15
16
|
end
|
16
17
|
|
17
18
|
|
@@ -20,11 +21,16 @@ class ChartOfAccounts
|
|
20
21
|
end
|
21
22
|
|
22
23
|
|
23
|
-
def initialize(input_lines)
|
24
|
+
def initialize(input_lines, filespec = nil)
|
25
|
+
@filespec = filespec
|
24
26
|
@accounts = []
|
25
|
-
input_lines
|
27
|
+
parse_lines(input_lines)
|
26
28
|
# TODO: Add validation for required fields.
|
29
|
+
check_for_missing_fields
|
30
|
+
end
|
31
|
+
|
27
32
|
|
33
|
+
def check_for_missing_fields
|
28
34
|
missing_fields = REQUIRED_FIELDS.select do |field|
|
29
35
|
instance_variable_get("@#{field}").nil?
|
30
36
|
end
|
@@ -35,6 +41,19 @@ class ChartOfAccounts
|
|
35
41
|
end
|
36
42
|
|
37
43
|
|
44
|
+
def parse_lines(input_lines)
|
45
|
+
input_lines.each_with_index do |line, line_num|
|
46
|
+
begin
|
47
|
+
parse_line(line)
|
48
|
+
rescue => e
|
49
|
+
file_message_fragment = (@filespec ? " in file '#{@filespec}'" : '')
|
50
|
+
puts "Error parsing chart of accounts#{file_message_fragment}. Bad line is line ##{line_num}, text is:\n#{line}\n\n"
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
38
57
|
def parse_date(date_string)
|
39
58
|
# TODO: Add better handling for this error.
|
40
59
|
# begin
|
@@ -69,16 +88,14 @@ class ChartOfAccounts
|
|
69
88
|
rest = matcher[2]
|
70
89
|
|
71
90
|
matcher = rest.match(/^(\S+)\s+(.*)$/)
|
91
|
+
|
72
92
|
account_type_token = matcher[1]
|
73
|
-
account_type = AccountType.
|
93
|
+
account_type = AccountType.letter_to_type(account_type_token)
|
74
94
|
|
75
95
|
name = matcher[2]
|
76
96
|
|
77
|
-
accounts << Account.new(code, account_type, name)
|
97
|
+
accounts << Account.new(code, account_type.symbol, name)
|
78
98
|
end
|
79
|
-
rescue => e
|
80
|
-
puts "Error parsing chart of accounts. Line text is:\n#{line}\n\n"
|
81
|
-
raise
|
82
99
|
end
|
83
100
|
|
84
101
|
end
|
@@ -105,7 +122,7 @@ class ChartOfAccounts
|
|
105
122
|
|
106
123
|
|
107
124
|
def report_string
|
108
|
-
result =
|
125
|
+
result = StringIO.new
|
109
126
|
|
110
127
|
if title
|
111
128
|
result << title << "\n\n"
|
@@ -113,9 +130,9 @@ class ChartOfAccounts
|
|
113
130
|
|
114
131
|
code_width = @accounts.inject(0) { |width, a| width = [width, a.code.length].max }
|
115
132
|
format_string = "%-#{code_width}s %-10.10s %s\n"
|
116
|
-
accounts.each { |a| result << (format_string
|
133
|
+
accounts.each { |a| result << sprintf(format_string, a.code, a.type.to_s, a.name) }
|
117
134
|
|
118
|
-
result
|
135
|
+
result.string
|
119
136
|
end
|
120
137
|
|
121
138
|
|
@@ -7,7 +7,7 @@ require_relative '../types/acct_amount'
|
|
7
7
|
require_relative '../types/journal_entry_context'
|
8
8
|
require_relative 'journal_entry'
|
9
9
|
require_relative 'journal_entry_builder'
|
10
|
-
require_relative '../reports/
|
10
|
+
require_relative '../reports/helpers/text_report_helper'
|
11
11
|
|
12
12
|
module RockBooks
|
13
13
|
|
@@ -45,9 +45,7 @@ class Journal
|
|
45
45
|
end
|
46
46
|
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
def self.acct_amounts_in_documents(documents, entries_filter = nil, acct_amounts_filter = nil)
|
48
|
+
def self.acct_amounts_in_documents(documents, entries_filter = nil, acct_amounts_filter = nil)
|
51
49
|
entries = entries_in_documents(documents, entries_filter)
|
52
50
|
|
53
51
|
acct_amounts = entries.each_with_object([]) do |entry, acct_amounts|
|
@@ -72,7 +70,6 @@ class Journal
|
|
72
70
|
@short_name = short_name
|
73
71
|
@entries = []
|
74
72
|
@date_prefix = ''
|
75
|
-
@title = ''
|
76
73
|
input_lines.each_with_index do |line, linenum|
|
77
74
|
context = JournalEntryContext.new(self, linenum + 1, line)
|
78
75
|
parse_line(context)
|
@@ -131,7 +128,6 @@ class Journal
|
|
131
128
|
end
|
132
129
|
|
133
130
|
|
134
|
-
|
135
131
|
def acct_amounts
|
136
132
|
entries.each_with_object([]) { |entry, acct_amounts| acct_amounts << entry.acct_amounts }.flatten
|
137
133
|
end
|
@@ -32,12 +32,17 @@ class JournalEntry < Struct.new(:date, :acct_amounts, :doc_short_name, :descript
|
|
32
32
|
|
33
33
|
def self.sort_entries_by_amount_descending!(entries)
|
34
34
|
entries.sort_by! do |entry|
|
35
|
-
[entry.total_absolute_value, entry.doc_short_name]
|
35
|
+
[-entry.total_absolute_value, entry.doc_short_name]
|
36
36
|
end
|
37
|
-
entries.reverse!
|
38
37
|
end
|
39
38
|
|
40
39
|
|
40
|
+
def self.sort_entries_by_date!(entries)
|
41
|
+
entries.sort_by! { |entry| [entry.date, entry.doc_short_name] }
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
41
46
|
def total_for_code(account_code)
|
42
47
|
acct_amounts_with_code(account_code).map(&:amount).sum
|
43
48
|
end
|