treasurer 0.6.0 → 0.7.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/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
|