treasurer 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|