2 # This file is part of SMR.
4 # SMR is free software: you can redistribute it and/or modify it under the
5 # terms of the GNU General Public License as published by the Free Software
6 # Foundation, either version 3 of the License, or (at your option) any later
9 # SMR is distributed in the hope that it will be useful, but WITHOUT ANY
10 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along with
14 # SMR. If not, see <http://www.gnu.org/licenses/>.
18 # Log of Cashflows happened up to :date
20 # Cashflow is generated from Order executions and Dividend received.
22 def initialize(start_date, end_date, id_user)
23 raise ':start_date must be of Time' unless start_date.is_a?(Time)
24 raise ':end_date must be of Time' unless end_date.is_a?(Time)
26 @start_date=start_date.to_i; @end_date=end_date.to_i; @id_user=id_user;
36 # loops over SmrCashflowLogItems we have up to date
38 generate_log if not @made_log
43 # tell whether there is something
45 generate_log if not @made_log
50 # list of filters that may be used on us. Also see set_filter().
54 'Dividend' => :dividend,
55 'All Cost Charged' => :charges,
56 'Provisions Charged' => :provision,
57 'Courtage Charged' => :courtage,
58 'Expenses Charged' => :expense,
59 'Ordered Transactions' => :orders,
64 # apply a filter when creating the log, see filters()
65 def set_filter(filter)
66 raise 'filter must be one value from those filters() returns' unless self.filters.has_value?(filter)
71 # cumulated cashflow from all SmrCashflowLogItems
73 generate_log if not @made_log
75 @log.collect{|i| total += i.total }
82 # compose a log of cashflows from orders and dividend received
87 log_orders = Array.new
88 log_dividends = Array.new
90 if [:none, :orders, :charges, :provision, :courtage, :expense].include?(@filter) then
91 # cashflow from transactions
92 orders = Order.select('`order`.*', 'pr.date AS executed')
93 .where(:issued=>(@start_date..@end_date))
95 .joins('LEFT JOIN position_revision pr ON pr.id_order = order.id')
96 .joins('LEFT JOIN position p ON p.id = order.id_position')
97 .joins('LEFT JOIN stock s ON s.id = p.id_stock')
105 tmp << '%.2f Provisions' % o.provision if o.provision > 0
106 tmp << '%.2f Courtage' % o.courtage if o.courtage > 0
107 tmp << '%.2f Expenses' % o.expense if o.expense > 0
109 what = 'payed %s on Order #%i (%s)' % [tmp.join(', '), o.id, o.to_s]
110 total = o.provision + o.courtage + o.expense
113 what = 'payed %.2f Provisions on Order #%i (%s)' % [o.provision, o.id, o.to_s]
117 what = 'payed %.2f Courtage on Order #%i (%s)' % [o.courtage, o.id, o.to_s]
121 what = 'payed %.2f Expenses on Order #%i (%s)' % [o.expense, o.id, o.to_s]
124 else # :orders and :none
125 what = '%s in Order #%i' % [o.to_s, o.id]
126 total = o.shares * o.quote
127 total *= -1 if o.type == 'buy'
130 next if total == 0.0 # skip everything that did not create any cashflow
131 log_orders << SmrCashflowLogItem.new(Time.at(o.executed), what, total, o.comment)
135 if [:none, :dividend].include?(@filter) then
136 # cashflow from dividend received
138 .select(:id, :date, :received, 'stock.name', 'position_revision.shares')
139 .where(:date=>(@start_date..@end_date))
140 .joins(Position: :PositionRevision)
141 .joins(Position: :Portfolio)
142 .joins(Position: :Stock)
143 .where('portfolio.id_user' => @id_user)
144 .where('(position.closed=0 OR position.closed>=dividend.date)')
145 .where('dividend.received * position_revision.shares > 0')
146 .order('dividend.date DESC, position_revision.date DESC')
149 dividends.each do |d|
150 if known[d.id].nil? then
151 log_dividends << SmrCashflowLogItem.new(d.time,
152 'received dividend of %f for %f shares from %s' % [d.received, d.shares, d.name],
153 d.shares * d.received
160 # merge cashflows by date
161 @log = log_orders + log_dividends
162 @log.sort_by!{ |i| i.date}.reverse!
167 # Represents a single item of cashflow.
169 # Cashflow may be generated by an order, a dividend payment or something else.
170 # This class is made handy for presenting data in templates.
171 class SmrCashflowLogItem
172 def initialize(date, what, total, comment='')
173 @date=date; @what=what; @total=total; @comment = comment;