Class: Cashflow::Report

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Report

Instance methods



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/cashflow/report.rb', line 12

def initialize(options)
  if options
    @options = options

    # Get the start date.
    start_date = get_start_date

    # Retrieve all transactions since the start date,
    # optionally scoped by a given account number.
    transactions = get_transactions(start_date, options[:account])

    # In prior months, discard any transactions past the
    # current day of the month.
    transactions = restrict_by_day_of_month(transactions, Date.today.day)

    # Build a hash to contain the transactions grouped by month.
    by_month = build_hash_by_month

    # Organise the transactions by month and by type.
    by_month = group_transactions_by_month_and_type(by_month, transactions)

    # Sum the debits & credits for each month.
    sums = sum_transactions(by_month)

    # Work out the averages.
    averages = determine_averages(sums)

    # Work out the difference between the current month and prior average.
    diff = compare_current_to_average(sums[:current], averages)

    # Build & expose a summary.
    @summary = {
      start_date: start_date,
      sums:       sums,
      averages:   averages,
      diff:       diff
    }
  end
end

Instance Attribute Details

#summaryObject

Accessors



7
8
9
# File 'lib/cashflow/report.rb', line 7

def summary
  @summary
end

Instance Method Details

#build_hash_by_monthObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/cashflow/report.rb', line 70

def build_hash_by_month
  by_month = { current: { debits: [], credits: [] } }
  today    = Date.today

  @options[:span].times do |n|
    date = today << (n+1)
    key  = "#{date.year}-#{date.month}"
    by_month[key] = { debits: [], credits: [] }
  end

  # {
  #   :current  => { debits: [], credits: [] },
  #   '2013-10' => { debits: [], credits: [] },
  #   '2013-9'  => { debits: [], credits: [] },
  #   '2013-8'  => { debits: [], credits: [] }
  # }

  by_month
end

#compare_current_to_average(current, averages) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/cashflow/report.rb', line 152

def compare_current_to_average(current, averages)
  diffs = {}

  averages.each do |type, average|
    diffs[type] = current[type] - average
  end

  # {
  #   debits: 0,
  #   credits: 0
  # }

  diffs
end

#determine_averages(sums) ⇒ Object



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
# File 'lib/cashflow/report.rb', line 125

def determine_averages(sums)
  averages = { debits: 0, credits: 0 }

  sums.each do |month, by_type|
    unless month == :current
      by_type.each do |type, sum|
        averages[type] += sum
      end
    end
  end

  averages.each do |type, sum|
    begin
      averages[type] = sum / @options[:span]
    rescue ZeroDivisionError
      averages[type] = 0
    end
  end

  # {
  #   debits: -100,
  #   credits: 100
  # }

  averages
end

#get_start_dateObject

Set the initial start date to the first of the month, [n] months ago.



53
54
55
56
# File 'lib/cashflow/report.rb', line 53

def get_start_date
  date = Date.today << (@options[:span])
  Date.new(date.year, date.month, 1)
end

#get_transactions(start_date, account_number = nil) ⇒ Object



58
59
60
61
62
# File 'lib/cashflow/report.rb', line 58

def get_transactions(start_date, =nil)
  transactions = Transaction.where("date >= ?", start_date)
  transactions = transactions.where(account_number: ) if 
  transactions
end

#group_transactions_by_month_and_type(by_month, transactions) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/cashflow/report.rb', line 90

def group_transactions_by_month_and_type(by_month, transactions)
  transactions.each do |transaction|
    this, year, month = Date.today, transaction.date.year, transaction.date.month
    type = "#{transaction.transaction_type}s".to_sym # pluralize by appending "s"
    key  = "#{year}-#{month}"
    key  = :current if year == this.year && month == this.month
    by_month[key][type] << transaction
  end

  by_month
end

Summarise and print the analysis.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/cashflow/report.rb', line 168

def print(cli)
  # Define columns widths.
  cols = "%-11s %-11s %-11s %-11s\n"

  # Intro.
  cli.say("\n")
  cli.say("Using transactions up to and including the #{Date.today.day.ordinalize} of the month")
  cli.say("Transactions begin #{summary[:start_date].strftime('%B')} #{summary[:start_date].day.ordinalize}, #{summary[:start_date].strftime('%Y')}")
  cli.say("\n")

  # Table header.
  printf(cols, "", "Average", "This month", "Difference")

  # Print the debits & credits comparison.
  %i(debits credits).each do |type|
    current   = summary[:sums][:current][type]
    avg       = summary[:averages][type]
    diff      = summary[:diff][type]
    in_or_out = type == :debits ? 'out' : 'in'
    is_good   = diff >= 0
    colour    = is_good ? :green : :red

    # Table row.
    printf(cols, "Money #{in_or_out}:", avg.to_currency, current.to_currency, cli.set_color(diff.to_currency, colour))
  end

  # Calculate net position.
  net_position = summary[:diff][:debits] + summary[:diff][:credits]
  is_good      = net_position >= 0
  colour       = is_good ? :green : :red
  position     = is_good ? 'improvement' : 'decline'

  # Print the net position.
  cli.say("\n")
  cli.say("Comparison: #{cli.set_color(net_position.to_currency(false) + ' ' + position + ' compared to average', colour)}")
  cli.say("\n")
end

#restrict_by_day_of_month(transactions, day_of_month) ⇒ Object



64
65
66
67
68
# File 'lib/cashflow/report.rb', line 64

def restrict_by_day_of_month(transactions, day_of_month)
  transactions.select do |transaction|
    transaction.date.day <= day_of_month
  end
end

#sum_transactions(by_month) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/cashflow/report.rb', line 102

def sum_transactions(by_month)
  sums = {}

  by_month.each do |month, by_type|
    by_type.each do |type, transactions|
      sums[month] ||= {}
      sums[month][type] = transactions.inject(0) do |sum, transaction|
        sum += transaction.amount
        sum
      end
    end
  end

  # {
  #   :current  => { debits: -100, credits: 100 },
  #   '2013-10' => { debits: -100, credits: 100 },
  #   '2013-9'  => { debits: -100, credits: 100 },
  #   '2013-8'  => { debits: -100, credits: 100 }
  # }

  sums
end