diff --git a/app/models/account.rb b/app/models/account.rb index 43e02cfd..222062b4 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -64,14 +64,14 @@ class Account < ApplicationRecord transaction do # Create 2 valuations for new accounts to establish a value history for users to see account.entries.build( - name: "Current Balance", + name: Valuation.build_current_anchor_name(account.accountable_type), date: Date.current, amount: account.balance, currency: account.currency, entryable: Valuation.new ) account.entries.build( - name: "Initial Balance", + name: Valuation.build_opening_anchor_name(account.accountable_type), date: 1.day.ago.to_date, amount: initial_balance, currency: account.currency, diff --git a/app/models/account/balance_updater.rb b/app/models/account/balance_updater.rb index d006df3f..a8100d9b 100644 --- a/app/models/account/balance_updater.rb +++ b/app/models/account/balance_updater.rb @@ -23,7 +23,7 @@ class Account::BalanceUpdater valuation_entry.amount = balance valuation_entry.currency = currency if currency.present? - valuation_entry.name = "Manual #{account.accountable.balance_display_name} update" + valuation_entry.name = Valuation.build_reconciliation_name(account.accountable_type) valuation_entry.notes = notes if notes.present? valuation_entry.save! end diff --git a/app/models/account_import.rb b/app/models/account_import.rb index aa4c6dfe..4836ce55 100644 --- a/app/models/account_import.rb +++ b/app/models/account_import.rb @@ -18,8 +18,8 @@ class AccountImport < Import account.entries.create!( amount: row.amount, currency: row.currency, - date: Date.current, - name: "Imported account value", + date: 2.years.ago.to_date, + name: Valuation.build_opening_anchor_name(account.accountable_type), entryable: Valuation.new ) end diff --git a/app/models/demo/generator.rb b/app/models/demo/generator.rb index fb64c87d..e12e5b85 100644 --- a/app/models/demo/generator.rb +++ b/app/models/demo/generator.rb @@ -1176,7 +1176,7 @@ class Demo::Generator @home.entries.create!( entryable: Valuation.new, amount: 350_000, - name: "Current Market Value", + name: Valuation.build_current_anchor_name(@home.accountable_type), currency: "USD", date: Date.current ) @@ -1185,7 +1185,7 @@ class Demo::Generator @honda_accord.entries.create!( entryable: Valuation.new, amount: 18_000, - name: "Current Market Value", + name: Valuation.build_current_anchor_name(@honda_accord.accountable_type), currency: "USD", date: Date.current ) @@ -1193,7 +1193,7 @@ class Demo::Generator @tesla_model3.entries.create!( entryable: Valuation.new, amount: 4_500, - name: "Current Market Value", + name: Valuation.build_current_anchor_name(@tesla_model3.accountable_type), currency: "USD", date: Date.current ) @@ -1201,7 +1201,7 @@ class Demo::Generator @jewelry.entries.create!( entryable: Valuation.new, amount: 2000, - name: "Current Market Value", + name: Valuation.build_reconciliation_name(@jewelry.accountable_type), currency: "USD", date: 90.days.ago.to_date ) @@ -1209,7 +1209,7 @@ class Demo::Generator @personal_loc.entries.create!( entryable: Valuation.new, amount: 800, - name: "Owed", + name: Valuation.build_reconciliation_name(@personal_loc.accountable_type), currency: "USD", date: 120.days.ago.to_date ) diff --git a/app/models/trade.rb b/app/models/trade.rb index 5d71d978..f7be4682 100644 --- a/app/models/trade.rb +++ b/app/models/trade.rb @@ -8,6 +8,13 @@ class Trade < ApplicationRecord validates :qty, presence: true validates :price, :currency, presence: true + class << self + def build_name(type, qty, ticker) + prefix = type == "buy" ? "Buy" : "Sell" + "#{prefix} #{qty.to_d.abs} shares of #{ticker}" + end + end + def unrealized_gain_loss return nil if qty.negative? current_price = security.current_price diff --git a/app/models/trade/create_form.rb b/app/models/trade/create_form.rb index 8e761878..ed26d9b6 100644 --- a/app/models/trade/create_form.rb +++ b/app/models/trade/create_form.rb @@ -29,13 +29,11 @@ class Trade::CreateForm end def create_trade - prefix = type == "sell" ? "Sell " : "Buy " - trade_name = prefix + "#{qty.to_i.abs} shares of #{security.ticker}" signed_qty = type == "sell" ? -qty.to_d : qty.to_d signed_amount = signed_qty * price.to_d trade_entry = account.entries.new( - name: trade_name, + name: Trade.build_name(type, qty, security.ticker), date: date, amount: signed_amount, currency: currency, diff --git a/app/models/valuation.rb b/app/models/valuation.rb index 6d1d2b4b..fe3febcc 100644 --- a/app/models/valuation.rb +++ b/app/models/valuation.rb @@ -1,3 +1,23 @@ class Valuation < ApplicationRecord include Entryable + + class << self + def build_reconciliation_name(accountable_type) + Valuation::Name.new("reconciliation", accountable_type).to_s + end + + def build_opening_anchor_name(accountable_type) + Valuation::Name.new("opening_anchor", accountable_type).to_s + end + + def build_current_anchor_name(accountable_type) + Valuation::Name.new("current_anchor", accountable_type).to_s + end + end + + # TODO: Remove this method when `kind` column is added to valuations table + # This is a temporary implementation until the database migration is complete + def kind + "reconciliation" + end end diff --git a/app/models/valuation/name.rb b/app/models/valuation/name.rb new file mode 100644 index 00000000..6b442876 --- /dev/null +++ b/app/models/valuation/name.rb @@ -0,0 +1,57 @@ +class Valuation::Name + def initialize(valuation_kind, accountable_type) + @valuation_kind = valuation_kind + @accountable_type = accountable_type + end + + def to_s + case valuation_kind + when "opening_anchor" + opening_anchor_name + when "current_anchor" + current_anchor_name + else + recon_name + end + end + + private + attr_reader :valuation_kind, :accountable_type + + def opening_anchor_name + case accountable_type + when "Property" + "Original purchase price" + when "Loan" + "Original principal" + when "Investment" + "Opening account value" + else + "Opening balance" + end + end + + def current_anchor_name + case accountable_type + when "Property" + "Current market value" + when "Loan" + "Current loan balance" + when "Investment" + "Current account value" + else + "Current balance" + end + end + + def recon_name + case accountable_type + when "Property", "Investment" + "Manual value update" + when "Loan" + "Manual principal update" + else + "Manual balance update" + end + end +end diff --git a/test/controllers/valuations_controller_test.rb b/test/controllers/valuations_controller_test.rb index d9ee00b3..52c62ad4 100644 --- a/test/controllers/valuations_controller_test.rb +++ b/test/controllers/valuations_controller_test.rb @@ -23,7 +23,7 @@ class ValuationsControllerTest < ActionDispatch::IntegrationTest end created_entry = Entry.order(created_at: :desc).first - assert_equal "Manual account value update", created_entry.name + assert_equal "Manual value update", created_entry.name assert_equal Date.current, created_entry.date assert_equal account.balance + 100, created_entry.amount_money.to_f diff --git a/test/models/trade_test.rb b/test/models/trade_test.rb new file mode 100644 index 00000000..c358a5ba --- /dev/null +++ b/test/models/trade_test.rb @@ -0,0 +1,23 @@ +require "test_helper" + +class TradeTest < ActiveSupport::TestCase + test "build_name generates buy trade name" do + name = Trade.build_name("buy", 10, "AAPL") + assert_equal "Buy 10.0 shares of AAPL", name + end + + test "build_name generates sell trade name" do + name = Trade.build_name("sell", 5, "MSFT") + assert_equal "Sell 5.0 shares of MSFT", name + end + + test "build_name handles absolute value for negative quantities" do + name = Trade.build_name("sell", -5, "GOOGL") + assert_equal "Sell 5.0 shares of GOOGL", name + end + + test "build_name handles decimal quantities" do + name = Trade.build_name("buy", 0.25, "BTC") + assert_equal "Buy 0.25 shares of BTC", name + end +end diff --git a/test/models/valuation/name_test.rb b/test/models/valuation/name_test.rb new file mode 100644 index 00000000..7fa41cca --- /dev/null +++ b/test/models/valuation/name_test.rb @@ -0,0 +1,66 @@ +require "test_helper" + +class Valuation::NameTest < ActiveSupport::TestCase + # Opening anchor tests + test "generates opening anchor name for Property" do + name = Valuation::Name.new("opening_anchor", "Property") + assert_equal "Original purchase price", name.to_s + end + + test "generates opening anchor name for Loan" do + name = Valuation::Name.new("opening_anchor", "Loan") + assert_equal "Original principal", name.to_s + end + + test "generates opening anchor name for Investment" do + name = Valuation::Name.new("opening_anchor", "Investment") + assert_equal "Opening account value", name.to_s + end + + test "generates opening anchor name for other account types" do + name = Valuation::Name.new("opening_anchor", "Depository") + assert_equal "Opening balance", name.to_s + end + + # Current anchor tests + test "generates current anchor name for Property" do + name = Valuation::Name.new("current_anchor", "Property") + assert_equal "Current market value", name.to_s + end + + test "generates current anchor name for Loan" do + name = Valuation::Name.new("current_anchor", "Loan") + assert_equal "Current loan balance", name.to_s + end + + test "generates current anchor name for Investment" do + name = Valuation::Name.new("current_anchor", "Investment") + assert_equal "Current account value", name.to_s + end + + test "generates current anchor name for other account types" do + name = Valuation::Name.new("current_anchor", "Depository") + assert_equal "Current balance", name.to_s + end + + # Reconciliation tests + test "generates recon name for Property" do + name = Valuation::Name.new("reconciliation", "Property") + assert_equal "Manual value update", name.to_s + end + + test "generates recon name for Investment" do + name = Valuation::Name.new("reconciliation", "Investment") + assert_equal "Manual value update", name.to_s + end + + test "generates recon name for Loan" do + name = Valuation::Name.new("reconciliation", "Loan") + assert_equal "Manual principal update", name.to_s + end + + test "generates recon name for other account types" do + name = Valuation::Name.new("reconciliation", "Depository") + assert_equal "Manual balance update", name.to_s + end +end diff --git a/test/system/trades_test.rb b/test/system/trades_test.rb index 21435a2b..7d0183c3 100644 --- a/test/system/trades_test.rb +++ b/test/system/trades_test.rb @@ -31,7 +31,7 @@ class TradesTest < ApplicationSystemTestCase visit_trades within_trades do - assert_text "Buy #{shares_qty} shares of AAPL" + assert_text "Buy #{shares_qty}.0 shares of AAPL" end end @@ -52,7 +52,7 @@ class TradesTest < ApplicationSystemTestCase visit_trades within_trades do - assert_text "Sell #{qty} shares of AAPL" + assert_text "Sell #{qty}.0 shares of AAPL" end end