treasurer 0.6.0 → 0.7.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/lib/treasurer/accounts.rb +74 -16
- data/lib/treasurer/analysis.rb +4 -3
- data/lib/treasurer/report.rb +101 -89
- data/treasurer.gemspec +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2048cb90864a5b22bc6bb26e1d226040caeb731
|
4
|
+
data.tar.gz: 340e5a5daf1026576358fc596ce9894566fac808
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0ac2576887308f53d2e3f72f3e73ece698785c4798d0ae2d8a14a1f114670eb7b44f18462742cab5b7b97c634a20ce71a7cc600d4f816d47d75859e44c1b511
|
7
|
+
data.tar.gz: cc2da7e7611fc6cf38502565a2b3721e64c45084627e2adb6bb7df043060af09f377a314e24683591284820aaac63eef9d611f018a676c4006db755d927f608f
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
data/lib/treasurer/accounts.rb
CHANGED
@@ -13,6 +13,8 @@ class Treasurer::Reporter
|
|
13
13
|
#ep ['sub_accounts333', name, @runs.size, runs.size]
|
14
14
|
end
|
15
15
|
end
|
16
|
+
class ReportAccount < Account
|
17
|
+
end
|
16
18
|
class Account
|
17
19
|
attr_reader :name, :external, :runs, :currency
|
18
20
|
attr_accessor :projection, :average, :original_currency
|
@@ -23,21 +25,66 @@ class Treasurer::Reporter
|
|
23
25
|
@currency = options[:currency]
|
24
26
|
#@projected_accounts_info =Hash[projected_accounts_info.find_all{|k,v| v[:account] == name}]
|
25
27
|
@external = external
|
26
|
-
@runs =
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
28
|
+
unless @runs = options[:input_runs]
|
29
|
+
@runs = runs.find_all do |r|
|
30
|
+
#p ['checking11', name, @currency, ACCOUNT_INFO[r.account]] if name == r.external_account and @currency and @external
|
31
|
+
#@external ? r.external_account : r.account) == name}
|
32
|
+
if not @external
|
33
|
+
r.account == name
|
34
|
+
elsif @currency and info and cur = info[:currencies] and cur.size > 1
|
35
|
+
#p ['checking11', name, @currency, ACCOUNT_INFO[r.account]] if name == r.external_account and @currency
|
36
|
+
r.external_account == name and acinfo = ACCOUNT_INFO[r.account] and acinfo[:currencies] == [@currency]
|
37
|
+
else
|
38
|
+
r.external_account == name
|
39
|
+
end
|
36
40
|
end
|
41
|
+
|
42
|
+
if should_report?
|
43
|
+
if @external
|
44
|
+
@report_runs = runs.find_all do |r|
|
45
|
+
r.external_account == name
|
46
|
+
end
|
47
|
+
else
|
48
|
+
@report_runs = @runs
|
49
|
+
end
|
50
|
+
end
|
51
|
+
else
|
52
|
+
@report_runs = []
|
37
53
|
end
|
38
54
|
#p ['Accountinf', name, @currency, @runs.size, runs.size]
|
39
55
|
info[:external] = external if info
|
40
56
|
end
|
57
|
+
|
58
|
+
# Make the account object that does the reporting. This only
|
59
|
+
# gets called if we are doing a currency conversion and
|
60
|
+
# this account is in the reeport currency.
|
61
|
+
def generate_report_account
|
62
|
+
p [name_c, @report_runs.class, @runs.class]
|
63
|
+
@report_account = ReportAccount.new(@name, @reporter, @runner, nil, @external, {currency: @currency, input_runs: @report_runs})
|
64
|
+
@report_account.instance_variable_set(:@currency, @reporter.report_currency)
|
65
|
+
@report_account.instance_variable_set(:@original_currency, currency)
|
66
|
+
end
|
67
|
+
|
68
|
+
# The object that actually does the reporting. If there is no
|
69
|
+
# currency conversion this is just self.
|
70
|
+
# A separate report object is needed as just lumping all the
|
71
|
+
# different currencies together across the board results
|
72
|
+
# in double counting.
|
73
|
+
#
|
74
|
+
# The report account is used for reporting information
|
75
|
+
# regarding a particular account. The main accoun is
|
76
|
+
# used for calculations e.g. Equity
|
77
|
+
def report_account
|
78
|
+
@report_account || self
|
79
|
+
end
|
80
|
+
|
81
|
+
# Should I report? If there is no currency conversion
|
82
|
+
# all accounts report. If there is currency conversion
|
83
|
+
# only non-external accounts and accounts in the
|
84
|
+
# right currency report.
|
85
|
+
def should_report?
|
86
|
+
!@reporter.report_currency or !@external or (@original_currency||currency) == @reporter.report_currency
|
87
|
+
end
|
41
88
|
def sub_accounts
|
42
89
|
@sub_accounts ||= @runs.map{|r| r.sub_account}.uniq.compact.map{|acc| SubAccount.new(acc, @reporter, @runner, @runs, @external, currency: @currency)}
|
43
90
|
end
|
@@ -137,7 +184,7 @@ EOF
|
|
137
184
|
def summary_line(today, days_before)
|
138
185
|
|
139
186
|
<<EOF
|
140
|
-
#{name_c} & #{balance} & #{deposited(today, days_before)} & #{withdrawn(today, days_before)}
|
187
|
+
#{name_c} & #{balance.to_tex} & #{deposited(today, days_before).to_tex} & #{withdrawn(today, days_before).to_tex}
|
141
188
|
EOF
|
142
189
|
end
|
143
190
|
def money_in_sign
|
@@ -237,13 +284,15 @@ EOF
|
|
237
284
|
#exit
|
238
285
|
@reporter.projected_account_factor = nil
|
239
286
|
kit += ( kit4 + kit5 + kit2)
|
240
|
-
kit.yrange = [kit.data.map{|dk| dk.y.data.min}.min, kit.data.map{|dk| dk.y.data.max}.max]
|
287
|
+
kit.yrange = [(m = kit.data.map{|dk| dk.y.data.min}.min; m-m.abs*0.1), (m=kit.data.map{|dk| dk.y.data.max}.max; m+m.abs*0.1)]
|
241
288
|
#kit += (kit2)
|
242
289
|
kit = kit3 + kit
|
243
290
|
kit.title = "Balance for #{name_c}"
|
244
291
|
kit.xlabel = %['Date' offset 0,-2]
|
245
292
|
kit.xlabel = nil
|
246
293
|
kit.ylabel = "Balance"
|
294
|
+
kit.gp.mytics= "5"
|
295
|
+
kit.gp.grid = "ytics mytics lw 2,lw 1"
|
247
296
|
|
248
297
|
|
249
298
|
kit.data[0].gp.title = 'Limit'
|
@@ -255,14 +304,20 @@ EOF
|
|
255
304
|
kit.data.each{|dk| dk.gp.with = "l lw 5"}
|
256
305
|
kit.data[4].gp.with = "l lw 5 dt 2 lc rgb 'black' "
|
257
306
|
kit.gp.key = ' bottom left '
|
258
|
-
kit.gp.key = ' rmargin '
|
307
|
+
kit.gp.key = ' rmargin samplen 2'
|
259
308
|
|
260
309
|
#(p kit; STDIN.gets) if name == :LloydsCreditCard
|
261
310
|
CodeRunner::Budget.kit_time_format_x(kit)
|
311
|
+
size = case type
|
312
|
+
when :Equity
|
313
|
+
"4.0in,4.0in"
|
314
|
+
else
|
315
|
+
"4.0in,2.5in"
|
316
|
+
end
|
262
317
|
|
263
318
|
fork do
|
264
|
-
(kit).gnuplot_write("#{name_c_file}_balance.eps", size:
|
265
|
-
%x[epspdf #{name_c_file}_balance.eps]
|
319
|
+
(kit).gnuplot_write("#{name_c_file}_balance.eps", size: size) #, latex: true)
|
320
|
+
%x[epspdf -b #{name_c_file}_balance.eps]
|
266
321
|
end
|
267
322
|
#%x[epspdf #{name}_balance.eps]
|
268
323
|
end
|
@@ -281,6 +336,9 @@ EOF
|
|
281
336
|
@accounts = accounts #.find_all{|acc| not acc.external}
|
282
337
|
@currency = options[:currency]
|
283
338
|
end
|
339
|
+
def should_report?
|
340
|
+
true
|
341
|
+
end
|
284
342
|
def type
|
285
343
|
:Equity
|
286
344
|
end
|
@@ -336,7 +394,7 @@ Balance & #{balance} \\\\
|
|
336
394
|
EOF
|
337
395
|
end
|
338
396
|
def summary_line(today, days_before)
|
339
|
-
"#{name_c} & #{balance(today)} & & "
|
397
|
+
"#{name_c} & #{balance(today).to_tex} & & "
|
340
398
|
end
|
341
399
|
end
|
342
400
|
end
|
data/lib/treasurer/analysis.rb
CHANGED
@@ -22,7 +22,8 @@ module Analysis
|
|
22
22
|
#start_date = [(account.info[:start]||@start_date), @start_date].max
|
23
23
|
expenditure = 0
|
24
24
|
items_temp = []
|
25
|
-
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].original_currency == account.original_currency}
|
25
|
+
#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].original_currency == account.original_currency}
|
26
|
+
items = account.runs.find_all{|r| r.in_date(account.info)}
|
26
27
|
#ep ['items', items.map{|i| i.date}]
|
27
28
|
#ep ['account', account.name_c]
|
28
29
|
counter = 0
|
@@ -142,7 +143,7 @@ module Analysis
|
|
142
143
|
sum_out = regular_items.inject(0) do |sum, (account, item)|
|
143
144
|
item = [item] unless item.kind_of? Array
|
144
145
|
# ep item
|
145
|
-
|
146
|
+
value_out = item.inject(0) do |value,info|
|
146
147
|
finish = (info[:end] and info[:end] < end_date) ? info[:end] : end_date
|
147
148
|
#today = (Time.now.to_i / (24.0*3600.0)).round
|
148
149
|
|
@@ -212,7 +213,7 @@ module Analysis
|
|
212
213
|
value + nunits * (info[:size]||account.projection*(@projected_account_factor||1.0))
|
213
214
|
|
214
215
|
end
|
215
|
-
sum +
|
216
|
+
sum + value_out
|
216
217
|
#(rcp.excluding? and rcp.excluding.include?(name)) ? sum : sum + value
|
217
218
|
end
|
218
219
|
sum_out
|
data/lib/treasurer/report.rb
CHANGED
@@ -11,39 +11,44 @@ class Float
|
|
11
11
|
sprintf("%.2f", self)
|
12
12
|
end
|
13
13
|
end
|
14
|
+
class Numeric
|
15
|
+
def to_tex
|
16
|
+
sprintf("%.2f", self).reverse.gsub(/(\d{3})(?=\d)/){"#$1,\\"}.reverse
|
17
|
+
end
|
18
|
+
end
|
14
19
|
class Date
|
15
20
|
def inspect
|
16
21
|
"Date.parse('#{to_s}')"
|
17
22
|
end
|
18
23
|
end
|
19
|
-
# Some thoughts on double entry accounting:
|
24
|
+
# Some thoughts on double entry accounting:
|
20
25
|
#
|
21
26
|
# assets - liabilities = equity
|
22
27
|
# where equity = equity_at_start + income - expenses
|
23
28
|
#
|
24
|
-
# so
|
29
|
+
# so
|
25
30
|
#
|
26
31
|
# assets - liabilities = equity_at_start + income - expenses
|
27
32
|
#
|
28
|
-
# or alternatively
|
33
|
+
# or alternatively
|
29
34
|
#
|
30
35
|
# assets + expenses = equity_at_start + income + liabilities (1)
|
31
36
|
#
|
32
37
|
# Good things:
|
33
38
|
# Positive equity_at_start, positive assets, positive income, negative liabilities, negative expenses
|
34
39
|
#
|
35
|
-
# A debit on the left of (1) must be matched by a credit on the right of (1) and
|
36
|
-
# vice versa.
|
40
|
+
# A debit on the left of (1) must be matched by a credit on the right of (1) and
|
41
|
+
# vice versa.
|
37
42
|
#
|
38
43
|
#
|
39
44
|
# A debit to an asset account increases the value of the asset. This means buying some land
|
40
|
-
# or supplies or depositing some cash in a bank account. You can think of it as a debit because
|
45
|
+
# or supplies or depositing some cash in a bank account. You can think of it as a debit because
|
41
46
|
# you are locking up your equity in a way that may not be realisable. A credit to the asset account
|
42
47
|
# means drawing down on the asset, for example selling a bit of land or taking money out of a
|
43
48
|
# bank account.
|
44
49
|
#
|
45
50
|
# Similarly, a debit to an expense account, effectively, spending money on that expense,
|
46
|
-
# increases the value of that account. Debits here are clearly negative things from
|
51
|
+
# increases the value of that account. Debits here are clearly negative things from
|
47
52
|
# the point of view of your wealth! (Credits to expense accounts would be something like
|
48
53
|
# travel reimbursements).
|
49
54
|
#
|
@@ -52,16 +57,16 @@ end
|
|
52
57
|
# example a bank account, i.e. you must effectively spend it by buying an asset: remember
|
53
58
|
# a bank may fail... a bank account is an asset with risk just as much as a painting).
|
54
59
|
#
|
55
|
-
# A credit to liabilities increases the value of the liability, for example taking out a
|
60
|
+
# A credit to liabilities increases the value of the liability, for example taking out a
|
56
61
|
# loan. Once you credit a liability you have to either buy (debit) an asset, or buy (debit)
|
57
62
|
# an expense directly (for example a loan to pay some fees).
|
58
|
-
#
|
63
|
+
#
|
59
64
|
# In any accounting period, the sum of all debits and credits should be 0. Also, at the end
|
60
65
|
# of the accounting period,
|
61
66
|
#
|
62
67
|
# equity_at_end = assets - liabilities = equity_at_start + income - expenses
|
63
68
|
#
|
64
|
-
# This seems obvious to me!!
|
69
|
+
# This seems obvious to me!!
|
65
70
|
class Treasurer
|
66
71
|
class Reporter
|
67
72
|
#include LocalCustomisations
|
@@ -72,7 +77,7 @@ class Treasurer
|
|
72
77
|
attr_reader :accounts
|
73
78
|
attr_reader :equity
|
74
79
|
attr_reader :projected_accounts_info
|
75
|
-
attr_reader :days_before
|
80
|
+
attr_reader :days_before
|
76
81
|
attr_reader :report_currency
|
77
82
|
attr_reader :accounts_hash
|
78
83
|
def initialize(runner, options)
|
@@ -87,30 +92,30 @@ class Treasurer
|
|
87
92
|
@report_currency = options[:report_currency]
|
88
93
|
|
89
94
|
if run = @runs.find{|r| not r.external_account}
|
90
|
-
raise "External_account not specified for #{run.data_line}"
|
95
|
+
raise "External_account not specified for #{run.data_line}"
|
91
96
|
end
|
92
97
|
@indateruns = @runs.find_all{|r| r.days_ago(@today) < @days_before}
|
93
98
|
@stable_discretionary_account_factors = {}
|
94
99
|
@in_limit_discretionary_account_factors = {}
|
95
|
-
#p 'accounts256',@runs.size, @runs.map{|r| r.account}.uniq
|
100
|
+
#p 'accounts256',@runs.size, @runs.map{|r| r.account}.uniq
|
96
101
|
|
97
102
|
end
|
98
103
|
def generate_accounts
|
99
|
-
accounts = @runs.map{|r| r.account}.uniq.map{|acc| Account.new(acc, self, @runner, @runs, false)}
|
100
|
-
external_accounts = (@runs.map{|r| r.external_account}.uniq - accounts.map{|acc| acc.name}).map{|acc| Account.new(acc, self, @runner, @runs, true)}
|
104
|
+
accounts = @runs.map{|r| r.account}.uniq.map{|acc| Account.new(acc, self, @runner, @runs, false)}
|
105
|
+
external_accounts = (@runs.map{|r| r.external_account}.uniq - accounts.map{|acc| acc.name}).map{|acc| Account.new(acc, self, @runner, @runs, true)}
|
101
106
|
#if not @report_currency
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
new_accounts.delete_if{|a| a.runs.size == 0}
|
109
|
-
new_accounts
|
110
|
-
else
|
111
|
-
acc
|
107
|
+
external_accounts = external_accounts.map do |acc|
|
108
|
+
if acc_inf = ACCOUNT_INFO[acc.name] and currencies = acc_inf[:currencies] and currencies.size > 1
|
109
|
+
raise "Only expense accounts can have multiple currencies: #{acc.name} has type #{acc.type}" unless acc.type == :Expense
|
110
|
+
new_accounts = currencies.map do |curr|
|
111
|
+
Account.new(acc.name, self, @runner, @runs, true, currency: curr)
|
112
112
|
end
|
113
|
+
new_accounts.delete_if{|a| a.runs.size == 0}
|
114
|
+
new_accounts
|
115
|
+
else
|
116
|
+
acc
|
113
117
|
end
|
118
|
+
end
|
114
119
|
#end
|
115
120
|
external_accounts = external_accounts.flatten
|
116
121
|
@accounts = accounts + external_accounts
|
@@ -148,6 +153,10 @@ class Treasurer
|
|
148
153
|
acc.info[:opening_balance] *= EXCHANGE_RATES[[acc.currency, @report_currency]]
|
149
154
|
end
|
150
155
|
end
|
156
|
+
if acc.should_report?
|
157
|
+
#p acc.name_c
|
158
|
+
acc.generate_report_account
|
159
|
+
end
|
151
160
|
acc.instance_variable_set(:@original_currency, acc.currency)
|
152
161
|
acc.instance_variable_set(:@currency, @report_currency)
|
153
162
|
acc.info[:currencies] = [@report_currency]
|
@@ -164,7 +173,7 @@ class Treasurer
|
|
164
173
|
end
|
165
174
|
@equities = @equities.to_h
|
166
175
|
end
|
167
|
-
|
176
|
+
|
168
177
|
def report
|
169
178
|
generate_accounts
|
170
179
|
#get_actual_accounts
|
@@ -199,18 +208,18 @@ class Treasurer
|
|
199
208
|
<<EOF
|
200
209
|
\\section{Summary of Accounts}
|
201
210
|
#{[:Equity, :Asset, :Liability, :Income, :Expense].map{|type|
|
202
|
-
accs = @accounts.find_all{|acc| acc.type == type }
|
211
|
+
accs = @accounts.find_all{|acc| acc.type == type and acc.should_report?}
|
203
212
|
"\\subsection{#{type}}
|
204
|
-
\\begin{tabulary}{0.9\\textwidth}{ R |
|
213
|
+
\\begin{tabulary}{0.9\\textwidth}{ R | r | r | r}
|
205
214
|
Account & Balance & Deposited & Withdrawn \\\\
|
206
215
|
\\hline
|
207
216
|
\\Tstrut
|
208
|
-
#{(accs.map{|acc| acc.summary_line(@today, @days_before)} +
|
209
|
-
(type == :Asset ? ASSETS.map{|n,details| "#{n} (#{details[:currency]}) & #{details[:size]} & & "} : [])).join("\\\\\n")}
|
217
|
+
#{(accs.map{|acc| acc.report_account.summary_line(@today, @days_before)} +
|
218
|
+
(type == :Asset ? ASSETS.map{|n,details| "#{n} (#{details[:currency]}) & #{details[:size].to_tex} & & "} : [])).join("\\\\\n")}
|
210
219
|
#{type!=:Equity&&false ? "
|
211
220
|
\\\\ \\hline
|
212
221
|
\\Tstrut
|
213
|
-
Totals & #{accs.map{|a| a.balance}.sum} & #{accs.map{|a| a.deposited(@today, @days_before)}.sum} & #{accs.map{|a| a.withdrawn(@today, @days_before)}.sum} \\\\ " : "\\\\"}
|
222
|
+
Totals & #{accs.map{|a| a.balance}.sum.to_tex} & #{accs.map{|a| a.deposited(@today, @days_before)}.sum.to_tex} & #{accs.map{|a| a.withdrawn(@today, @days_before)}.sum.to_tex} \\\\ " : "\\\\"}
|
214
223
|
\\end{tabulary}"
|
215
224
|
}.join("\n\n")}
|
216
225
|
EOF
|
@@ -219,7 +228,7 @@ EOF
|
|
219
228
|
<<EOF
|
220
229
|
\\section{Graphs of Recent Balances}
|
221
230
|
#{[:Equity, :Asset, :Liability].map{|typ|
|
222
|
-
"\\subsection{#{typ}}\\vspace{3em}" +
|
231
|
+
"\\subsection{#{typ}}\\vspace{3em}" +
|
223
232
|
@accounts.find_all{|acc| acc.type == typ}.map{|acc|
|
224
233
|
acc.write_balance_graph(@today, @days_before, @days_ahead)
|
225
234
|
acc.balance_graph_string
|
@@ -234,9 +243,10 @@ EOF
|
|
234
243
|
\\subsection{Totals for #@days_before-day Budget Period}
|
235
244
|
#{expense_pie_charts_by_currency('accountperiod', @expense_accounts){|r| r.days_ago(@today) < @days_before}}
|
236
245
|
\\subsection{Expense Account Breakdown}
|
237
|
-
#{@expense_accounts.map{|
|
238
|
-
|
239
|
-
|
246
|
+
#{@expense_accounts.find_all{|exaccount| exaccount.should_report?}.map{|exaccount|
|
247
|
+
account = exaccount.report_account
|
248
|
+
"
|
249
|
+
\\subsection{#{account.name_c}}
|
240
250
|
#{expense_pie_chart(account.name_c_file + 'breakdown', account.sub_accounts, account){|r|r.days_ago(@today) < @days_before }}"
|
241
251
|
}.join("\n\n")}
|
242
252
|
EOF
|
@@ -258,7 +268,7 @@ EOF
|
|
258
268
|
currencies.map do |curr|
|
259
269
|
str = ""
|
260
270
|
str << "\\subsubsection{#{curr}}\n" if curr
|
261
|
-
str << expense_pie_chart(name + curr.to_s, accounts.find_all{|acc| acc.currency == curr}, &block)
|
271
|
+
str << expense_pie_chart(name + curr.to_s, accounts.find_all{|acc| acc.currency == curr and acc.should_report?}.map{|acc| acc.report_account}, &block)
|
262
272
|
str
|
263
273
|
end
|
264
274
|
).join("\n\n")
|
@@ -269,27 +279,27 @@ EOF
|
|
269
279
|
#ep ['labels22539', name, labels, exps]
|
270
280
|
|
271
281
|
kit = if subacc
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
282
|
+
start_dates, end_dates, _exps, _items = account_expenditure(subacc)
|
283
|
+
end_dates = end_dates.reverse #Now from earliest to latest
|
284
|
+
start_dates = start_dates.reverse
|
285
|
+
pp ['DATES', start_dates, end_dates, subacc.name]
|
286
|
+
return "No expenditure in account period." if end_dates.size==0
|
287
|
+
k = (
|
288
|
+
end_dates.size.times.map do |i|
|
289
|
+
exps = accounts.map{|acc| acc.deposited(end_dates[i], end_dates[i] - start_dates[i], &block)}
|
290
|
+
kt = GraphKit.quick_create([labels.size.times.to_a.map{|l| l.to_f + i.to_f/end_dates.size.to_f}, exps])
|
291
|
+
kt.data[0].gp.title = "Ending #{end_dates[i].strftime("#{end_dates[i].mday.ordinalize} %B")}; total = #{exps.sum}"
|
292
|
+
kt.gp.key = "tmargin"
|
293
|
+
kt
|
294
|
+
end
|
295
|
+
).sum
|
296
|
+
k
|
297
|
+
else
|
298
|
+
exps = accounts.map{|acc| acc.deposited(@today, 50000, &block)}
|
299
|
+
labels, exps = [labels, exps].transpose.find_all{|l, e| e != 0.0}.transpose
|
300
|
+
return "No expenditure in account period." if not labels #<F8> labels.size==0
|
301
|
+
GraphKit.quick_create([labels.size.times.to_a, exps])
|
302
|
+
end
|
293
303
|
|
294
304
|
|
295
305
|
#sum = exps.sum
|
@@ -311,7 +321,7 @@ EOF
|
|
311
321
|
i = -1
|
312
322
|
kit.gp.xtics = "(#{labels.map{|l| %["#{l}" #{i+=1}]}.join(', ')}) rotate by 315"
|
313
323
|
pp ['kit222', kit, labels]
|
314
|
-
fork do
|
324
|
+
fork do
|
315
325
|
kit.gnuplot_write("#{name}.eps", size: "4.0in,2.0in")
|
316
326
|
%x[epspdf #{name}.eps]
|
317
327
|
end
|
@@ -362,16 +372,18 @@ EOF
|
|
362
372
|
#exit
|
363
373
|
end
|
364
374
|
def discretionary_account_table(currency)
|
365
|
-
discretionary_accounts = accounts_with_averages(
|
375
|
+
discretionary_accounts = accounts_with_averages(
|
376
|
+
@projected_accounts_info.find_all{|acc,inf| acc.currency == currency and acc.should_report?}.map{|acc,inf| [acc.report_account,inf]}.to_h)
|
377
|
+
accounts_with_projections(discretionary_accounts.keys)
|
366
378
|
|
367
379
|
<<EOF
|
368
380
|
\\section{Discretionary Budget Summary (#{currency})}
|
369
|
-
\\begin{tabulary}{0.9\\textwidth}{ R |
|
381
|
+
\\begin{tabulary}{0.9\\textwidth}{ R | r r r r }
|
370
382
|
Budget & Average & Projection & Limit & Stable \\\\
|
371
383
|
#{discretionary_accounts.map{|account, info|
|
372
384
|
#ep info
|
373
385
|
"#{account.name_c} & #{account.average} & #{account.projection} & #{
|
374
|
-
(account.projection * @in_limit_discretionary_account_factors[currency]).round(2)} &
|
386
|
+
(account.projection * @in_limit_discretionary_account_factors[currency]).round(2)} &
|
375
387
|
#{(account.projection * @stable_discretionary_account_factors[currency]).round(2)} \\\\"
|
376
388
|
}.join("\n\n")
|
377
389
|
}
|
@@ -381,15 +393,15 @@ EOF
|
|
381
393
|
def account_expenditure_graphs
|
382
394
|
<<EOF
|
383
395
|
\\section{Expenditure by Account Period}
|
384
|
-
#{currency_list.map{|curr|
|
385
|
-
|
386
|
-
|
387
|
-
|
396
|
+
#{currency_list.map{|curr|
|
397
|
+
account_and_transfer_graphs(@expense_accounts.find_all{|acc|
|
398
|
+
acc.info and acc.info[:period] and acc.currency == curr and acc.should_report?
|
399
|
+
}.map{|acc| acc.report_account})
|
388
400
|
}.join("\n")}
|
389
401
|
EOF
|
390
402
|
end
|
391
403
|
def account_and_transfer_graphs(accounts, options={})
|
392
|
-
"#{accounts.map{|account|
|
404
|
+
"#{accounts.map{|account|
|
393
405
|
account_info = account.info
|
394
406
|
#ep ['accountbadf', account, account_info]
|
395
407
|
start_dates, dates, expenditures, _items = account_expenditure(account)
|
@@ -416,11 +428,11 @@ EOF
|
|
416
428
|
kit.xlabel = nil
|
417
429
|
kit.ylabel = nil
|
418
430
|
unless options[:transfers]
|
419
|
-
kits = accounts_with_averages({account => account_info}).map{|
|
431
|
+
kits = accounts_with_averages({account => account_info}).map{|acco, acco_info|
|
420
432
|
#ep 'Budget is ', account
|
421
433
|
kit2 = GraphKit.quick_create([
|
422
|
-
[dates[0], dates[-1]].map{|d| d.to_time.to_i - barsize},
|
423
|
-
[
|
434
|
+
[dates[0], dates[-1]].map{|d| d.to_time.to_i - barsize},
|
435
|
+
[acco.average, acco.average]
|
424
436
|
])
|
425
437
|
kit2.data[0].gp.with = 'l lw 5'
|
426
438
|
kit2
|
@@ -436,7 +448,7 @@ EOF
|
|
436
448
|
CodeRunner::Budget.kit_time_format_x(kit)
|
437
449
|
#kit.gnuplot
|
438
450
|
#ep ['kit1122', account, kit]
|
439
|
-
fork do
|
451
|
+
fork do
|
440
452
|
kit.gnuplot_write("#{account.name_c_file}.eps", size: "4.0in,2.0in")
|
441
453
|
exec "epspdf #{account.name_c_file}.eps"
|
442
454
|
end
|
@@ -487,8 +499,8 @@ This section sums items from accounts drawn from an alternate account, i.e. it d
|
|
487
499
|
|
488
500
|
\\Tstrut
|
489
501
|
|
490
|
-
#{piece.map{|r|
|
491
|
-
([:id] + CodeRunner::Budget.rcp.component_results - [:sc]).map{|res|
|
502
|
+
#{piece.map{|r|
|
503
|
+
([:id] + CodeRunner::Budget.rcp.component_results - [:sc]).map{|res|
|
492
504
|
r.send(res).to_s.latex_escape
|
493
505
|
#rcp.component_results.map{|res| r.send(res).to_s.gsub(/(.{20})/, '\1\\\\\\\\').latex_escape
|
494
506
|
}.join(" & ")
|
@@ -517,12 +529,12 @@ EOF
|
|
517
529
|
def account_breakdown
|
518
530
|
<<EOF
|
519
531
|
\\section{SubAccount Breakdown}
|
520
|
-
#{(@actual_accounts).map{|account, account_info|
|
532
|
+
#{(@actual_accounts).map{|account, account_info|
|
521
533
|
_start_dates, dates, expenditures, account_items = account_expenditure(account, account_info)
|
522
534
|
#pp account, account_items.map{|items| items.map{|i| i.date.to_s}}
|
523
|
-
"\\subsection{#{account}}" +
|
535
|
+
"\\subsection{#{account}}" +
|
524
536
|
account_items.zip(dates, expenditures).map{|items, date, expenditure|
|
525
|
-
|
537
|
+
if items.size > 0
|
526
538
|
"
|
527
539
|
\\small
|
528
540
|
\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{ #{"c " * 3 + " L " + " r " * 2 + " c " }}
|
@@ -530,8 +542,8 @@ EOF
|
|
530
542
|
#{date.to_s.latex_escape} & & & Total & #{expenditure} & \\\\
|
531
543
|
\\hline
|
532
544
|
\\Tstrut
|
533
|
-
#{items.map{|r|
|
534
|
-
( CodeRunner::Budget.rcp.component_results + [:external_account] - [:sc, :balance ]).map{|res|
|
545
|
+
#{items.map{|r|
|
546
|
+
( CodeRunner::Budget.rcp.component_results + [:external_account] - [:sc, :balance ]).map{|res|
|
535
547
|
r.send(res).to_s.latex_escape
|
536
548
|
}.join(" & ")
|
537
549
|
}.join("\\\\\n")
|
@@ -541,7 +553,7 @@ EOF
|
|
541
553
|
\\end{tabulary}
|
542
554
|
\\normalsize
|
543
555
|
\\vspace{1em}\n\n"
|
544
|
-
|
556
|
+
else
|
545
557
|
""
|
546
558
|
end
|
547
559
|
}.join("\n\n")
|
@@ -553,7 +565,7 @@ EOF
|
|
553
565
|
def transactions_by_account
|
554
566
|
<<EOF
|
555
567
|
\\section{Recent Transactions}
|
556
|
-
#{@accounts.find_all{|acc| not acc.type == :Equity}.sort_by{|acc| acc.external ? 0 : 1}.map{|acc|
|
568
|
+
#{@accounts.find_all{|acc| not acc.type == :Equity}.sort_by{|acc| acc.external ? 0 : 1}.map{|acc|
|
557
569
|
"\\subsection{#{acc.name_c}}
|
558
570
|
\\tiny
|
559
571
|
#{all = acc.runs.find_all{|r| r.days_ago(@today) < @days_before}
|
@@ -566,10 +578,10 @@ EOF
|
|
566
578
|
#ep ['acc', acc, 'ids', all.map{|r| r.id}, 'size', all.size]
|
567
579
|
all.pieces((all.size.to_f/50.to_f).ceil).map{|piece|
|
568
580
|
"\\setlength{\\parindent}{0cm}\n\n\\begin{tabulary}{0.99\\textwidth}{ #{"c " * 3 + " l " + " r " * 3 + "l"}}
|
569
|
-
#{piece.map{|r|
|
570
|
-
(CodeRunner::Budget.rcp.component_results - [:sc] + [:sub_account]).map{|res|
|
581
|
+
#{piece.map{|r|
|
582
|
+
(CodeRunner::Budget.rcp.component_results - [:sc] + [:sub_account]).map{|res|
|
571
583
|
entry = r.send(res).to_s.latex_escape
|
572
|
-
#if
|
584
|
+
#if
|
573
585
|
entry = entry[0...25] if entry.length > 25
|
574
586
|
#if entry.length > 40
|
575
587
|
#entry = entry.split(/.{40}/).join(" \\newline ")
|
@@ -596,9 +608,9 @@ EOF
|
|
596
608
|
\\usepackage{libertine}
|
597
609
|
\\usepackage{xcolor,listings}
|
598
610
|
\\newcommand\\Tstrut{\\rule{0pt}{2.8ex}}
|
599
|
-
\\newcommand\\myfigure[1]{\\vspace*{
|
611
|
+
\\newcommand\\myfigure[1]{\\vspace*{1em}\\begin{center}
|
600
612
|
|
601
|
-
\\includegraphics[width=0.
|
613
|
+
\\includegraphics[width=0.99\\textwidth]{#1}
|
602
614
|
|
603
615
|
\\end{center}\\vspace*{0em}
|
604
616
|
|
@@ -636,10 +648,10 @@ EOF
|
|
636
648
|
end
|
637
649
|
end
|
638
650
|
#\\subsection{Last Week}
|
639
|
-
|
640
|
-
|
641
|
-
|
651
|
+
##{expense_pie_charts_by_currency('lastweekexpenses', @expense_accounts){|r|
|
652
|
+
##p ['r.daysago', r.days_ago(@today)];
|
653
|
+
#r.days_ago(@today) < 7}}
|
642
654
|
#\\subsection{Last Month}
|
643
|
-
|
655
|
+
##{expense_pie_charts_by_currency('lastmonthexpenses', @expense_accounts){|r| r.days_ago(@today) < 30}}
|
644
656
|
#\\subsection{Last Year}
|
645
|
-
|
657
|
+
##{expense_pie_charts_by_currency('lastyearexpenses', @expense_accounts){|r| r.days_ago(@today) < 365}}
|
data/treasurer.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: treasurer 0.
|
5
|
+
# stub: treasurer 0.7.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "treasurer".freeze
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.7.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-06"
|
15
15
|
s.description = "A simple command line tool for managing accounts and finances. Easily import internet banking spreadsheets and generate sophisticated reports and projections.".freeze
|
16
16
|
s.email = "edmundhighcock@users.sourceforge.net".freeze
|
17
17
|
s.executables = ["treasurer".freeze]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: treasurer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.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-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|