moneymanager 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|