treasurer 0.3.0 → 0.5.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/Gemfile +2 -2
- data/VERSION +1 -1
- data/lib/treasurer/accounts.rb +307 -0
- data/lib/treasurer/analysis.rb +30 -28
- data/lib/treasurer/commands.rb +10 -5
- data/lib/treasurer/report.rb +435 -589
- data/lib/treasurer.rb +4 -0
- data/treasurer.gemspec +10 -6
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 931217424d6cdc37f7c8dcc760fd08bc9d5d2a3d
|
4
|
+
data.tar.gz: a48e8e11f67f770600ff93f6506a4eed78eb2c8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abb2e38f758b4737b9084479661e274a2dcc5fb536b01327d032374991ab02da419fb33d412fdd26799da0ebe53b018bf73fe77cff90a361dfe3668384e232c1
|
7
|
+
data.tar.gz: 9abf97d6b4166d1e71b636d0486ab69369f7645644882b0d212541d19f37ae90e35cc4f8a823cdb3f39221ab9d99dd76ba9763c39b6cfa909d71082525f7edbe
|
data/Gemfile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
# Add dependencies required to use your gem here.
|
3
3
|
# Example:
|
4
|
-
|
4
|
+
gem "activesupport", ">= 5.0.0"
|
5
5
|
gem "coderunner", ">= 0.14.16"
|
6
|
-
gem "budgetcrmod", ">= 0.2.
|
6
|
+
gem "budgetcrmod", ">= 0.2.1"
|
7
7
|
gem "command-line-flunky", ">= 1.0.0"
|
8
8
|
|
9
9
|
# Add dependencies to develop your gem here.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
@@ -0,0 +1,307 @@
|
|
1
|
+
class Treasurer::Reporter
|
2
|
+
class Account
|
3
|
+
end
|
4
|
+
class SubAccount < Account
|
5
|
+
def initialize(name, reporter, runner, runs, external, options={})
|
6
|
+
@name = name
|
7
|
+
@reporter = reporter
|
8
|
+
@runner = runner
|
9
|
+
#@projected_accounts_info =Hash[projected_accounts_info.find_all{|k,v| v[:account] == name}]
|
10
|
+
@external = external
|
11
|
+
@runs = runs.find_all{|r| r.sub_account == name}
|
12
|
+
info[:external] = external if info
|
13
|
+
#ep ['sub_accounts333', name, @runs.size, runs.size]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class Account
|
17
|
+
attr_reader :name, :external, :runs, :currency
|
18
|
+
attr_accessor :projection, :average
|
19
|
+
def initialize(name, reporter, runner, runs, external, options={})
|
20
|
+
@name = name
|
21
|
+
@reporter = reporter
|
22
|
+
@runner = runner
|
23
|
+
@currency = options[:currency]
|
24
|
+
#@projected_accounts_info =Hash[projected_accounts_info.find_all{|k,v| v[:account] == name}]
|
25
|
+
@external = external
|
26
|
+
@runs = runs.find_all do |r|
|
27
|
+
#p ['checking11', name, @currency, ACCOUNT_INFO[r.account]] if name == r.external_account and @currency and @external
|
28
|
+
#@external ? r.external_account : r.account) == name}
|
29
|
+
if not @external
|
30
|
+
r.account == name
|
31
|
+
elsif info and cur = info[:currencies] and cur.size > 1
|
32
|
+
#p ['checking11', name, @currency, ACCOUNT_INFO[r.account]] if name == r.external_account and @currency
|
33
|
+
r.external_account == name and acinfo = ACCOUNT_INFO[r.account] and acinfo[:currencies] == [@currency]
|
34
|
+
else
|
35
|
+
r.external_account == name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
#p ['Accountinf', name, @currency, @runs.size, runs.size]
|
39
|
+
info[:external] = external if info
|
40
|
+
end
|
41
|
+
def sub_accounts
|
42
|
+
@sub_accounts ||= @runs.map{|r| r.sub_account}.uniq.compact.map{|acc| SubAccount.new(acc, @reporter, @runner, @runs, @external, currency: @currency)}
|
43
|
+
end
|
44
|
+
def type
|
45
|
+
#account_type(name)
|
46
|
+
if ACCOUNT_INFO[name] and type = ACCOUNT_INFO[name][:type]
|
47
|
+
type
|
48
|
+
else
|
49
|
+
:Expense
|
50
|
+
end
|
51
|
+
end
|
52
|
+
def red_line(date)
|
53
|
+
if Treasurer::LocalCustomisations.instance_methods.include? :red_line
|
54
|
+
super(name, date)
|
55
|
+
else
|
56
|
+
0.0
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def report_start
|
60
|
+
@reporter.today - @reporter.days_before
|
61
|
+
end
|
62
|
+
def opening_date
|
63
|
+
(info && info[:start]) || @runs.map{|r| r.date}.min
|
64
|
+
end
|
65
|
+
def opening_balance
|
66
|
+
(info && info[:opening_balance]) || 0.0
|
67
|
+
end
|
68
|
+
def has_balance?
|
69
|
+
not @runs.find{|r| not r.has_balance?}
|
70
|
+
end
|
71
|
+
def balance(date = @reporter.today)
|
72
|
+
date_i = date.to_datetime.to_time.to_i
|
73
|
+
#if !date
|
74
|
+
#@runs.sort_by{|r| r.date}[-1].balance
|
75
|
+
if @external or not has_balance?
|
76
|
+
#p ['name is ', name, type]
|
77
|
+
#
|
78
|
+
balance = (@runs.find_all{|r| r.date <= date and r.date >= opening_date }.map{|r| money_in_sign * (r.deposit - r.withdrawal) * (@external ? -1 : 1)}.sum || 0.0)
|
79
|
+
balance += info[:opening_balance] if info[:opening_balance]
|
80
|
+
balance
|
81
|
+
#Temporary....
|
82
|
+
#0.0
|
83
|
+
else
|
84
|
+
#p ['name33 is ', name, type, @runs.size, @currency]
|
85
|
+
nearest_time = @runs.map{|r| (r.date_i - date_i).to_f.abs}.sort[0]
|
86
|
+
@runs.find_all{|r| (r.date_i - date_i).to_f.abs == nearest_time}.sort_by{|r| r.id}[-1].balance
|
87
|
+
end
|
88
|
+
end
|
89
|
+
def deposited(today, days_before, &block)
|
90
|
+
#p ['name22 is ', name, type, @runs.size]
|
91
|
+
#@runs.find_all{|r| r.days_ago(today) < days_before and (!block or yield(r)) }.map{|r| (@external and not ([:Liability, :Income].include?(type))) ? r.withdrawal : r.deposit }.sum || 0
|
92
|
+
@runs.find_all{|r| r.days_ago(today) < days_before and (!block or yield(r)) }.map{|r| (@external) ? r.withdrawal : r.deposit }.sum || 0
|
93
|
+
end
|
94
|
+
def withdrawn(today, days_before)
|
95
|
+
#@runs.find_all{|r| r.days_ago(today) < days_before }.map{|r| (@external and not ([:Liability, :Income].include?(type))) ? r.deposit : r.withdrawal }.sum || 0
|
96
|
+
@runs.find_all{|r| r.days_ago(today) < days_before }.map{|r| (@external) ? r.deposit : r.withdrawal }.sum || 0
|
97
|
+
end
|
98
|
+
def currency
|
99
|
+
@currency || (info[:currencies] && info[:currencies][0])
|
100
|
+
end
|
101
|
+
def currency_label
|
102
|
+
if @currency
|
103
|
+
" (#@currency)"
|
104
|
+
else
|
105
|
+
''
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def name_c
|
110
|
+
name + currency_label
|
111
|
+
end
|
112
|
+
def name_c_file
|
113
|
+
name_c.to_s.gsub(/[: ()]/, '_')
|
114
|
+
end
|
115
|
+
|
116
|
+
def summary_table(today, days_before)
|
117
|
+
|
118
|
+
<<EOF
|
119
|
+
\\subsubsection{#{name_c}}
|
120
|
+
\\begin{tabulary}{0.8\\textwidth}{ r | l}
|
121
|
+
Balance & #{balance} \\\\
|
122
|
+
Deposited & #{deposited(today, days_before)} \\\\
|
123
|
+
Withdrawn & #{withdrawn(today, days_before)} \\\\
|
124
|
+
\\end{tabulary}
|
125
|
+
EOF
|
126
|
+
end
|
127
|
+
def summary_line(today, days_before)
|
128
|
+
|
129
|
+
<<EOF
|
130
|
+
#{name_c} & #{balance} & #{deposited(today, days_before)} & #{withdrawn(today, days_before)}
|
131
|
+
EOF
|
132
|
+
end
|
133
|
+
def money_in_sign
|
134
|
+
case type
|
135
|
+
when :Liability, :Income
|
136
|
+
-1.0
|
137
|
+
else
|
138
|
+
1.0
|
139
|
+
end
|
140
|
+
end
|
141
|
+
def discretionary
|
142
|
+
info and info[:discretionary]
|
143
|
+
end
|
144
|
+
def info
|
145
|
+
ACCOUNT_INFO[name] ||= {}
|
146
|
+
end
|
147
|
+
def projected_balance(date)
|
148
|
+
#return 0.0 if @external # Temporary Hack
|
149
|
+
#ep ['projected', @reporter.projected_accounts_info]
|
150
|
+
raise "Only should be called for Asset and Liability accounts" unless [:Asset, :Liability].include? type
|
151
|
+
non_discretionary_projected_balance(date) -
|
152
|
+
@reporter.sum_regular(linked_projected_account_info, date)
|
153
|
+
|
154
|
+
#(discretionary ? @reporter.sum_regular({name => info}, date) : 0.0)
|
155
|
+
end
|
156
|
+
def linked_projected_account_info
|
157
|
+
Hash[@reporter.projected_accounts_info.find_all{|ext_ac,inf| inf[:linked_account] == name and ext_ac.currency == currency}]
|
158
|
+
end
|
159
|
+
def cache
|
160
|
+
@cache ||={}
|
161
|
+
end
|
162
|
+
def non_discretionary_projected_balance(date)
|
163
|
+
#ep ['FUTURE_INCOME', FUTURE_INCOME, name] if FUTURE_INCOME.size > 0
|
164
|
+
cache[[:non_discretionary_projected_balance, date]] ||=
|
165
|
+
balance +
|
166
|
+
#@reporter.sum_regular(REGULAR_EXPENDITURE[name], date) +
|
167
|
+
#@reporter.sum_regular(REGULAR_INCOME[name], date) -
|
168
|
+
#@reporter.sum_future(FUTURE_EXPENDITURE[name], date) +
|
169
|
+
#@reporter.sum_future(FUTURE_INCOME[name], date) +
|
170
|
+
(FUTURE_TRANSFERS.keys.find_all{|from,to| to == name}.map{|key|
|
171
|
+
@reporter.sum_future(FUTURE_TRANSFERS[key], date) * money_in_sign
|
172
|
+
}.sum||0) -
|
173
|
+
(FUTURE_TRANSFERS.keys.find_all{|from,to| from == name}.map{|key|
|
174
|
+
@reporter.sum_future( FUTURE_TRANSFERS[key], date) * money_in_sign
|
175
|
+
}.sum||0) +
|
176
|
+
(REGULAR_TRANSFERS.keys.find_all{|from,to| to == name}.map{|key|
|
177
|
+
@reporter.sum_regular(REGULAR_TRANSFERS[key], date) * money_in_sign
|
178
|
+
}.sum||0) -
|
179
|
+
(REGULAR_TRANSFERS.keys.find_all{|from,to| from == name}.map{|key|
|
180
|
+
@reporter.sum_regular( REGULAR_TRANSFERS[key], date) * money_in_sign
|
181
|
+
}.sum||0)
|
182
|
+
end
|
183
|
+
# Write an eps graph to disk of past and projected
|
184
|
+
# balance of the account
|
185
|
+
def write_balance_graph(today, days_before, days_ahead)
|
186
|
+
#accshort = name.gsub(/\s/, '')
|
187
|
+
if not (@external or type == :Equity or not has_balance?)
|
188
|
+
kit = @runner.graphkit(['date.to_time.to_i', 'balance'], {conditions: "account == #{name.inspect} and days_ago(Date.parse(#{today.to_s.inspect})) < #{days_before} and days_ago(Date.parse(#{today.to_s.inspect})) > -1", sort: '[date, id]'})
|
189
|
+
else
|
190
|
+
pastdates = (today-days_before..today).to_a
|
191
|
+
balances = pastdates.map{|date| balance(date)}
|
192
|
+
kit = GraphKit.quick_create([pastdates.map{|d| d.to_time.to_i}, balances])
|
193
|
+
end
|
194
|
+
futuredates = (today..today+days_ahead).to_a
|
195
|
+
projection = futuredates.map{|date| projected_balance(date) }
|
196
|
+
kit2 = GraphKit.quick_create([futuredates.map{|d| d.to_time.to_i}, projection])
|
197
|
+
red = futuredates.map{|date| red_line(date)}
|
198
|
+
kit3 = GraphKit.quick_create([futuredates.map{|d| d.to_time.to_i}, red])
|
199
|
+
@reporter.projected_account_factor = @reporter.in_limit_discretionary_account_factors[currency]
|
200
|
+
limit = futuredates.map{|date| projected_balance(date)}
|
201
|
+
kit4 = GraphKit.quick_create([futuredates.map{|d| d.to_time.to_i}, limit])
|
202
|
+
@reporter.projected_account_factor = @reporter.stable_discretionary_account_factors[currency]
|
203
|
+
#ep ['projected_account_factor!!!!', @reporter.projected_account_factor]
|
204
|
+
stable = futuredates.map{|date| projected_balance(date)}
|
205
|
+
kit5 = GraphKit.quick_create([futuredates.map{|d| d.to_time.to_i}, stable])
|
206
|
+
#exit
|
207
|
+
@reporter.projected_account_factor = nil
|
208
|
+
kit += (kit2 + kit4 + kit5)
|
209
|
+
#kit += (kit2)
|
210
|
+
kit = kit3 + kit
|
211
|
+
kit.title = "Balance for #{name_c}"
|
212
|
+
kit.xlabel = %['Date' offset 0,-2]
|
213
|
+
kit.xlabel = nil
|
214
|
+
kit.ylabel = "Balance"
|
215
|
+
|
216
|
+
|
217
|
+
kit.data[0].gp.title = 'Limit'
|
218
|
+
kit.data[1].gp.title = 'Previous'
|
219
|
+
kit.data[2].gp.title = '0 GBP Discretionary'
|
220
|
+
kit.data[2].gp.title = 'Projection'
|
221
|
+
kit.data[3].gp.title = 'Limit'
|
222
|
+
kit.data[4].gp.title = 'Stable'
|
223
|
+
kit.data.each{|dk| dk.gp.with = "l lw 5"}
|
224
|
+
kit.gp.key = ' bottom left '
|
225
|
+
kit.gp.key = ' rmargin '
|
226
|
+
|
227
|
+
#(p kit; STDIN.gets) if name == :LloydsCreditCard
|
228
|
+
CodeRunner::Budget.kit_time_format_x(kit)
|
229
|
+
|
230
|
+
fork do
|
231
|
+
(kit).gnuplot_write("#{name_c_file}_balance.eps", size: "4.0in,1.5in") #, latex: true)
|
232
|
+
%x[epspdf #{name_c_file}_balance.eps]
|
233
|
+
end
|
234
|
+
#%x[epspdf #{name}_balance.eps]
|
235
|
+
end
|
236
|
+
# A string to include the balance graph in the document
|
237
|
+
def balance_graph_string
|
238
|
+
#accshort = name.gsub(/\s/, '')
|
239
|
+
#"\\begin{center}\\includegraphics[width=3.0in]{#{name}_balance.eps}\\end{center}"
|
240
|
+
#"\\begin{center}\\includegraphics[width=0.9\\textwidth]{#{name}_balance.eps}\\end{center}"
|
241
|
+
"\\myfigure{#{name_c_file}_balance.pdf}"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
class Equity < Account
|
245
|
+
def initialize(reporter, runner, accounts, options={})
|
246
|
+
@reporter = reporter
|
247
|
+
@runner = runner
|
248
|
+
@accounts = accounts #.find_all{|acc| not acc.external}
|
249
|
+
@currency = options[:currency]
|
250
|
+
end
|
251
|
+
def type
|
252
|
+
:Equity
|
253
|
+
end
|
254
|
+
def name
|
255
|
+
:Equity
|
256
|
+
end
|
257
|
+
def red_line(date)
|
258
|
+
@accounts.map{|acc|
|
259
|
+
case acc.type
|
260
|
+
when :Asset
|
261
|
+
acc.red_line(date)
|
262
|
+
when :Liability
|
263
|
+
-acc.red_line(date)
|
264
|
+
else
|
265
|
+
0.0
|
266
|
+
end
|
267
|
+
}.sum
|
268
|
+
end
|
269
|
+
def balance(date=@reporter.today)
|
270
|
+
@accounts.map{|acc|
|
271
|
+
case acc.type
|
272
|
+
when :Asset
|
273
|
+
acc.balance(date)
|
274
|
+
when :Liability
|
275
|
+
-acc.balance(date)
|
276
|
+
else
|
277
|
+
0.0
|
278
|
+
end
|
279
|
+
}.sum
|
280
|
+
end
|
281
|
+
def projected_balance(date=@reporter.today)
|
282
|
+
@accounts.map{|acc|
|
283
|
+
case acc.type
|
284
|
+
when :Asset
|
285
|
+
acc.projected_balance(date)
|
286
|
+
when :Liability
|
287
|
+
-acc.projected_balance(date)
|
288
|
+
else
|
289
|
+
0.0
|
290
|
+
end
|
291
|
+
}.sum
|
292
|
+
end
|
293
|
+
def summary_table(today, days_before)
|
294
|
+
|
295
|
+
<<EOF
|
296
|
+
\\subsubsection{#{name}}
|
297
|
+
\\begin{tabulary}{0.8\\textwidth}{ r | l}
|
298
|
+
Balance & #{balance} \\\\
|
299
|
+
\\end{tabulary}
|
300
|
+
EOF
|
301
|
+
end
|
302
|
+
def summary_line(today, days_before)
|
303
|
+
"#{name_c} & #{balance(today)} & & "
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
data/lib/treasurer/analysis.rb
CHANGED
@@ -6,32 +6,32 @@ module Analysis
|
|
6
6
|
# period, along with a list of the expenditures
|
7
7
|
# for each period and a list of the items within
|
8
8
|
# each period
|
9
|
-
def account_expenditure(account,
|
9
|
+
def account_expenditure(account, options={})
|
10
10
|
dates = []
|
11
11
|
expenditures = []
|
12
12
|
account_items = []
|
13
|
-
date =
|
14
|
-
start_date = [(
|
13
|
+
date = account.info[:end]||@today
|
14
|
+
#start_date = [(account.info[:start]||@start_date), @start_date].max
|
15
15
|
expenditure = 0
|
16
16
|
items_temp = []
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
items = @runner.component_run_list.values.find_all{|r| r.external_account == account.name and r.in_date(account.info) and @accounts_hash[r.account].currency == account.currency}
|
18
|
+
#ep ['items', items.map{|i| i.date}]
|
19
|
+
#ep ['account', account.name_c]
|
20
20
|
counter = 0
|
21
|
-
if not
|
21
|
+
if not account.info[:period]
|
22
22
|
dates.push date
|
23
23
|
account_items.push items
|
24
|
-
expenditures.push (items.map{|r| (r.deposit - r.withdrawal) * (
|
24
|
+
expenditures.push (items.map{|r| (r.deposit - r.withdrawal) * (account.info[:external] ? -1 : 1)}+[0]).sum
|
25
25
|
else
|
26
26
|
|
27
|
-
case
|
27
|
+
case account.info[:period][1]
|
28
28
|
when :month
|
29
29
|
while date > @start_date
|
30
30
|
items_temp += items.find_all{|r| r.date == date}
|
31
|
-
if date.mday == (
|
31
|
+
if date.mday == (account.info[:monthday] or 1)
|
32
32
|
counter +=1
|
33
|
-
if counter %
|
34
|
-
expenditure = (items_temp.map{|r| (r.deposit - r.withdrawal) * (
|
33
|
+
if counter % account.info[:period][0] == 0
|
34
|
+
expenditure = (items_temp.map{|r| (r.deposit - r.withdrawal) * (account.info[:external] ? -1 : 1)}+[0]).sum
|
35
35
|
dates.push date
|
36
36
|
expenditures.push expenditure
|
37
37
|
account_items.push items_temp
|
@@ -46,8 +46,8 @@ module Analysis
|
|
46
46
|
items_temp += items.find_all{|r| r.date == date}
|
47
47
|
#expenditure += (account_items[-1].map{|r| r.debit}+[0]).sum
|
48
48
|
counter +=1
|
49
|
-
if counter %
|
50
|
-
expenditure = (items_temp.map{|r| (r.deposit - r.withdrawal) * (
|
49
|
+
if counter % account.info[:period][0] == 0
|
50
|
+
expenditure = (items_temp.map{|r| (r.deposit - r.withdrawal) * (account.info[:external] ? -1 : 1)}+[0]).sum
|
51
51
|
dates.push date
|
52
52
|
expenditures.push expenditure
|
53
53
|
account_items.push items_temp
|
@@ -68,21 +68,21 @@ module Analysis
|
|
68
68
|
projected_accounts_info.each{|key,v| projected_accounts_info[key]=projected_accounts_info[key].dup}
|
69
69
|
projected_accounts_info.each do |account, account_info|
|
70
70
|
#account_info = accounts[account]
|
71
|
-
|
72
|
-
|
71
|
+
_dates, expenditures, _items = account_expenditure(account, account_info)
|
72
|
+
account.average = expenditures.mean rescue 0.0
|
73
73
|
end
|
74
74
|
projected_accounts_info
|
75
75
|
end
|
76
76
|
# Work out the projected spend from the account and include it in the account info
|
77
|
-
def accounts_with_projections(
|
78
|
-
projected_accounts_info = accounts.dup
|
79
|
-
projected_accounts_info.each{|key,v| projected_accounts_info[key]=projected_accounts_info[key].dup}
|
80
|
-
|
77
|
+
def accounts_with_projections(projected_accounts, options={})
|
78
|
+
#projected_accounts_info = accounts.dup
|
79
|
+
#projected_accounts_info.each{|key,v| projected_accounts_info[key]=projected_accounts_info[key].dup}
|
80
|
+
projected_accounts.each do |account|
|
81
81
|
#account_info = accounts[account]
|
82
|
-
|
83
|
-
|
82
|
+
_dates, expenditures, _items = account_expenditure(account)
|
83
|
+
account.projection = expenditures.mean rescue 0.0
|
84
84
|
end
|
85
|
-
|
85
|
+
projected_accounts.map{|acc| [acc, acc.info]}.to_h
|
86
86
|
end
|
87
87
|
## Get a list of accounts to be included in the report
|
88
88
|
## i.e. accounts with non-empty expenditure
|
@@ -96,9 +96,11 @@ module Analysis
|
|
96
96
|
# expenditure from that account based on past
|
97
97
|
# expenditure (currently only a simple average)
|
98
98
|
def get_projected_accounts
|
99
|
-
|
100
|
-
|
99
|
+
#@projected_accounts_info = Hash[ACCOUNT_INFO.dup.find_all{|k,v| v[:discretionary]}]
|
100
|
+
#@projected_accounts_info = accounts_with_projections(@projected_accounts_info)
|
101
101
|
#@projected_accounts_info = @accounts.find_all{|acc| info = ACCOUNT_INFO[acc.name] and info[:discretionary]}
|
102
|
+
projected_accounts = @accounts.find_all{|acc| acc.info and acc.info[:discretionary]}
|
103
|
+
@projected_accounts_info = accounts_with_projections(projected_accounts)
|
102
104
|
end
|
103
105
|
# Calculate the sum of all items within future
|
104
106
|
# items that fall before end_date
|
@@ -121,7 +123,7 @@ module Analysis
|
|
121
123
|
# regular items that falls within the account period
|
122
124
|
def sum_regular(regular_items, end_date, options={})
|
123
125
|
#end_date = @today + @days_ahead
|
124
|
-
|
126
|
+
sum_out = regular_items.inject(0) do |sum, (account, item)|
|
125
127
|
item = [item] unless item.kind_of? Array
|
126
128
|
# ep item
|
127
129
|
value = item.inject(0) do |value,info|
|
@@ -182,13 +184,13 @@ module Analysis
|
|
182
184
|
|
183
185
|
#ep ['name2234', name, info, @projected_account_factor] if info[:discretionary]
|
184
186
|
|
185
|
-
|
187
|
+
value + nunits * (info[:size]||account.projection*(@projected_account_factor||1.0))
|
186
188
|
|
187
189
|
end
|
188
190
|
sum + value
|
189
191
|
#(rcp.excluding? and rcp.excluding.include?(name)) ? sum : sum + value
|
190
192
|
end
|
191
|
-
|
193
|
+
sum_out
|
192
194
|
end
|
193
195
|
end
|
194
196
|
include Analysis
|
data/lib/treasurer/commands.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
class Treasurer
|
3
3
|
class << self
|
4
4
|
def add_file(file, account, copts={})
|
5
|
-
load_treasurer_folder
|
5
|
+
load_treasurer_folder(copts)
|
6
6
|
ep 'entries', Dir.entries
|
7
7
|
CodeRunner.submit(p: "{data_file: '#{File.expand_path(file)}', account: :#{account}}")
|
8
8
|
end
|
@@ -23,9 +23,13 @@ class << self
|
|
23
23
|
reporter.report()
|
24
24
|
end
|
25
25
|
def fetch_reporter(copts = {})
|
26
|
-
load_treasurer_folder
|
27
|
-
reporter = Reporter.new(CodeRunner.fetch_runner(h: :component), days_before: copts[:b]||360, days_ahead: copts[:a]||180, today: copts[:t])
|
26
|
+
load_treasurer_folder(copts)
|
27
|
+
reporter = Reporter.new(CodeRunner.fetch_runner(h: :component, A: true), days_before: copts[:b]||360, days_ahead: copts[:a]||180, today: copts[:t])
|
28
28
|
end
|
29
|
+
def status(copts={})
|
30
|
+
load_treasurer_folder(copts)
|
31
|
+
CodeRunner.status(eval(copts[:C]||"{}"))
|
32
|
+
end
|
29
33
|
def init_root_folder(folder, copts={})
|
30
34
|
raise "Folder already exists" if FileTest.exist? folder
|
31
35
|
FileUtils.makedirs(folder)
|
@@ -33,15 +37,16 @@ class << self
|
|
33
37
|
CodeRunner.fetch_runner(Y: folder, C: 'budget', X: '/dev/null')
|
34
38
|
eputs "\n\n Your treasurer folder '#{folder}' has been set up. All further treasurer commands should be run from within this folder.\n"
|
35
39
|
end
|
36
|
-
def load_treasurer_folder
|
40
|
+
def load_treasurer_folder(copts={})
|
37
41
|
check_is_treasurer_folder
|
38
42
|
Treasurer.send(:remove_const, :LocalCustomisations) if defined? Treasurer::LocalCustomisations
|
39
43
|
load 'local_customisations.rb'
|
40
44
|
Treasurer::Reporter.send(:include, Treasurer::LocalCustomisations)
|
41
45
|
Treasurer::Reporter::Account.send(:include, Treasurer::LocalCustomisations)
|
42
46
|
Treasurer::Reporter::Analysis.send(:include, Treasurer::LocalCustomisations)
|
43
|
-
|
47
|
+
require 'budgetcrmod'
|
44
48
|
CodeRunner::Budget.send(:include, Treasurer::LocalCustomisations)
|
49
|
+
_runner = CodeRunner.fetch_runner(eval(copts[:C]||"{}"))
|
45
50
|
end
|
46
51
|
|
47
52
|
def method_missing(meth, *args)
|