Files
sure/app/controllers/trades_controller.rb
soky srm 6ebe8da928 Add investment tracking to expenses (#381)
* Add investment tracking to expenses

Add new sections to dashboard and reporting around investments.

* Create investment-integration-assessment.md

* Delete .claude/settings.local.json

Signed-off-by: soky srm <sokysrm@gmail.com>

* Category trades

* Simplify

* Simplification and test fixes

* FIX merge

* Update views

* Update 20251125141213_add_category_to_trades.rb

* FIX tests

* FIX statements and account status

* cleanup

* Add default cat for csv imports

* Delete docs/roadmap/investment-integration-assessment.md

Signed-off-by: soky srm <sokysrm@gmail.com>

* Update trend calculation

Use already existing column cost basis for trend calculation
   - Current value: qty * price (already stored as amount)
  - Cost basis total: qty * cost_basis
  - Unrealized gain: current value - cost basis total
Fixes N+1 query also

---------

Signed-off-by: soky srm <sokysrm@gmail.com>
2026-01-09 13:03:40 +01:00

85 lines
2.6 KiB
Ruby

class TradesController < ApplicationController
include EntryableResource
# Defaults to a buy trade
def new
@account = Current.family.accounts.find_by(id: params[:account_id])
@model = Current.family.entries.new(
account: @account,
currency: @account ? @account.currency : Current.family.currency,
entryable: Trade.new
)
end
# Can create a trade, transaction (e.g. "fees"), or transfer (e.g. "withdrawal")
def create
@account = Current.family.accounts.find(params[:account_id])
@model = Trade::CreateForm.new(create_params.merge(account: @account)).create
if @model.persisted?
flash[:notice] = t("entries.create.success")
respond_to do |format|
format.html { redirect_back_or_to account_path(@account) }
format.turbo_stream { stream_redirect_back_or_to account_path(@account) }
end
else
render :new, status: :unprocessable_entity
end
end
def update
if @entry.update(update_entry_params)
@entry.sync_account_later
respond_to do |format|
format.html { redirect_back_or_to account_path(@entry.account), notice: t("entries.update.success") }
format.turbo_stream do
render turbo_stream: [
turbo_stream.replace(
"header_entry_#{@entry.id}",
partial: "trades/header",
locals: { entry: @entry }
),
turbo_stream.replace("entry_#{@entry.id}", partial: "entries/entry", locals: { entry: @entry })
]
end
end
else
render :show, status: :unprocessable_entity
end
end
private
def entry_params
params.require(:entry).permit(
:name, :date, :amount, :currency, :excluded, :notes, :nature,
entryable_attributes: [ :id, :qty, :price, :category_id ]
)
end
def create_params
params.require(:model).permit(
:date, :amount, :currency, :qty, :price, :ticker, :manual_ticker, :type, :transfer_account_id
)
end
def update_entry_params
return entry_params unless entry_params[:entryable_attributes].present?
update_params = entry_params
update_params = update_params.merge(entryable_type: "Trade")
qty = update_params[:entryable_attributes][:qty]
price = update_params[:entryable_attributes][:price]
if qty.present? && price.present?
qty = update_params[:nature] == "inflow" ? -qty.to_d : qty.to_d
update_params[:entryable_attributes][:qty] = qty
update_params[:amount] = qty * price.to_d
end
update_params.except(:nature)
end
end