budgetcrmod 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/budgetcrmod.gemspec +4 -3
- data/lib/budgetcrmod/account_choices.rb +145 -0
- data/lib/budgetcrmod/budget.rb +1 -452
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2015715dae350f93b7931297fa1696a27ab988f3
|
4
|
+
data.tar.gz: 719be9cb86645aa5a7ecc46c4588fb6baa2b17d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 11dfb82752c234ca805a69b9abe16456201adf18adc849c29799ea927d0e317705f30dba08c9907f041a536da483980ee7fffc1d6c6664b9c876b5d01a9de432
|
7
|
+
data.tar.gz: 969c97060b903b1c2661823f3c4df19d05700a4724249b41e9a03f9219a7b2dc111d549b9cce62dc4597be274785b01a0aaded206b0d815a84c84ae8133a32fe
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/budgetcrmod.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: budgetcrmod 0.
|
5
|
+
# stub: budgetcrmod 0.3.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "budgetcrmod".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.3.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Edmund Highcock".freeze]
|
14
|
-
s.date = "2018-04-
|
14
|
+
s.date = "2018-04-10"
|
15
15
|
s.description = "A CodeRunner module to help you do your budget".freeze
|
16
16
|
s.email = "edmundhighcock@users.sourceforge.net".freeze
|
17
17
|
s.extra_rdoc_files = [
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
"VERSION",
|
28
28
|
"budgetcrmod.gemspec",
|
29
29
|
"lib/budgetcrmod.rb",
|
30
|
+
"lib/budgetcrmod/account_choices.rb",
|
30
31
|
"lib/budgetcrmod/budget.rb",
|
31
32
|
"lib/budgetcrmod/defaults_files/budget_defaults.rb",
|
32
33
|
"test/helper.rb",
|
@@ -0,0 +1,145 @@
|
|
1
|
+
|
2
|
+
class CodeRunner::Budget
|
3
|
+
# All transactions occur between two accounts.
|
4
|
+
# One of those accounts is always physical (e.g. bank account, loan, credit card)
|
5
|
+
# and the other can be either physical or a virtual account of the users choice,
|
6
|
+
# e.g. Food or Petrol or Energy, or maybe WeeklyBudget and LongTermBudget etc.
|
7
|
+
def external_account
|
8
|
+
return @external_account if @external_account
|
9
|
+
ext_account = false
|
10
|
+
Dir.chdir(@runner.root_folder) do
|
11
|
+
chosen = false
|
12
|
+
Hash.phoenix('account_choices.rb') do |choices_hash|
|
13
|
+
if choices_hash[data_line]
|
14
|
+
#choices_hash[data_line][:external_account] =
|
15
|
+
#choices_hash[data_line][:external_account].to_sym #fixes earlier bug
|
16
|
+
#choices_hash[data_line][:sub_account] =
|
17
|
+
#choices_hash[data_line][:sub_account].to_sym #fixes earlier bug
|
18
|
+
chosen = choices_hash[data_line][:external_account]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return @external_account = chosen if chosen
|
22
|
+
chosen = false
|
23
|
+
sym = nil
|
24
|
+
while not chosen
|
25
|
+
Hash.phoenix('external_accounts.rb') do |account_hash|
|
26
|
+
#account_hash.each{|k,v| v[:name] = v[:name].to_sym} #Fixes an earlier bug
|
27
|
+
#choices = account_arr.size.times.map{|i| [i,account_arr[i][:name]]}
|
28
|
+
choices = account_hash.map{|k,v| [v[:sym], k]}.to_h
|
29
|
+
puts Terminal.default_colour
|
30
|
+
puts
|
31
|
+
puts "-" * data_line.size
|
32
|
+
puts data_line
|
33
|
+
puts "-" * data_line.size
|
34
|
+
puts
|
35
|
+
puts choices.inspect
|
36
|
+
puts
|
37
|
+
puts "Please choose from the above external accounts for this transaction."
|
38
|
+
puts "If you wish to add a new account type 0. To quit type q"
|
39
|
+
puts "To start again for this transaction, type z"
|
40
|
+
while not chosen
|
41
|
+
require 'io/console'
|
42
|
+
choice = STDIN.getch
|
43
|
+
if choice == "q"
|
44
|
+
throw :quit_data_entry
|
45
|
+
elsif choice == "0"
|
46
|
+
puts "Please type the name of the new account"
|
47
|
+
name = STDIN.gets.chomp.to_sym
|
48
|
+
puts "Please enter a symbol to represent this account (e.g. digit, letter, punctuation)."
|
49
|
+
sym = false
|
50
|
+
until sym
|
51
|
+
sym = STDIN.getch
|
52
|
+
if choices.keys.include? sym
|
53
|
+
puts "This symbol is taken"
|
54
|
+
sym = false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
account_hash[name] = {name: name, sym: sym, sub_accounts: {}}
|
58
|
+
#choices_hash[@id] = name
|
59
|
+
chosen = name
|
60
|
+
elsif choice == "z"
|
61
|
+
chosen = false
|
62
|
+
break
|
63
|
+
elsif not choices.keys.include? choice
|
64
|
+
puts "Error: this symbol does not correspond to an account"
|
65
|
+
else
|
66
|
+
chosen = choices[choice] #account_hash[choice][:name]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
#Hash.phoenix('account_choices.rb') do |choices_hash|
|
70
|
+
#choices_hash[data_line] = {external_account: chosen}
|
71
|
+
#end
|
72
|
+
end
|
73
|
+
ext_account = chosen
|
74
|
+
next if not chosen
|
75
|
+
chosen = false
|
76
|
+
Hash.phoenix('external_accounts.rb') do |account_hash|
|
77
|
+
#choices = account_arr.size.times.map{|i| [i,account_arr[i][:name]]}
|
78
|
+
sub_accounts = account_hash[ext_account][:sub_accounts]
|
79
|
+
sub_accounts.each{|k,v| v[:name] = v[:name].to_sym} #Fixes an earlier bug
|
80
|
+
choices = sub_accounts.map{|k,v| [v[:sym], k]}.to_h
|
81
|
+
puts "-" * data_line.size
|
82
|
+
puts
|
83
|
+
puts choices.inspect
|
84
|
+
puts
|
85
|
+
puts "Please choose from the above sub-accounts for this transaction."
|
86
|
+
puts "If you wish to add a new sub account, type 0. To quit, type q"
|
87
|
+
puts "To start again for this transaction, type z"
|
88
|
+
while not chosen
|
89
|
+
require 'io/console'
|
90
|
+
choice = STDIN.getch
|
91
|
+
if choice == "q"
|
92
|
+
throw :quit_data_entry
|
93
|
+
elsif choice == "0"
|
94
|
+
puts "Please type the name of the new sub account"
|
95
|
+
name = STDIN.gets.chomp.to_sym
|
96
|
+
puts "Please enter a symbol to represent this account (e.g. digit, letter, punctuation)."
|
97
|
+
sym = false
|
98
|
+
until sym
|
99
|
+
sym = STDIN.getch
|
100
|
+
if choices.keys.include? sym
|
101
|
+
puts "This symbol is taken"
|
102
|
+
sym = false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
sub_accounts[name] = {name: name, sym: sym}
|
106
|
+
#choices_hash[@id] = name
|
107
|
+
chosen = name
|
108
|
+
elsif choice == "z"
|
109
|
+
chosen = false
|
110
|
+
break
|
111
|
+
elsif not choices.keys.include? choice
|
112
|
+
puts "Error: this symbol does not correspond to a sub-account"
|
113
|
+
else
|
114
|
+
chosen = choices[choice] #sub_accounts[choice][:name]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
next if not chosen
|
119
|
+
Hash.phoenix('account_choices.rb') do |choices_hash|
|
120
|
+
choices_hash[data_line] = {external_account: ext_account, sub_account: chosen}
|
121
|
+
end
|
122
|
+
end #while not chosen
|
123
|
+
|
124
|
+
end
|
125
|
+
ext_account
|
126
|
+
end
|
127
|
+
# All transactions have a subaccount. For transactions between
|
128
|
+
# physical accounts this will almost always be just 'Transfer'
|
129
|
+
# or similar, but virtual accounts will have more meaningful
|
130
|
+
# sub_accounts, e.g. Food might have Groceries, EatingOut
|
131
|
+
# or WeeklyBudget might have Transport, Food, Clothes... depending
|
132
|
+
# on the users preferred way of organising things.
|
133
|
+
# The sub_accounts are primarily a labelling exercise, but done
|
134
|
+
# well can be very helpful in showing a breakdown of expenditure.
|
135
|
+
def sub_account
|
136
|
+
return @sub_account if @sub_account
|
137
|
+
Dir.chdir(@runner.root_folder) do
|
138
|
+
external_account until (
|
139
|
+
choices = Hash.phoenix('account_choices.rb'){|choices_hash| choices_hash[data_line]}
|
140
|
+
p [choices, data_line]
|
141
|
+
) and choices[:sub_account]
|
142
|
+
@sub_account = choices[:sub_account]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/budgetcrmod/budget.rb
CHANGED
@@ -39,15 +39,6 @@ class CodeRunner
|
|
39
39
|
|
40
40
|
@code_module_folder = File.dirname(File.expand_path(__FILE__)) # i.e. the directory this file is in
|
41
41
|
|
42
|
-
# ["05/07/2010",
|
43
|
-
# "DEB",
|
44
|
-
# "308760",
|
45
|
-
# "25387560",
|
46
|
-
# "ANGELSCD 0655",
|
47
|
-
# "",
|
48
|
-
# "11.50",
|
49
|
-
# "4506.80"]
|
50
|
-
#
|
51
42
|
@component_results = [:date, :type, :sc, :ac, :description, :deposit, :withdrawal, :balance]
|
52
43
|
@results = [:date_i, :data, :data_line, :dataset] + @component_results
|
53
44
|
def generate_input_file
|
@@ -241,10 +232,6 @@ class CodeRunner
|
|
241
232
|
end
|
242
233
|
end
|
243
234
|
def days_ago(today = Date.today)
|
244
|
-
#ep ['today', today, date]
|
245
|
-
# sprintf("%04d%02d%02d", date.year, date.month, date.day).to_i
|
246
|
-
#cache[:days_ago] ||= {}
|
247
|
-
#cache[:days_ago][today.to_s] ||=
|
248
235
|
- ((date.to_datetime.to_time.to_i - today.to_datetime.to_time.to_i) / 24 / 3600).to_i
|
249
236
|
end
|
250
237
|
def idate
|
@@ -255,164 +242,7 @@ class CodeRunner
|
|
255
242
|
end
|
256
243
|
|
257
244
|
|
258
|
-
#def self.sum_future(future_items, end_date, options={})
|
259
|
-
#sum = future_items.inject(0) do |sum, (name, item)|
|
260
|
-
#item = [item] unless item.kind_of? Array
|
261
|
-
#value = item.inject(0) do |value,info|
|
262
|
-
#value += info[:size] unless (options[:today]||Date.today > info[:date]) or (info[:date] > end_date) # add unless we have already passed that date
|
263
|
-
#value
|
264
|
-
#end
|
265
|
-
#rcp.excluding.include?(name) ? sum : sum + value
|
266
|
-
#end
|
267
|
-
#sum
|
268
|
-
#end
|
269
|
-
|
270
|
-
#def self.budget_expenditure(runner, budget, budget_info, start_date, options={})
|
271
|
-
#dates = []
|
272
|
-
#expenditures = []
|
273
|
-
#budget_items = []
|
274
|
-
#date = budget_info[:end]||options[:today]||Date.today
|
275
|
-
#start_date = [(budget_info[:start]||start_date), start_date].max
|
276
|
-
#expenditure = 0
|
277
|
-
#items_temp = []
|
278
|
-
#items = runner.component_run_list.values.find_all{|r| r.budget == budget and r.in_date(budget_info)}
|
279
|
-
##ep ['items', items]
|
280
|
-
##ep ['budget', budget]
|
281
|
-
#counter = 0
|
282
|
-
#if not budget_info[:period]
|
283
|
-
#dates.push date
|
284
|
-
#budget_items.push items
|
285
|
-
#expenditures.push (items.map{|r| r.debit - r.credit}+[0]).sum
|
286
|
-
#else
|
287
|
-
|
288
|
-
#case budget_info[:period][1]
|
289
|
-
#when :month
|
290
|
-
#while date > start_date
|
291
|
-
#items_temp += items.find_all{|r| r.date == date}
|
292
|
-
#if date.mday == (budget_info[:monthday] or 1)
|
293
|
-
#counter +=1
|
294
|
-
#if counter % budget_info[:period][0] == 0
|
295
|
-
#expenditure = (items_temp.map{|r| r.debit - r.credit}+[0]).sum
|
296
|
-
#dates.push date
|
297
|
-
#expenditures.push expenditure
|
298
|
-
#budget_items.push items_temp
|
299
|
-
#items_temp = []
|
300
|
-
#expenditure = 0
|
301
|
-
#end
|
302
|
-
#end
|
303
|
-
#date-=1
|
304
|
-
#end
|
305
|
-
#when :day
|
306
|
-
#while date > start_date
|
307
|
-
#items_temp += items.find_all{|r| r.date == date}
|
308
|
-
##expenditure += (budget_items[-1].map{|r| r.debit}+[0]).sum
|
309
|
-
#counter +=1
|
310
|
-
#if counter % budget_info[:period][0] == 0
|
311
|
-
#expenditure = (items_temp.map{|r| r.debit - r.credit}+[0]).sum
|
312
|
-
#dates.push date
|
313
|
-
#expenditures.push expenditure
|
314
|
-
#budget_items.push items_temp
|
315
|
-
#items_temp = []
|
316
|
-
#expenditure = 0
|
317
|
-
#end
|
318
|
-
#date-=1
|
319
|
-
#end
|
320
|
-
#end
|
321
|
-
#end
|
322
|
-
|
323
|
-
#[dates, expenditures, budget_items]
|
324
|
-
|
325
|
-
#end
|
326
|
-
|
327
|
-
#def self.sum_regular(regular_items, end_date, options={})
|
328
|
-
#today = options[:today]||Date.today
|
329
|
-
#sum = regular_items.inject(0) do |sum, (name, item)|
|
330
|
-
#item = [item] unless item.kind_of? Array
|
331
|
-
## ep item
|
332
|
-
#value = item.inject(0) do |value,info|
|
333
|
-
#finish = (info[:end] and info[:end] < end_date) ? info[:end] : end_date
|
334
|
-
##today = (Time.now.to_i / (24.0*3600.0)).round
|
335
|
-
|
336
|
-
#nunits = 0
|
337
|
-
#counter = info[:period][0] == 1 ? 0 : nil
|
338
|
-
#####################unless counter
|
339
|
-
#####################date = today
|
340
|
-
#####################counter = 0
|
341
|
-
#####################case info[:period][1]
|
342
|
-
#####################when :month
|
343
|
-
#####################while date >= (info[:start] or Date.today)
|
344
|
-
#####################counter +=1 if date.mday == (info[:monthday] or 1)
|
345
|
-
#####################date -= 1
|
346
|
-
#####################end
|
347
|
-
#####################when :year
|
348
|
-
#####################while date >= (info[:start] or Date.today)
|
349
|
-
#####################counter +=1 if date.yday == (info[:yearday] or 1)
|
350
|
-
#####################date -= 1
|
351
|
-
#####################end
|
352
|
-
#####################when :day
|
353
|
-
#####################while date > (info[:start] or Date.today)
|
354
|
-
#####################counter +=1
|
355
|
-
#####################date -= 1
|
356
|
-
#####################end
|
357
|
-
#####################end
|
358
|
-
#####################end
|
359
|
-
#date = today
|
360
|
-
#########################case info[:period][1]
|
361
|
-
#########################when :month
|
362
|
-
##########################p date, info
|
363
|
-
#########################while date <= finish
|
364
|
-
#########################if date.mday == (info[:monthday] or 1)
|
365
|
-
#########################nunits += 1 if counter % info[:period][0] == 0
|
366
|
-
#########################counter +=1
|
367
|
-
#########################end
|
368
|
-
#########################date += 1
|
369
|
-
#########################end
|
370
|
-
#########################when :year
|
371
|
-
#########################while date <= finish
|
372
|
-
#########################if date.yday == (info[:yearday] or 1)
|
373
|
-
#########################nunits += 1 if counter % info[:period][0] == 0
|
374
|
-
#########################counter +=1
|
375
|
-
#########################end
|
376
|
-
#########################date += 1
|
377
|
-
#########################end
|
378
|
-
#########################when :day
|
379
|
-
#########################while date <= finish
|
380
|
-
#########################nunits += 1 if counter % info[:period][0] == 0
|
381
|
-
#########################counter +=1
|
382
|
-
#########################date += 1
|
383
|
-
#########################end
|
384
|
-
#########################end
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
##nyears = (finish.year - today.year)
|
391
|
-
##nmonths = nyears * 12 + (finish.month - today.month)
|
392
|
-
##(puts "Number of Months: #{nmonths}"; @pnmonths=true) unless @pnmonths
|
393
|
-
##ndays = nyears * 12 + (finish.yday - today.yday)
|
394
|
-
##number = case info[:period][1]
|
395
|
-
##when :month
|
396
|
-
##(nmonths / info[:period][0]).ceil
|
397
|
-
##when :day
|
398
|
-
##(ndays / info[:period][0]).ceil
|
399
|
-
##end
|
400
|
-
##value + number * info[:size]
|
401
|
-
##eputs "Regular Expenditure Item: #{sprintf("%10s", name)} -- #{nunits} payments, total #{nunits * info[:size]}"
|
402
|
-
#value + nunits * info[:size]
|
403
|
-
|
404
|
-
#end
|
405
|
-
#(rcp.excluding? and rcp.excluding.include?(name)) ? sum : sum + value
|
406
|
-
#end
|
407
|
-
#sum
|
408
|
-
#end
|
409
245
|
def self.predictable_component_ids(runner)
|
410
|
-
#runner.instance_variable_set(:@component_run_list, {})
|
411
|
-
#runner.instance_variable_set(:@component_ids, [])
|
412
|
-
#runner.instance_variable_set(:@component_id, -1)
|
413
|
-
#runner.run_list.each{|r| r.instance_variable_set(:@component_runs, [])}
|
414
|
-
#runner.run_list.values.sort_by{|r| r.id}.each{|r| r.generate_component_runs}
|
415
|
-
#runner.save_large_cache
|
416
246
|
end
|
417
247
|
def self.kit_time_format_x(kit)
|
418
248
|
kit.gp.timefmt = %["%s"]
|
@@ -425,289 +255,8 @@ class CodeRunner
|
|
425
255
|
kit.gp.xtics = "rotate by 340 offset 0,-0.5 2629746"
|
426
256
|
end
|
427
257
|
|
428
|
-
|
429
|
-
@excluding = (options[:excluding] or [])
|
430
|
-
runner = CodeRunner.fetch_runner(Y: Dir.pwd)
|
431
|
-
puts "------------------------------"
|
432
|
-
puts " Budget Report"
|
433
|
-
puts "------------------------------"
|
434
|
-
balance = runner.component_run_list.values.sort_by{|r| [r.date, r.id]}.map{|r| r.balance}[-1]
|
435
|
-
puts "Balance: #{balance}"
|
436
|
-
end_date = Date.parse("01/10/2011")
|
437
|
-
puts "Regular Expenditure: #{total_regular = sum_regular(REGULAR_EXPENDITURE, end_date)}"
|
438
|
-
puts "Future Expenditure: #{total_future = sum_future(FUTURE_EXPENDITURE, end_date)}"
|
439
|
-
puts "Total Expenditure: #{total_expenditure = total_future + total_regular}"
|
440
|
-
puts "Total Income: #{total_incoming = sum_future(FUTURE_INCOME, end_date)}"
|
441
|
-
total = balance + total_incoming - total_expenditure
|
442
|
-
puts "Weekly Budget: #{total/((end_date.to_datetime.to_time.to_i - Time.now.to_i) / 3600 / 24 / 7)}"
|
443
|
-
end
|
444
|
-
|
445
|
-
#def self.budgets_with_averages(runner, budgets, start_date, options={})
|
446
|
-
#projected_budgets = budgets.dup
|
447
|
-
#projected_budgets.each{|key,v| projected_budgets[key]=projected_budgets[key].dup}
|
448
|
-
#projected_budgets.each do |budget, budget_info|
|
449
|
-
##budget_info = budgets[budget]
|
450
|
-
#dates, expenditures, items = budget_expenditure(runner, budget, budget_info, start_date, today: options[:today])
|
451
|
-
#budget_info[:size] = expenditures.mean rescue 0.0
|
452
|
-
#end
|
453
|
-
#projected_budgets
|
454
|
-
#end
|
455
|
-
|
456
|
-
#def self.latex_budget_transfers(runner, budgets, options)
|
457
|
-
#numdays = options[:days]
|
458
|
-
#today = options[:today]||Date.today
|
459
|
-
#"#{budgets.map{|budget, budget_info|
|
460
|
-
#dates, expenditures, items = budget_expenditure(runner, budget, budget_info, today - numdays, today: options[:today])
|
461
|
-
##ep ['budget', budget, dates, expenditures]
|
462
|
-
#kit = GraphKit.quick_create([dates.map{|d| d.to_time.to_i}, expenditures])
|
463
|
-
#kit.data.each{|dk| dk.gp.with="boxes"}
|
464
|
-
#kit.gp.style = "fill solid"
|
465
|
-
#kit.xlabel = nil
|
466
|
-
#kit.ylabel = "Expenditure"
|
467
|
-
#unless options[:transfers]
|
468
|
-
#kits = budgets_with_averages(runner, {budget => budget_info}, today - numdays, today: today).map{|budget, budget_info|
|
469
|
-
##ep 'Budget is ', budget
|
470
|
-
#kit2 = GraphKit.quick_create([
|
471
|
-
#[dates[0], dates[-1]].map{|d| d.to_time.to_i},
|
472
|
-
#[budget_info[:size], budget_info[:size]]
|
473
|
-
#])
|
474
|
-
#kit2.data[0].gp.with = 'lp lw 4'
|
475
|
-
#kit2
|
476
|
-
#}
|
477
|
-
##$debug_gnuplot = true
|
478
|
-
##kits.sum.gnuplot
|
479
|
-
#kit += kits.sum
|
480
|
-
|
481
|
-
#else
|
482
|
-
#kit.data[0].y.data.map!{|expen| expen*-1.0}
|
483
|
-
#end
|
484
|
-
#kit.title = "#{budget} Expenditure with average (Total = #{kit.data[0].y.data.sum})"
|
485
|
-
#kit_time_format_x(kit)
|
486
|
-
##kit.gnuplot
|
487
|
-
#kit.gnuplot_write("#{budget}.eps")
|
488
|
-
#"\\begin{center}\\includegraphics[width=4.0in]{#{budget}.eps}\\vspace{1em}\\end{center}"
|
489
|
-
#}.join("\n\n")
|
490
|
-
#}"
|
491
|
-
#end
|
492
|
-
|
493
|
-
#def self.latex_report(options={})
|
494
|
-
#runner = CodeRunner.fetch_runner(Y: Dir.pwd, h: :component)
|
495
|
-
#numdays = options[:days]
|
496
|
-
#today = options[:today] || Date.today
|
497
|
-
## Delete budgets that contain no items
|
498
|
-
#actual_budgets = BUDGETS.dup
|
499
|
-
#BUDGETS.keys.each do |budget|
|
500
|
-
#actual_budgets.delete(budget) if budget_expenditure(runner, budget, BUDGETS[budget], today - numdays, today: today)[0].size == 0
|
501
|
-
#end
|
502
|
-
##predictable_component_ids(runner)
|
503
|
-
#days_ahead = options[:days_ahead]
|
504
|
-
#runs = runner.component_run_list.values
|
505
|
-
#indateruns = runs.find_all{|r| r.days_ago < numdays}
|
506
|
-
#accounts = runs.map{|r| r.account}.uniq
|
507
|
-
#ep 'Accounts', accounts
|
508
|
-
#projected_budgets = Hash[actual_budgets.dup.find_all{|k,v| v[:discretionary]}]
|
509
|
-
#projected_budgets = budgets_with_averages(runner,projected_budgets, today - numdays, today: today)
|
510
|
-
##projected_budgets.each{|key,v| projected_budgets[key]=projected_budgets[key].dup}
|
511
|
-
##projected_budgets.each do |budget, budget_info|
|
512
|
-
###budget_info = budgets[budget]
|
513
|
-
##dates, expenditures, items = budget_expenditure(runner, budget, budget_info, today - numdays)
|
514
|
-
##budget_info[:size] = expenditures.mean
|
515
|
-
##end
|
516
|
-
#ep 'projected_budgets', projected_budgets
|
517
|
-
#File.open('report.tex', 'w') do |file|
|
518
|
-
#file.puts <<EOF
|
519
|
-
#\\documentclass{article}
|
520
|
-
#\\usepackage[cm]{fullpage}
|
521
|
-
#\\usepackage{tabulary}
|
522
|
-
#\\usepackage{graphicx}
|
523
|
-
#%\\usepackage{hyperlink}
|
524
|
-
#\\newcommand\\Tstrut{\\rule{0pt}{2.8ex}}
|
525
|
-
#\\begin{document}
|
526
|
-
#\\title{#{numdays}-day Budget Report}
|
527
|
-
#\\maketitle
|
528
|
-
#\\tableofcontents
|
529
|
-
|
530
|
-
#\\section{Summary of Accounts}
|
531
|
-
##{accounts.map{|acc|
|
532
|
-
#"\\subsection{#{acc}}
|
533
|
-
#\\begin{tabulary}{0.8\\textwidth}{ r l}
|
534
|
-
###Balance & #{runs.find_all{|r| r.account==acc}.sort_by{|r|
|
535
|
-
###r.date
|
536
|
-
###}[-1].balance} \\\\
|
537
|
-
#####Expenditure & #{runs.find_all{|r| r.account==acc &&
|
538
|
-
#####r.days_ago < numdays
|
539
|
-
#####}.map{|r|
|
540
|
-
#####r.debit
|
541
|
-
#####}.sum} \\\\
|
542
|
-
###Income & #{runs.find_all{|r| r.account==acc &&
|
543
|
-
###r.days_ago < numdays
|
544
|
-
###}.map{|r| r.credit}.sum} \\\\
|
545
|
-
#\\end{tabulary}"}.join("\n\n")
|
546
|
-
#}
|
547
|
-
|
548
|
-
#\\section{Graphs of Recent Balances}
|
549
|
-
##{accounts.map{|acc|
|
550
|
-
#balance = runs.find_all{|r| r.account==acc}.sort_by{|r| r.date }[-1].balance
|
551
|
-
#accshort = acc.gsub(/\s/, '')
|
552
|
-
#kit = runner.graphkit(['date.to_time.to_i', 'balance'], {conditions: "account == #{acc.inspect} and days_ago < #{numdays}", sort: 'date'})
|
553
|
-
#futuredates = (today..today+days_ahead).to_a
|
554
|
-
##p ["Regtrans", REGULAR_TRANSFERS.values_at(*REGULAR_TRANSFERS.keys.find_all{|from,to| to == acc})]
|
555
|
-
|
556
|
-
#budgets = Hash[projected_budgets.find_all{|k,v| v[:account] == acc}]
|
557
|
-
#ep ['budgets', budgets]
|
558
|
-
#projection = futuredates.map{|date| balance -
|
559
|
-
#sum_regular(REGULAR_EXPENDITURE[acc], date, today: today) +
|
560
|
-
#sum_regular(REGULAR_INCOME[acc], date, today: today) -
|
561
|
-
#sum_regular(budgets, date, today: today) -
|
562
|
-
#sum_future(FUTURE_EXPENDITURE[acc], date, today: today) +
|
563
|
-
#sum_future(FUTURE_INCOME[acc], date, today: today) +
|
564
|
-
#(REGULAR_TRANSFERS.keys.find_all{|from,to| to == acc}.map{|key|
|
565
|
-
##p [acc, 'to', "key", key]
|
566
|
-
#sum_regular( REGULAR_TRANSFERS[key], date, today: today)
|
567
|
-
#}.sum||0) -
|
568
|
-
#(REGULAR_TRANSFERS.keys.find_all{|from,to| from == acc}.map{|key|
|
569
|
-
##p [acc, 'from',"key", key]
|
570
|
-
#sum_regular( REGULAR_TRANSFERS[key], date, today: today)
|
571
|
-
#}.sum||0)
|
572
|
-
#}
|
573
|
-
#kit2 = GraphKit.quick_create([futuredates.map{|d| d.to_time.to_i}, projection])
|
574
|
-
#kit += kit2
|
575
|
-
#kit.title = "Balance for #{acc}"
|
576
|
-
#kit.xlabel = %['Date' offset 0,-2]
|
577
|
-
#kit.xlabel = nil
|
578
|
-
#kit.ylabel = "Balance"
|
579
|
-
|
580
|
-
#kit.data[0].gp.title = 'Previous'
|
581
|
-
#kit.data[1].gp.title = '0 GBP Discretionary'
|
582
|
-
#kit.data[1].gp.title = 'Projection'
|
583
|
-
#kit.data.each{|dk| dk.gp.with = "lp"}
|
584
|
-
|
585
|
-
#kit_time_format_x(kit)
|
586
|
-
|
587
|
-
#(kit).gnuplot_write("#{accshort}_balance.eps", size: "4.0in,3.0in")
|
588
|
-
#"\\begin{center}\\includegraphics[width=4.0in]{#{accshort}_balance.eps}\\end{center}"
|
589
|
-
#}.join("\n\n")
|
590
|
-
#}
|
591
|
-
|
592
|
-
|
593
|
-
#\\section{Budget Expenditure}
|
594
|
-
##{latex_budget_transfers(runner,actual_budgets, options)}
|
595
|
-
|
596
|
-
#\\section{Transfers}
|
597
|
-
##{latex_budget_transfers(runner, TRANSFERS, options.dup.absorb({transfers: true}))}
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
#\\section{Budget Resolutions}
|
258
|
+
require 'budgetcrmod/account_choices.rb'
|
602
259
|
|
603
|
-
#This section sums items from budgets drawn from an alternate account, i.e. it determines how much should be transferred from one account to another as a result of expenditure from a given budget.
|
604
|
-
|
605
|
-
##{actual_budgets.map{|budget, budget_info|
|
606
|
-
|
607
|
-
########################################"\\subsection{#{budget} }
|
608
|
-
########################################\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{r l}
|
609
|
-
########################################%\\hline
|
610
|
-
########################################Account Owed & Amount \\\\
|
611
|
-
########################################\\hline
|
612
|
-
########################################\\Tstrut
|
613
|
-
#########################################{budget_items = indateruns.find_all{|r| r.budget == budget}
|
614
|
-
########################################alternate_accounts = budget_items.map{|r| r.account}.uniq - [budget_info[:account]]
|
615
|
-
########################################alternate_accounts.map{|acc|
|
616
|
-
########################################alternate_items = budget_items.find_all{|r| r.account == acc}
|
617
|
-
########################################total = alternate_items.map{|r| r.debit - r.credit}.sum
|
618
|
-
########################################"#{acc} & #{total} \\\\"
|
619
|
-
########################################}.join("\n\n")
|
620
|
-
########################################}
|
621
|
-
|
622
|
-
########################################\\\\
|
623
|
-
########################################\\hline
|
624
|
-
########################################\\end{tabulary}
|
625
|
-
########################################\\normalsize
|
626
|
-
########################################\\vspace{1em}\n\n
|
627
|
-
|
628
|
-
#########################################{ alternate_accounts.map{|acc|
|
629
|
-
########################################alternate_items = budget_items.find_all{|r| r.account == acc}
|
630
|
-
########################################alternate_items.pieces((alternate_items.size.to_f/50.to_f).ceil).map{|piece|
|
631
|
-
########################################"\\footnotesize\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{ #{"c " * 4 + " L " + " r " * 3 }}
|
632
|
-
#########################################{budget}: & #{budget_info[:account]} & owes & #{acc} &&&&\\\\
|
633
|
-
########################################\\hline
|
634
|
-
|
635
|
-
########################################\\Tstrut
|
636
|
-
|
637
|
-
#########################################{piece.map{|r|
|
638
|
-
########################################([:id] + rcp.component_results - [:sc]).map{|res|
|
639
|
-
########################################r.send(res).to_s.latex_escape
|
640
|
-
#########################################rcp.component_results.map{|res| r.send(res).to_s.gsub(/(.{20})/, '\1\\\\\\\\').latex_escape
|
641
|
-
########################################}.join(" & ")
|
642
|
-
########################################}.join("\\\\\n")
|
643
|
-
########################################}
|
644
|
-
########################################\\end{tabulary}\\normalsize"}.join("\n\n")
|
645
|
-
########################################}.join("\n\n")}
|
646
|
-
########################################"
|
647
|
-
#}.join("\n\n")
|
648
|
-
#}
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
#\\section{Budget and Transfer Breakdown}
|
653
|
-
##{(TRANSFERS + actual_budgets).map{|budget, budget_info|
|
654
|
-
#dates, expenditures, budget_items = budget_expenditure(runner, budget, budget_info, today - numdays, today: today)
|
655
|
-
#pp budget, budget_items.map{|items| items.map{|i| i.date.to_s}}
|
656
|
-
#"\\subsection{#{budget}}" +
|
657
|
-
########################budget_items.zip(dates, expenditures).map{|items, date, expenditure|
|
658
|
-
########################if items.size > 0
|
659
|
-
########################"
|
660
|
-
########################\\footnotesize
|
661
|
-
########################\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{ #{"c " * 4 + " L " + " r " * 2 }}
|
662
|
-
########################%\\hline
|
663
|
-
########################& #{date.to_s.latex_escape} & & & Total & #{expenditure} & \\\\
|
664
|
-
########################\\hline
|
665
|
-
########################\\Tstrut
|
666
|
-
#########################{items.map{|r|
|
667
|
-
########################([:id] + rcp.component_results - [:sc, :balance]).map{|res|
|
668
|
-
########################r.send(res).to_s.latex_escape
|
669
|
-
########################}.join(" & ")
|
670
|
-
########################}.join("\\\\\n")
|
671
|
-
########################}
|
672
|
-
########################\\\\
|
673
|
-
########################\\hline
|
674
|
-
########################\\end{tabulary}
|
675
|
-
########################\\normalsize
|
676
|
-
########################\\vspace{1em}\n\n"
|
677
|
-
########################else
|
678
|
-
########################""
|
679
|
-
########################end
|
680
|
-
########################}.join("\n\n")
|
681
|
-
#}.join("\n\n")
|
682
|
-
#}
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
#\\section{Recent Transactions}
|
687
|
-
##{accounts.map{|acc|
|
688
|
-
#"\\subsection{#{acc}}
|
689
|
-
#\\footnotesize
|
690
|
-
##{all = runs.find_all{|r| r.account == acc and r.days_ago < numdays}.sort_by{|r| [r.date, r.id]}.reverse
|
691
|
-
#ep ['acc', acc, 'ids', all.map{|r| r.id}, 'size', all.size]
|
692
|
-
########all.pieces((all.size.to_f/50.to_f).ceil).map{|piece|
|
693
|
-
########"\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{ #{"c " * 4 + " L " + " r " * 3 + "l"}}
|
694
|
-
#########{piece.map{|r|
|
695
|
-
########([:id] + rcp.component_results - [:sc] + [:budget]).map{|res| r.send(res).to_s.latex_escape
|
696
|
-
#########rcp.component_results.map{|res| r.send(res).to_s.gsub(/(.{20})/, '\1\\\\\\\\').latex_escape
|
697
|
-
########}.join(" & ")
|
698
|
-
########}.join("\\\\\n")}
|
699
|
-
########\\end{tabulary}"}.join("\n\n")}"
|
700
|
-
#}.join("\n\n")}
|
701
|
-
#\\end{document}
|
702
|
-
#EOF
|
703
|
-
|
704
|
-
|
705
|
-
#end
|
706
|
-
#system "latex report.tex && latex report.tex"
|
707
|
-
#end
|
708
|
-
#require 'treasurer'
|
709
|
-
#require 'local_customisations.rb'
|
710
|
-
#include Treasurer::LocalCustomisations
|
711
260
|
|
712
261
|
end # class Budget
|
713
262
|
end #class CodeRunner
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: budgetcrmod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edmund Highcock
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coderunner
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- VERSION
|
97
97
|
- budgetcrmod.gemspec
|
98
98
|
- lib/budgetcrmod.rb
|
99
|
+
- lib/budgetcrmod/account_choices.rb
|
99
100
|
- lib/budgetcrmod/budget.rb
|
100
101
|
- lib/budgetcrmod/defaults_files/budget_defaults.rb
|
101
102
|
- test/helper.rb
|