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/>.
16 require 'uploaded_file'
19 # Controller for AssetPosition
21 # This also cares about orders and other things since an AssetPosition
22 # is more than just the Position model.
23 class PositionController < ApplicationController
26 # Show details about a AssetPosition.
28 @position = Smr::AssetPosition.new(params[:id].to_i, current_user.id, smr_browse_date)
29 redirect_to root_path if @position.is_cash_position?
31 if @position.is_new? then
32 smr_menu_addsubitem('assets', {
33 '+ order'=>new_position_path + '?id_position=%i'%params[:id],
34 '- sell off'=>'/close?id=%i' % params[:id]
36 elsif not @position.is_closed?
37 smr_menu_addsubitem('assets', {
38 '+ order'=>new_position_path + '?id_position=%i' % params[:id],
39 '+ dividend'=>position_path + '?add_dividend=true',
40 '- sell off'=>'/close?id=%i' % params[:id],
41 '+ document'=>position_path + '?add_document=true',
43 elsif @position.is_closed? and @position.time_closed > 1.month.ago
44 smr_menu_addsubitem('assets', {
45 '+ dividend'=>position_path + '?add_dividend=true'
50 @documents, @total_pages = smr_paginate(
52 Smr::UploadedFiles.new(current_user.id, :id_position=>@position.id, :date=>smr_browse_date)
55 if params[:add_dividend] then
56 @dividend = Dividend.new(:date_exdate=>smr_browse_date - 2.days, :id_position=>@position.id)
61 # conditionally make a new position
63 # Most of the time this will not create a new position but rather add an
64 # order to an existing position. It can perform one of these things
67 # 1) make a new order on existing position
68 # 2) make new position in given portfolio with new order
69 # 3) make new position in selectable portfolio holding selectable security
72 # make new order on selected existing position
74 # In any case the +session+ is checked for :position_prefilled_order which
75 # will be used as basis for the new order, if present.
77 if session[:position_prefilled_order] and session[:position_prefilled_order].is_a?(Order) then
78 @order = session[:position_prefilled_order]
80 @order = Order.new(:time_issued=>smr_browse_date, :time_expire=>(smr_browse_date+1.month).end_of_day)
83 if params[:id_position] then
85 @position = Smr::AssetPosition.new(params[:id_position], current_user.id, smr_browse_date)
86 elsif params[:id_portfolio] then
88 @portfolio = Portfolio.find_by_id(params[:id_portfolio])
89 @securities = Security.where.not(:id=>Smr::ID_CASH_SECURITY).all.to_a
92 @portfolios = Portfolio.select(:id, :name).where(:id_user=>current_user.id).order(order: :desc)
93 @open_positions = Smr::Asset.new(current_user.id, smr_browse_date, :skip_cash_positions=>true).open_positions
94 @securities = Security.where.not(:id=>Smr::ID_CASH_SECURITY).all.to_a
99 # creates an position/order by taking POST
101 # FIXME: Gummicode! Test carefully, ie issue on closed position?
105 order = Order.new(order_params)
106 order.time_issued = Time.parse params[:time_issued]
107 order.time_expire = Time.parse params[:time_expire]
109 if not params[:id_position].empty? then
111 order.id_position = params[:id_position].to_i
112 redirect = position_path(order.id_position)
113 elsif params[:id_portfolio].empty? or params[:id_security].empty? then
114 redirect_to :back, :notice=>'Please select some Security and Portfolio or use an existing Position to order.'
118 position = Position.new(
119 :id_portfolio=>params[:id_portfolio].to_i,
120 :id_security=>params[:id_security].to_i,
125 order.id_position=position.id
127 redirect = position_path(position.id)
133 if params[:execute_now].to_i == 1 and params[:execute_quote].to_f > 0.0 then
134 execute_time = Time.parse(params[:execute_time])
135 t = Smr::Transaction.new(
136 Position.find(order.id_position),
138 :issue_time=>order.time_issued,
139 :order=>order, :order_is_redemption=>(params[:is_redemption] || false)
141 t.execute(params[:execute_quote].to_f, execute_time)
144 if params[:close_position].to_i == 1 then
145 stat = Smr::AssetPosition.new(order.id_position, current_user.id, smr_browse_date)
147 n += ' Closed position because all shares were sold.' if stat.is_a?(TrueClass)
150 n = 'Issued new Order to %s %f shares.' % [order.type, order.shares]
154 if params[:order][:document] then
155 doc = Smr::UploadedFile.store(current_user.id, params[:order][:document])
156 doc.assign(:order=>order.id)
159 redirect_to redirect, :notice=>n
163 # update Position details
164 # - that is things that wont change the positions` status
166 if params[:id] and params[:comment]
167 p = Position.find(params[:id])
168 p.comment = params[:comment]
175 # close this position at smr_browse_date
177 p = Smr::AssetPosition.new(params[:id].to_i, current_user.id, smr_browse_date)
178 stat = p.close(smr_browse_date)
179 if stat.is_a?(TrueClass) then
180 n='Closed position #%i as of %s.' % [p.id, p.time_closed]
182 elsif stat.is_a?(Order) then
183 session[:position_prefilled_order] = stat
184 n='Position holds shares. Can not close it right away. A new '\
185 +'order to sell them off has been pre-filled, please edit and '\
187 r=new_position_path + '?id_position=%i' % p.id
189 n='Can not close position #%i because it is closed already.' % p.id
192 redirect_to r, :notice=>n
202 # apply Order to Position at #smr_browse_date
204 execute_time = Time.parse(params[:execute_time])
205 p = Smr::AssetPosition.new(params[:id], current_user.id, smr_browse_date)
206 t = Smr::Transaction.new(p, current_user, :issue_time=>execute_time, :order=>Order.find(params[:id_order]))
207 t.execute(params[:execute_quote].to_f, execute_time)
209 # try to close the position, it may remain open unless empty
211 Smr::AssetPosition.new(params[:id], current_user.id, execute_time+1.second).close
214 redirect_to :back, :notice=>t.to_s
218 # cancel pending order by setting the canceled flag
220 o = Order.find_by_id(params[:id_order])
223 redirect_to :back, :notice=>'Order #%i has been canceled' % o.id
229 # internal helper defining which parameters to accept for an order
231 params.require(:order).permit(
232 :exchange, :shares, :limit, :addon, :provision, :courtage, :type,
233 :comment, :expense, :accrued_interest, :time_issued, :time_expire