Class: QuickPep

Inherits:
Object
  • Object
show all
Defined in:
lib/quickpep.rb

Overview

Quick Personal Expenses Planner - for people too lazy to use a

spreadsheet or sfinance app

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(s, balance: 0, currency: '', today: Date.today, ignorewarnings: false, debug: false) ⇒ QuickPep

Returns a new instance of QuickPep.



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/quickpep.rb', line 16

def initialize(s, balance: 0, currency: '', today: Date.today,
               ignorewarnings: false, debug: false)

  @balance, @currency, @debug = balance, currency, debug
  @today = today
  @warnings = []
  @to_s = calc_expenses(s)

  warnings() if @warnings.any? and not ignorewarnings

end

Instance Attribute Details

#inputObject (readonly)

Returns the value of attribute input.



14
15
16
# File 'lib/quickpep.rb', line 14

def input
  @input
end

#to_dxObject (readonly)

Returns the value of attribute to_dx.



14
15
16
# File 'lib/quickpep.rb', line 14

def to_dx
  @to_dx
end

#to_sObject (readonly)

Returns the value of attribute to_s.



14
15
16
# File 'lib/quickpep.rb', line 14

def to_s
  @to_s
end

Instance Method Details

#annual_costs(perx = :year, per: perx) ⇒ Object

options: year, month, weel, day



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/quickpep.rb', line 30

def annual_costs(perx=:year, per: perx)

  rows = @date_events.map do |date, title|

    amount = @h[title].amount

    prefix = amount[0] == '+' ? '' : '-'
    amountx = (prefix + amount.gsub(/\D/,'')).to_f

    [date, title, amountx]

  end

  a = rows.group_by {|date,title, amount| title }\
      .map {|key, rows| [key, rows.map(&:last).sum]}.sort_by(&:last)

  a.map do |title, total|

    amount = case per.to_sym
    when :year
      total
    when :month
      total / (12 - @today.month)
    when :week
      total / (52 - @today.cweek )
    when :day
      total / (365 - @today.yday)
    end

    [title, amount.round(2)]
  end

end

#breakdownObject

Each expense annually as a percentage of total expenses



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/quickpep.rb', line 66

def breakdown()

  tot = total_expenses().abs
  r = annual_costs()
  a = r.select {| _, cost | cost < 0 }\
      .map {|title, cost| [title, (100 / (tot / cost.abs)).round] }

  def a.to_table()
    TableFormatter.new(source: self,
                      labels: %w(Item %:), markdown: true).display
  end

  return a
end

#costs_summaryObject



81
82
83
84
85
86
87
88
89
# File 'lib/quickpep.rb', line 81

def costs_summary()

  a = %i(year month day).map {|x| annual_costs x}.transpose\
      .map do |x|
    [x.first.first, *x.map {|y| "%s%0.2f" % [@currency, y.last.abs]}]
  end
  TableFormatter.new(source: a, labels: %w(Title Year: Month: Day:),
                     markdown: true).display
end

#to_html(titlex = "Personal Budget #{@today.year}", title: titlex) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/quickpep.rb', line 91

def to_html(titlex="Personal Budget #{@today.year}", title: titlex)

  dx = to_dx()
  t = dx.to_table
  t.labels =  %w(date: title debit: credit: balance: uid:)
  table = t.display markdown: true

  tot = total_expenses().abs
  costs_per_interval = "
* daily: #{"%s%0.2f" % [@currency, (tot / 365.0)]}
* weekly: #{"%s%0.2f" % [@currency, (tot / 52.0)]}
* monthly: #{"%s%0.2f" % [@currency, (tot / 12.0)]}
* yearly: #{@currency + tot.to_s}
"

  t2 = @input.to_table
  t2.labels = %w(Title Amount: :Day: :Recurring: :Notes:)
  table2 = t2.display markdown: true

  "<html>
    <head>
      <meta name='viewport' content='width=device-width, initial-scale=1'>
      <title>#{title}</title>
      <style>
        table {border-collapse: collapse; width: 700px}
        tr:nth-child(even) {
          background-color: #aca;
        }
        @media print {

          tr:nth-child(even) {
            background-color: #ccc;
          }

        }
        table tr td, table thead th {padding: 0.3em; margin: 0.1em}
        #input table {border: 4px;  background-color: #d3a;}
        #input table thead {color: #131;}
        #input table tr, #input table td {border: 1px solid green; padding: 3px;  background-color: #dea;}
        #input table tr td {
          text-align: center;
        }
        #summary div {background-color: transparent; float: left; margin: 0.3em; padding: 1.2em; border: 1px solid #18e}

        #breakdown table {background-color: transparent; width: 190px}
        #breakdown table tr {background-color: transparent;}
        #costsum table {background-color: transparent; width: 400px}
        #costsum table tr {background-color: transparent; border-bottom: 1px solid #888;}
        #costsum table tr td {background-color: transparent; padding: 1.0em 0.5em; margin: 0.4em 0.2em}
        #summary div ul  {list-style-type: none; background-color: transparent; padding: 0.5em; }
        .break {page-break-before: always}
        #input {clear: both;}
        footer {font-size: 0.8em; color: #888;}
      </style>

    </head>
    <body>
      <h1>#{title}</h1>
      #{RDiscount.new(table).to_html}
      <div id='summary'>
        <h2>Summary</h2>

        <div id='breakdown'>
        <h3>Breakdown</h3>
        #{RDiscount.new(breakdown().to_table()).to_html}
        </div>

        <div id='costsum'>
        <h3>Expense per item</h3>
        #{RDiscount.new(costs_summary()).to_html}
        </div>
        <div>
        <h3>Running expense</h3>

        #{RDiscount.new(costs_per_interval).to_html}
        </div>
      </div>
      <div id='input'>
        <h3>Input</h3>

        #{RDiscount.new(table2).to_html}
      </div>
      <hr/>
      <footer>Generated by QuickPEP; #{Time.now.strftime("%d %b %Y")}</footer>
    </body>
  </html>"
end

#total_expensesObject



179
180
181
# File 'lib/quickpep.rb', line 179

def total_expenses()
  to_dx().all.map {|x| x.debit.sub(/\D/,'').to_f}.sum
end

#warningsObject



183
184
185
# File 'lib/quickpep.rb', line 183

def warnings()
  @warnings.each {|warning| puts warning.warn }
end

#year_end_balanceObject



187
188
189
# File 'lib/quickpep.rb', line 187

def year_end_balance()
  to_dx().all.last.balance.sub(/[^-0-9]+/,'').to_f
end