rvgp 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +23 -0
  4. data/LICENSE +504 -0
  5. data/README.md +223 -0
  6. data/Rakefile +32 -0
  7. data/bin/rvgp +8 -0
  8. data/lib/rvgp/application/config.rb +159 -0
  9. data/lib/rvgp/application/descendant_registry.rb +122 -0
  10. data/lib/rvgp/application/status_output.rb +139 -0
  11. data/lib/rvgp/application.rb +170 -0
  12. data/lib/rvgp/base/command.rb +457 -0
  13. data/lib/rvgp/base/grid.rb +531 -0
  14. data/lib/rvgp/base/reader.rb +29 -0
  15. data/lib/rvgp/base/reconciler.rb +434 -0
  16. data/lib/rvgp/base/validation.rb +261 -0
  17. data/lib/rvgp/commands/cashflow.rb +160 -0
  18. data/lib/rvgp/commands/grid.rb +70 -0
  19. data/lib/rvgp/commands/ireconcile.rb +95 -0
  20. data/lib/rvgp/commands/new_project.rb +296 -0
  21. data/lib/rvgp/commands/plot.rb +41 -0
  22. data/lib/rvgp/commands/publish_gsheets.rb +83 -0
  23. data/lib/rvgp/commands/reconcile.rb +58 -0
  24. data/lib/rvgp/commands/rotate_year.rb +202 -0
  25. data/lib/rvgp/commands/validate_journal.rb +59 -0
  26. data/lib/rvgp/commands/validate_system.rb +44 -0
  27. data/lib/rvgp/commands.rb +160 -0
  28. data/lib/rvgp/dashboard.rb +252 -0
  29. data/lib/rvgp/fakers/fake_feed.rb +245 -0
  30. data/lib/rvgp/fakers/fake_journal.rb +57 -0
  31. data/lib/rvgp/fakers/fake_reconciler.rb +88 -0
  32. data/lib/rvgp/fakers/faker_helpers.rb +25 -0
  33. data/lib/rvgp/gem.rb +80 -0
  34. data/lib/rvgp/journal/commodity.rb +453 -0
  35. data/lib/rvgp/journal/complex_commodity.rb +214 -0
  36. data/lib/rvgp/journal/currency.rb +101 -0
  37. data/lib/rvgp/journal/journal.rb +141 -0
  38. data/lib/rvgp/journal/posting.rb +156 -0
  39. data/lib/rvgp/journal/pricer.rb +267 -0
  40. data/lib/rvgp/journal.rb +24 -0
  41. data/lib/rvgp/plot/gnuplot.rb +478 -0
  42. data/lib/rvgp/plot/google-drive/output_csv.rb +44 -0
  43. data/lib/rvgp/plot/google-drive/output_google_sheets.rb +434 -0
  44. data/lib/rvgp/plot/google-drive/sheet.rb +67 -0
  45. data/lib/rvgp/plot.rb +293 -0
  46. data/lib/rvgp/pta/hledger.rb +237 -0
  47. data/lib/rvgp/pta/ledger.rb +308 -0
  48. data/lib/rvgp/pta.rb +311 -0
  49. data/lib/rvgp/reconcilers/csv_reconciler.rb +424 -0
  50. data/lib/rvgp/reconcilers/journal_reconciler.rb +41 -0
  51. data/lib/rvgp/reconcilers/shorthand/finance_gem_hacks.rb +48 -0
  52. data/lib/rvgp/reconcilers/shorthand/international_atm.rb +152 -0
  53. data/lib/rvgp/reconcilers/shorthand/investment.rb +144 -0
  54. data/lib/rvgp/reconcilers/shorthand/mortgage.rb +195 -0
  55. data/lib/rvgp/utilities/grid_query.rb +190 -0
  56. data/lib/rvgp/utilities/yaml.rb +131 -0
  57. data/lib/rvgp/utilities.rb +44 -0
  58. data/lib/rvgp/validations/balance_validation.rb +68 -0
  59. data/lib/rvgp/validations/duplicate_tags_validation.rb +48 -0
  60. data/lib/rvgp/validations/uncategorized_validation.rb +15 -0
  61. data/lib/rvgp.rb +66 -0
  62. data/resources/README.MD/2022-cashflow-google.png +0 -0
  63. data/resources/README.MD/2022-cashflow.png +0 -0
  64. data/resources/README.MD/all-wealth-growth-google.png +0 -0
  65. data/resources/README.MD/all-wealth-growth.png +0 -0
  66. data/resources/gnuplot/default.yml +80 -0
  67. data/resources/i18n/en.yml +192 -0
  68. data/resources/iso-4217-currencies.json +171 -0
  69. data/resources/skel/Rakefile +5 -0
  70. data/resources/skel/app/grids/cashflow_grid.rb +27 -0
  71. data/resources/skel/app/grids/monthly_income_and_expenses_grid.rb +25 -0
  72. data/resources/skel/app/grids/wealth_growth_grid.rb +35 -0
  73. data/resources/skel/app/plots/cashflow.yml +33 -0
  74. data/resources/skel/app/plots/monthly-income-and-expenses.yml +17 -0
  75. data/resources/skel/app/plots/wealth-growth.yml +20 -0
  76. data/resources/skel/config/csv-format-acme-checking.yml +9 -0
  77. data/resources/skel/config/google-secrets.yml +5 -0
  78. data/resources/skel/config/rvgp.yml +0 -0
  79. data/resources/skel/journals/prices.db +0 -0
  80. data/rvgp.gemspec +6 -0
  81. data/test/assets/ledger_total_monthly_liabilities_with_empty.xml +383 -0
  82. data/test/assets/ledger_total_monthly_liabilities_with_empty2.xml +428 -0
  83. data/test/test_command_base.rb +61 -0
  84. data/test/test_commodity.rb +270 -0
  85. data/test/test_csv_reconciler.rb +60 -0
  86. data/test/test_currency.rb +24 -0
  87. data/test/test_fake_feed.rb +228 -0
  88. data/test/test_fake_journal.rb +98 -0
  89. data/test/test_fake_reconciler.rb +60 -0
  90. data/test/test_journal_parse.rb +545 -0
  91. data/test/test_ledger.rb +102 -0
  92. data/test/test_plot.rb +133 -0
  93. data/test/test_posting.rb +50 -0
  94. data/test/test_pricer.rb +139 -0
  95. data/test/test_pta_adapter.rb +575 -0
  96. data/test/test_utilities.rb +45 -0
  97. metadata +268 -0
@@ -0,0 +1,171 @@
1
+ [
2
+ {
3
+ "Entity":"UNITED STATES",
4
+ "Currency":"US Dollar",
5
+ "Alphabetic Code":"USD",
6
+ "Numeric Code":"840",
7
+ "Minor unit":"2",
8
+ "Symbol":"$"
9
+ },
10
+ {
11
+ "Entity":"EUROPEAN UNION ",
12
+ "Currency":"Euro",
13
+ "Alphabetic Code":"EUR",
14
+ "Numeric Code":"978",
15
+ "Minor unit":"2"
16
+ },
17
+ {
18
+ "Entity":"HONDURAS",
19
+ "Currency":"Lempira",
20
+ "Alphabetic Code":"HNL",
21
+ "Numeric Code":"340",
22
+ "Minor unit":"2"
23
+ },
24
+ {
25
+ "Entity":"COLOMBIA",
26
+ "Currency":"Colombian Peso",
27
+ "Alphabetic Code":"COP",
28
+ "Numeric Code":"170",
29
+ "Minor unit":"2"
30
+ },
31
+ {
32
+ "Entity":"COLOMBIA",
33
+ "Currency":"Unidad de Valor Real",
34
+ "Alphabetic Code":"COU",
35
+ "Numeric Code":"970",
36
+ "Minor unit":"2"
37
+ },
38
+ {
39
+ "Entity":"THAILAND",
40
+ "Currency":"Baht",
41
+ "Alphabetic Code":"THB",
42
+ "Numeric Code":"764",
43
+ "Minor unit":"2"
44
+ },
45
+ {
46
+ "Entity":"UNITED KINGDOM",
47
+ "Currency":"Pound Sterling",
48
+ "Alphabetic Code":"GBP",
49
+ "Numeric Code":"826",
50
+ "Minor unit":"2"
51
+ },
52
+ {
53
+ "Entity":"CANADA",
54
+ "Currency":"Canadian Dollar",
55
+ "Alphabetic Code":"CAD",
56
+ "Numeric Code":"124",
57
+ "Minor unit":"2"
58
+ },
59
+ {
60
+ "Entity":"ARGENTINA",
61
+ "Currency":"Argentine Peso",
62
+ "Alphabetic Code":"ARS",
63
+ "Numeric Code":"032",
64
+ "Minor unit":"2"
65
+ },
66
+ {
67
+ "Entity":"CHILE",
68
+ "Currency":"Unidades de fomento",
69
+ "Alphabetic Code":"CLF",
70
+ "Numeric Code":"990",
71
+ "Minor unit":"0"
72
+ },
73
+ {
74
+ "Entity":"CHILE",
75
+ "Currency":"Chilean Peso",
76
+ "Alphabetic Code":"CLP",
77
+ "Numeric Code":"152",
78
+ "Minor unit":"0"
79
+ },
80
+ {
81
+ "Entity":"NICARAGUA",
82
+ "Currency":"Cordoba",
83
+ "Alphabetic Code":"NIC",
84
+ "Numeric Code":"—",
85
+ "Withdrawal Date":"1990-10"
86
+ },
87
+ {
88
+ "Entity":"PANAMA",
89
+ "Currency":"Balboa",
90
+ "Alphabetic Code":"PAB",
91
+ "Numeric Code":"590",
92
+ "Minor unit":"2"
93
+ },
94
+ {
95
+ "Entity":"COSTA RICA",
96
+ "Currency":"Costa Rican Colon",
97
+ "Alphabetic Code":"CRC",
98
+ "Numeric Code":"188",
99
+ "Minor unit":"2"
100
+ },
101
+ {
102
+ "Entity":"BRAZIL",
103
+ "Currency":"Brazilian Real",
104
+ "Alphabetic Code":"BRL",
105
+ "Numeric Code":"986",
106
+ "Minor unit":"2"
107
+ },
108
+ {
109
+ "Entity":"MEXICO",
110
+ "Currency":"Mexican Peso",
111
+ "Alphabetic Code":"MXN",
112
+ "Numeric Code":"484",
113
+ "Minor unit":"2"
114
+ },
115
+ {
116
+ "Entity":"MEXICO",
117
+ "Currency":"Mexican Unidad de Inversion (UDI)",
118
+ "Alphabetic Code":"MXV",
119
+ "Numeric Code":"979",
120
+ "Minor unit":"2"
121
+ },
122
+ {
123
+ "Entity":"EL SALVADOR",
124
+ "Currency":"El Salvador Colon",
125
+ "Alphabetic Code":"SVC",
126
+ "Numeric Code":"222",
127
+ "Minor unit":"2"
128
+ },
129
+ {
130
+ "Entity":"URUGUAY",
131
+ "Currency":"Uruguay Peso en Unidades Indexadas (URUIURUI)",
132
+ "Alphabetic Code":"UYI",
133
+ "Numeric Code":"940",
134
+ "Minor unit":"0"
135
+ },
136
+ {
137
+ "Entity":"URUGUAY",
138
+ "Currency":"Peso Uruguayo",
139
+ "Alphabetic Code":"UYU",
140
+ "Numeric Code":"858",
141
+ "Minor unit":"2"
142
+ },
143
+ {
144
+ "Entity":"PARAGUAY",
145
+ "Currency":"Guarani",
146
+ "Alphabetic Code":"PYG",
147
+ "Numeric Code":"600",
148
+ "Minor unit":"0"
149
+ },
150
+ {
151
+ "Entity":"PERU",
152
+ "Currency":"Nuevo Sol",
153
+ "Alphabetic Code":"PEN",
154
+ "Numeric Code":"604",
155
+ "Minor unit":"2"
156
+ },
157
+ {
158
+ "Entity":"JAPAN",
159
+ "Currency":"Yen",
160
+ "Alphabetic Code":"JPY",
161
+ "Numeric Code":"392",
162
+ "Minor unit":"0"
163
+ },
164
+ {
165
+ "Entity":"GUATEMALA",
166
+ "Currency":"Quetzal",
167
+ "Alphabetic Code":"GTQ",
168
+ "Numeric Code":"320",
169
+ "Minor unit":"2"
170
+ }
171
+ ]
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rvgp'
4
+
5
+ RVGP.initialize_app(File.dirname(__FILE__)).initialize_rake! self
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class writes the cashflow numbers, by month
4
+ class CashFlowGrid < RVGP::Base::Grid
5
+ grid 'cashflow', 'Generate Cashflow Grids', 'Cashflows by month (%s)',
6
+ output_path_template: '%s-cashflow'
7
+
8
+ def sheet_header
9
+ ['Account'] + map_months { |month| month.strftime('%m-%y') }
10
+ end
11
+
12
+ def sheet_body
13
+ # NOTE: I think it only makes sense to sort these by account name. Mostly
14
+ # because any other sorting mechanism wouldn't 'line up' with the
15
+ # other years. But, it's also nice that the git diff's would be
16
+ # easier to parse.
17
+ monthly_amounts_by_account
18
+ .sort_by { |acct, _| acct }
19
+ .map { |account, by_month| [account] + map_months { |m| by_month[m].round(2) if by_month[m] } }
20
+ end
21
+
22
+ private
23
+
24
+ def map_months(&block)
25
+ months_through(starting_at, ending_at).map(&block)
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class writes the monthly income and expense numbers, by month
4
+ class MonthlyIncomeAndExpensesGrid < RVGP::Base::Grid
5
+ grid 'income_and_expenses',
6
+ 'Generate Income & Expense Grids',
7
+ 'Income & Expense by month (%s)',
8
+ output_path_template: '%s-monthly-income-and-expenses'
9
+
10
+ def sheet_header
11
+ %w[Date Income Expense]
12
+ end
13
+
14
+ def sheet_body
15
+ table = { 'Income' => monthly_amounts('Income'), 'Expense' => monthly_amounts('Expense') }
16
+
17
+ # This deserializes our lookup hash(es) into rows:
18
+ months_through(starting_at, ending_at).collect do |month|
19
+ [month.strftime('%m-%y')] + %w[Income Expense].map do |direction|
20
+ cell = table[direction][month]
21
+ cell ? cell.abs : nil
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class writes the wealth growth grid, by month
4
+ class WealthGrowthGrid < RVGP::Base::Grid
5
+ grid 'wealth_growth', 'Generate Wealth Growth Grids', 'Wealth Growth by month (%s)',
6
+ output_path_template: '%s-wealth-growth'
7
+
8
+ def sheet_header
9
+ %w[Date Assets Liabilities]
10
+ end
11
+
12
+ def sheet_body
13
+ # NOTE: If we're having a problem with prices not matching outputs,
14
+ # depending on whether we're rebuilding the whole grids directory, as
15
+ # compared to just rebuilding the newest year, it's probably because of
16
+ # the notes on prices there at the bottom of prices.db
17
+ assets, liabilities = *%w[Assets Liabilities].collect do |acct|
18
+ monthly_totals acct, accrue_before_begin: true
19
+ end
20
+
21
+ months = months_through starting_at, ending_at
22
+
23
+ months.collect.with_index do |month, i|
24
+ # NOTE: The reason we use this last_month hack, is because ledger tends to
25
+ # omit column values, if there's no 'activity' in a category, at the end
26
+ # of the display range. hledger doesn't do that, and we can probably nix
27
+ # this if/when we switch the register command over to hledger...
28
+ last_month = months[i - 1] if i.positive?
29
+
30
+ [month.strftime('%m-%y'),
31
+ assets[month] || assets[last_month],
32
+ liabilities[month] || liabilities[last_month]]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ title: "Cashflow Expenses (%{year})"
2
+ glob: "%{year}-cashflow.csv"
3
+ grid_hacks:
4
+ # NOTE: "date"/cornerstone column is the 1 here
5
+ keystone: "Date"
6
+ select_rows: !!proc >
7
+ /\:Expenses\:/.match name
8
+ # TODO: Change this to keystone:
9
+ sort_rows_by: !!proc >
10
+ row[1...].compact.sum * -1
11
+ truncate_rows: 25 # Sheet::MAX_COLUMNS-1
12
+ # TODO: Hmmm, I guess Google may need this?
13
+ switch_rows_columns: true
14
+ google:
15
+ chart_type: area
16
+ axis:
17
+ left: "Amount"
18
+ bottom: "Month"
19
+ stacked_type: "STACKED"
20
+ series_colors: {}
21
+ gnuplot:
22
+ chart_type: area
23
+ domain: monthly
24
+ is_stacked: true
25
+ axis:
26
+ left: "Amount"
27
+ bottom: "Month"
28
+ # TODO: For cashflow, Invert the legend order... why is hotels on bottom right, instead of top left
29
+ additional_lines: |+
30
+ set xtics scale 0 rotate by 45 offset -1.4,-1.4
31
+ set xtics out
32
+ set tics front
33
+ set key title ' '
@@ -0,0 +1,17 @@
1
+ title: "Monthly Income & Expenses (%{year})"
2
+ glob: "%{year}-monthly-income-and-expenses.csv"
3
+ google:
4
+ chart_type: column
5
+ axis:
6
+ left: "Amount"
7
+ bottom: "Month"
8
+ gnuplot:
9
+ chart_type: column
10
+ is_clustered: true
11
+ xrange_start: 1
12
+ axis:
13
+ left: "Amount"
14
+ bottom: "Month"
15
+ additional_lines: |+
16
+ set xtics scale 0 rotate by 45 offset -1.4,-1.4
17
+ set key title ' '
@@ -0,0 +1,20 @@
1
+ title: "Wealth Growth (%{year})"
2
+ glob: "%{year}-wealth-growth.csv"
3
+ grid_hacks:
4
+ store_cell: !!proc >
5
+ (cell) ? cell.to_f.abs : nil
6
+ google:
7
+ chart_type: area
8
+ axis:
9
+ left: "Amount"
10
+ bottom: "Date"
11
+ gnuplot:
12
+ chart_type: area
13
+ domain: monthly
14
+ axis:
15
+ left: "Amount"
16
+ bottom: "Date"
17
+ additional_lines: |+
18
+ set xtics scale 0 rotate by 45 offset -1.4,-1.4
19
+ set key title ' '
20
+ set style fill transparent solid 0.7 border
@@ -0,0 +1,9 @@
1
+ csv_headers: true
2
+ reverse_order: true
3
+ default_currency: $
4
+ fields:
5
+ date: !!proc Date.strptime(row['Date'], '%m/%d/%Y')
6
+ amount: !!proc >
7
+ withdrawal, deposit = row[3..4].collect {|a| a.to_commodity unless a.empty?};
8
+ ( deposit ? deposit.invert! : withdrawal ).quantity_as_s
9
+ description: !!proc row['Description']
@@ -0,0 +1,5 @@
1
+ client_id: "841596637004-vcljkfs9o45s12nq6g3r54vtu6htp8b9.apps.googleusercontent.com"
2
+ project_id: "ruby-rake-accounting"
3
+ client_secret: "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"
4
+ token_path: "google-token.yml"
5
+ application_name: "rvgp"
File without changes
File without changes
data/rvgp.gemspec ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env gem build
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'lib/rvgp/gem'
5
+
6
+ RVGP::Gem.specification