moneymanager 0.3.1 → 0.3.2

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
  SHA1:
3
- metadata.gz: c07fde9f3699dfb8fe2264cfd3fbe5d935bc3e57
4
- data.tar.gz: 596525dc60a1324c392f750a047e31165d349aa0
3
+ metadata.gz: b48c22d9b20b8fb3a2079e37481b02312fb33dd9
4
+ data.tar.gz: 4798bf1ef13e3b70e7a9abf2e396e8780c7d3a94
5
5
  SHA512:
6
- metadata.gz: e3f41e6655efd33ee4e8f187bd73553f7d3d5fca7162fd90374d9db44f352bb5bcf2373e0c6e441c5e91e2af9a8a4455687c9174d6d816c9926edc3d05529b3a
7
- data.tar.gz: 1b73623c3070702ecaff7fb6042d7e6a08fe6b5ebf6501f6b973038a13f395af8d2837c6df1c3781da7d824d6b8f3e28b1dd90aa16145873eaf66d8f1338f4dd
6
+ metadata.gz: 5cda47c9009ade56c80330082717e72bd6b679d1c152f123f9d96efeb910d781810e39f8a20baf2ecbd3169273e63ef2a7b69b851f4253d6e4f09b5a5d54e969
7
+ data.tar.gz: a7c7d07db40d9155aba911407e030778b9d26ca13568ef0c43cd9ef0924cf5a181e2bab2322acf3d3fdef2a729788ef36b76e4c5dc1a91e29a0a88939b165e1d
data/README.md CHANGED
@@ -22,6 +22,7 @@ I wrote my own tool instead of using MoneyWiz because I like writing ruby code a
22
22
  * Total expense
23
23
  * All incomes grouped by category
24
24
  * All expenses grouped by category
25
+ * All the entries with a specific tag
25
26
  * Trend of tag overtime
26
27
 
27
28
  ## Why you shouldn't use this
@@ -125,6 +126,15 @@ Assign a tag to a transaction. To generate hierarchy of tags, use a `/` like `Ca
125
126
  | ✔︎ | 17/08/31 | ◼◼◼◼◼◼ Censored ◼◼◼◼◼◼ | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
126
127
  +-----+----------+------------------------+--------------------------------------------------+-------------+
127
128
 
129
+
130
+ #### Mark a transaction as bank transfer in order to be skipped on the normal reports
131
+
132
+ The edit command supports only one option so far.
133
+
134
+ $ mm edit --entry c88f92
135
+ Select one option: (Use arrow keys, press Enter to select)
136
+ ‣ Toggle banck transfer state
137
+
128
138
  ## Reporting
129
139
 
130
140
  #### Total (Incomes or Expenses)
@@ -140,6 +150,7 @@ Print the total of the incomes or expenses on the whole archive or on the select
140
150
  All Incomes
141
151
  All Expenses
142
152
  Specific Tag
153
+ Specific Tag (grouped by month)
143
154
 
144
155
 
145
156
  Which type of report? Total (Incomes)
@@ -159,6 +170,7 @@ Print the list of all the incomes (or expenses) grouped by tag. The entries with
159
170
  ‣ All Incomes
160
171
  All Expenses
161
172
  Specific Tag
173
+ Specific Tag (grouped by month)
162
174
 
163
175
 
164
176
 
@@ -173,7 +185,6 @@ Print the list of all the incomes (or expenses) grouped by tag. The entries with
173
185
  | 9999999.0 € |
174
186
  +--------------+----------+
175
187
 
176
-
177
188
  #### One tag grouped by month
178
189
 
179
190
  Print al list in which the entries with the selected tag are grouped by month. This is the report you want to use to understand if your heating bill is becoming bigger overtime.
@@ -185,6 +196,37 @@ Print al list in which the entries with the selected tag are grouped by month. T
185
196
  All Incomes
186
197
  All Expenses
187
198
  ‣ Specific Tag
199
+ Specific Tag (grouped by month)
200
+
201
+ Select a tag. (Use arrow keys, press Enter to select)
202
+ ‣ Heating
203
+ Mortage
204
+ Car/Gasoline
205
+ Car/Insurance
206
+ Car/Tire
207
+
208
+ Select a tag. Heating
209
+ +-----+----------+---------+--------------------------------------------------+-------------+
210
+ | ✔/✖︎ | Date | Tag | Reason | Amount |
211
+ +-----+----------+---------+--------------------------------------------------+-------------+
212
+ | ✔︎ | 17/08/01 | Heating | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
213
+ | ✔︎ | 17/08/01 | Heating | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
214
+ | ✔︎ | 17/08/31 | Heating | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € |
215
+ +-----+----------+---------+--------------------------------------------------+-------------+
216
+
217
+
218
+ #### One tag grouped by month
219
+
220
+ Print al list in which the entries with the selected tag are grouped by month. This is the report you want to use to understand if your heating bill is becoming bigger overtime.
221
+
222
+ $ mm report
223
+ Which type of report? (Use arrow keys, press Enter to select)
224
+ Total (Incomes)
225
+ Total (Expenses)
226
+ All Incomes
227
+ All Expenses
228
+ Specific Tag
229
+ ‣ Specific Tag (grouped by month)
188
230
 
189
231
  Select a tag. (Use arrow keys, press Enter to select)
190
232
  ‣ Heating
@@ -201,19 +243,38 @@ Print al list in which the entries with the selected tag are grouped by month. T
201
243
  | -198.0 € |
202
244
  +-----------+---------+
203
245
 
246
+ #### One tag grouped by month
204
247
 
248
+ If you're moving some money to/from a different account of yours, the related entries should be marked as "bank transfer" in order to not compromise your income/expense reports. This specific report can be used to print only the bank transfers entries
205
249
 
250
+ Which type of report? (Use arrow keys, press Enter to select)
251
+ ‣ Total (Incomes)
252
+ Total (Expenses)
253
+ All Incomes
254
+ All Expenses
255
+ Specific Tag
256
+ Specific Tag (grouped by month)
257
+ Bank transfers
258
+
259
+ +-----+---+----------+--------+-------------------------------------------------+--------------+--------+
260
+ | ✔/✖︎ | ♻︎ | Date | Tag | Reason | Amount | SHA1 |
261
+ +-----+---+----------+--------+-------------------------------------------------+--------------+--------+
262
+ | ✔︎ | ♻︎ | 01/01/17 | Invest | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € | 2949af |
263
+ | ✔︎ | ♻︎ | 01/02/17 | Invest | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € | 002862 |
264
+ | ✔︎ | ♻︎ | 01/03/17 | Invest | ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ C E N S O R E D ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼︎ | 99999.99 € | c88f92 |
265
+ +-----+---+----------+--------+-------------------------------------------------+--------------+--------+
206
266
 
207
267
  ## To do
208
268
 
209
269
  * [x] Filter by one single entry
210
270
  * [x] Report for one tag splitted by month
271
+ * [x] Add a backup options
272
+ * [x] Exclude account transfers from the list of expenses/incomes
211
273
  * [ ] Report for nested tags ( Car/Gasoline, Car/Insurance etc)
212
274
  * [ ] Multiple tags
213
- * [ ] Add a backup options
214
- * [ ] Manage multiple banck account
215
- * [ ] Exclude account transfer from the list of expenses/incomes
275
+ * [ ] Manage multiple bank account
216
276
  * [ ] Print fancy chart in html
277
+ * [ ] Add more parameters to directly generate the reports avoid the manual selection.
217
278
 
218
279
 
219
280
  ## Contributing
data/exe/mm CHANGED
@@ -18,13 +18,20 @@ command :add do |c|
18
18
  end
19
19
  end
20
20
 
21
+ command :backup do |c|
22
+ c.syntax = 'mm backup'
23
+ c.description = 'Create a backup copy of your archive (~/.moneymanager)'
24
+ c.action do |_args, _options|
25
+ archiver = Moneymanager::Archiver.new
26
+ archiver.backup
27
+ end
28
+ end
29
+
21
30
  command :reset do |c|
22
31
  c.syntax = 'mm reset'
23
32
  c.description = 'Delete the current archive (danger zone!)'
24
33
  c.action do |_args, _options|
25
- if agree('Do you really want to delete everything?')
26
- Moneymanager::Archiver.reset
27
- end
34
+ Moneymanager::Archiver.reset if agree('Do you really want to delete everything?')
28
35
  end
29
36
  end
30
37
 
@@ -39,6 +46,31 @@ command :print do |c|
39
46
  end
40
47
  end
41
48
 
49
+ command :edit do |c|
50
+ c.syntax = 'mm edit --entry SHA1'
51
+ c.description = 'Edit the selected entry'
52
+ c.option '--entry STRING', String, 'Specify the entry to edit.'
53
+ c.action do |_args, options|
54
+ raise ArgumentError, '--entry is required!' unless options.entry
55
+ entry = get_entries(nil, options.entry).first
56
+ prompt = TTY::Prompt.new
57
+ command = prompt.select('Select one option:') do |menu|
58
+ menu.choice 'Toggle bank transfer state', :toggle_bank_transfer
59
+ menu.choice 'Delete', :delete_transaction
60
+ end
61
+ case command
62
+ when :toggle_bank_transfer
63
+ archiver = Moneymanager::Archiver.new
64
+ entry.bank_transfer = !entry.bank_transfer
65
+ archiver.update(entry)
66
+ when :delete_transaction
67
+ archiver = Moneymanager::Archiver.new
68
+ Layout.print_single(entry)
69
+ archiver.delete(entry) if agree('Delete?')
70
+ end
71
+ end
72
+ end
73
+
42
74
  command :tag do |c|
43
75
  c.syntax = 'mm tags'
44
76
  c.description = 'Print the list of transactions'
@@ -69,12 +101,14 @@ command :report do |c|
69
101
  entries = get_entries(options.month, nil)
70
102
 
71
103
  prompt = TTY::Prompt.new
72
- command = prompt.select('Which type of report?') do |menu|
104
+ command = prompt.select('Which type of report?', per_page: 30) do |menu|
73
105
  menu.choice 'Total (Incomes)', :global_incomes
74
106
  menu.choice 'Total (Expenses)', :global_expenses
75
107
  menu.choice 'All Incomes', :all_incomes
76
108
  menu.choice 'All Expenses', :all_expenses
77
109
  menu.choice 'Specific Tag', :one_tag
110
+ menu.choice 'Specific Tag (grouped by month)', :one_tag_grouped_by_month
111
+ menu.choice 'Bank transfers', :bank_transfers
78
112
  end
79
113
  report = Report.new
80
114
  case command
@@ -86,17 +120,24 @@ command :report do |c|
86
120
  report.print_group_by_categories_report(entries, true)
87
121
  when :all_expenses
88
122
  report.print_group_by_categories_report(entries, false)
123
+ when :one_tag_grouped_by_month
124
+ archiver = Moneymanager::Archiver.new
125
+ tags = archiver.tags.sort!
126
+ tag = prompt.select('Select a tag.', tags, per_page: 30)
127
+ report.print_group_by_month_report(entries, tag)
89
128
  when :one_tag
90
129
  archiver = Moneymanager::Archiver.new
91
130
  tags = archiver.tags.sort!
92
131
  tag = prompt.select('Select a tag.', tags, per_page: 30)
93
- report.print_group_by_month_report(entries,tag)
132
+ report.print_only_matching_tag(entries, tag)
133
+ when :bank_transfers
134
+ archiver = Moneymanager::Archiver.new
135
+ entries = archiver.all_bank_transfers
136
+ Layout.print_multiple(entries)
94
137
  end
95
138
  end
96
139
  end
97
140
 
98
-
99
-
100
141
  def get_entries(month, entry_id)
101
142
  archiver = Moneymanager::Archiver.new
102
143
  result = archiver.all_entries
@@ -114,4 +155,3 @@ def get_entries(month, entry_id)
114
155
  end
115
156
  result
116
157
  end
117
-
@@ -1,9 +1,21 @@
1
1
  require 'yaml'
2
+ require 'fileutils'
2
3
 
3
4
  module Moneymanager
4
5
  class Archiver
5
- def self.archive_path
6
- File.join(Dir.home, '.moneymanager')
6
+ attr_accessor :home_folder
7
+
8
+ def base_path
9
+ File.join(home_folder, '.moneymanager')
10
+ end
11
+
12
+ def archive_path
13
+ File.join(base_path, 'archive')
14
+ end
15
+
16
+ def backup_path
17
+ date_filename = Time.now.to_i.to_s
18
+ File.join(base_path, date_filename)
7
19
  end
8
20
 
9
21
  def self.empty_archive
@@ -15,16 +27,23 @@ module Moneymanager
15
27
  File.write(Archiver.archive_path, Archiver.empty_archive.to_yaml)
16
28
  end
17
29
 
18
- def initialize
19
- if File.exist? Archiver.archive_path
20
- @db = YAML.load_file(Archiver.archive_path)
21
- else
22
- @db = Archiver.empty_archive
23
- end
30
+ def backup
31
+ File.write(backup_path, @db.to_yaml)
32
+ end
33
+
34
+ def initialize(home_folder = Dir.home)
35
+ self.home_folder = home_folder
36
+
37
+ FileUtils.mkdir_p(base_path)
38
+ @db = if File.exist? archive_path
39
+ YAML.load_file(archive_path)
40
+ else
41
+ Archiver.empty_archive
42
+ end
24
43
  end
25
44
 
26
45
  def save
27
- File.write(Archiver.archive_path, @db.to_yaml)
46
+ File.write(archive_path, @db.to_yaml)
28
47
  end
29
48
 
30
49
  def store(entries)
@@ -46,10 +65,20 @@ module Moneymanager
46
65
  save
47
66
  end
48
67
 
68
+ def delete(entry)
69
+ puts entry
70
+ @db[:entries].delete_if { |obj| obj.digest == entry.digest }
71
+ save
72
+ end
73
+
49
74
  def all_entries
50
75
  @db[:entries].sort_by(&:date)
51
76
  end
52
77
 
78
+ def all_bank_transfers
79
+ @db[:entries].sort_by(&:date).select(&:bank_transfer)
80
+ end
81
+
53
82
  def tags
54
83
  @db[:tags]
55
84
  end
@@ -1,10 +1,12 @@
1
1
  require 'digest/sha1'
2
2
  module Moneymanager
3
3
  class Entry
4
- attr_accessor :date, :reason, :amount, :company, :raw, :approved, :tag
4
+ attr_accessor :id, :date, :reason, :amount, :company, :raw, :approved, :tag, :bank_transfer
5
5
 
6
6
  def initialize
7
+ @amount = 0
7
8
  @approved = false
9
+ @bank_transfer = false
8
10
  end
9
11
 
10
12
  def digest
@@ -23,17 +25,29 @@ module Moneymanager
23
25
  end
24
26
  end
25
27
 
28
+ def formatted_is_bank_tranfer
29
+ if bank_transfer
30
+ '♻︎'.yellow
31
+ else
32
+ ''
33
+ end
34
+ end
35
+
26
36
  def formatted_amount
27
37
  s = amount.to_s + ' €'
28
38
  amount < 0 ? s.red : s.green
29
39
  end
30
40
 
31
41
  def expense?
32
- amount < 0
42
+ amount < 0 && !bank_transfer
33
43
  end
34
44
 
35
45
  def income?
36
- !expense?
46
+ amount > 0 && !bank_transfer
47
+ end
48
+
49
+ def bank_transfer?
50
+ bank_transfer
37
51
  end
38
52
  end
39
53
  end
@@ -4,10 +4,10 @@ class Layout
4
4
  print_single(entries.first)
5
5
  else
6
6
  clear
7
- rows = entries.map { |entry| [entry.formatted_approved, entry.date.strftime('%y/%m/%d'), entry.tag, entry.reason[0...50], entry.formatted_amount, entry.digest[0...6]] }
7
+ rows = entries.map { |entry| [entry.formatted_approved, entry.formatted_is_bank_tranfer, entry.date.strftime('%d/%m/%y'), entry.tag, entry.reason[0...50], entry.formatted_amount, entry.digest[0...6]] }
8
8
 
9
- table = Terminal::Table.new headings: ['✔/✖︎', 'Date', 'Tag', 'Reason', 'Amount', 'SHA1'], rows: rows
10
- table.align_column(4, :right)
9
+ table = Terminal::Table.new headings: ['✔/✖︎', '♻︎', 'Date', 'Tag', 'Reason', 'Amount', 'SHA1'], rows: rows
10
+ table.align_column(5, :right)
11
11
  table.align_column(0, :center)
12
12
 
13
13
  puts table
@@ -22,6 +22,7 @@ class Layout
22
22
  amount: entry.formatted_amount,
23
23
  company: entry.company,
24
24
  approved: entry.formatted_approved,
25
+ bank_transfer: entry.formatted_is_bank_tranfer,
25
26
  tag: entry.tag
26
27
  }
27
28
  rows = hash.map { |k, v| [k.to_s.capitalize, v] }
@@ -29,7 +30,7 @@ class Layout
29
30
  end
30
31
 
31
32
  def self.formatted_amount(amount)
32
- s = sprintf('%.2f €', amount)
33
+ s = format('%.2f €', amount)
33
34
  amount < 0 ? s.red : s.green
34
35
  end
35
36
 
@@ -43,15 +44,16 @@ class Layout
43
44
 
44
45
  def self.print_generic_rows(rows)
45
46
  return unless rows.count > 0
46
- sum = rows.reduce(0) { | tot, row | tot + row.last }
47
+ sum = rows.reduce(0) { |tot, row| tot + row.last }
47
48
  table = Terminal::Table.new
48
- rows = rows.each { |row|
49
+ rows.each do |row|
49
50
  table.add_row [
50
- { :value => row[0], :alignment => :left},
51
- { :value => formatted_amount(row.last), :alignment => :right }]
52
- }
51
+ { value: row[0], alignment: :left },
52
+ { value: formatted_amount(row.last), alignment: :right }
53
+ ]
54
+ end
53
55
  table.add_separator
54
- table.add_row [{ :value => formatted_amount(sum), :colspan => 2, :alignment => :right }]
56
+ table.add_row [{ value: formatted_amount(sum), colspan: 2, alignment: :right }]
55
57
 
56
58
  puts table
57
59
  end
@@ -29,15 +29,21 @@ module Moneymanager
29
29
  def parse
30
30
  options = { headers: true, return_headers: false, header_converters: :symbol, converters: :all, col_sep: ';' }
31
31
  entries = []
32
+ invalid = 0
32
33
  CSV.foreach(@local_file, options) do |row|
33
- entry = Entry.new
34
- entry.date = Date.strptime(row[:buchungstag], '%d.%m.%y')
35
- entry.reason = row[:verwendungszweck].squeeze(' ')
36
- entry.amount = row[:betrag].to_s.gsub(',', '.').to_f
37
- entry.company = row[:beguenstigterzahlungspflichtiger].squeeze(' ')
38
- entry.raw = row.to_csv.squeeze(' ')
39
- entries << entry
34
+ if row[:info] == 'Umsatz gebucht'
35
+ entry = Entry.new
36
+ entry.date = Date.strptime(row[:buchungstag], '%d.%m.%y')
37
+ entry.reason = row[:verwendungszweck].squeeze(' ')
38
+ entry.amount = row[:betrag].to_s.tr(',', '.').to_f
39
+ entry.company = row[:beguenstigterzahlungspflichtiger].squeeze(' ')
40
+ entry.raw = row.to_csv.gsub(/\s+/, "")
41
+ entries << entry
42
+ else
43
+ invalid += 1
44
+ end
40
45
  end
46
+ puts "Invalid: #{invalid}"
41
47
  entries
42
48
  end
43
49
  end
@@ -1,35 +1,43 @@
1
1
  class Report
2
-
3
- def print_total_report(entries, onlyIncome)
4
- total = 0
5
- if (onlyIncome)
6
- total = entries.reject(&:expense?).map(&:amount).reduce(:+)
7
- else
8
- total = entries.reject(&:income?).map(&:amount).reduce(:+)
9
- end
2
+ def print_total_report(entries, only_income)
3
+ total = if only_income
4
+ entries.select(&:income?).map(&:amount).reduce(:+)
5
+ else
6
+ entries.select(&:expense?).map(&:amount).reduce(:+)
7
+ end
10
8
  Layout.print_single_value(total)
11
9
  end
12
10
 
13
- def print_group_by_categories_report(entries, onlyIncome)
14
-
15
- entries = entries.select { |entry|
16
- entry.income? == onlyIncome
17
- }.each_with_object(Hash.new(0)) { |current, sum|
11
+ def print_group_by_categories_report(entries, only_income)
12
+ entries = entries.select do |entry|
13
+ if only_income
14
+ entry.income?
15
+ else
16
+ entry.expense?
17
+ end
18
+ end.each_with_object(Hash.new(0)) do |current, sum|
18
19
  tag = current.tag ||= 'Unknown'
19
20
  sum[tag] += current.amount
20
- }.map { |x, v|
21
+ end.map do |x, v|
21
22
  [x, v]
22
- }.sort! { |r1, r2| r1.first <=> r2.first }
23
+ end.sort! { |r1, r2| r1.first <=> r2.first }
23
24
  Layout.print_generic_rows(entries)
24
25
  end
25
26
 
26
27
  def print_group_by_month_report(entries, tag)
27
- entries = entries.select { |entry|
28
+ entries = entries.select do |entry|
28
29
  entry.tag == tag
29
- }.each_with_object(Hash.new(0)) { | current, sum |
30
- month = current.date.strftime("%B")
30
+ end.each_with_object(Hash.new(0)) do |current, sum|
31
+ month = current.date.strftime('%B')
31
32
  sum[month] += current.amount
32
- }
33
+ end
33
34
  Layout.print_generic_rows(entries)
34
35
  end
36
+
37
+ def print_only_matching_tag(entries, tag)
38
+ entries = entries.select do |entry|
39
+ entry.tag == tag
40
+ end
41
+ Layout.print_multiple(entries)
42
+ end
35
43
  end
@@ -1,3 +1,3 @@
1
1
  module Moneymanager
2
- VERSION = '0.3.1'.freeze
2
+ VERSION = '0.3.2'.freeze
3
3
  end
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.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - ignazioc
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-21 00:00:00.000000000 Z
11
+ date: 2018-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -157,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  version: '0'
158
158
  requirements: []
159
159
  rubyforge_project:
160
- rubygems_version: 2.6.13
160
+ rubygems_version: 2.6.14
161
161
  signing_key:
162
162
  specification_version: 4
163
163
  summary: Import dta from your bank and manage your money