budgetcrmod 0.2.3 → 0.3.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/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
|