rvgp 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +23 -0
- data/LICENSE +504 -0
- data/README.md +223 -0
- data/Rakefile +32 -0
- data/bin/rvgp +8 -0
- data/lib/rvgp/application/config.rb +159 -0
- data/lib/rvgp/application/descendant_registry.rb +122 -0
- data/lib/rvgp/application/status_output.rb +139 -0
- data/lib/rvgp/application.rb +170 -0
- data/lib/rvgp/base/command.rb +457 -0
- data/lib/rvgp/base/grid.rb +531 -0
- data/lib/rvgp/base/reader.rb +29 -0
- data/lib/rvgp/base/reconciler.rb +434 -0
- data/lib/rvgp/base/validation.rb +261 -0
- data/lib/rvgp/commands/cashflow.rb +160 -0
- data/lib/rvgp/commands/grid.rb +70 -0
- data/lib/rvgp/commands/ireconcile.rb +95 -0
- data/lib/rvgp/commands/new_project.rb +296 -0
- data/lib/rvgp/commands/plot.rb +41 -0
- data/lib/rvgp/commands/publish_gsheets.rb +83 -0
- data/lib/rvgp/commands/reconcile.rb +58 -0
- data/lib/rvgp/commands/rotate_year.rb +202 -0
- data/lib/rvgp/commands/validate_journal.rb +59 -0
- data/lib/rvgp/commands/validate_system.rb +44 -0
- data/lib/rvgp/commands.rb +160 -0
- data/lib/rvgp/dashboard.rb +252 -0
- data/lib/rvgp/fakers/fake_feed.rb +245 -0
- data/lib/rvgp/fakers/fake_journal.rb +57 -0
- data/lib/rvgp/fakers/fake_reconciler.rb +88 -0
- data/lib/rvgp/fakers/faker_helpers.rb +25 -0
- data/lib/rvgp/gem.rb +80 -0
- data/lib/rvgp/journal/commodity.rb +453 -0
- data/lib/rvgp/journal/complex_commodity.rb +214 -0
- data/lib/rvgp/journal/currency.rb +101 -0
- data/lib/rvgp/journal/journal.rb +141 -0
- data/lib/rvgp/journal/posting.rb +156 -0
- data/lib/rvgp/journal/pricer.rb +267 -0
- data/lib/rvgp/journal.rb +24 -0
- data/lib/rvgp/plot/gnuplot.rb +478 -0
- data/lib/rvgp/plot/google-drive/output_csv.rb +44 -0
- data/lib/rvgp/plot/google-drive/output_google_sheets.rb +434 -0
- data/lib/rvgp/plot/google-drive/sheet.rb +67 -0
- data/lib/rvgp/plot.rb +293 -0
- data/lib/rvgp/pta/hledger.rb +237 -0
- data/lib/rvgp/pta/ledger.rb +308 -0
- data/lib/rvgp/pta.rb +311 -0
- data/lib/rvgp/reconcilers/csv_reconciler.rb +424 -0
- data/lib/rvgp/reconcilers/journal_reconciler.rb +41 -0
- data/lib/rvgp/reconcilers/shorthand/finance_gem_hacks.rb +48 -0
- data/lib/rvgp/reconcilers/shorthand/international_atm.rb +152 -0
- data/lib/rvgp/reconcilers/shorthand/investment.rb +144 -0
- data/lib/rvgp/reconcilers/shorthand/mortgage.rb +195 -0
- data/lib/rvgp/utilities/grid_query.rb +190 -0
- data/lib/rvgp/utilities/yaml.rb +131 -0
- data/lib/rvgp/utilities.rb +44 -0
- data/lib/rvgp/validations/balance_validation.rb +68 -0
- data/lib/rvgp/validations/duplicate_tags_validation.rb +48 -0
- data/lib/rvgp/validations/uncategorized_validation.rb +15 -0
- data/lib/rvgp.rb +66 -0
- data/resources/README.MD/2022-cashflow-google.png +0 -0
- data/resources/README.MD/2022-cashflow.png +0 -0
- data/resources/README.MD/all-wealth-growth-google.png +0 -0
- data/resources/README.MD/all-wealth-growth.png +0 -0
- data/resources/gnuplot/default.yml +80 -0
- data/resources/i18n/en.yml +192 -0
- data/resources/iso-4217-currencies.json +171 -0
- data/resources/skel/Rakefile +5 -0
- data/resources/skel/app/grids/cashflow_grid.rb +27 -0
- data/resources/skel/app/grids/monthly_income_and_expenses_grid.rb +25 -0
- data/resources/skel/app/grids/wealth_growth_grid.rb +35 -0
- data/resources/skel/app/plots/cashflow.yml +33 -0
- data/resources/skel/app/plots/monthly-income-and-expenses.yml +17 -0
- data/resources/skel/app/plots/wealth-growth.yml +20 -0
- data/resources/skel/config/csv-format-acme-checking.yml +9 -0
- data/resources/skel/config/google-secrets.yml +5 -0
- data/resources/skel/config/rvgp.yml +0 -0
- data/resources/skel/journals/prices.db +0 -0
- data/rvgp.gemspec +6 -0
- data/test/assets/ledger_total_monthly_liabilities_with_empty.xml +383 -0
- data/test/assets/ledger_total_monthly_liabilities_with_empty2.xml +428 -0
- data/test/test_command_base.rb +61 -0
- data/test/test_commodity.rb +270 -0
- data/test/test_csv_reconciler.rb +60 -0
- data/test/test_currency.rb +24 -0
- data/test/test_fake_feed.rb +228 -0
- data/test/test_fake_journal.rb +98 -0
- data/test/test_fake_reconciler.rb +60 -0
- data/test/test_journal_parse.rb +545 -0
- data/test/test_ledger.rb +102 -0
- data/test/test_plot.rb +133 -0
- data/test/test_posting.rb +50 -0
- data/test/test_pricer.rb +139 -0
- data/test/test_pta_adapter.rb +575 -0
- data/test/test_utilities.rb +45 -0
- metadata +268 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RVGP
|
4
|
+
# This module contains helper methods used throughout RVGP. These are just common
|
5
|
+
# codepaths, that have little in common, save for their general utility.
|
6
|
+
module Utilities
|
7
|
+
# This returns each month in a series from the first date, to the last, in the
|
8
|
+
# provided array of dates
|
9
|
+
# @overload months_through(date, ...)
|
10
|
+
# @param [Array<Date>] date A date, that will be used to calculate the range of months to construct a range from.
|
11
|
+
# @param [Array<Date>] ... More dates. This method will automatically select the max and min from the sample
|
12
|
+
# provided.
|
13
|
+
# @return [Array<Date>] An array, containing a Date, set to the first of every month, in the provided range.
|
14
|
+
def months_through(*args)
|
15
|
+
dates = args.flatten.uniq.sort
|
16
|
+
|
17
|
+
ret = []
|
18
|
+
unless dates.empty?
|
19
|
+
d = Date.new dates.first.year, dates.first.month, 1 # start_at
|
20
|
+
while d <= Date.new(dates.last.year, dates.last.month, 1) # end_at
|
21
|
+
ret << d
|
22
|
+
d = d >> 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
ret
|
26
|
+
end
|
27
|
+
|
28
|
+
# Convert the provided string, into a Regexp. Note that the the ixm suffixes are supported, unlike
|
29
|
+
# ruby's Regexp.new(str) method
|
30
|
+
# @param [String] str A string, in the 'standard' regexp format: '/Running (?:to|at) the Park/i'
|
31
|
+
# @return [Regexp] The conversion to a useable regexp, for the provided string
|
32
|
+
def string_to_regex(str)
|
33
|
+
if %r{\A/(.*)/([imx]?[imx]?[imx]?)\Z}.match str
|
34
|
+
Regexp.new(::Regexp.last_match(1), ::Regexp.last_match(2).chars.map do |c|
|
35
|
+
case c
|
36
|
+
when 'i' then Regexp::IGNORECASE
|
37
|
+
when 'x' then Regexp::EXTENDED
|
38
|
+
when 'm' then Regexp::MULTILINE
|
39
|
+
end
|
40
|
+
end.reduce(:|))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RVGP
|
4
|
+
module Validations
|
5
|
+
# This validation asserts that the ledger-reported balance, matches a provided
|
6
|
+
# balance, on a given day. These balances, should be stipulated in a section
|
7
|
+
# of your reconciler, that looks like this:
|
8
|
+
# ```
|
9
|
+
# balances:
|
10
|
+
# '2022-01-01': $ 105.63
|
11
|
+
# '2022-09-01': $ 300.29
|
12
|
+
# '2022-10-01': $ 400.33
|
13
|
+
# ```
|
14
|
+
# These balances are expected to come from a bank statement, and this validation
|
15
|
+
# ensures that rvgp is matching the records of your financial institution
|
16
|
+
class BalanceValidation < RVGP::Base::JournalValidation
|
17
|
+
# If there are no checkpoints in the 'balances' line of the reconciler, this
|
18
|
+
# fires a warning. If there are checkpoints, then, we scan the register to
|
19
|
+
# ensure that the balance of the reconciler.from, on the checkpoint date,
|
20
|
+
# matches the ledger/hledger balance, on that date. (and if it doesnt,
|
21
|
+
# fires an error)
|
22
|
+
def validate
|
23
|
+
if reconciler.balances.nil? || reconciler.balances.empty?
|
24
|
+
warning! 'No balance checkpoints found.'
|
25
|
+
else
|
26
|
+
is_account_valid = true
|
27
|
+
cite_balances = reconciler.balances.map do |d, expected_balance_s|
|
28
|
+
expected_balance = expected_balance_s.to_commodity
|
29
|
+
|
30
|
+
balances_on_day = pta.balance format('^%s$', reconciler.from),
|
31
|
+
depth: 1,
|
32
|
+
end: d.to_s,
|
33
|
+
file: RVGP.app.config.project_journal_path
|
34
|
+
|
35
|
+
balances_found = balances_on_day.accounts.map(&:amounts).flatten.find_all do |amount|
|
36
|
+
amount.code == expected_balance.code
|
37
|
+
end
|
38
|
+
|
39
|
+
found = if balances_found.empty?
|
40
|
+
# Rather than operate from nil, we'll establish that we're '0' of units
|
41
|
+
# of the expected symbol
|
42
|
+
RVGP::Journal::Commodity.from_symbol_and_amount expected_balance.code, 0
|
43
|
+
else
|
44
|
+
balances_found.sum
|
45
|
+
end
|
46
|
+
|
47
|
+
found_as_s = if found
|
48
|
+
format('Found: %s', found.to_s)
|
49
|
+
else
|
50
|
+
found = RVGP::Journal::Commodity.from_symbol_and_amount expected_balance.code, 0
|
51
|
+
'(Nil)'
|
52
|
+
end
|
53
|
+
|
54
|
+
is_valid = expected_balance == found
|
55
|
+
is_account_valid = false unless is_valid
|
56
|
+
|
57
|
+
format('(%<day>s) Expected: %<expected>s %<indicator>s',
|
58
|
+
day: d.to_s,
|
59
|
+
expected: expected_balance.to_s,
|
60
|
+
indicator: RVGP.pastel.send(is_valid ? :green : :red, found_as_s))
|
61
|
+
end
|
62
|
+
|
63
|
+
error! 'Failed Checkpoint(s):', cite_balances unless is_account_valid
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RVGP
|
4
|
+
module Validations
|
5
|
+
# This class implements a journal validation that ensures a given transfer, hasn't
|
6
|
+
# been tagged more than once, with the same tag.
|
7
|
+
class DuplicateTagsValidation < RVGP::Base::JournalValidation
|
8
|
+
# Reviews every transfer, and post, to ensure that there are no tags occurring more than once, in
|
9
|
+
# any given entry. Unlike most of the validations in RVGP, this one doesn't use ledger or hledger
|
10
|
+
# to validate. This validation parses the file itself, in ruby, and ensures based on the contents.
|
11
|
+
def validate
|
12
|
+
journal = RVGP::Journal.parse File.read(reconciler.output_file)
|
13
|
+
dupe_messages = []
|
14
|
+
|
15
|
+
journal.postings.each do |posting|
|
16
|
+
posting_tag_names = posting.tags.map(&:key)
|
17
|
+
found_dupes = posting_tag_names.find_all { |tag| posting_tag_names.count(tag) > 1 }.uniq
|
18
|
+
|
19
|
+
if found_dupes.empty?
|
20
|
+
posting.transfers.each do |transfer|
|
21
|
+
transfer_tag_names = transfer.tags.map(&:key) + posting_tag_names
|
22
|
+
|
23
|
+
found_dupes = transfer_tag_names.find_all { |tag| transfer_tag_names.count(tag) > 1 }.uniq
|
24
|
+
|
25
|
+
next if found_dupes.empty?
|
26
|
+
|
27
|
+
dupe_messages << format('Line %<line>d: %<date>s %<desc>s (Transfer: %<tags>s)',
|
28
|
+
line: posting.line_number,
|
29
|
+
date: posting.date,
|
30
|
+
desc: posting.description,
|
31
|
+
tags: found_dupes.join(', '))
|
32
|
+
end
|
33
|
+
else
|
34
|
+
dupe_messages << format('Line %<line>d: %<date>s %<desc>s (%<tags>s)',
|
35
|
+
line: posting.line_number,
|
36
|
+
date: posting.date,
|
37
|
+
desc: posting.description,
|
38
|
+
tags: found_dupes.join(','))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
unless dupe_messages.empty?
|
43
|
+
error! 'These postings have been tagged with the same tag, more than once', dupe_messages
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RVGP
|
4
|
+
# This module provides a number of basic, and common, validations for use in your projects
|
5
|
+
module Validations
|
6
|
+
# This class implements a journal validation that ensures there are no uncategorized
|
7
|
+
# expenses in the journal
|
8
|
+
class UncategorizedValidation < RVGP::Base::JournalValidation
|
9
|
+
# Ensures that there is no balance for 'Unknown' categories in a journal
|
10
|
+
def validate
|
11
|
+
validate_no_balance 'Uncategorized Transactions', 'Unknown'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/rvgp.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'rvgp/utilities/yaml'
|
4
|
+
require_relative 'rvgp/application'
|
5
|
+
require_relative 'rvgp/commands'
|
6
|
+
require_relative 'rvgp/base/reconciler'
|
7
|
+
|
8
|
+
# NOTE: Reconcilers & shorthand may want to go into a registry system at
|
9
|
+
# some point, akin to grids/validations.
|
10
|
+
require_relative 'rvgp/reconcilers/csv_reconciler'
|
11
|
+
require_relative 'rvgp/reconcilers/journal_reconciler'
|
12
|
+
require_relative 'rvgp/reconcilers/shorthand/mortgage'
|
13
|
+
require_relative 'rvgp/reconcilers/shorthand/investment'
|
14
|
+
require_relative 'rvgp/reconcilers/shorthand/international_atm'
|
15
|
+
|
16
|
+
require_relative 'rvgp/base/validation'
|
17
|
+
|
18
|
+
require_relative 'rvgp/journal'
|
19
|
+
require_relative 'rvgp/pta/ledger'
|
20
|
+
require_relative 'rvgp/pta/hledger'
|
21
|
+
|
22
|
+
require_relative 'rvgp/base/grid'
|
23
|
+
|
24
|
+
# Gem Paths / Resources:
|
25
|
+
require_relative 'rvgp/gem'
|
26
|
+
|
27
|
+
I18n.load_path << Dir[RVGP::Gem.root('resources/i18n/*.yml')]
|
28
|
+
RVGP::Journal::Currency.currencies_config = RVGP::Gem.root('resources/iso-4217-currencies.json')
|
29
|
+
|
30
|
+
# The base module, under which all RVGP code is filed
|
31
|
+
module RVGP
|
32
|
+
# @param from_path [String] The directory path, to an RVGP project.
|
33
|
+
# @return [RVGP::Application] The initialized application, that was stored in RVGP.app
|
34
|
+
def self.initialize_app(from_path)
|
35
|
+
raise StandardError, 'Application is already initialized' if @app
|
36
|
+
|
37
|
+
@app = Application.new from_path
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [RVGP::Application] The currently-initialized RVGP:Application
|
41
|
+
def self.app
|
42
|
+
@app
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Pastel] The global pastel object, used to output to the console.
|
46
|
+
def self.pastel
|
47
|
+
@pastel ||= Pastel.new enabled: $stdout.tty?
|
48
|
+
end
|
49
|
+
|
50
|
+
# @!attribute [r] self.commands
|
51
|
+
# Contains an array of all available objects, with parent of type {RVGP::Base::Command}.
|
52
|
+
# @return [Array<RVGP::Base::Command>] the commands that are available in this project
|
53
|
+
# @!attribute [r] self.grids
|
54
|
+
# Contains an array of all available objects, with parent of type {RVGP::Base::Grid}.<br>
|
55
|
+
# **NOTE:** RVGP.app.task_names => Array<String>, will return all grid-building tasks that have been defined in the
|
56
|
+
# project.
|
57
|
+
# @return [Array<RVGP::Base::Grid>] the grids that are available in this project
|
58
|
+
# @!attribute [r] self.journal_validations
|
59
|
+
# Contains an array of all available objects, with parent of type {RVGP::Base::JournalValidation}.
|
60
|
+
# @return [Array<RVGP::Base::JournalValidation>] the journal validations that are available in this project
|
61
|
+
# @!attribute [r] self.system_validations
|
62
|
+
# Contains an array of all available objects, with parent of type {RVGP::Base::SystemValidation}.<br>
|
63
|
+
# **NOTE:** RVGP.system_validations.task_names => Array<String>, will return all system validation tasks that have
|
64
|
+
# been defined in the project.
|
65
|
+
# @return [Array<RVGP::Base::SystemValidation>] the system validations that are available in this project
|
66
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,80 @@
|
|
1
|
+
colors:
|
2
|
+
base:
|
3
|
+
# Solarized Light:
|
4
|
+
base03: '#002b36'
|
5
|
+
base02: '#073642'
|
6
|
+
base01: '#586e75'
|
7
|
+
base00: '#657b83'
|
8
|
+
base0: '#839496'
|
9
|
+
base1: '#93a1a1'
|
10
|
+
base2: '#eee8d5'
|
11
|
+
base3: '#fdf6e3'
|
12
|
+
yellow: '#b58900'
|
13
|
+
orange: '#cb4b16'
|
14
|
+
red: '#dc322f'
|
15
|
+
magenta: '#d33682'
|
16
|
+
violet: '#6c71c4'
|
17
|
+
blue: '#268bd2'
|
18
|
+
cyan: '#2aa198'
|
19
|
+
green: '#859900'
|
20
|
+
font: :base03
|
21
|
+
title: :font
|
22
|
+
grid: :base02
|
23
|
+
axis: :base02
|
24
|
+
key_text: :font
|
25
|
+
background: :base3
|
26
|
+
series:
|
27
|
+
# https://www.heavy.ai/blog/12-color-palettes-for-telling-better-stories-with-your-data
|
28
|
+
# Spring Pastels
|
29
|
+
- "#7eb0d5"
|
30
|
+
- "#fd7f6f"
|
31
|
+
- "#b2e061"
|
32
|
+
- "#bd7ebe"
|
33
|
+
- "#ffb55a"
|
34
|
+
- "#ffee65"
|
35
|
+
- "#beb9db"
|
36
|
+
- "#fdcce5"
|
37
|
+
- "#8bd3c7"
|
38
|
+
# Retro Metro
|
39
|
+
- "#ea5545"
|
40
|
+
- "#f46a9b"
|
41
|
+
- "#ef9b20"
|
42
|
+
- "#edbf33"
|
43
|
+
- "#ede15b"
|
44
|
+
- "#bdcf32"
|
45
|
+
- "#87bc45"
|
46
|
+
- "#27aeef"
|
47
|
+
# http://www.gnuplotting.org/data/dark2.pal
|
48
|
+
- '#1B9E77'
|
49
|
+
- '#D95F02'
|
50
|
+
- '#7570B3'
|
51
|
+
- '#E7298A'
|
52
|
+
- '#66A61E'
|
53
|
+
- '#E6AB02'
|
54
|
+
- '#A6761D'
|
55
|
+
# Blue to Yellow
|
56
|
+
- "#115f9a"
|
57
|
+
- "#1984c5"
|
58
|
+
- "#22a7f0"
|
59
|
+
- "#48b5c4"
|
60
|
+
- "#76c68f"
|
61
|
+
- "#a6d75b"
|
62
|
+
- "#c9e52f"
|
63
|
+
- "#d0ee11"
|
64
|
+
- "#d0f400"
|
65
|
+
header: |+
|
66
|
+
set datafile separator ","
|
67
|
+
set title "%{title}" font "sans,11" textcolor rgb "%{title_rgb}" enhanced
|
68
|
+
set terminal wxt size 1200,400 persist enhanced font 'sans,10' background rgb '%{background_rgb}'
|
69
|
+
set style line 102 lc rgb '%{grid_rgb}' lt 0 lw 1
|
70
|
+
set grid back ls 102
|
71
|
+
set style line 101 lc rgb '%{axis_rgb}' lt 1 lw 1
|
72
|
+
set border 3 front ls 101
|
73
|
+
set xtics font ",9"
|
74
|
+
set ytics font ",11"
|
75
|
+
set timefmt "%%m-%%y"
|
76
|
+
set format x "%%b-%%y"
|
77
|
+
set format y "$ %%'.0f"
|
78
|
+
unset colorbox
|
79
|
+
set key on under center textcolor rgb "%{key_text_rgb}" enhanced font 'sans,9'
|
80
|
+
set decimal locale
|
@@ -0,0 +1,192 @@
|
|
1
|
+
en:
|
2
|
+
help:
|
3
|
+
usage: 'Usage: %{program} [OPTION]... [COMMAND] [TARGET]...'
|
4
|
+
indent: ' '
|
5
|
+
description: >
|
6
|
+
A plain text accounting workflow tool for: (r)econciling, (v)alidating, (g)rid-production and (p)lotting your finances with ruby. See the program github for more details.
|
7
|
+
|
8
|
+
command_introduction: >
|
9
|
+
COMMAND - This is a required parameter. Command-specific options are
|
10
|
+
further available, once you've specified a command mode. See the 'Available Commands' section for a list of supported commands.
|
11
|
+
target_introduction: >
|
12
|
+
TARGET(s) - Depending on which command you select, a list of targets can be supplied. Typically,
|
13
|
+
supplying the -l option, in lieu of any targets, will output the targets supported by the command.
|
14
|
+
Note that any asterisk encountered in a target parameter, will expand to include all targets that
|
15
|
+
can be matched given the provided (target) string.
|
16
|
+
command_list_introduction: 'Available Commands:'
|
17
|
+
global_option_introduction: >
|
18
|
+
Global Options:
|
19
|
+
The following options are available to all commands:
|
20
|
+
|
21
|
+
-d --dir[=PATH] Use the supplied PATH as the active rvgp directory.
|
22
|
+
If unsupplied, this option defaults to the basedir of
|
23
|
+
the LEDGER_FILE environment variable.
|
24
|
+
commands:
|
25
|
+
cashflow:
|
26
|
+
description: 'Output a convenient dashboard with income/expense flows, based on intention'
|
27
|
+
options:
|
28
|
+
all: 'Output a dashboard for every intention in the system'
|
29
|
+
list: 'List all available intention-tag values'
|
30
|
+
date: 'Specify a date to use, when calculatingg the "recent months" to display. Defaults to "today".'
|
31
|
+
new_project:
|
32
|
+
description: 'Create a new plain text accounting project, populated with random data, in the path specified by --dir.'
|
33
|
+
plot:
|
34
|
+
description: 'Build one or more gnuplots, based on a grid variant.'
|
35
|
+
options:
|
36
|
+
all: 'Build all available plots'
|
37
|
+
list: 'List all available plots'
|
38
|
+
stdout: 'Output build to STDOUT instead of output_file'
|
39
|
+
publish_gsheets:
|
40
|
+
description: 'Publish plots, both as a spreadsheet, as well as a graph, into a google sheets workbook.'
|
41
|
+
options:
|
42
|
+
all: 'Publish all available plots'
|
43
|
+
list: 'List all available plot variants'
|
44
|
+
csvdir: 'Output the provided plots, as csvs, with grid hacks applied, into the specified directory. Mostly useful for debugging.'
|
45
|
+
title: 'The title of the Google doc being published. Defaults to "RVGP Finance Report %m/%d/%y %H:%M". '
|
46
|
+
sleep: 'Seconds to sleep, between each sheet upload. This sleep prevents Google from aborting the publish, under the auspice of api spamming. Defaults to 5.'
|
47
|
+
ireconcile:
|
48
|
+
description: 'Open an interactive vim session, to edit and build a reconcile'
|
49
|
+
options:
|
50
|
+
all: 'Process all available reconcilers'
|
51
|
+
list: 'List all available reconcilers'
|
52
|
+
vsplit: 'Split the input and output panes vertically, instead of horizontally (the default)'
|
53
|
+
grid:
|
54
|
+
description: "Generate Grid csv's in build/grids"
|
55
|
+
options:
|
56
|
+
all: 'Process all available grids'
|
57
|
+
list: 'List all available grids'
|
58
|
+
reconcile:
|
59
|
+
description: 'Create/Update the build/*.journal, based on ./reconcilers/*.yml'
|
60
|
+
options:
|
61
|
+
stdout: 'Output build to STDOUT instead of output_file'
|
62
|
+
all: 'Process all available reconcilers'
|
63
|
+
list: 'List all available reconcilers'
|
64
|
+
concise: "Concise output mode. Strips output that's unrelated to errors and warnings. (Mostly used by the ireconcile command)"
|
65
|
+
rotate_year:
|
66
|
+
description: "Rotate the given reconcilers, for a new year. And, move the last year's input files into the historical directory under your project feeds."
|
67
|
+
options:
|
68
|
+
all: 'Rotate all eligible reconcilers'
|
69
|
+
list: 'List reconcilers eligible for rotation'
|
70
|
+
validate_journal:
|
71
|
+
description: 'Validate reconciled journals, using the app/validations'
|
72
|
+
options:
|
73
|
+
all: 'Process all available journals'
|
74
|
+
list: 'List all available journals'
|
75
|
+
validate_system:
|
76
|
+
description: 'Run validations on the ledger, once the individual journals are valid'
|
77
|
+
options:
|
78
|
+
all: 'Process all available system validations'
|
79
|
+
list: 'List all available system validations'
|
80
|
+
commands:
|
81
|
+
cashflow:
|
82
|
+
list_targets: 'The following cashflow intentions are available:'
|
83
|
+
account: 'Account'
|
84
|
+
expenses: 'Expenses'
|
85
|
+
income: 'Income'
|
86
|
+
cash_flow: 'Cash Flow'
|
87
|
+
errors:
|
88
|
+
screen_too_small: 'Screen width "%{screen_width}" is too small. Minimum width is %{minimum_width}.'
|
89
|
+
unrecognized_path: 'Unrecognized path: %{file}'
|
90
|
+
new_project:
|
91
|
+
directory_exists_prompt: "The directory \"%{dir}\" already exists. Continuing will overwrite some of its contents. Are you sure you wish to continue creating a new project in this directory? (Type \"Yes\" to continue) : "
|
92
|
+
project_name_prompt: "Whose project is this? A person's full name or a company name will work: "
|
93
|
+
project_name_confirmation: "You entered \"%{project_name}\". Is that correct? (Type \"Yes\" to continue) : "
|
94
|
+
confirm_operation: "Yes"
|
95
|
+
operation_aborted: "\"new_project\" project operation aborted"
|
96
|
+
completed_banner: "\nThe new project has been generated successfully.\nThough you may want to add the following line to your ~/.bashrc:\n export LEDGER_FILE=\"%{journal_path}\"\n\nYou're ready to begin working on this project. Try cd'ing into its directory, and running `rake`."
|
97
|
+
initialize:
|
98
|
+
project_directory: "Project directory"
|
99
|
+
bank_feeds: 'Randomized bank feeds'
|
100
|
+
reconcilers: 'Randomized reconcilers'
|
101
|
+
errors:
|
102
|
+
missing_app_dir: "An application directory was not provided, and is required. Set this parameter via --dir argument, or via the LEDGER_FILE environment variable"
|
103
|
+
directory_exists: "The directory \"%{dir}\" could not be created because it already exists."
|
104
|
+
plot:
|
105
|
+
target_description: 'Build the %{name} plot file, and its variants'
|
106
|
+
rotate_year:
|
107
|
+
list_targets: 'The following reconcilers are eligible for annual rotation:'
|
108
|
+
operations_header: 'The following command(s) will be executed:'
|
109
|
+
operation_rotate: 'Rotate "%{name}"'
|
110
|
+
operation_mkdir: 'mkdir %{path}'
|
111
|
+
confirm_operation: "Yes"
|
112
|
+
confirm_operation_prompt: "Would you like to run the above operations? (Type \"Yes\" to continue) "
|
113
|
+
operation_aborted: "\"rotate_year\" project operation aborted"
|
114
|
+
operation_element: ' 🟢 %{operation}'
|
115
|
+
publish_gsheets:
|
116
|
+
errors:
|
117
|
+
missing_google_secrets: 'Missing a readable config/google-secrets.yml file in your project directory'
|
118
|
+
unable_to_write_to_csvdir: 'Unable to write to path "%{csvdir}"'
|
119
|
+
grid:
|
120
|
+
list_targets: 'The following grids are available:'
|
121
|
+
target_description: '%{description} for %{year}'
|
122
|
+
rescan_grids:
|
123
|
+
target_description: 'Re-scan the journal directory, and register previously unavaible grid targets into the running build'
|
124
|
+
rescan_plots:
|
125
|
+
target_description: 'Re-scan the grid directory, and register previously unavaible plot targets into the running build'
|
126
|
+
reconcile:
|
127
|
+
list_targets: 'The following reconcilers are available:'
|
128
|
+
target_description: 'Reconcile the "%{input_file}" journal'
|
129
|
+
errors:
|
130
|
+
journal_missing: 'Journal(s) Missing.'
|
131
|
+
either_concise_or_stdout: 'Either -concise or -stdout mode can be specified. But, alas, not both.'
|
132
|
+
validate_journal:
|
133
|
+
list_targets: 'The following journal validations are available:'
|
134
|
+
target_description: 'Validate the "%{input_file}" journal'
|
135
|
+
validate_system:
|
136
|
+
list_targets: 'The following system validations are available:'
|
137
|
+
|
138
|
+
error:
|
139
|
+
error: 'Error'
|
140
|
+
warning: 'Warning'
|
141
|
+
missing_entry_in_prices_db: ": The following entry is missing in the prices database:\n P %{time} %{from} %{to}"
|
142
|
+
end_of_args: 'Missing an expected parameter value, in the argument list'
|
143
|
+
no_targets: "No targets specified"
|
144
|
+
missing_target: "One or more targets not found : %{targets}"
|
145
|
+
missing_command: 'No command specified. Try running --help to view the available program modes'
|
146
|
+
command_unrecognized: '"%{command}" command is unrecognized. Consult the help page.'
|
147
|
+
command_errors: "Unable to %{command}:"
|
148
|
+
command_error: " 🟢 %{error}"
|
149
|
+
no_application_dir: "Unable to determine the directory of your application. Consider setting the LEDGER_FILE environment variable, or providing a directory via the --dir parameter"
|
150
|
+
invalid_application_dir: 'Invalid or missing project found at the directory "%{directory}"'
|
151
|
+
status:
|
152
|
+
indicators:
|
153
|
+
complete: '🟢'
|
154
|
+
complete_and: '%{left} & %{right} '
|
155
|
+
fill: '.'
|
156
|
+
indent: ' '
|
157
|
+
truncated: '…'
|
158
|
+
attention1: '🟢'
|
159
|
+
attention2: ' ▩ '
|
160
|
+
commands:
|
161
|
+
reconcile:
|
162
|
+
icon: '🏗️ '
|
163
|
+
header: Building Journals from Feeds
|
164
|
+
prefix: Expanding
|
165
|
+
generate:
|
166
|
+
icon: 🏦
|
167
|
+
header: Generating Automatic Transactions
|
168
|
+
prefix: Making
|
169
|
+
validate_journal:
|
170
|
+
icon: 📒
|
171
|
+
header: Inspecting Individual Journal Files
|
172
|
+
prefix: Validating
|
173
|
+
validate_system:
|
174
|
+
icon: 📚
|
175
|
+
header: Inspecting System State
|
176
|
+
prefix: Validating
|
177
|
+
grid:
|
178
|
+
icon: ▦
|
179
|
+
header: Generating Grids
|
180
|
+
prefix: Calculating
|
181
|
+
plot:
|
182
|
+
icon: 📈
|
183
|
+
header: Generating Plots
|
184
|
+
prefix: Plotting
|
185
|
+
publish_gsheets:
|
186
|
+
icon: 📑
|
187
|
+
header: Publishing to Google Sheets
|
188
|
+
prefix: Sheeting
|
189
|
+
new_project:
|
190
|
+
icon: 📖
|
191
|
+
header: New Project
|
192
|
+
prefix: Initializing
|