moneymanager 0.1.1 → 0.2.0
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.
- checksums.yaml +4 -4
- data/README.md +187 -22
- data/exe/mm +67 -9
- data/lib/moneymanager/archiver.rb +4 -3
- data/lib/moneymanager/entry.rb +4 -4
- data/lib/moneymanager/layout.rb +17 -3
- data/lib/moneymanager/tagger.rb +1 -3
- data/lib/moneymanager/version.rb +1 -1
- data/lib/moneymanager.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39450e9d5be4a772dec12a2db8fb9d0067ead553
|
4
|
+
data.tar.gz: 0db1716715290873ac2c5a903ef24a0ca9cef7ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79a578a780c6c0f523665c2b4da019912cc45588fc9ccaf76abb58e56a146a8998f2d8247b3165c91fc172ef0d19460b844eaf6a1e7faf3298b3f9b6289a9451
|
7
|
+
data.tar.gz: 0c3112832a722691da332cd101b5fbe39a721551b2e9135984f39cae1451444f1c21f45f9735eac9b7b889317df84e7beebfe2927d7f924668270704915f47cb
|
data/README.md
CHANGED
@@ -1,34 +1,199 @@
|
|
1
1
|
# Moneymanager
|
2
2
|
|
3
|
-
|
3
|
+
This is ruby app I wrote to help me managing my personal finance. Some features are still missing, I'll add in the future.
|
4
|
+
I ended up writing my own tool instead of using MoneyWiz et simila is that all the tools I tried are either overcomplicated or dont'have the basic information I need (and also because I like writing Ruby code)
|
4
5
|
|
5
|
-
|
6
|
+
## Features
|
6
7
|
|
7
|
-
|
8
|
+
* Import transactions from a `CSV - CAMT` file. I'm not sure about your bank, but SparkasseBerlin has this option.
|
9
|
+
* The import process is idempotent. Import same transaction multiple times doesn't get duplicate.
|
10
|
+
* Print the list of transacions.
|
11
|
+
* Review the transaction and flag all the approved ones.
|
12
|
+
* Tag the transaction and assign a tag to each one
|
13
|
+
* Print the summary of income/expense general or divided by category.
|
14
|
+
* All the actions have an options to consider only a specific month.
|
8
15
|
|
9
|
-
|
16
|
+
## Why you shouldn't use this
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install moneymanager
|
18
|
+
* The database is just a plain, non-encrypted file.
|
19
|
+
* There are no fancy charts.
|
20
|
+
* The `print/review/tag` taks are _monthly_ based. If you have undreds of transaction per month using this tool can be tedious.
|
21
|
+
*
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
25
|
+
#### Install the gem
|
26
|
+
|
27
|
+
$ gem install moneymanager
|
28
|
+
|
29
|
+
#### Import your CSV FILE
|
30
|
+
|
31
|
+
$ mm add exported.csv
|
32
|
+
Parsed: 99
|
33
|
+
Skipped: 0
|
34
|
+
Inserted: 99
|
35
|
+
# If executed twice, the entries are not duplicated
|
36
|
+
$ mm add exported.csv
|
37
|
+
Parsed: 99
|
38
|
+
Skipped: 99
|
39
|
+
Inserted: 0
|
40
|
+
|
41
|
+
#### Print the transactions
|
42
|
+
By default all the transactions are printed. A month can be specified with the `--month` parameter
|
43
|
+
|
44
|
+
$ mm print
|
45
|
+
+-----+----------+--------------+----------------------------------------------------+-------------+
|
46
|
+
| ✔/✖︎ | Date | Tag | Reason | Amount |
|
47
|
+
+-----+----------+--------------+----------------------------------------------------+-------------+
|
48
|
+
| ✖︎︎ | 17/08/01 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
49
|
+
| ✖︎ | 17/08/01 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
50
|
+
| ✖︎ | 17/08/01 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
51
|
+
| ✖︎ | 17/08/01 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
52
|
+
| ✖︎ | 17/08/01 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
53
|
+
| ✖︎ | 17/08/02 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
54
|
+
| ✖︎ | 17/08/31 | | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
55
|
+
+-----+----------+--------------+----------------------------------------------------+-------------+
|
56
|
+
|
57
|
+
|
58
|
+
#### Review and approve the transactions
|
59
|
+
Flag all the approved transaction.
|
60
|
+
|
61
|
+
$ mm review
|
62
|
+
+----------+------------------------------------------------------+
|
63
|
+
| Date | 2017-08-01 |
|
64
|
+
| Reason | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ |
|
65
|
+
| Amount | -999.0 € |
|
66
|
+
| Company | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ |
|
67
|
+
| Approved | ✖ |
|
68
|
+
| Tag | |
|
69
|
+
+----------+------------------------------------------------------+
|
70
|
+
Do you recognize? (Use arrow keys, press Enter to select)
|
71
|
+
‣ yes
|
72
|
+
no
|
73
|
+
skip
|
74
|
+
abort
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
#### Tag each transaction
|
79
|
+
|
80
|
+
Assign a tag to each (or not) transaction. To generate hierarchy of tags, use a `/` like `Car/Insurance`s
|
81
|
+
|
82
|
+
$ mm tag
|
83
|
+
+----------+------------------------------------------------------+
|
84
|
+
| Date | 2017-08-01 |
|
85
|
+
| Reason | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ |
|
86
|
+
| Amount | -99.0 € |
|
87
|
+
| Company | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ |
|
88
|
+
| Approved | ✔︎ |
|
89
|
+
| Tag | |
|
90
|
+
+----------+------------------------------------------------------+
|
91
|
+
Do you want add a tags? (Use arrow keys, press Enter to select)
|
92
|
+
‣ 1. Skip
|
93
|
+
2. Abort
|
94
|
+
3. Create
|
95
|
+
Car/Gasoline
|
96
|
+
Car/Insurance
|
97
|
+
Car/Tire
|
98
|
+
Heating
|
99
|
+
Mortage
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
#### Enjoi the list of transaction
|
104
|
+
|
105
|
+
$ mm print
|
106
|
+
+-----+----------+------------------------+--------------------------------------------------+-------------+
|
107
|
+
| ✔/✖︎ | Date | Tag | Reason | Amount |
|
108
|
+
+-----+----------+------------------------+--------------------------------------------------+-------------+
|
109
|
+
| ✔︎ | 17/08/01 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
110
|
+
| ✔︎ | 17/08/01 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
111
|
+
| ✔︎ | 17/08/01 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
112
|
+
| ✔︎ | 17/08/31 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
113
|
+
| ✔︎ | 17/08/31 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
114
|
+
| ✔︎ | 17/08/31 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
115
|
+
| ✔︎ | 17/08/31 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
|
116
|
+
+-----+----------+------------------------+--------------------------------------------------+-------------+
|
117
|
+
|
118
|
+
## Reporting
|
119
|
+
|
120
|
+
#### Global Incomes/Expenses
|
121
|
+
|
122
|
+
$ mm report --month 8
|
123
|
+
|
124
|
+
$ mm report --month 8
|
125
|
+
Which type of report? (Use arrow keys, press Enter to select)
|
126
|
+
‣ Global Incomes/Expenses
|
127
|
+
All categories
|
128
|
+
One category
|
129
|
+
|
130
|
+
|
131
|
+
+---------+-----------+
|
132
|
+
| Summary |
|
133
|
+
+---------+-----------+
|
134
|
+
| Income | 1234.0 € |
|
135
|
+
| Expense | -5678.0 € |
|
136
|
+
| Delta | 9999.0 € |
|
137
|
+
+---------+-----------+
|
138
|
+
|
139
|
+
#### Global Incomes/Expenses
|
140
|
+
|
141
|
+
|
142
|
+
$ mm report
|
143
|
+
Which type of report? (Use arrow keys, press Enter to select)
|
144
|
+
Global Incomes/Expenses
|
145
|
+
‣ All categories
|
146
|
+
One category
|
147
|
+
|
148
|
+
|
149
|
+
+------------+----------+
|
150
|
+
| Incomes |
|
151
|
+
+------------+----------+
|
152
|
+
| Salary | 999.0 € |
|
153
|
+
| Investment | 999.0 € |
|
154
|
+
| Rent | 999.0 € |
|
155
|
+
+------------+----------+
|
156
|
+
+-------------------+-----------+
|
157
|
+
| Expenses |
|
158
|
+
+-------------------+-----------+
|
159
|
+
| Heating | -99.0 € |
|
160
|
+
| Mortage | -99.0 € |
|
161
|
+
| Car/Gasoline | -99.0 € |
|
162
|
+
| Car/Insurace | -9999.0 € |
|
163
|
+
| Car/Tire | -999.0 € |
|
164
|
+
+-------------------+-----------+
|
165
|
+
|
166
|
+
|
167
|
+
#### Report for one Tag
|
168
|
+
|
169
|
+
|
170
|
+
$ mm report
|
171
|
+
Which type of report? (Use arrow keys, press Enter to select)
|
172
|
+
Global Incomes/Expenses
|
173
|
+
All categories
|
174
|
+
‣ One category
|
175
|
+
|
176
|
+
Select a tag. (Use arrow keys, press Enter to select)
|
177
|
+
‣ Heating
|
178
|
+
Mortage
|
179
|
+
Car/Gasoline
|
180
|
+
Car/Insurance
|
181
|
+
Car/Tire
|
182
|
+
|
183
|
+
+-----------------+---------+
|
184
|
+
| Expenses |
|
185
|
+
+-----------------+---------+
|
186
|
+
| Heating | -99.0 € |
|
187
|
+
+-----------------+---------+
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
|
192
|
+
## Next release
|
193
|
+
|
194
|
+
* Report for nested tags ( Car/Gasoline, Car/Insurance etc)
|
195
|
+
* Multiple tags
|
196
|
+
* Report for one tag splitted by month
|
32
197
|
|
33
198
|
## Contributing
|
34
199
|
|
data/exe/mm
CHANGED
@@ -18,6 +18,16 @@ command :add do |c|
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
command :reset do |c|
|
22
|
+
c.syntax = 'mm reset'
|
23
|
+
c.description = 'Delete the current archive (danger zone!)'
|
24
|
+
c.action do |_args, _options|
|
25
|
+
if agree('Do you really want to delete everything?')
|
26
|
+
Moneymanager::Archiver.reset
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
21
31
|
command :print do |c|
|
22
32
|
c.syntax = 'mm print [--month <month>]'
|
23
33
|
c.description = 'Print the list of transactions'
|
@@ -48,21 +58,69 @@ command :review do |c|
|
|
48
58
|
end
|
49
59
|
end
|
50
60
|
|
51
|
-
command :
|
52
|
-
c.syntax = 'mm
|
53
|
-
c.description = 'Print
|
54
|
-
c.option '--month INTEGER', Integer, 'Specify the month to
|
61
|
+
command :report do |c|
|
62
|
+
c.syntax = 'mm report'
|
63
|
+
c.description = 'Print all the revenues and all the expenses grouped by tag'
|
64
|
+
c.option '--month INTEGER', Integer, 'Specify the month to report.'
|
55
65
|
c.action do |_args, options|
|
56
66
|
entries = get_entries(options.month)
|
57
|
-
expenses = entries.reject(&:is_income).map(&:amount).reduce(:+)
|
58
|
-
incomes = entries.reject(&:is_expense).map(&:amount).reduce(:+)
|
59
|
-
Layout.print_summary(incomes, expenses)
|
60
67
|
|
68
|
+
prompt = TTY::Prompt.new
|
69
|
+
command = prompt.select('Which type of report?') do |menu|
|
70
|
+
menu.choice 'Global Incomes/Expenses', :global
|
71
|
+
menu.choice 'All categories', :all
|
72
|
+
menu.choice 'Specific Tag', :one
|
73
|
+
end
|
74
|
+
|
75
|
+
case command
|
76
|
+
when :global
|
77
|
+
print_global_report(entries)
|
78
|
+
when :all
|
79
|
+
print_all_categories_report(entries)
|
80
|
+
when :one
|
81
|
+
archiver = Moneymanager::Archiver.new
|
82
|
+
tags = archiver.tags.sort!
|
83
|
+
tag = prompt.select('Select a tag.', tags, per_page: 30)
|
84
|
+
print_one_category_report(entries, tag)
|
85
|
+
end
|
61
86
|
end
|
62
87
|
end
|
63
88
|
|
89
|
+
def print_global_report(entries)
|
90
|
+
expenses = entries.reject(&:income?).map(&:amount).reduce(:+)
|
91
|
+
incomes = entries.reject(&:expense?).map(&:amount).reduce(:+)
|
92
|
+
Layout.print_summary(incomes, expenses)
|
93
|
+
end
|
94
|
+
|
95
|
+
def print_all_categories_report(entries)
|
96
|
+
expenses = entries.reject(&:income?).each_with_object(Hash.new(0)) do |current, sum|
|
97
|
+
tag = current.tag ||= 'Unknown'
|
98
|
+
sum[tag] += current.amount
|
99
|
+
end
|
100
|
+
incomes = entries.reject(&:expense?).each_with_object(Hash.new(0)) do |current, sum|
|
101
|
+
tag = current.tag ||= 'Unknown'
|
102
|
+
sum[tag] += current.amount
|
103
|
+
end
|
104
|
+
|
105
|
+
incomes = incomes.map { |x, v| [x, v] }
|
106
|
+
Layout.print_summary_per_category('Incomes', incomes)
|
107
|
+
|
108
|
+
expenses = expenses.map { |x, v| [x, v] }
|
109
|
+
Layout.print_summary_per_category('Expenses', expenses)
|
110
|
+
end
|
111
|
+
|
112
|
+
def print_one_category_report(entries, tag)
|
113
|
+
entries = entries.select do |entry|
|
114
|
+
entry.tag == tag
|
115
|
+
end
|
116
|
+
print_all_categories_report(entries)
|
117
|
+
end
|
118
|
+
|
64
119
|
def get_entries(month)
|
65
|
-
month ||= Date.today.month
|
66
120
|
archiver = Moneymanager::Archiver.new
|
67
|
-
|
121
|
+
if month.nil?
|
122
|
+
archiver.all_entries
|
123
|
+
else
|
124
|
+
archiver.all_entries_per_month(month)
|
125
|
+
end
|
68
126
|
end
|
@@ -16,10 +16,10 @@ module Moneymanager
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def initialize
|
19
|
-
|
20
|
-
YAML.load_file(Archiver.archive_path)
|
19
|
+
if File.exist? Archiver.archive_path
|
20
|
+
@db = YAML.load_file(Archiver.archive_path)
|
21
21
|
else
|
22
|
-
Archiver.empty_archive
|
22
|
+
@db = Archiver.empty_archive
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -59,6 +59,7 @@ module Moneymanager
|
|
59
59
|
def tags
|
60
60
|
@db[:tags]
|
61
61
|
end
|
62
|
+
|
62
63
|
def store_tag(tag)
|
63
64
|
@db[:tags] << tag
|
64
65
|
save
|
data/lib/moneymanager/entry.rb
CHANGED
data/lib/moneymanager/layout.rb
CHANGED
@@ -24,8 +24,8 @@ class Layout
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.formatted_amount(amount)
|
27
|
-
|
28
|
-
|
27
|
+
s = amount.to_s + ' €'
|
28
|
+
amount < 0 ? s.red : s.green
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.print_summary(income, expenses)
|
@@ -36,7 +36,21 @@ class Layout
|
|
36
36
|
t << ['Delta', formatted_amount(delta)]
|
37
37
|
end
|
38
38
|
table.align_column(1, :right)
|
39
|
-
table.title =
|
39
|
+
table.title = 'Summary'
|
40
|
+
puts table
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.print_summary_per_category(title, rows)
|
44
|
+
return unless rows.count > 0
|
45
|
+
rows = rows.sort! { |r1, r2| r1.first <=> r2.first }
|
46
|
+
rows = rows.map do |row|
|
47
|
+
row[-1] = formatted_amount(row.last)
|
48
|
+
row
|
49
|
+
end
|
50
|
+
table = Terminal::Table.new rows: rows
|
51
|
+
table.align_column(1, :right)
|
52
|
+
table.title = title
|
53
|
+
|
40
54
|
puts table
|
41
55
|
end
|
42
56
|
|
data/lib/moneymanager/tagger.rb
CHANGED
@@ -6,13 +6,11 @@ class Tagger
|
|
6
6
|
def retag(entries)
|
7
7
|
archiver = Moneymanager::Archiver.new
|
8
8
|
|
9
|
-
|
10
|
-
|
11
9
|
prompt = TTY::Prompt.new
|
12
10
|
entries.each do |entry|
|
13
11
|
Layout.clear
|
14
12
|
Layout.print_single(entry)
|
15
|
-
options = default_options.concat(archiver.tags)
|
13
|
+
options = default_options.concat(archiver.tags.sort!)
|
16
14
|
action = prompt.select('Do you want add a tags?', options, per_page: 30)
|
17
15
|
|
18
16
|
if action == default_options[0]
|
data/lib/moneymanager/version.rb
CHANGED
data/lib/moneymanager.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moneymanager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ignazioc
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|