1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-18 20:59:39 +02:00

Centralize entry naming (#2454)
Some checks failed
Publish Docker image / ci (push) Has been cancelled
Publish Docker image / Build docker image (push) Has been cancelled

* Centralize entry naming

* Lint fixes, code style
This commit is contained in:
Zach Gollwitzer 2025-07-10 18:40:38 -04:00 committed by GitHub
parent afbfb474c2
commit 9110ab27d2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 187 additions and 16 deletions

View file

@ -64,14 +64,14 @@ class Account < ApplicationRecord
transaction do transaction do
# Create 2 valuations for new accounts to establish a value history for users to see # Create 2 valuations for new accounts to establish a value history for users to see
account.entries.build( account.entries.build(
name: "Current Balance", name: Valuation.build_current_anchor_name(account.accountable_type),
date: Date.current, date: Date.current,
amount: account.balance, amount: account.balance,
currency: account.currency, currency: account.currency,
entryable: Valuation.new entryable: Valuation.new
) )
account.entries.build( account.entries.build(
name: "Initial Balance", name: Valuation.build_opening_anchor_name(account.accountable_type),
date: 1.day.ago.to_date, date: 1.day.ago.to_date,
amount: initial_balance, amount: initial_balance,
currency: account.currency, currency: account.currency,

View file

@ -23,7 +23,7 @@ class Account::BalanceUpdater
valuation_entry.amount = balance valuation_entry.amount = balance
valuation_entry.currency = currency if currency.present? 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.notes = notes if notes.present?
valuation_entry.save! valuation_entry.save!
end end

View file

@ -18,8 +18,8 @@ class AccountImport < Import
account.entries.create!( account.entries.create!(
amount: row.amount, amount: row.amount,
currency: row.currency, currency: row.currency,
date: Date.current, date: 2.years.ago.to_date,
name: "Imported account value", name: Valuation.build_opening_anchor_name(account.accountable_type),
entryable: Valuation.new entryable: Valuation.new
) )
end end

View file

@ -1176,7 +1176,7 @@ class Demo::Generator
@home.entries.create!( @home.entries.create!(
entryable: Valuation.new, entryable: Valuation.new,
amount: 350_000, amount: 350_000,
name: "Current Market Value", name: Valuation.build_current_anchor_name(@home.accountable_type),
currency: "USD", currency: "USD",
date: Date.current date: Date.current
) )
@ -1185,7 +1185,7 @@ class Demo::Generator
@honda_accord.entries.create!( @honda_accord.entries.create!(
entryable: Valuation.new, entryable: Valuation.new,
amount: 18_000, amount: 18_000,
name: "Current Market Value", name: Valuation.build_current_anchor_name(@honda_accord.accountable_type),
currency: "USD", currency: "USD",
date: Date.current date: Date.current
) )
@ -1193,7 +1193,7 @@ class Demo::Generator
@tesla_model3.entries.create!( @tesla_model3.entries.create!(
entryable: Valuation.new, entryable: Valuation.new,
amount: 4_500, amount: 4_500,
name: "Current Market Value", name: Valuation.build_current_anchor_name(@tesla_model3.accountable_type),
currency: "USD", currency: "USD",
date: Date.current date: Date.current
) )
@ -1201,7 +1201,7 @@ class Demo::Generator
@jewelry.entries.create!( @jewelry.entries.create!(
entryable: Valuation.new, entryable: Valuation.new,
amount: 2000, amount: 2000,
name: "Current Market Value", name: Valuation.build_reconciliation_name(@jewelry.accountable_type),
currency: "USD", currency: "USD",
date: 90.days.ago.to_date date: 90.days.ago.to_date
) )
@ -1209,7 +1209,7 @@ class Demo::Generator
@personal_loc.entries.create!( @personal_loc.entries.create!(
entryable: Valuation.new, entryable: Valuation.new,
amount: 800, amount: 800,
name: "Owed", name: Valuation.build_reconciliation_name(@personal_loc.accountable_type),
currency: "USD", currency: "USD",
date: 120.days.ago.to_date date: 120.days.ago.to_date
) )

View file

@ -8,6 +8,13 @@ class Trade < ApplicationRecord
validates :qty, presence: true validates :qty, presence: true
validates :price, :currency, 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 def unrealized_gain_loss
return nil if qty.negative? return nil if qty.negative?
current_price = security.current_price current_price = security.current_price

View file

@ -29,13 +29,11 @@ class Trade::CreateForm
end end
def create_trade 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_qty = type == "sell" ? -qty.to_d : qty.to_d
signed_amount = signed_qty * price.to_d signed_amount = signed_qty * price.to_d
trade_entry = account.entries.new( trade_entry = account.entries.new(
name: trade_name, name: Trade.build_name(type, qty, security.ticker),
date: date, date: date,
amount: signed_amount, amount: signed_amount,
currency: currency, currency: currency,

View file

@ -1,3 +1,23 @@
class Valuation < ApplicationRecord class Valuation < ApplicationRecord
include Entryable 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 end

View file

@ -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

View file

@ -23,7 +23,7 @@ class ValuationsControllerTest < ActionDispatch::IntegrationTest
end end
created_entry = Entry.order(created_at: :desc).first 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 Date.current, created_entry.date
assert_equal account.balance + 100, created_entry.amount_money.to_f assert_equal account.balance + 100, created_entry.amount_money.to_f

23
test/models/trade_test.rb Normal file
View file

@ -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

View file

@ -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

View file

@ -31,7 +31,7 @@ class TradesTest < ApplicationSystemTestCase
visit_trades visit_trades
within_trades do within_trades do
assert_text "Buy #{shares_qty} shares of AAPL" assert_text "Buy #{shares_qty}.0 shares of AAPL"
end end
end end
@ -52,7 +52,7 @@ class TradesTest < ApplicationSystemTestCase
visit_trades visit_trades
within_trades do within_trades do
assert_text "Sell #{qty} shares of AAPL" assert_text "Sell #{qty}.0 shares of AAPL"
end end
end end