+
<% @top_spenders.first(3).each do |account| %>
<%= link_to account, class: "border border-alpha-black-25 rounded-full p-1 pr-2 flex items-center gap-1 text-xs text-gray-900 font-medium hover:bg-gray-25", data: { controller: "tooltip" } do %>
- <%= image_tag account_logo_url(account), class: "w-5 h-5" %>
+ <%= render "accounts/logo", account: account, size: "sm" %>
-<%= Money.new(account.spending, account.currency) %>
- <%= render partial: "shared/text_tooltip", locals: { tooltip_text: account.name } %>
+ <%= render partial: "shared/text_tooltip", locals: { tooltip_text: account.name } %>
<% end %>
<% end %>
<% if @top_spenders.count > 3 %>
@@ -141,9 +141,9 @@
<% @top_savers.first(3).each do |account| %>
<% unless account.savings_rate.infinite? %>
<%= link_to account, class: "border border-alpha-black-25 rounded-full p-1 pr-2 flex items-center gap-1 text-xs text-gray-900 font-medium hover:bg-gray-25", data: { controller: "tooltip" } do %>
- <%= image_tag account_logo_url(account), class: "w-5 h-5" %>
+ <%= render "accounts/logo", account: account, size: "sm" %>
<%= account.savings_rate > 0 ? "+" : "-" %><%= number_to_percentage(account.savings_rate.abs * 100, precision: 2) %>
- <%= render partial: "shared/text_tooltip", locals: { tooltip_text: account.name } %>
+ <%= render partial: "shared/text_tooltip", locals: { tooltip_text: account.name } %>
<% end %>
<% end %>
<% end %>
diff --git a/app/views/shared/_circle_logo.html.erb b/app/views/shared/_circle_logo.html.erb
index 328cb476..17f1948a 100644
--- a/app/views/shared/_circle_logo.html.erb
+++ b/app/views/shared/_circle_logo.html.erb
@@ -2,7 +2,7 @@
<% size_classes = {
"sm" => "w-6 h-6",
- "md" => "w-8 h-8",
+ "md" => "w-9 h-9",
"lg" => "w-10 h-10",
"full" => "w-full h-full"
} %>
diff --git a/app/views/shared/_no_account_empty_state.html.erb b/app/views/shared/_no_account_empty_state.html.erb
index cfb79003..b4eda597 100644
--- a/app/views/shared/_no_account_empty_state.html.erb
+++ b/app/views/shared/_no_account_empty_state.html.erb
@@ -7,7 +7,7 @@
<%= t(".no_account_subtitle") %>
- <%= link_to new_account_path, class: "btn btn--primary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
+ <%= link_to new_account_path(step: "method"), class: "btn btn--primary flex items-center gap-1", data: { turbo_frame: "modal" } do %>
<%= lucide_icon("plus", class: "w-5 h-5") %>
<%= t(".new_account") %>
<% end %>
diff --git a/config/brakeman.ignore b/config/brakeman.ignore
index 71a47b67..78648c48 100644
--- a/config/brakeman.ignore
+++ b/config/brakeman.ignore
@@ -23,6 +23,74 @@
],
"note": ""
},
+ {
+ "warning_type": "Dynamic Render Path",
+ "warning_code": 15,
+ "fingerprint": "42595161ffdc9ce9a10c4ba2a75fd2bb668e273bc4e683880b0ea906d0bd28f8",
+ "check_name": "Render",
+ "message": "Render path contains parameter value",
+ "file": "app/views/accounts/show.html.erb",
+ "line": 8,
+ "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
+ "code": "render(action => permitted_accountable_partial(Current.family.accounts.find(params[:id]), \"header\"), { :account => Current.family.accounts.find(params[:id]) })",
+ "render_path": [
+ {
+ "type": "controller",
+ "class": "AccountsController",
+ "method": "show",
+ "line": 39,
+ "file": "app/controllers/accounts_controller.rb",
+ "rendered": {
+ "name": "accounts/show",
+ "file": "app/views/accounts/show.html.erb"
+ }
+ }
+ ],
+ "location": {
+ "type": "template",
+ "template": "accounts/show"
+ },
+ "user_input": "params[:id]",
+ "confidence": "Weak",
+ "cwe_id": [
+ 22
+ ],
+ "note": ""
+ },
+ {
+ "warning_type": "Dynamic Render Path",
+ "warning_code": 15,
+ "fingerprint": "a35b18785608dbdf35607501363573576ed8c304039f8387997acd1408ca1025",
+ "check_name": "Render",
+ "message": "Render path contains parameter value",
+ "file": "app/views/accounts/show.html.erb",
+ "line": 35,
+ "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
+ "code": "render(action => permitted_accountable_partial(Current.family.accounts.find(params[:id]), \"tooltip\"), { :account => Current.family.accounts.find(params[:id]) })",
+ "render_path": [
+ {
+ "type": "controller",
+ "class": "AccountsController",
+ "method": "show",
+ "line": 39,
+ "file": "app/controllers/accounts_controller.rb",
+ "rendered": {
+ "name": "accounts/show",
+ "file": "app/views/accounts/show.html.erb"
+ }
+ }
+ ],
+ "location": {
+ "type": "template",
+ "template": "accounts/show"
+ },
+ "user_input": "params[:id]",
+ "confidence": "Weak",
+ "cwe_id": [
+ 22
+ ],
+ "note": ""
+ },
{
"warning_type": "Cross-Site Scripting",
"warning_code": 2,
@@ -38,7 +106,7 @@
"type": "controller",
"class": "PagesController",
"method": "changelog",
- "line": 35,
+ "line": 36,
"file": "app/controllers/pages_controller.rb",
"rendered": {
"name": "pages/changelog",
@@ -60,19 +128,19 @@
{
"warning_type": "Dynamic Render Path",
"warning_code": 15,
- "fingerprint": "b7a59d6dd91f4d30873b271659636c7975e25b47f436b4f03900a08809af2e92",
+ "fingerprint": "c5c512a13c34c9696024bd4e2367a657a5c140b5b6a0f5c352e9b69965f63e1b",
"check_name": "Render",
"message": "Render path contains parameter value",
"file": "app/views/accounts/show.html.erb",
- "line": 105,
+ "line": 63,
"link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
- "code": "render(action => selected_account_tab(Current.family.accounts.find(params[:id]))[:partial_path], { :account => Current.family.accounts.find(params[:id]) })",
+ "code": "render(action => permitted_accountable_partial(Current.family.accounts.find(params[:id]), \"tabs\"), { :account => Current.family.accounts.find(params[:id]), :selected_tab => params[:tab] })",
"render_path": [
{
"type": "controller",
"class": "AccountsController",
"method": "show",
- "line": 38,
+ "line": 39,
"file": "app/controllers/accounts_controller.rb",
"rendered": {
"name": "accounts/show",
@@ -98,7 +166,7 @@
"check_name": "Render",
"message": "Render path contains parameter value",
"file": "app/views/import/configurations/show.html.erb",
- "line": 13,
+ "line": 15,
"link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/",
"code": "render(partial => permitted_import_configuration_path(Current.family.imports.find(params[:import_id])), { :locals => ({ :import => Current.family.imports.find(params[:import_id]) }) })",
"render_path": [
@@ -126,6 +194,6 @@
"note": ""
}
],
- "updated": "2024-09-28 13:27:09 -0400",
+ "updated": "2024-10-17 11:30:15 -0400",
"brakeman_version": "6.2.1"
}
diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml
index cb6668ef..0e12a0f5 100644
--- a/config/locales/views/accounts/en.yml
+++ b/config/locales/views/accounts/en.yml
@@ -1,37 +1,88 @@
---
en:
accounts:
+ sync_all_button:
+ sync: Sync all
account:
has_issues: Issue detected.
troubleshoot: Troubleshoot
+ account_list:
+ new_account: "New %{type}"
+ empty:
+ no_accounts: No accounts yet
+ empty_message: Add an account either via connection, importing or entering manually.
+ new_account: New account
+ form:
+ name_label: Account name
+ name_placeholder: Example account name
+ institution: Financial institution
+ ungrouped: "(none)"
+ balance: Today's balance
+ accountable_type: Account type
+ type_prompt: Select a type
+ header:
+ accounts: Accounts
+ manage: Manage accounts
+ new: New account
+ institution_accounts:
+ add_account_to_institution: Add new account
+ has_issues: Issue detected, see accounts
+ syncing: Syncing...
+ status: "Last synced %{last_synced_at} ago"
+ status_never: Requires data sync
+ edit: Edit institution
+ delete: Delete institution
+ confirm_title: Delete financial institution?
+ confirm_body: Don't worry, none of the accounts within this institution will be affected by this deletion. Accounts will be ungrouped and all historical data will remain intact.
+ confirm_accept: Delete institution
+ new_account: Add account
+ institutionless_accounts:
+ other_accounts: Other accounts
+ menu:
+ edit: Edit
+ import: Import transactions
+ confirm_title: Delete account?
+ confirm_body_html: "
By deleting this account, you will erase its value history, affecting various aspects of your overall account. This action will have a direct impact on your net worth calculations and the account graphs.
After deletion, there is no way you'll be able to restore the account information because you'll need to add it as a new account.
"
+ confirm_accept: 'Delete "%{name}"'
accountables:
- investment:
- prompt: Select a subtype
- none: None
credit_card:
- annual_fee: Annual fee
- annual_fee_placeholder: '99'
- apr: APR
- apr_placeholder: '15.99'
- available_credit: Available credit
- available_credit_placeholder: '10000'
- expiration_date: Expiration date
- minimum_payment: Minimum payment
- minimum_payment_placeholder: '100'
+ form:
+ available_credit: Available credit
+ available_credit_placeholder: '10000'
+ minimum_payment: Minimum payment
+ minimum_payment_placeholder: '100'
+ apr: APR
+ apr_placeholder: '15.99'
+ expiration_date: Expiration date
+ annual_fee: Annual fee
+ annual_fee_placeholder: '99'
overview:
amount_owed: Amount Owed
- annual_fee: Annual Fee
- apr: APR
available_credit: Available Credit
- expiration_date: Expiration Date
minimum_payment: Minimum Payment
+ apr: APR
+ expiration_date: Expiration Date
+ annual_fee: Annual Fee
unknown: Unknown
depository:
- prompt: Select a subtype
- none: None
+ form:
+ none: None
+ prompt: Select a subtype
+ investment:
+ form:
+ none: None
+ prompt: Select a subtype
+ tooltip:
+ cash: Cash
+ holdings: Holdings
+ total_value_tooltip: The total value is the sum of cash balance and your holdings value, minus margin loans.
loan:
- interest_rate: Interest rate
- interest_rate_placeholder: '5.25'
+ form:
+ interest_rate: Interest rate
+ interest_rate_placeholder: '5.25'
+ rate_type: Rate type
+ term_months: Term (months)
+ term_months_placeholder: '360'
overview:
interest_rate: Interest Rate
monthly_payment: Monthly Payment
@@ -41,18 +92,19 @@ en:
term: Term
type: Type
unknown: Unknown
- rate_type: Rate type
- term_months: Term (months)
- term_months_placeholder: '360'
property:
- additional_info: Additional info
- area_unit: Area unit
- area_value: Area value
- city: City
- country: Country
- line1: Address line 1
- line2: Address line 2
- optional: optional
+ form:
+ additional_info: Additional info
+ area_unit: Area unit
+ area_value: Area value
+ city: City
+ country: Country
+ line1: Address line 1
+ line2: Address line 2
+ optional: optional
+ postal_code: Postal code
+ state: State
+ year_built: Year built
overview:
living_area: Living Area
market_value: Market Value
@@ -60,17 +112,17 @@ en:
trend: Trend
unknown: Unknown
year_built: Year Built
- postal_code: Postal code
- state: State
- year_built: Year built
vehicle:
- make: Make
- make_placeholder: Toyota
- mileage: Mileage
- mileage_placeholder: '15000'
- mileage_unit: Unit
- model: Model
- model_placeholder: Camry
+ form:
+ make: Make
+ make_placeholder: Toyota
+ mileage: Mileage
+ mileage_placeholder: '15000'
+ mileage_unit: Unit
+ model: Model
+ model_placeholder: Camry
+ year: Year
+ year_placeholder: '2023'
overview:
current_price: Current Price
make_model: Make & Model
@@ -79,70 +131,22 @@ en:
trend: Trend
unknown: Unknown
year: Year
- year: Year
- year_placeholder: '2023'
- create:
- success: New account created successfully
- destroy:
- success: Account deleted successfully
edit:
- edit: Edit %{account}
- empty:
- empty_message: Add an account either via connection, importing or entering manually.
- new_account: New account
- no_accounts: No accounts yet
- form:
- institution: Financial institution
- ungrouped: "(none)"
- balance: Current balance
- name_label: Account name
- name_placeholder: Example account name
- start_balance: Start balance (optional)
- start_date: Start date (optional)
- header:
- accounts: Accounts
- manage: Manage accounts
- new: New account
+ edit: "Edit %{account}"
index:
accounts: Accounts
add_institution: Add institution
new_account: New account
- institution_accounts:
- add_account_to_institution: Add new account
- confirm_accept: Delete institution
- confirm_body: Don't worry, none of the accounts within this institution will
- be affected by this deletion. Accounts will be ungrouped and all historical
- data will remain intact.
- confirm_title: Delete financial institution?
- delete: Delete institution
- edit: Edit institution
- has_issues: Issue detected, see accounts
- new_account: Add account
- status: Last synced %{last_synced_at} ago
- status_never: Requires data sync
- syncing: Syncing...
- institutionless_accounts:
- other_accounts: Other accounts
new:
- select_accountable_type: What would you like to add?
title: Add an account
+ manual_entry: Enter account manually
+ csv_entry: Import accounts CSV
+ connected_entry: Securely link account with Plaid (coming soon)
show:
cash: Cash
- confirm_accept: Delete "%{name}"
- confirm_body_html: "
By deleting this account, you will erase its value history,
- affecting various aspects of your overall account. This action will have a
- direct impact on your net worth calculations and the account graphs.
After deletion, there is no way you'll be able to restore the account
- information because you'll need to add it as a new account.
"
- confirm_title: Delete account?
- edit: Edit
holdings: Holdings
- import: Import transactions
no_change: No change
overview: Overview
- sync_message_missing_rates: Since exchange rates haven't been synced, balance
- graphs may not reflect accurate values.
- sync_message_unknown_error: An error has occurred during the sync.
total_owed: Total Owed
total_value: Total Value
trades: Transactions
@@ -151,21 +155,17 @@ en:
summary:
new: New
no_assets: No assets found
- no_assets_description: Add an asset either via connection, importing or entering
- manually.
+ no_assets_description: Add an asset either via connection, importing or entering manually.
no_liabilities: No liabilities found
- no_liabilities_description: Add a liability either via connection, importing
- or entering manually.
- sync_all:
- button_text: Sync all
- success: Successfully queued accounts for syncing.
- tooltip:
- cash: Cash
- holdings: Holdings
- total_value_tooltip: The total value is the sum of cash balance and your holdings
- value, minus margin loans.
+ no_liabilities_description: Add a liability either via connection, importing or entering manually.
+ create:
+ success: New account created successfully
+ destroy:
+ success: Account deleted successfully
update:
success: Account updated
+ sync_all:
+ success: Successfully queued accounts for syncing.
credit_cards:
create:
success: Credit card created successfully
diff --git a/config/locales/views/imports/en.yml b/config/locales/views/imports/en.yml
index 7227a9f2..e5fd7920 100644
--- a/config/locales/views/imports/en.yml
+++ b/config/locales/views/imports/en.yml
@@ -69,7 +69,7 @@ en:
import_mint: Import from Mint
import_portfolio: Import investments
import_transactions: Import transactions
- resume: Resume latest import
+ resume: Resume %{type}
sources: Sources
title: New CSV Import
ready:
diff --git a/config/routes.rb b/config/routes.rb
index 2cfa2b2d..079943a7 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -61,8 +61,6 @@ Rails.application.routes.draw do
end
scope module: :account do
- resource :logo, only: :show
-
resources :holdings, only: %i[index new show destroy]
resources :cashes, only: :index
diff --git a/test/helpers/application_helper_test.rb b/test/helpers/application_helper_test.rb
index d4c1be45..e4c3bf36 100644
--- a/test/helpers/application_helper_test.rb
+++ b/test/helpers/application_helper_test.rb
@@ -11,12 +11,6 @@ class ApplicationHelperTest < ActionView::TestCase
assert_equal "Test Header Title", content_for(:header_title)
end
- test "#permitted_accountable_partial(accountable_type)" do
- assert_equal "account", permitted_accountable_partial("Account")
- assert_equal "user", permitted_accountable_partial("User")
- assert_equal "admin_user", permitted_accountable_partial("AdminUser")
- end
-
def setup
@account1 = Account.new(currency: "USD", balance: 1)
@account2 = Account.new(currency: "USD", balance: 2)
diff --git a/test/models/account/balance/syncer_test.rb b/test/models/account/balance/syncer_test.rb
index 9bfeffcb..748b3e6a 100644
--- a/test/models/account/balance/syncer_test.rb
+++ b/test/models/account/balance/syncer_test.rb
@@ -35,15 +35,6 @@ class Account::Balance::SyncerTest < ActiveSupport::TestCase
assert_equal [ 19600, 19500, 19500, 20000, 20000, 20000 ], @account.balances.chronological.map(&:balance)
end
- test "syncs account with trades only" do
- aapl = securities(:aapl)
- create_trade(aapl, account: @investment_account, date: 1.day.ago.to_date, qty: 10)
-
- run_sync_for @investment_account
-
- assert_equal [ 52140, 50000, 50000 ], @investment_account.balances.chronological.map(&:balance)
- end
-
test "syncs account with valuations and transactions" do
create_valuation(account: @account, date: 5.days.ago.to_date, amount: 20000)
create_transaction(account: @account, date: 3.days.ago.to_date, amount: -500)
diff --git a/test/system/.keep b/test/system/.keep
deleted file mode 100644
index e69de29b..00000000
diff --git a/test/system/accounts_test.rb b/test/system/accounts_test.rb
index 1b7248c0..97f3fd91 100644
--- a/test/system/accounts_test.rb
+++ b/test/system/accounts_test.rb
@@ -80,19 +80,15 @@ class AccountsTest < ApplicationSystemTestCase
end
def assert_account_created(accountable_type, &block)
- click_link humanized_accountable(accountable_type)
- click_link "Enter account balance manually"
+ click_link "Enter account manually"
account_name = "[system test] #{accountable_type} Account"
+ select accountable_type.titleize, from: "Account type"
fill_in "Account name", with: account_name
fill_in "account[balance]", with: 100.99
- fill_in "Start date (optional)", with: 10.days.ago.to_date
- fill_in "account[start_balance]", with: 95.25
- yield if block_given?
-
- click_button "Add #{humanized_accountable(accountable_type).downcase}"
+ click_button "Create Account"
find("details", text: humanized_accountable(accountable_type)).click
assert_text account_name
@@ -107,8 +103,10 @@ class AccountsTest < ApplicationSystemTestCase
click_on "Edit"
end
+ yield if block_given?
+
fill_in "Account name", with: "Updated account name"
- click_button "Update #{humanized_accountable(accountable_type).downcase}"
+ click_button "Update Account"
assert_selector "h2", text: "Updated account name"
end
diff --git a/test/system/tooltips_test.rb b/test/system/tooltips_test.rb
deleted file mode 100644
index 7666269c..00000000
--- a/test/system/tooltips_test.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require "application_system_test_case"
-
-class TooltipsTest < ApplicationSystemTestCase
- include ActionView::Helpers::NumberHelper
- include ApplicationHelper
-
- setup do
- sign_in @user = users(:family_admin)
- @account = accounts(:investment)
- end
-
- test "can see account information tooltip" do
- visit account_path(@account)
- tooltip_element = find('[data-controller="tooltip"]')
- tooltip_element.hover
- tooltip_contents = find('[data-tooltip-target="tooltip"]')
- assert tooltip_contents.visible?
- within tooltip_contents do
- assert_text I18n.t("accounts.tooltip.total_value_tooltip")
- assert_text I18n.t("accounts.tooltip.holdings")
- assert_text format_money(@account.investment.holdings_value, precision: 0)
- assert_text I18n.t("accounts.tooltip.cash")
- assert_text format_money(@account.balance_money, precision: 0)
- end
- find("body").click
- assert find('[data-tooltip-target="tooltip"]', visible: false)
- end
-end
diff --git a/test/system/trades_test.rb b/test/system/trades_test.rb
index 541a445c..c9f7835b 100644
--- a/test/system/trades_test.rb
+++ b/test/system/trades_test.rb
@@ -62,6 +62,6 @@ class TradesTest < ApplicationSystemTestCase
end
def visit_account_trades
- visit account_url(@account, tab: "trades")
+ visit account_url(@account, tab: "transactions")
end
end
diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb
index 4544c6c4..956e800b 100644
--- a/test/system/transactions_test.rb
+++ b/test/system/transactions_test.rb
@@ -156,6 +156,7 @@ class TransactionsTest < ApplicationSystemTestCase
test "can create deposit transaction for investment account" do
investment_account = accounts(:investment)
+ investment_account.entries.create!(name: "Investment account", date: Date.current, amount: 1000, currency: "USD", entryable: Account::Transaction.new)
transfer_date = Date.current
visit account_path(investment_account)
click_on "New transaction"
From 263d65ea7ede093b8bd906ea2ef11e3d6f2e6566 Mon Sep 17 00:00:00 2001
From: Zach Gollwitzer
Date: Fri, 18 Oct 2024 17:18:54 -0400
Subject: [PATCH 022/736] Basic account onboarding (#1328)
* Basic account onboarding
* Cleanup
---
app/controllers/accounts_controller.rb | 2 +-
app/controllers/credit_cards_controller.rb | 2 +-
app/controllers/loans_controller.rb | 2 +-
app/controllers/properties_controller.rb | 2 +-
app/controllers/vehicles_controller.rb | 2 +-
app/models/account.rb | 3 ++
app/models/account/balance/calculator.rb | 4 +-
app/views/accounts/_form.html.erb | 4 ++
.../accounts/_new_account_setup_bar.html.erb | 8 ----
.../accountables/_default_tabs.html.erb | 14 +++++--
.../accountables/_value_onboarding.html.erb | 16 +++++++
.../accountables/credit_card/_tabs.html.erb | 35 ++++++++++------
.../accountables/crypto/_tabs.html.erb | 2 +-
.../accountables/depository/_tabs.html.erb | 2 +-
.../accountables/investment/_tabs.html.erb | 42 +++++++++++--------
.../accounts/accountables/loan/_tabs.html.erb | 34 +++++++++------
app/views/accounts/show.html.erb | 4 --
app/views/shared/_text_tooltip.erb | 2 +-
config/locales/views/accounts/en.yml | 2 +
db/migrate/20241018201653_add_account_mode.rb | 5 +++
db/schema.rb | 6 +--
test/fixtures/accounts.yml | 8 ++++
test/models/account/balance/syncer_test.rb | 13 +++++-
test/system/accounts_test.rb | 5 ++-
24 files changed, 146 insertions(+), 73 deletions(-)
delete mode 100644 app/views/accounts/_new_account_setup_bar.html.erb
create mode 100644 app/views/accounts/accountables/_value_onboarding.html.erb
create mode 100644 db/migrate/20241018201653_add_account_mode.rb
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 033ed3b8..21419365 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -79,6 +79,6 @@ class AccountsController < ApplicationController
end
def account_params
- params.require(:account).permit(:name, :accountable_type, :balance, :start_date, :start_balance, :currency, :subtype, :is_active, :institution_id)
+ params.require(:account).permit(:name, :accountable_type, :mode, :balance, :start_date, :start_balance, :currency, :subtype, :is_active, :institution_id)
end
end
diff --git a/app/controllers/credit_cards_controller.rb b/app/controllers/credit_cards_controller.rb
index 5854c9fa..bb416ce7 100644
--- a/app/controllers/credit_cards_controller.rb
+++ b/app/controllers/credit_cards_controller.rb
@@ -27,7 +27,7 @@ class CreditCardsController < ApplicationController
def account_params
params.require(:account)
.permit(
- :name, :balance, :institution_id, :start_date, :start_balance, :currency, :accountable_type,
+ :name, :balance, :institution_id, :mode, :start_date, :start_balance, :currency, :accountable_type,
accountable_attributes: [
:id,
:available_credit,
diff --git a/app/controllers/loans_controller.rb b/app/controllers/loans_controller.rb
index b084e566..1b704290 100644
--- a/app/controllers/loans_controller.rb
+++ b/app/controllers/loans_controller.rb
@@ -27,7 +27,7 @@ class LoansController < ApplicationController
def account_params
params.require(:account)
.permit(
- :name, :balance, :institution_id, :start_date, :start_balance, :currency, :accountable_type,
+ :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type,
accountable_attributes: [
:id,
:rate_type,
diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb
index 71d46f0e..e37344d4 100644
--- a/app/controllers/properties_controller.rb
+++ b/app/controllers/properties_controller.rb
@@ -27,7 +27,7 @@ class PropertiesController < ApplicationController
def account_params
params.require(:account)
.permit(
- :name, :balance, :institution_id, :start_date, :start_balance, :currency, :accountable_type,
+ :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type,
accountable_attributes: [
:id,
:year_built,
diff --git a/app/controllers/vehicles_controller.rb b/app/controllers/vehicles_controller.rb
index e9822b9b..fe41a42f 100644
--- a/app/controllers/vehicles_controller.rb
+++ b/app/controllers/vehicles_controller.rb
@@ -27,7 +27,7 @@ class VehiclesController < ApplicationController
def account_params
params.require(:account)
.permit(
- :name, :balance, :institution_id, :start_date, :start_balance, :currency, :accountable_type,
+ :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type,
accountable_attributes: [
:id,
:make,
diff --git a/app/models/account.rb b/app/models/account.rb
index 9dd49d60..c2c91f37 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -1,7 +1,10 @@
class Account < ApplicationRecord
+ VALUE_MODES = %w[balance transactions]
+
include Syncable, Monetizable, Issuable
validates :name, :balance, :currency, presence: true
+ validates :mode, inclusion: { in: VALUE_MODES }, allow_nil: true
belongs_to :family
belongs_to :institution, optional: true
diff --git a/app/models/account/balance/calculator.rb b/app/models/account/balance/calculator.rb
index 68d85853..04dfb381 100644
--- a/app/models/account/balance/calculator.rb
+++ b/app/models/account/balance/calculator.rb
@@ -23,11 +23,11 @@ class Account::Balance::Calculator
attr_reader :account, :sync_start_date
def find_start_balance_for_partial_sync
- account.balances.find_by(currency: account.currency, date: sync_start_date - 1.day).balance
+ account.balances.find_by(currency: account.currency, date: sync_start_date - 1.day)&.balance
end
def find_start_balance_for_full_sync(cached_entries)
- account.balance + net_entry_flows(cached_entries)
+ account.balance + net_entry_flows(cached_entries.select { |e| e.account_transaction? })
end
def calculate_balance_for_date(date, entries:, prior_balance:)
diff --git a/app/views/accounts/_form.html.erb b/app/views/accounts/_form.html.erb
index e85448e0..65dee8df 100644
--- a/app/views/accounts/_form.html.erb
+++ b/app/views/accounts/_form.html.erb
@@ -2,6 +2,10 @@
<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %>
+ <% unless account.new_record? %>
+ <%= f.select :mode, Account::VALUE_MODES.map { |mode| [mode.titleize, mode] }, { label: t(".mode"), prompt: t(".mode_prompt") } %>
+ <% end %>
+
<%= f.select :accountable_type, Accountable::TYPES.map { |type| [type.titleize, type] }, { label: t(".accountable_type"), prompt: t(".type_prompt") }, required: true, autofocus: true %>
<%= f.text_field :name, placeholder: t(".name_placeholder"), required: "required", label: t(".name_label") %>
diff --git a/app/views/accounts/_new_account_setup_bar.html.erb b/app/views/accounts/_new_account_setup_bar.html.erb
deleted file mode 100644
index 16b6e430..00000000
--- a/app/views/accounts/_new_account_setup_bar.html.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
Setup your new account
-
-
- <%= link_to "Track balances only", new_account_valuation_path(@account), class: "btn btn--ghost", data: { turbo_frame: dom_id(@account.entries.account_valuations.new) } %>
- <%= link_to "Add your first transaction", new_transaction_path(account_id: @account.id), class: "btn btn--primary", data: { turbo_frame: :modal } %>
-
-
diff --git a/app/views/accounts/accountables/_default_tabs.html.erb b/app/views/accounts/accountables/_default_tabs.html.erb
index 0a2f355a..9b6274ef 100644
--- a/app/views/accounts/accountables/_default_tabs.html.erb
+++ b/app/views/accounts/accountables/_default_tabs.html.erb
@@ -1,7 +1,13 @@
-<%# locals: (account:) %>
+<%# locals: (account:, selected_tab:) %>
-<% if account.transactions.any? %>
- <%= render "accounts/accountables/transactions", account: account %>
+<% if account.mode.nil? %>
+ <%= render "accounts/accountables/value_onboarding", account: account %>
<% else %>
- <%= render "accounts/accountables/valuations", account: account %>
+
+ <% if account.mode == "transactions" %>
+ <%= render "accounts/accountables/transactions", account: account %>
+ <% else %>
+ <%= render "accounts/accountables/valuations", account: account %>
+ <% end %>
+
<% end %>
diff --git a/app/views/accounts/accountables/_value_onboarding.html.erb b/app/views/accounts/accountables/_value_onboarding.html.erb
new file mode 100644
index 00000000..26b20b6a
--- /dev/null
+++ b/app/views/accounts/accountables/_value_onboarding.html.erb
@@ -0,0 +1,16 @@
+<%# locals: (account:) %>
+
+
+
How would you like to track value for this account?
+
We will use this to determine what data to show for this account.
+
+ <%= button_to account_path(account, { account: { mode: "balance" } }), method: :put, class: "btn btn--outline", data: { controller: "tooltip", turbo: false } do %>
+ <%= render partial: "shared/text_tooltip", locals: { tooltip_text: "Choose this if you only need to track the historical value of this account over time and do not plan on importing any transactions." } %>
+ Balance only
+ <% end %>
+ <%= button_to account_path(account, { account: { mode: "transactions" } }), method: :put, class: "btn btn--primary", data: { controller: "tooltip", turbo: false } do %>
+ <%= render partial: "shared/text_tooltip", locals: { tooltip_text: "Choose this if you plan on importing transactions into this account for budgeting and other analytics." } %>
+ Transactions
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/accounts/accountables/credit_card/_tabs.html.erb b/app/views/accounts/accountables/credit_card/_tabs.html.erb
index 781cc6d0..d08ff8e2 100644
--- a/app/views/accounts/accountables/credit_card/_tabs.html.erb
+++ b/app/views/accounts/accountables/credit_card/_tabs.html.erb
@@ -1,15 +1,26 @@
<%# locals: (account:, selected_tab:) %>
-
- <%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
- <%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
-
+<% if account.mode.nil? %>
+ <%= render "accounts/accountables/value_onboarding", account: account %>
+<% else %>
+
+ <%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
-
- <% case selected_tab %>
- <% when nil, "overview" %>
- <%= render "accounts/accountables/credit_card/overview", account: account %>
- <% when "transactions" %>
- <%= render "accounts/accountables/transactions", account: account %>
- <% end %>
-
+ <% if account.mode == "transactions" %>
+ <%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
+ <% else %>
+ <%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
+ <% end %>
+
+
+
+ <% case selected_tab %>
+ <% when nil, "overview" %>
+ <%= render "accounts/accountables/credit_card/overview", account: account %>
+ <% when "transactions" %>
+ <%= render "accounts/accountables/transactions", account: account %>
+ <% when "value" %>
+ <%= render "accounts/accountables/valuations", account: account %>
+ <% end %>
+
+<% end %>
diff --git a/app/views/accounts/accountables/crypto/_tabs.html.erb b/app/views/accounts/accountables/crypto/_tabs.html.erb
index 381f7273..be74694e 100644
--- a/app/views/accounts/accountables/crypto/_tabs.html.erb
+++ b/app/views/accounts/accountables/crypto/_tabs.html.erb
@@ -1 +1 @@
-<%= render "accounts/accountables/default_tabs", account: account %>
+<%= render "accounts/accountables/default_tabs", account: account, selected_tab: selected_tab %>
diff --git a/app/views/accounts/accountables/depository/_tabs.html.erb b/app/views/accounts/accountables/depository/_tabs.html.erb
index 381f7273..be74694e 100644
--- a/app/views/accounts/accountables/depository/_tabs.html.erb
+++ b/app/views/accounts/accountables/depository/_tabs.html.erb
@@ -1 +1 @@
-<%= render "accounts/accountables/default_tabs", account: account %>
+<%= render "accounts/accountables/default_tabs", account: account, selected_tab: selected_tab %>
diff --git a/app/views/accounts/accountables/investment/_tabs.html.erb b/app/views/accounts/accountables/investment/_tabs.html.erb
index 8da4905d..bff1d3ce 100644
--- a/app/views/accounts/accountables/investment/_tabs.html.erb
+++ b/app/views/accounts/accountables/investment/_tabs.html.erb
@@ -1,28 +1,34 @@
<%# locals: (account:, selected_tab:) %>
-<% if account.entries.account_trades.any? || account.entries.account_transactions.any? %>
+<% if account.mode.nil? %>
+ <%= render "accounts/accountables/value_onboarding", account: account %>
+<% else %>
- <%= render "accounts/accountables/tab", account: account, key: "holdings", is_selected: selected_tab.in?([nil, "holdings"]) %>
- <%= render "accounts/accountables/tab", account: account, key: "cash", is_selected: selected_tab == "cash" %>
- <%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
+ <% if account.mode == "transactions" %>
+ <%= render "accounts/accountables/tab", account: account, key: "holdings", is_selected: selected_tab.in?([nil, "holdings"]) %>
+ <%= render "accounts/accountables/tab", account: account, key: "cash", is_selected: selected_tab == "cash" %>
+ <%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
+ <% end %>
- <% case selected_tab %>
- <% when nil, "holdings" %>
- <%= turbo_frame_tag dom_id(account, :holdings), src: account_holdings_path(account) do %>
- <%= render "account/entries/loading" %>
- <% end %>
- <% when "cash" %>
- <%= turbo_frame_tag dom_id(account, :cash), src: account_cashes_path(account) do %>
- <%= render "account/entries/loading" %>
- <% end %>
- <% when "transactions" %>
- <%= turbo_frame_tag dom_id(account, :trades), src: account_trades_path(account) do %>
- <%= render "account/entries/loading" %>
+ <% if account.mode == "transactions" %>
+ <% case selected_tab %>
+ <% when nil, "holdings" %>
+ <%= turbo_frame_tag dom_id(account, :holdings), src: account_holdings_path(account) do %>
+ <%= render "account/entries/loading" %>
+ <% end %>
+ <% when "cash" %>
+ <%= turbo_frame_tag dom_id(account, :cash), src: account_cashes_path(account) do %>
+ <%= render "account/entries/loading" %>
+ <% end %>
+ <% when "transactions" %>
+ <%= turbo_frame_tag dom_id(account, :trades), src: account_trades_path(account) do %>
+ <%= render "account/entries/loading" %>
+ <% end %>
<% end %>
+ <% else %>
+ <%= render "accounts/accountables/valuations", account: account %>
<% end %>
-<% else %>
- <%= render "accounts/accountables/valuations", account: account %>
<% end %>
diff --git a/app/views/accounts/accountables/loan/_tabs.html.erb b/app/views/accounts/accountables/loan/_tabs.html.erb
index 3ed1efcf..8c5ca4fe 100644
--- a/app/views/accounts/accountables/loan/_tabs.html.erb
+++ b/app/views/accounts/accountables/loan/_tabs.html.erb
@@ -1,15 +1,25 @@
<%# locals: (account:, selected_tab:) %>
-
- <%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
- <%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
-
+<% if account.mode.nil? %>
+ <%= render "accounts/accountables/value_onboarding", account: account %>
+<% else %>
+
+ <%= render "accounts/accountables/tab", account: account, key: "overview", is_selected: selected_tab.in?([nil, "overview"]) %>
+ <% if account.mode == "transactions" %>
+ <%= render "accounts/accountables/tab", account: account, key: "transactions", is_selected: selected_tab == "transactions" %>
+ <% else %>
+ <%= render "accounts/accountables/tab", account: account, key: "value", is_selected: selected_tab == "value" %>
+ <% end %>
+
-
- <% case selected_tab %>
- <% when nil, "overview" %>
- <%= render "accounts/accountables/loan/overview", account: account %>
- <% when "value" %>
- <%= render "accounts/accountables/valuations", account: account %>
- <% end %>
-
+
+ <% case selected_tab %>
+ <% when nil, "overview" %>
+ <%= render "accounts/accountables/loan/overview", account: account %>
+ <% when "transactions" %>
+ <%= render "accounts/accountables/transactions", account: account %>
+ <% when "value" %>
+ <%= render "accounts/accountables/valuations", account: account %>
+ <% end %>
+
+<% end %>
diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb
index c49b64e2..d250a38f 100644
--- a/app/views/accounts/show.html.erb
+++ b/app/views/accounts/show.html.erb
@@ -16,10 +16,6 @@
- <% if @account.entries.empty? && @account.depository? %>
- <%= render "accounts/new_account_setup_bar", account: @account %>
- <% end %>
-
<% if @account.highest_priority_issue %>
<%= render partial: "issues/issue", locals: { issue: @account.highest_priority_issue } %>
<% end %>
diff --git a/app/views/shared/_text_tooltip.erb b/app/views/shared/_text_tooltip.erb
index 53f93dd3..f6823c80 100644
--- a/app/views/shared/_text_tooltip.erb
+++ b/app/views/shared/_text_tooltip.erb
@@ -1,5 +1,5 @@
-
diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml
index 0e12a0f5..4dff4381 100644
--- a/config/locales/views/accounts/en.yml
+++ b/config/locales/views/accounts/en.yml
@@ -19,6 +19,8 @@ en:
ungrouped: "(none)"
balance: Today's balance
accountable_type: Account type
+ mode: Value tracking mode
+ mode_prompt: Select a mode
type_prompt: Select a type
header:
accounts: Accounts
diff --git a/db/migrate/20241018201653_add_account_mode.rb b/db/migrate/20241018201653_add_account_mode.rb
new file mode 100644
index 00000000..54a273d2
--- /dev/null
+++ b/db/migrate/20241018201653_add_account_mode.rb
@@ -0,0 +1,5 @@
+class AddAccountMode < ActiveRecord::Migration[7.2]
+ def change
+ add_column :accounts, :mode, :string
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c5a313ea..09baa1b2 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.2].define(version: 2024_10_17_204250) do
+ActiveRecord::Schema[7.2].define(version: 2024_10_18_201653) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@@ -19,7 +19,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_17_204250) do
# Note that some types may not work with other database engines. Be careful if changing database.
create_enum "account_status", ["ok", "syncing", "error"]
create_enum "import_status", ["pending", "importing", "complete", "failed"]
- create_enum "user_role", ["admin", "member", "super_admin"]
create_table "account_balances", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.uuid "account_id", null: false
@@ -122,6 +121,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_17_204250) do
t.uuid "institution_id"
t.virtual "classification", type: :string, as: "\nCASE\n WHEN ((accountable_type)::text = ANY (ARRAY[('Loan'::character varying)::text, ('CreditCard'::character varying)::text, ('OtherLiability'::character varying)::text])) THEN 'liability'::text\n ELSE 'asset'::text\nEND", stored: true
t.uuid "import_id"
+ t.string "mode"
t.index ["accountable_id", "accountable_type"], name: "index_accounts_on_accountable_id_and_accountable_type"
t.index ["accountable_type"], name: "index_accounts_on_accountable_type"
t.index ["family_id", "accountable_type"], name: "index_accounts_on_family_id_and_accountable_type"
@@ -535,7 +535,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_17_204250) do
t.datetime "updated_at", null: false
t.string "last_prompted_upgrade_commit_sha"
t.string "last_alerted_upgrade_commit_sha"
- t.enum "role", default: "member", null: false, enum_type: "user_role"
+ t.string "role", default: "member", null: false
t.boolean "active", default: true, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["family_id"], name: "index_users_on_family_id"
diff --git a/test/fixtures/accounts.yml b/test/fixtures/accounts.yml
index eeb616f3..9afbc8a1 100644
--- a/test/fixtures/accounts.yml
+++ b/test/fixtures/accounts.yml
@@ -5,6 +5,7 @@ other_asset:
currency: USD
accountable_type: OtherAsset
accountable: one
+ mode: balance
other_liability:
family: dylan_family
@@ -13,6 +14,7 @@ other_liability:
currency: USD
accountable_type: OtherLiability
accountable: one
+ mode: balance
depository:
family: dylan_family
@@ -22,6 +24,7 @@ depository:
accountable_type: Depository
accountable: one
institution: chase
+ mode: transactions
credit_card:
family: dylan_family
@@ -31,6 +34,7 @@ credit_card:
accountable_type: CreditCard
accountable: one
institution: chase
+ mode: transactions
investment:
family: dylan_family
@@ -39,6 +43,7 @@ investment:
currency: USD
accountable_type: Investment
accountable: one
+ mode: transactions
loan:
family: dylan_family
@@ -47,6 +52,7 @@ loan:
currency: USD
accountable_type: Loan
accountable: one
+ mode: transactions
property:
family: dylan_family
@@ -55,6 +61,7 @@ property:
currency: USD
accountable_type: Property
accountable: one
+ mode: transactions
vehicle:
family: dylan_family
@@ -63,3 +70,4 @@ vehicle:
currency: USD
accountable_type: Vehicle
accountable: one
+ mode: transactions
diff --git a/test/models/account/balance/syncer_test.rb b/test/models/account/balance/syncer_test.rb
index 748b3e6a..528863be 100644
--- a/test/models/account/balance/syncer_test.rb
+++ b/test/models/account/balance/syncer_test.rb
@@ -35,7 +35,7 @@ class Account::Balance::SyncerTest < ActiveSupport::TestCase
assert_equal [ 19600, 19500, 19500, 20000, 20000, 20000 ], @account.balances.chronological.map(&:balance)
end
- test "syncs account with valuations and transactions" do
+ test "syncs account with valuations and transactions when valuation starts" do
create_valuation(account: @account, date: 5.days.ago.to_date, amount: 20000)
create_transaction(account: @account, date: 3.days.ago.to_date, amount: -500)
create_transaction(account: @account, date: 2.days.ago.to_date, amount: 100)
@@ -47,6 +47,17 @@ class Account::Balance::SyncerTest < ActiveSupport::TestCase
assert_equal [ 20000, 20000, 20500, 20400, 25000, 25000 ], @account.balances.chronological.map(&:balance)
end
+ test "syncs account with valuations and transactions when transaction starts" do
+ new_account = families(:empty).accounts.create!(name: "Test Account", balance: 1000, currency: "USD", accountable: Depository.new)
+ create_transaction(account: new_account, date: 2.days.ago.to_date, amount: 250)
+ create_valuation(account: new_account, date: Date.current, amount: 1000)
+
+ run_sync_for(new_account)
+
+ assert_equal 1000, new_account.balance
+ assert_equal [ 1250, 1000, 1000, 1000 ], new_account.balances.chronological.map(&:balance)
+ end
+
test "syncs account with transactions in multiple currencies" do
ExchangeRate.create! date: 1.day.ago.to_date, from_currency: "EUR", to_currency: "USD", rate: 1.2
diff --git a/test/system/accounts_test.rb b/test/system/accounts_test.rb
index 97f3fd91..b7b6d18e 100644
--- a/test/system/accounts_test.rb
+++ b/test/system/accounts_test.rb
@@ -96,7 +96,10 @@ class AccountsTest < ApplicationSystemTestCase
visit accounts_url
assert_text account_name
- visit account_url(Account.order(:created_at).last)
+ created_account = Account.order(:created_at).last
+ created_account.update!(mode: "transactions")
+
+ visit account_url(created_account)
within "header" do
find('button[data-menu-target="button"]').click
From 3c0fdd84eefe9a5afb5cb3d2cc274ed6c3824e34 Mon Sep 17 00:00:00 2001
From: Zach Gollwitzer
Date: Fri, 18 Oct 2024 18:25:17 -0400
Subject: [PATCH 023/736] Fix mode bug
---
app/models/concerns/accountable.rb | 4 ++++
app/models/other_asset.rb | 4 ++++
app/models/other_liability.rb | 4 ++++
app/models/property.rb | 4 ++++
app/models/vehicle.rb | 4 ++++
app/views/accounts/_form.html.erb | 4 +++-
app/views/accounts/accountables/_value_onboarding.html.erb | 2 +-
.../accounts/accountables/credit_card/_overview.html.erb | 2 +-
app/views/accounts/accountables/loan/_overview.html.erb | 2 +-
9 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/app/models/concerns/accountable.rb b/app/models/concerns/accountable.rb
index a7a10284..5f5ce93d 100644
--- a/app/models/concerns/accountable.rb
+++ b/app/models/concerns/accountable.rb
@@ -33,4 +33,8 @@ module Accountable
rescue Money::ConversionError
TimeSeries.new([])
end
+
+ def mode_required?
+ true
+ end
end
diff --git a/app/models/other_asset.rb b/app/models/other_asset.rb
index 90ca9e32..29b2048a 100644
--- a/app/models/other_asset.rb
+++ b/app/models/other_asset.rb
@@ -4,4 +4,8 @@ class OtherAsset < ApplicationRecord
def color
"#12B76A"
end
+
+ def mode_required?
+ false
+ end
end
diff --git a/app/models/other_liability.rb b/app/models/other_liability.rb
index 04a3737b..4be8e38c 100644
--- a/app/models/other_liability.rb
+++ b/app/models/other_liability.rb
@@ -4,4 +4,8 @@ class OtherLiability < ApplicationRecord
def color
"#737373"
end
+
+ def mode_required?
+ false
+ end
end
diff --git a/app/models/property.rb b/app/models/property.rb
index 304c4d78..02f4b848 100644
--- a/app/models/property.rb
+++ b/app/models/property.rb
@@ -23,6 +23,10 @@ class Property < ApplicationRecord
"#06AED4"
end
+ def mode_required?
+ false
+ end
+
private
def first_valuation_amount
account.entries.account_valuations.order(:date).first&.amount_money || account.balance_money
diff --git a/app/models/vehicle.rb b/app/models/vehicle.rb
index 741070c2..92c5b940 100644
--- a/app/models/vehicle.rb
+++ b/app/models/vehicle.rb
@@ -19,6 +19,10 @@ class Vehicle < ApplicationRecord
"#F23E94"
end
+ def mode_required?
+ false
+ end
+
private
def first_valuation_amount
account.entries.account_valuations.order(:date).first&.amount_money || account.balance_money
diff --git a/app/views/accounts/_form.html.erb b/app/views/accounts/_form.html.erb
index 65dee8df..b5d17930 100644
--- a/app/views/accounts/_form.html.erb
+++ b/app/views/accounts/_form.html.erb
@@ -3,7 +3,9 @@
<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %>
<% unless account.new_record? %>
- <%= f.select :mode, Account::VALUE_MODES.map { |mode| [mode.titleize, mode] }, { label: t(".mode"), prompt: t(".mode_prompt") } %>
+ <% if account.accountable.mode_required? %>
+ <%= f.select :mode, Account::VALUE_MODES.map { |mode| [mode.titleize, mode] }, { label: t(".mode"), prompt: t(".mode_prompt") }, required: true %>
+ <% end %>
<% end %>
<%= f.select :accountable_type, Accountable::TYPES.map { |type| [type.titleize, type] }, { label: t(".accountable_type"), prompt: t(".type_prompt") }, required: true, autofocus: true %>
diff --git a/app/views/accounts/accountables/_value_onboarding.html.erb b/app/views/accounts/accountables/_value_onboarding.html.erb
index 26b20b6a..27798add 100644
--- a/app/views/accounts/accountables/_value_onboarding.html.erb
+++ b/app/views/accounts/accountables/_value_onboarding.html.erb
@@ -13,4 +13,4 @@
Transactions
<% end %>
-
\ No newline at end of file
+
diff --git a/app/views/accounts/accountables/credit_card/_overview.html.erb b/app/views/accounts/accountables/credit_card/_overview.html.erb
index 668326b5..032d8b52 100644
--- a/app/views/accounts/accountables/credit_card/_overview.html.erb
+++ b/app/views/accounts/accountables/credit_card/_overview.html.erb
@@ -28,4 +28,4 @@
<%= link_to "Edit account details", edit_account_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
-
\ No newline at end of file
+