rock_books 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba9e80afcb8f6644e9fa3cc629a4cac6d723843d1609bab54641c77b779fba89
4
- data.tar.gz: db3b9f6979da2408202715737fedf5f69b55d44657622364706d7597eac827bf
3
+ metadata.gz: 974a379630080a4b8ec174d0b79fe46ce629f0c0fab0c6e147e3b1e4cd472c3f
4
+ data.tar.gz: 289a1cccf88c3ab27fccac9bfd98c9b4e88f4d14d791d92ebcf52dfd6d7509ee
5
5
  SHA512:
6
- metadata.gz: de4ffe3cbf12789ffa874565e7e60299290e3cc8888a41a2756f0ef7b405152997286f2d4a0b9dd2c00aeb75afc8d2bb10245ae7e747492b14c9da4393948d79
7
- data.tar.gz: c19a5de4f323c6d50a6a684f87b38e3f12dab1cc55accbeed9ec8560521f02932bf8b6b8788069807496d37e4ff3c6d89056fc16cfcddf87f1c14d1af8e002da
6
+ metadata.gz: 57489817b4cae0dd70db00ee4fc10f8fc432ebb1a6ed01a93b6c1f646b681ae5eb456d171c5a7fe2d981bada1771da33eccba7ed08cebceee57925c5c1bb7560
7
+ data.tar.gz: 2f530db52499773bae28f24f6ee4cf0a243056b6e8df9a83723826b132b4cecc558451bcf357840946e437e6e22740aa4b7d417789df84ec3bbba6050917fe57
data/README.md CHANGED
@@ -47,17 +47,17 @@ Instead of a web interface, data input is done in plain text files. This isn't a
47
47
 
48
48
  * Users can use their favorite text editors.
49
49
 
50
- * All data entry can be done without moving the hands away from the keyboard.
50
+ * All data entry can be done without moving the hands away from the keyboard (assuming the editor software supports it, as does `vim`).
51
51
 
52
52
 
53
53
  #### The Accounting Period
54
54
 
55
- There is no handling of end of year closings or the like; the entire set of data in the input files is considered included in the reporting period when generating the reports. Therefore, the best approach is to create a new data set for each year. The chart of accounts and journal files can be copied and modified as necessary.
55
+ There is no handling of end of year closings or the like; the entire set of data in the input files is considered included in the reporting period when generating the reports. Therefore, the best approach is to create a new data set for each year. The chart of accounts and journal files can be copied from the previous year and modified as necessary.
56
56
 
57
57
  #### RockBooks Help Text
58
58
 
59
59
  ```
60
- Command Line Switches: [rock-books version 0.2.1 at https://github.com/keithrbennett/rock_books]
60
+ Command Line Switches: [rock-books version 0.10.0 at https://github.com/keithrbennett/rock_books]
61
61
 
62
62
  -i input directory specification, default: './rockbooks-inputs'
63
63
  -o output (reports) directory specification, default: './rockbooks-reports'
@@ -66,14 +66,13 @@ Command Line Switches: [rock-books version 0.2.1 at https://g
66
66
 
67
67
  Commands:
68
68
 
69
- rec[eipts] - receipts: a/:a all, m/:m missing, e/:e existing
69
+ rec[eipts] - receipts: a/:a all, m/:m missing, e/:e existing, u/:u unused
70
70
  rep[orts] - return an OpenStruct containing all reports (interactive shell mode only)
71
- d[isplay_reports] - display all reports on stdout
72
71
  w[rite_reports] - write all reports to the output directory (see -o option)
73
72
  c[hart_of_accounts] - chart of accounts
74
73
  h[elp] - prints this help
75
74
  jo[urnals] - list of the journals' short names
76
- proj[ect_page] - open the RockBooks Github project page in a browser
75
+ proj[ect_page] - prints the RockBooks Github project page URL
77
76
  rel[oad_data] - reload data from input files
78
77
  q[uit] - exits this program (interactive shell mode only) (see also 'x')
79
78
  x[it] - exits this program (interactive shell mode only) (see also 'q')
@@ -88,7 +87,8 @@ When in interactive shell mode:
88
87
 
89
88
  ## What RockBooks Is Not
90
89
 
91
- As a product written by a single developer in his spare time, RockBooks lacks some conveniences of traditional accounting software programs, such as:
90
+ As a product written by a single developer in his spare time,
91
+ RockBooks lacks many conveniences of traditional accounting software programs, such as:
92
92
 
93
93
  * Import of data from financial institutions
94
94
  * On the fly data validation
@@ -1,3 +1,15 @@
1
+ ### v0.10.0
2
+
3
+ * Add invoice hyperlinks to generated HTML.
4
+ * Improve documentation.
5
+ * Add progress bar to report generation.
6
+ * Change 'proj[ect]' command to print the project home page URL, rather than call `open` on it. This makes the command useful in more cases and removes environment dependency.
7
+ * Remove interactive 'display reports' option. It's not that useful and easy enough to write all reports to disk and selectively view them.
8
+ * Fix rep[orts] interactive option.
9
+ * Fix and refactor handling of receipt data on command line.
10
+ * Add styling to report HTML pages, mostly for centering the reports, increasing the font size, and providing a faint blue background.
11
+
12
+
1
13
  ### v0.9.0
2
14
 
3
15
  * Center generated index.html's content.
@@ -4,6 +4,7 @@ require 'ostruct'
4
4
 
5
5
  require_relative '../../rock_books'
6
6
  require_relative '../version'
7
+ require_relative '../reports/data/receipts_report_data'
7
8
  require_relative '../reports/helpers/text_report_helper'
8
9
  require_relative '../helpers/book_set_loader'
9
10
 
@@ -51,12 +52,11 @@ Commands:
51
52
 
52
53
  rec[eipts] - receipts: a/:a all, m/:m missing, e/:e existing, u/:u unused
53
54
  rep[orts] - return an OpenStruct containing all reports (interactive shell mode only)
54
- d[isplay_reports] - display all reports on stdout
55
55
  w[rite_reports] - write all reports to the output directory (see -o option)
56
56
  c[hart_of_accounts] - chart of accounts
57
57
  h[elp] - prints this help
58
58
  jo[urnals] - list of the journals' short names
59
- proj[ect_page] - open the RockBooks Github project page in a browser
59
+ proj[ect_page] - prints the RockBooks Github project page URL
60
60
  rel[oad_data] - reload data from input files
61
61
  q[uit] - exits this program (interactive shell mode only) (see also 'x')
62
62
  x[it] - exits this program (interactive shell mode only) (see also 'q')
@@ -281,7 +281,7 @@ When in interactive shell mode:
281
281
  # All reports as Ruby objects; only makes sense in shell mode.
282
282
  def cmd_rep
283
283
  unless run_options.interactive_mode
284
- raise Error.new("Option 'all_reports' is only available in shell mode. Try 'display_reports' or 'write_reports'.")
284
+ raise Error.new("Option 'all_reports' is only available in shell mode. Try 'write_reports'.")
285
285
  end
286
286
 
287
287
  os = OpenStruct.new(book_set.all_reports($filter))
@@ -297,18 +297,8 @@ When in interactive shell mode:
297
297
  end
298
298
 
299
299
 
300
- def cmd_d
301
- book_set.all_reports($filter).each do |short_name, text_report|
302
- puts "#{short_name}:\n\n"
303
- puts text_report
304
- puts "\n\n\n"
305
- end
306
- nil
307
- end
308
-
309
-
310
300
  def cmd_proj
311
- `open https://github.com/keithrbennett/rock_books`
301
+ puts 'https://github.com/keithrbennett/rock_books'
312
302
  end
313
303
 
314
304
 
@@ -317,7 +307,9 @@ When in interactive shell mode:
317
307
  raise Error.new("Receipt processing was requested but has been disabled with --no-receipts.")
318
308
  end
319
309
 
320
- missing, existing, unused = book_set.missing_existing_unused_receipts
310
+ data = ReceiptsReportData.new(all_entries, run_options.receipt_dir).fetch
311
+
312
+ missing, existing, unused = data[:missing], data[:existing], data[:unused]
321
313
 
322
314
  print_missing = -> { puts "\n\nMissing Receipts:"; ap missing }
323
315
  print_existing = -> { puts "\n\nExisting Receipts:"; ap existing }
@@ -326,11 +318,11 @@ When in interactive shell mode:
326
318
  case options.first.to_s
327
319
  when 'a' # all
328
320
  if run_options.interactive_mode
329
- { missing: missing, existing: existing, unused: unused }
321
+ data
330
322
  else
331
- print_missing.()
332
- print_existing.()
333
- print_unused.()
323
+ print_missing.()
324
+ print_existing.()
325
+ print_unused.()
334
326
  end
335
327
 
336
328
  when 'm'
@@ -372,7 +364,6 @@ When in interactive shell mode:
372
364
  @commands_ ||= [
373
365
  Command.new('rec', 'receipts', -> (*options) { cmd_rec(options) }),
374
366
  Command.new('rep', 'reports', -> (*_options) { cmd_rep }),
375
- Command.new('d', 'display_reports', -> (*_options) { cmd_d }),
376
367
  Command.new('w', 'write_reports', -> (*_options) { cmd_w }),
377
368
  Command.new('c', 'chart_of_accounts', -> (*_options) { cmd_c }),
378
369
  Command.new('jo', 'journals', -> (*_options) { cmd_j }),
@@ -38,6 +38,10 @@ module RockBooks
38
38
  @all_entries ||= Journal.entries_in_documents(journals)
39
39
  end
40
40
 
41
+
42
+ def all_reports(filter = nil)
43
+ BookSetReporter.new(self, nil, filter).get_all_report_data
44
+ end
41
45
  end
42
46
  end
43
47
 
@@ -16,13 +16,14 @@ require_relative 'helpers/text_report_helper'
16
16
  require_relative 'helpers/receipts_hyperlink_converter'
17
17
 
18
18
  require 'prawn'
19
+ require 'tty-progressbar'
19
20
 
20
21
  module RockBooks
21
22
  class BookSetReporter
22
23
 
23
24
  extend Forwardable
24
25
 
25
- attr_reader :book_set, :context, :filter, :output_dir
26
+ attr_reader :book_set, :context, :filter, :output_dir, :progress_bar
26
27
 
27
28
  def_delegator :book_set, :all_entries
28
29
  def_delegator :book_set, :journals
@@ -37,6 +38,7 @@ class BookSetReporter
37
38
  @output_dir = output_dir
38
39
  @filter = filter
39
40
  @context = ReportContext.new(book_set.chart_of_accounts, book_set.journals, 80)
41
+ @progress_bar = TTY::ProgressBar.new("[:bar] :caption", total: report_count + 10)
40
42
  end
41
43
 
42
44
 
@@ -49,9 +51,44 @@ class BookSetReporter
49
51
  do_transaction_reports
50
52
  do_single_account_reports
51
53
  do_receipts_report
54
+ progress_bar.advance(caption: 'Finished generating reports.')
55
+ progress_bar.finish
52
56
  end
53
57
 
54
58
 
59
+ def report_count
60
+ bal_sheet_income_statement = 2
61
+ journal_count = journals.size
62
+ txn_report_count = 3
63
+ single_account_count = chart_of_accounts.accounts.size
64
+ receipt_report_count = 1
65
+ bal_sheet_income_statement + journal_count + txn_report_count + single_account_count + receipt_report_count
66
+ end
67
+
68
+
69
+ def get_all_report_data
70
+ reports = {}
71
+
72
+ reports[:bs_is] = BsIsData.new(context)
73
+
74
+ reports[:journals] = journals.each_with_object({}) do |journal, journals|
75
+ journals[journal.short_name] = JournalData.new(journal, context, filter).fetch
76
+ end
77
+
78
+ reports[:txn_reports] = {
79
+ by_account: MultidocTxnByAccountData.new(context).fetch,
80
+ by_date: MultidocTxnReportData.new(context, :date, filter).fetch,
81
+ by_amount: MultidocTxnReportData.new(context, :amount, filter).fetch
82
+ }
83
+
84
+ reports[:single_accounts] = chart_of_accounts.accounts.each_with_object({}) do |account, single_accts|
85
+ single_accts[account.code.to_sym] = TxOneAccountData.new(context, account.code).fetch
86
+ end
87
+
88
+ reports[:receipts] = ReceiptsReportData.new(book_set.all_entries, run_options.receipt_dir).fetch
89
+ reports
90
+ end
91
+
55
92
  # All methods after this point are private.
56
93
 
57
94
  private def do_statements
@@ -181,38 +218,15 @@ class BookSetReporter
181
218
  create_pdf_report.()
182
219
  create_html_report.()
183
220
 
184
- puts "Created text, PDF, and HTML reports for #{short_name}."
185
- end
186
-
187
-
188
- private def missing_existing_unused_receipts
189
- missing_receipts = []
190
- existing_receipts = []
191
- receipt_full_filespec = ->(receipt_filespec) { File.join(run_options.receipt_dir, receipt_filespec) }
192
-
193
- # We will start out putting all filespecs in the unused array, and delete them as they are found in the transactions.
194
- unused_receipt_filespecs = Dir['receipts/**/*'].select { |s| File.file?(s) } \
195
- .sort \
196
- .map { |s| "./" + s } # Prepend './' to match the data
197
-
198
- all_entries.each do |entry|
199
- entry.receipts.each do |receipt|
200
- filespec = receipt_full_filespec.(receipt)
201
- unused_receipt_filespecs.delete(filespec)
202
- file_exists = File.file?(filespec)
203
- list = (file_exists ? existing_receipts : missing_receipts)
204
- list << { receipt: receipt, journal: entry.doc_short_name }
205
- end
206
- end
207
- [missing_receipts, existing_receipts, unused_receipt_filespecs]
221
+ progress_bar.advance(caption: "Generating report: #{short_name}")
208
222
  end
209
223
 
210
224
 
211
225
  private def create_index_html
226
+ progress_bar.advance(caption: 'Generating index.html')
212
227
  filespec = build_filespec(output_dir, 'index', 'html')
213
228
  content = IndexHtmlPage.new(context, html_metadata_comment('index.html'), run_options).generate
214
229
  File.write(filespec, content)
215
- puts "Created index.html"
216
230
  end
217
231
  end
218
232
  end
@@ -6,6 +6,7 @@ class ReceiptsHyperlinkConverter
6
6
  end
7
7
 
8
8
  RECEIPT_REGEX = /Receipt:\s*(\S*)/
9
+ INVOICE_REGEX = /Invoice:\s*(\S*)/
9
10
 
10
11
  attr_reader :html_string, :num_dirs_up
11
12
 
@@ -16,14 +17,19 @@ class ReceiptsHyperlinkConverter
16
17
 
17
18
 
18
19
  def convert
19
- html_string.split("\n").map do |line|
20
- matches = RECEIPT_REGEX.match(line)
20
+ process_link_type = ->(line, regex, dir_name) do
21
+ matches = regex.match(line)
21
22
  if matches
22
- listed_receipt_filespec = matches[1]
23
- receipt_anchor_line(line, listed_receipt_filespec)
23
+ listed_filespec = matches[1]
24
+ anchor_line(line, listed_filespec, dir_name)
24
25
  else
25
26
  line
26
27
  end
28
+ end
29
+
30
+ html_string.split("\n").map do |line|
31
+ line = process_link_type.(line, RECEIPT_REGEX, 'receipts')
32
+ process_link_type.(line, INVOICE_REGEX, 'invoices')
27
33
  end.join("\n")
28
34
  end
29
35
 
@@ -32,16 +38,22 @@ class ReceiptsHyperlinkConverter
32
38
  # the processed link should be '../../../receipts/[receipt_filespec]'
33
39
  # else it's in DATA_DIR/rockbooks-reports/html, and
34
40
  # the processed link should be '../../receipts/[receipt_filespec]'
35
- private def processed_receipt_filespec(listed_receipt_filespec)
36
- File.join(('../' * num_dirs_up), 'receipts', listed_receipt_filespec)
41
+ #
42
+ # `dir_name` will be 'receipts' or 'invoices'
43
+ private def dirized_filespec(listed_filespec, dir_name)
44
+ File.join(('../' * num_dirs_up), dir_name, listed_filespec)
37
45
  end
38
46
 
39
- private def receipt_anchor_line(line, listed_receipt_filespec)
47
+ private def anchor_line(line, listed_filespec, dir_name)
48
+ label = {
49
+ 'receipts' => 'Receipt',
50
+ 'invoices' => 'Invoice'
51
+ }.fetch(dir_name)
52
+
40
53
  line.gsub( \
41
- /Receipt:\s*#{listed_receipt_filespec}/, \
42
- %Q{Receipt: <a href="#{processed_receipt_filespec(listed_receipt_filespec)}">#{listed_receipt_filespec}</a>})
54
+ /#{label}:\s*#{listed_filespec}/, \
55
+ %Q{#{label}: <a href="#{dirized_filespec(listed_filespec, dir_name)}">#{listed_filespec}</a>})
43
56
  end
44
-
45
57
  end
46
58
  end
47
59
 
@@ -4,6 +4,18 @@
4
4
  <head>
5
5
  <title><%= title %></title>
6
6
  <meta name="generator" content="RockBooks Accounting"/>
7
+ <style>
8
+ body {
9
+ padding: 36px;
10
+ background-color: #d5f3fb;
11
+ color: #01182d;
12
+ max-width: 1024px;
13
+ float: none !important;
14
+ margin: 0 auto !important;
15
+ border: 0px;
16
+ font-size: 15px !important;
17
+ }
18
+ </style>
7
19
  </head>
8
20
  <body>
9
21
  <pre>
@@ -1,4 +1,4 @@
1
1
  module RockBooks
2
- VERSION = '0.9.0'
2
+ VERSION = '0.10.0'
3
3
  PROJECT_URL = 'https://github.com/keithrbennett/rock_books'
4
4
  end
data/manual.md CHANGED
@@ -15,7 +15,7 @@ Install the RockBooks software:
15
15
  It is recommended that you create a directory structure such as this:
16
16
 
17
17
  ```.
18
- ├── 2018-xyz-inc
18
+ ├── 2021-xyz-inc
19
19
  │   ├── invoices
20
20
  │   ├── receipts
21
21
  │   ├── references
@@ -44,9 +44,9 @@ Feel free to organize your files in subdirectories of these directories in whate
44
44
 
45
45
  ### Version Control
46
46
 
47
- Tracking this directory tree with version control software such as `git` in a private repository is _highly_ recommended because it provides:
47
+ Tracking this directory tree with version control software such as `git` is _highly_ recommended because it provides:
48
48
 
49
- * free cloud backup with Github, Gitlab, and/or Bitbucket
49
+ * free cloud backup in a private repository with Github, Gitlab, and/or Bitbucket
50
50
  * an audit trail with human readable diffs
51
51
  * manageable collaboration
52
52
 
@@ -58,7 +58,7 @@ You will need a chart of accounts in the `rockbooks-inputs` directory. A sample
58
58
 
59
59
  ### Journals
60
60
 
61
- You will need journals. Usually there would be one journal per external financial institution accounts, such as checking and credit card accounts. Samples have been provided in the sample_data/minimal/rockbooks-inputs directory of the gem:
61
+ You will need journals. Usually there would be one journal per external financial institution account, such as checking and credit card accounts. Samples have been provided in the sample_data/minimal/rockbooks-inputs directory of the gem:
62
62
 
63
63
  * [Checking](sample_data/minimal/rockbooks-inputs/2018-xyz-checking-journal.txt)
64
64
  * [Credit Card](sample_data/minimal/rockbooks-inputs/2018-xyz-visa-journal.txt)
@@ -92,10 +92,8 @@ Fields are space separated; any number of spaces can be used.
92
92
 
93
93
  #### Comment Lines
94
94
 
95
- Lines beginning with `#` will be ignored when the input data is parsed. Comment lines are useful for:
96
-
97
- * explanations of the input itself
98
- * information that you would like to be available for deeper research or examination but not printed in the reports
95
+ Lines beginning with `#` will be ignored when the input data is parsed. Therefore, comment lines will not be included in the generated reports. Comment lines are useful for explanations that are too verbose for the reports, but that should be available for deeper research. An example might be several lines of explanatory notes about an unusual transaction.
96
+
99
97
 
100
98
  #### Document Properties
101
99
 
@@ -110,19 +108,19 @@ as opposed to input records, will be expressed as lines beginning with `@`:
110
108
 
111
109
  #### Input Records
112
110
 
113
- Input records are multiple records for the type appropriate to the document:
111
+ Input records are records of a type appropriate to the document:
114
112
 
115
113
  * chart of accounts - each account
116
114
  * journals - each transaction
117
115
 
118
- Input records are, in general, entered into the text files after all properties. One exception is that the `@date_prefix` is often specified in multiple places in the journal, usually with a new month (e.g. `@date_prefix: 2018-11`).
116
+ Input records are, in general, entered into the text files after all properties. One exception is that the `@date_prefix` is often specified in multiple places in the journal, usually with a new month (e.g. `@date_prefix: 2021-11`).
119
117
 
120
118
 
121
119
 
122
120
  Data lines will contain fields that an be separated with an arbitrary number of spaces, e.g.:
123
121
 
124
122
  ```
125
- 2018-05-18 123.45 supplies
123
+ 2021-05-18 123.45 supplies
126
124
  ```
127
125
 
128
126
  In journals, all entries will begin with dates, and all dates begin with numerals, so the
@@ -133,11 +131,11 @@ its other data and included in reports.
133
131
 
134
132
  In order to make the entry of dates more convenient, many documents will support
135
133
  a `@date_prefix` property that will be prepended to dates. For example, if this prefix
136
- contains `2018-`, then subsequent dates must exclude that prefix since it will be
134
+ contains `2021-`, then subsequent dates must exclude that prefix since it will be
137
135
  automatically prepended. So, for example, a journal might contain the following lines:
138
136
 
139
137
  ```
140
- @date_prefix: 2018-
138
+ @date_prefix: 2021-
141
139
  # ...more lines...
142
140
  05-29 37.50 ofc.spls
143
141
  05-30 22.20 tr.taxi
@@ -236,9 +234,8 @@ the cash account), you would set the property to `debit`:
236
234
 
237
235
  #### General Journal
238
236
 
239
- The general journal is a special form of journal that does not have a primary account.
240
-
241
- In this journal, debits and credits need to be specified literally as account code/amount
237
+ Since the general journal is a special form of journal that does not have a primary account,
238
+ debits and credits need to be specified literally as account code/amount
242
239
  pairs, where positive numbers will result in debits, and negative numbers will result in credits, e.g.:
243
240
 
244
241
  ```
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency 'os', '> 1.0.0'
35
35
  spec.add_dependency 'pry', '> 0.0.0'
36
36
  spec.add_dependency 'prawn', '>= 2.1'
37
+ spec.add_dependency 'tty-progressbar'
37
38
 
38
39
  spec.add_development_dependency "bundler", "~> 2.0"
39
40
  spec.add_development_dependency "rake", ">= 12.3.3"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rock_books
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Bennett
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-19 00:00:00.000000000 Z
11
+ date: 2021-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: amazing_print
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tty-progressbar
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement