From a63c55fa127b115710c20e794ca6fa2078704793 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Thu, 31 Oct 2024 06:53:47 -0400 Subject: [PATCH 01/19] Remove balance mode, sketch out refactor --- app/controllers/depositories_controller.rb | 32 +++++++++ app/helpers/accounts_helper.rb | 4 ++ app/models/account.rb | 5 +- app/models/concerns/accountable.rb | 4 -- app/models/credit_card.rb | 4 ++ app/models/crypto.rb | 4 ++ app/models/depository.rb | 4 ++ app/models/investment.rb | 4 ++ app/models/loan.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/_account_type.html.erb | 13 ++-- app/views/accounts/_entry_method.html.erb | 17 ----- app/views/accounts/_form.html.erb | 6 -- .../accountables/_default_tabs.html.erb | 14 +--- .../accountables/_value_onboarding.html.erb | 16 ----- app/views/accounts/new.html.erb | 70 +++++-------------- app/views/accounts/new/_container.html.erb | 40 +++++++++++ app/views/accounts/new/_form.html.erb | 20 ++++++ .../accounts/new/_method_selector.html.erb | 19 +++++ app/views/depositories/_form.html.erb | 36 ++++++++++ app/views/depositories/new.html.erb | 3 + app/views/shared/_modal_form.html.erb | 6 +- config/locales/views/accounts/en.yml | 22 ++++-- config/routes.rb | 1 + .../20241030151105_remove_account_mode.rb | 5 ++ db/schema.rb | 17 ++--- .../depositories_controller_test.rb | 45 ++++++++++++ test/fixtures/accounts.yml | 8 --- 31 files changed, 288 insertions(+), 151 deletions(-) create mode 100644 app/controllers/depositories_controller.rb delete mode 100644 app/views/accounts/_entry_method.html.erb delete mode 100644 app/views/accounts/accountables/_value_onboarding.html.erb create mode 100644 app/views/accounts/new/_container.html.erb create mode 100644 app/views/accounts/new/_form.html.erb create mode 100644 app/views/accounts/new/_method_selector.html.erb create mode 100644 app/views/depositories/_form.html.erb create mode 100644 app/views/depositories/new.html.erb create mode 100644 db/migrate/20241030151105_remove_account_mode.rb create mode 100644 test/controllers/depositories_controller_test.rb diff --git a/app/controllers/depositories_controller.rb b/app/controllers/depositories_controller.rb new file mode 100644 index 00000000000..83bdb834a8f --- /dev/null +++ b/app/controllers/depositories_controller.rb @@ -0,0 +1,32 @@ +class DepositoriesController < AccountsController + before_action :set_account, only: [ :update ] + + def new + @account = Current.family.accounts.depositories.build( + currency: Current.family.currency, + ) + end + + def create + @account = Current.family.accounts.create!( + depository_params.merge(accountable: Depository.new) + ) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(depository_params) + redirect_to @account, notice: t(".success") + end + + private + def set_account + @account = Current.family.accounts.depositories.find_by(accountable_id: params[:id]) + end + + def depository_params + params.require(:depository).permit( + :name, :balance, :subtype, :currency + ) + end +end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index b65033c59cb..924558eb6ff 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -1,4 +1,8 @@ module AccountsHelper + def new_accountable_path(type) + "/#{type.model_name.plural}/new" + end + def permitted_accountable_partial(account, name = nil) permitted_names = %w[tooltip header tabs form] folder = account.accountable_type.underscore diff --git a/app/models/account.rb b/app/models/account.rb index c2c91f37e75..f75ca9f5144 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -1,10 +1,7 @@ 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 @@ -34,7 +31,7 @@ class Account < ApplicationRecord delegated_type :accountable, types: Accountable::TYPES, dependent: :destroy - accepts_nested_attributes_for :accountable + accepts_nested_attributes_for :accountable, update_only: true delegate :value, :series, to: :accountable diff --git a/app/models/concerns/accountable.rb b/app/models/concerns/accountable.rb index 5f5ce93d346..a7a1028430e 100644 --- a/app/models/concerns/accountable.rb +++ b/app/models/concerns/accountable.rb @@ -33,8 +33,4 @@ def series(period: Period.all, currency: account.currency) rescue Money::ConversionError TimeSeries.new([]) end - - def mode_required? - true - end end diff --git a/app/models/credit_card.rb b/app/models/credit_card.rb index bdde91c808c..dc269516575 100644 --- a/app/models/credit_card.rb +++ b/app/models/credit_card.rb @@ -16,4 +16,8 @@ def annual_fee_money def color "#F13636" end + + def icon + "credit-card" + end end diff --git a/app/models/crypto.rb b/app/models/crypto.rb index e4f81ae43eb..1aba075e08d 100644 --- a/app/models/crypto.rb +++ b/app/models/crypto.rb @@ -4,4 +4,8 @@ class Crypto < ApplicationRecord def color "#737373" end + + def icon + "bitcoin" + end end diff --git a/app/models/depository.rb b/app/models/depository.rb index 90abe087253..b6408bdd142 100644 --- a/app/models/depository.rb +++ b/app/models/depository.rb @@ -4,4 +4,8 @@ class Depository < ApplicationRecord def color "#875BF7" end + + def icon + "landmark" + end end diff --git a/app/models/investment.rb b/app/models/investment.rb index 1912899fc2e..e9df9a4f511 100644 --- a/app/models/investment.rb +++ b/app/models/investment.rb @@ -50,4 +50,8 @@ def series(period: Period.all, currency: account.currency) def color "#1570EF" end + + def icon + "line-chart" + end end diff --git a/app/models/loan.rb b/app/models/loan.rb index 5051b69b851..41bd4d7b505 100644 --- a/app/models/loan.rb +++ b/app/models/loan.rb @@ -20,4 +20,8 @@ def monthly_payment def color "#D444F1" end + + def icon + "hand-coins" + end end diff --git a/app/models/other_asset.rb b/app/models/other_asset.rb index 29b2048a9dc..68d3915ed45 100644 --- a/app/models/other_asset.rb +++ b/app/models/other_asset.rb @@ -5,7 +5,7 @@ def color "#12B76A" end - def mode_required? - false + def icon + "plus" end end diff --git a/app/models/other_liability.rb b/app/models/other_liability.rb index 4be8e38c03e..18e44171f34 100644 --- a/app/models/other_liability.rb +++ b/app/models/other_liability.rb @@ -5,7 +5,7 @@ def color "#737373" end - def mode_required? - false + def icon + "minus" end end diff --git a/app/models/property.rb b/app/models/property.rb index 02f4b848ca2..5090019089b 100644 --- a/app/models/property.rb +++ b/app/models/property.rb @@ -23,8 +23,8 @@ def color "#06AED4" end - def mode_required? - false + def icon + "home" end private diff --git a/app/models/vehicle.rb b/app/models/vehicle.rb index 92c5b940fb9..70f2045764b 100644 --- a/app/models/vehicle.rb +++ b/app/models/vehicle.rb @@ -19,8 +19,8 @@ def color "#F23E94" end - def mode_required? - false + def icon + "car-front" end private diff --git a/app/views/accounts/_account_type.html.erb b/app/views/accounts/_account_type.html.erb index d4b695271bf..5d6a00ba962 100644 --- a/app/views/accounts/_account_type.html.erb +++ b/app/views/accounts/_account_type.html.erb @@ -1,10 +1,9 @@ -<%= link_to new_account_path( - type: type.class.name.demodulize, - institution_id: params[:institution_id] - ), +<%# locals: (accountable:) %> + +<%= link_to new_account_path(type: accountable.class), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-alpha-black-25 hover:bg-alpha-black-25 border border-transparent block px-2 rounded-lg p-2" do %> - - <%= lucide_icon(icon, class: "#{text_color} w-5 h-5") %> + + <%= lucide_icon(accountable.icon, style: "color: #{accountable.color}", class: "w-5 h-5") %> - <%= type.model_name.human %> + <%= accountable.model_name.human %> <% end %> diff --git a/app/views/accounts/_entry_method.html.erb b/app/views/accounts/_entry_method.html.erb deleted file mode 100644 index 1e9b697125c..00000000000 --- a/app/views/accounts/_entry_method.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%# locals: (text:, icon:, disabled: false) %> - -<% if disabled %> - - - <%= lucide_icon(icon, class: "text-gray-500 w-5 h-5") %> - - <%= text %> - -<% else %> - <%= link_to new_account_path(institution_id: params[:institution_id]), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %> - - <%= lucide_icon(icon, class: "text-gray-500 w-5 h-5") %> - - <%= text %> - <% end %> -<% end %> diff --git a/app/views/accounts/_form.html.erb b/app/views/accounts/_form.html.erb index b5d17930d8b..e85448e018f 100644 --- a/app/views/accounts/_form.html.erb +++ b/app/views/accounts/_form.html.erb @@ -2,12 +2,6 @@ <%= 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? %> - <% 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 %> <%= f.text_field :name, placeholder: t(".name_placeholder"), required: "required", label: t(".name_label") %> diff --git a/app/views/accounts/accountables/_default_tabs.html.erb b/app/views/accounts/accountables/_default_tabs.html.erb index 9b6274ef29c..d38114d466f 100644 --- a/app/views/accounts/accountables/_default_tabs.html.erb +++ b/app/views/accounts/accountables/_default_tabs.html.erb @@ -1,13 +1,5 @@ <%# locals: (account:, selected_tab:) %> -<% if account.mode.nil? %> - <%= render "accounts/accountables/value_onboarding", account: account %> -<% else %> -
- <% if account.mode == "transactions" %> - <%= render "accounts/accountables/transactions", account: account %> - <% else %> - <%= render "accounts/accountables/valuations", account: account %> - <% end %> -
-<% end %> +
+ <%= render "accounts/accountables/valuations", account: account %> +
diff --git a/app/views/accounts/accountables/_value_onboarding.html.erb b/app/views/accounts/accountables/_value_onboarding.html.erb deleted file mode 100644 index 27798adddec..00000000000 --- a/app/views/accounts/accountables/_value_onboarding.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -<%# 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 %> -
-
diff --git a/app/views/accounts/new.html.erb b/app/views/accounts/new.html.erb index 9e8a562f8a2..105acbb7a32 100644 --- a/app/views/accounts/new.html.erb +++ b/app/views/accounts/new.html.erb @@ -1,53 +1,17 @@ -

<%= t(".title") %>

-<%= modal do %> -
- <% if params[:step] == 'method' %> -
- How would you like to add it? -
-
- - - - <%= render "entry_method", text: t(".manual_entry"), icon: "keyboard" %> - - <%= link_to new_import_path(import: { type: "AccountImport" }), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %> - - <%= lucide_icon("sheet", class: "text-gray-500 w-5 h-5") %> - - <%= t(".csv_entry") %> - <% end %> - - <%= render "entry_method", text: t(".connected_entry"), icon: "link-2", disabled: true %> -
-
-
-
- Select - <%= lucide_icon("corner-down-left", class: "inline w-3 h-3") %> -
-
- Navigate - <%= lucide_icon("arrow-up", class: "inline w-3 h-3") %> - <%= lucide_icon("arrow-down", class: "inline w-3 h-3") %> -
-
-
- - ESC -
-
- <% else %> -
- <%= link_to new_account_path(step: "method"), class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 focus:outline-gray-300 focus:outline" do %> - <%= lucide_icon("arrow-left", class: "text-gray-500 w-5 h-5") %> - <% end %> - Add account -
- -
- <%= render "form", account: @account, url: new_account_form_url(@account) %> -
- <% end %> -
-<% end %> +<% if params[:type].present? %> + <%= render "accounts/new/method_selector", path: new_accountable_path(params[:type].constantize) %> +<% else %> + <%= render layout: "accounts/new/container", locals: { title: t(".title") } do %> +
+ <%= render "account_type", accountable: Depository.new %> + <%= render "account_type", accountable: Investment.new %> + <%= render "account_type", accountable: Crypto.new %> + <%= render "account_type", accountable: Property.new %> + <%= render "account_type", accountable: Vehicle.new %> + <%= render "account_type", accountable: CreditCard.new %> + <%= render "account_type", accountable: Loan.new %> + <%= render "account_type", accountable: OtherAsset.new %> + <%= render "account_type", accountable: OtherLiability.new %> +
+ <% end %> +<% end %> \ No newline at end of file diff --git a/app/views/accounts/new/_container.html.erb b/app/views/accounts/new/_container.html.erb new file mode 100644 index 00000000000..7f61e131926 --- /dev/null +++ b/app/views/accounts/new/_container.html.erb @@ -0,0 +1,40 @@ +<%# locals: (title:, back_path: nil) %> + +<%= modal do %> +
+
+ <% if back_path %> + <%= link_to back_path, class: "flex w-8 h-8 shrink-0 grow-0 items-center justify-center rounded-lg bg-alpha-black-50 focus:outline-gray-300 focus:outline" do %> + <%= lucide_icon("arrow-left", class: "text-gray-500 w-5 h-5") %> + <% end %> + <% end %> + + <%= title %> +
+ +
+ + + + <%= yield %> +
+ +
+
+
+ Select + <%= lucide_icon("corner-down-left", class: "inline w-3 h-3") %> +
+
+ Navigate + <%= lucide_icon("arrow-up", class: "inline w-3 h-3") %> + <%= lucide_icon("arrow-down", class: "inline w-3 h-3") %> +
+
+
+ + ESC +
+
+
+<% end %> \ No newline at end of file diff --git a/app/views/accounts/new/_form.html.erb b/app/views/accounts/new/_form.html.erb new file mode 100644 index 00000000000..9b7991b79ba --- /dev/null +++ b/app/views/accounts/new/_form.html.erb @@ -0,0 +1,20 @@ +<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %> +
+ <%= 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") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.money_field :balance, label: t(".balance"), required: true, default_currency: Current.family.currency %> + + <% if account.accountable %> + <%= render permitted_accountable_partial(account, "form"), f: f %> + <% end %> +
+ + <%= f.submit %> +<% end %> diff --git a/app/views/accounts/new/_method_selector.html.erb b/app/views/accounts/new/_method_selector.html.erb new file mode 100644 index 00000000000..9fd96a6b253 --- /dev/null +++ b/app/views/accounts/new/_method_selector.html.erb @@ -0,0 +1,19 @@ +<%# locals: (path:) %> + +<%= render layout: "accounts/new/container", locals: { title: t(".title"), back_path: new_account_path } do %> +
+ <%= link_to path, class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-gray-50 border border-transparent focus:border focus:border-gray-200 px-2 hover:bg-gray-50 rounded-lg p-2" do %> + + <%= lucide_icon("keyboard", class: "text-gray-500 w-5 h-5") %> + + <%= t(".manual_entry") %> + <% end %> + + + + <%= lucide_icon("link-2", class: "text-gray-500 w-5 h-5") %> + + <%= t(".connected_entry") %> + +
+<% end %> \ No newline at end of file diff --git a/app/views/depositories/_form.html.erb b/app/views/depositories/_form.html.erb new file mode 100644 index 00000000000..b19c578ecf8 --- /dev/null +++ b/app/views/depositories/_form.html.erb @@ -0,0 +1,36 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: depositories_path, + scope: :depository, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.select :subtype, + [["Checking", "checking"], ["Savings", "savings"]], + { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> +
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/depositories/new.html.erb b/app/views/depositories/new.html.erb new file mode 100644 index 00000000000..cd7b7da8f68 --- /dev/null +++ b/app/views/depositories/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "depositories/form", account: @account %> +<% end %> diff --git a/app/views/shared/_modal_form.html.erb b/app/views/shared/_modal_form.html.erb index 68a462ee76e..e0e69e0127f 100644 --- a/app/views/shared/_modal_form.html.erb +++ b/app/views/shared/_modal_form.html.erb @@ -3,9 +3,9 @@ <%= modal do %>
-
-

<%= title %>

- <%= lucide_icon("x", class: "w-5 h-5 text-gray-500", data: { action: "click->modal#close" }) %> +
+

<%= title %>

+ <%= lucide_icon("x", class: "cursor-pointer w-5 h-5 text-gray-500", data: { action: "click->modal#close" }) %>
<% if subtitle.present? %> diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index f7885d6c298..b220fbf83e6 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -1,5 +1,17 @@ --- en: + depositories: + create: + success: Depository account created + update: + success: Depository account updated + new: + title: Enter account balance + form: + name_placeholder: Chase checking account + name_label: Account name + balance: Current balance + subtype_prompt: Select account type accounts: account: has_issues: Issue detected. @@ -149,10 +161,12 @@ en: edit: Edit import: Import transactions new: - connected_entry: Securely link account with Plaid (coming soon) - csv_entry: Import accounts CSV - manual_entry: Enter account manually - title: Add an account + container: + manual_entry: Enter account balance + connected_entry: Link account (coming soon) + title: What would you like to add? + method_selector: + title: How would you like to add it? show: cash: Cash holdings: Holdings diff --git a/config/routes.rb b/config/routes.rb index 70e5903292b..812e6eca514 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,6 +85,7 @@ end end + resources :depositories, only: %i[new create update] resources :properties, only: %i[create update] resources :vehicles, only: %i[create update] resources :credit_cards, only: %i[create update] diff --git a/db/migrate/20241030151105_remove_account_mode.rb b/db/migrate/20241030151105_remove_account_mode.rb new file mode 100644 index 00000000000..7c01db1dce7 --- /dev/null +++ b/db/migrate/20241030151105_remove_account_mode.rb @@ -0,0 +1,5 @@ +class RemoveAccountMode < ActiveRecord::Migration[7.2] + def change + remove_column :accounts, :mode + end +end diff --git a/db/schema.rb b/db/schema.rb index 507fd0f97e3..b7556d35294 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_29_184115) do +ActiveRecord::Schema[7.2].define(version: 2024_10_30_151105) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -121,7 +121,6 @@ t.uuid "institution_id" t.virtual "classification", type: :string, as: "\nCASE\n WHEN ((accountable_type)::text = ANY ((ARRAY['Loan'::character varying, 'CreditCard'::character varying, '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" @@ -481,9 +480,7 @@ t.string "country_code" t.string "exchange_mic" t.string "exchange_acronym" - t.virtual "search_vector", type: :tsvector, as: "(setweight(to_tsvector('simple'::regconfig, (COALESCE(ticker, ''::character varying))::text), 'B'::\"char\") || to_tsvector('simple'::regconfig, (COALESCE(name, ''::character varying))::text))", stored: true t.index ["country_code"], name: "index_securities_on_country_code" - t.index ["search_vector"], name: "index_securities_on_search_vector", using: :gin t.index ["ticker", "exchange_mic"], name: "index_securities_on_ticker_and_exchange_mic", unique: true end @@ -524,14 +521,14 @@ t.string "mic", null: false t.string "country", null: false t.string "country_code", null: false - t.string "city", null: false + t.string "city" t.string "website" - t.string "timezone_name", null: false - t.string "timezone_abbr", null: false + t.string "timezone_name" + t.string "timezone_abbr" t.string "timezone_abbr_dst" - t.string "currency_code", null: false - t.string "currency_symbol", null: false - t.string "currency_name", null: false + t.string "currency_code" + t.string "currency_symbol" + t.string "currency_name" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["country"], name: "index_stock_exchanges_on_country" diff --git a/test/controllers/depositories_controller_test.rb b/test/controllers/depositories_controller_test.rb new file mode 100644 index 00000000000..8b91df9b769 --- /dev/null +++ b/test/controllers/depositories_controller_test.rb @@ -0,0 +1,45 @@ +require "test_helper" + +class DepositoriesControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @depository = depositories(:one) + end + + test "new" do + get new_depository_url + assert_response :success + end + + test "create" do + assert_difference [ "Account.count", "Depository.count" ], 1 do + post depositories_url, params: { + depository: { + name: "New depository", + balance: 10000, + currency: "USD", + subtype: "checking" + } + } + end + + assert_redirected_to Account.order(:created_at).last + assert_equal "Depository account created", flash[:notice] + end + + test "update" do + assert_no_difference [ "Account.count", "Depository.count" ] do + patch depository_url(@depository), params: { + depository: { + name: "Updated name", + balance: 10000, + currency: "USD", + subtype: "checking" + } + } + end + + assert_redirected_to @depository + assert_equal "Depository account updated", flash[:notice] + end +end diff --git a/test/fixtures/accounts.yml b/test/fixtures/accounts.yml index 9afbc8a1c12..eeb616f3da3 100644 --- a/test/fixtures/accounts.yml +++ b/test/fixtures/accounts.yml @@ -5,7 +5,6 @@ other_asset: currency: USD accountable_type: OtherAsset accountable: one - mode: balance other_liability: family: dylan_family @@ -14,7 +13,6 @@ other_liability: currency: USD accountable_type: OtherLiability accountable: one - mode: balance depository: family: dylan_family @@ -24,7 +22,6 @@ depository: accountable_type: Depository accountable: one institution: chase - mode: transactions credit_card: family: dylan_family @@ -34,7 +31,6 @@ credit_card: accountable_type: CreditCard accountable: one institution: chase - mode: transactions investment: family: dylan_family @@ -43,7 +39,6 @@ investment: currency: USD accountable_type: Investment accountable: one - mode: transactions loan: family: dylan_family @@ -52,7 +47,6 @@ loan: currency: USD accountable_type: Loan accountable: one - mode: transactions property: family: dylan_family @@ -61,7 +55,6 @@ property: currency: USD accountable_type: Property accountable: one - mode: transactions vehicle: family: dylan_family @@ -70,4 +63,3 @@ vehicle: currency: USD accountable_type: Vehicle accountable: one - mode: transactions From 044c31e645ddeb0169d7a72f1489f2c4e610b2b2 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Thu, 31 Oct 2024 16:34:51 -0400 Subject: [PATCH 02/19] Activity view checkpoint --- app/controllers/account/entries_controller.rb | 10 +++ app/controllers/accounts_controller.rb | 37 ++------ app/controllers/concerns/filterable.rb | 23 ----- app/controllers/credit_cards_controller.rb | 31 +++---- app/controllers/cryptos_controller.rb | 33 +++++++ app/controllers/depositories_controller.rb | 17 ++-- app/controllers/investments_controller.rb | 33 +++++++ app/controllers/loans_controller.rb | 24 +++--- app/controllers/other_assets_controller.rb | 33 +++++++ .../other_liabilities_controller.rb | 33 +++++++ app/controllers/pages_controller.rb | 3 +- app/controllers/properties_controller.rb | 24 +++--- app/controllers/vehicles_controller.rb | 26 +++--- app/helpers/accounts_helper.rb | 23 +++++ app/helpers/application_helper.rb | 23 ----- .../controllers/bulk_select_controller.js | 11 ++- .../time_series_chart_controller.js | 2 +- app/models/account.rb | 31 +++---- app/models/period.rb | 16 ++-- .../account/entries/_selection_bar.html.erb | 15 ++++ app/views/account/entries/index.html.erb | 85 +++++++++++++++++++ app/views/accounts/show.html.erb | 9 +- app/views/accounts/show/_chart.html.erb | 7 ++ .../accounts/show/_chart_header.html.erb | 31 +++++++ app/views/accounts/show/_header.html.erb | 31 +++++++ app/views/accounts/summary.html.erb | 10 ++- app/views/credit_cards/_form.html.erb | 68 +++++++++++++++ app/views/credit_cards/new.html.erb | 3 + app/views/credit_cards/show.html.erb | 4 + app/views/cryptos/_form.html.erb | 36 ++++++++ app/views/cryptos/new.html.erb | 3 + app/views/cryptos/show.html.erb | 4 + app/views/depositories/show.html.erb | 16 ++++ app/views/investments/_form.html.erb | 36 ++++++++ app/views/investments/new.html.erb | 3 + app/views/investments/show.html.erb | 4 + app/views/loans/_form.html.erb | 57 +++++++++++++ app/views/loans/new.html.erb | 3 + app/views/loans/show.html.erb | 4 + app/views/other_assets/_form.html.erb | 36 ++++++++ app/views/other_assets/new.html.erb | 3 + app/views/other_assets/show.html.erb | 4 + app/views/other_liabilities/_form.html.erb | 36 ++++++++ app/views/other_liabilities/new.html.erb | 3 + app/views/other_liabilities/show.html.erb | 4 + app/views/properties/_form.html.erb | 79 +++++++++++++++++ app/views/properties/new.html.erb | 3 + app/views/properties/show.html.erb | 4 + app/views/vehicles/_form.html.erb | 64 ++++++++++++++ app/views/vehicles/new.html.erb | 3 + app/views/vehicles/show.html.erb | 4 + config/locales/views/account/entries/en.yml | 4 + config/locales/views/accounts/en.yml | 41 ++------- config/locales/views/credit_cards/en.yml | 22 +++++ config/locales/views/cryptos/en.yml | 15 ++++ config/locales/views/depositories/en.yml | 14 +++ config/locales/views/investments/en.yml | 15 ++++ config/locales/views/loans/en.yml | 18 ++++ config/locales/views/other_assets/en.yml | 15 ++++ config/locales/views/other_liabilities/en.yml | 15 ++++ config/locales/views/properties/en.yml | 27 +++++- config/locales/views/vehicles/en.yml | 19 ++++- config/routes.rb | 18 ++-- test/controllers/accounts_controller_test.rb | 42 +-------- .../credit_cards_controller_test.rb | 44 ++++++---- test/controllers/cryptos_controller_test.rb | 51 +++++++++++ .../depositories_controller_test.rb | 12 ++- .../investments_controller_test.rb | 51 +++++++++++ test/controllers/loans_controller_test.rb | 36 +++++--- .../other_assets_controller_test.rb | 51 +++++++++++ .../other_liabilities_controller_test.rb | 51 +++++++++++ .../controllers/properties_controller_test.rb | 24 ++++-- test/controllers/vehicles_controller_test.rb | 24 ++++-- test/fixtures/accounts.yml | 8 ++ 74 files changed, 1416 insertions(+), 306 deletions(-) delete mode 100644 app/controllers/concerns/filterable.rb create mode 100644 app/controllers/cryptos_controller.rb create mode 100644 app/controllers/investments_controller.rb create mode 100644 app/controllers/other_assets_controller.rb create mode 100644 app/controllers/other_liabilities_controller.rb create mode 100644 app/views/account/entries/_selection_bar.html.erb create mode 100644 app/views/account/entries/index.html.erb create mode 100644 app/views/accounts/show/_chart.html.erb create mode 100644 app/views/accounts/show/_chart_header.html.erb create mode 100644 app/views/accounts/show/_header.html.erb create mode 100644 app/views/credit_cards/_form.html.erb create mode 100644 app/views/credit_cards/new.html.erb create mode 100644 app/views/credit_cards/show.html.erb create mode 100644 app/views/cryptos/_form.html.erb create mode 100644 app/views/cryptos/new.html.erb create mode 100644 app/views/cryptos/show.html.erb create mode 100644 app/views/depositories/show.html.erb create mode 100644 app/views/investments/_form.html.erb create mode 100644 app/views/investments/new.html.erb create mode 100644 app/views/investments/show.html.erb create mode 100644 app/views/loans/_form.html.erb create mode 100644 app/views/loans/new.html.erb create mode 100644 app/views/loans/show.html.erb create mode 100644 app/views/other_assets/_form.html.erb create mode 100644 app/views/other_assets/new.html.erb create mode 100644 app/views/other_assets/show.html.erb create mode 100644 app/views/other_liabilities/_form.html.erb create mode 100644 app/views/other_liabilities/new.html.erb create mode 100644 app/views/other_liabilities/show.html.erb create mode 100644 app/views/properties/_form.html.erb create mode 100644 app/views/properties/new.html.erb create mode 100644 app/views/properties/show.html.erb create mode 100644 app/views/vehicles/_form.html.erb create mode 100644 app/views/vehicles/new.html.erb create mode 100644 app/views/vehicles/show.html.erb create mode 100644 config/locales/views/credit_cards/en.yml create mode 100644 config/locales/views/cryptos/en.yml create mode 100644 config/locales/views/depositories/en.yml create mode 100644 config/locales/views/investments/en.yml create mode 100644 config/locales/views/loans/en.yml create mode 100644 config/locales/views/other_assets/en.yml create mode 100644 config/locales/views/other_liabilities/en.yml create mode 100644 test/controllers/cryptos_controller_test.rb create mode 100644 test/controllers/investments_controller_test.rb create mode 100644 test/controllers/other_assets_controller_test.rb create mode 100644 test/controllers/other_liabilities_controller_test.rb diff --git a/app/controllers/account/entries_controller.rb b/app/controllers/account/entries_controller.rb index fb394f2dbfc..2985e655621 100644 --- a/app/controllers/account/entries_controller.rb +++ b/app/controllers/account/entries_controller.rb @@ -4,6 +4,11 @@ class Account::EntriesController < ApplicationController before_action :set_account before_action :set_entry, only: %i[edit update show destroy] + def index + @q = search_params + @pagy, @entries = pagy(@account.entries.search(@q).reverse_chronological, limit: params[:per_page] || "10") + end + def edit render entryable_view_path(:edit) end @@ -45,4 +50,9 @@ def set_entry def entry_params params.require(:account_entry).permit(:name, :date, :amount, :currency) end + + def search_params + params.fetch(:q, {}) + .permit(:search) + end end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 214193656fe..067b4f34f4c 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,7 +1,6 @@ class AccountsController < ApplicationController layout :with_sidebar - include Filterable before_action :set_account, only: %i[edit show destroy sync update] def index @@ -10,6 +9,7 @@ def index end def summary + @period = Period.from_param(params[:period]) snapshot = Current.family.snapshot(@period) @net_worth_series = snapshot[:net_worth_series] @asset_series = snapshot[:asset_series] @@ -18,25 +18,12 @@ def summary @account_groups = @accounts.by_group(period: @period, currency: Current.family.currency) end - def list - render layout: false - end - - def new - @account = Account.new(currency: Current.family.currency) - @account.accountable = Accountable.from_type(params[:type])&.new if params[:type].present? - @account.accountable.address = Address.new if @account.accountable.is_a?(Property) - - if params[:institution_id] - @account.institution = Current.family.institutions.find_by(id: params[:institution_id]) - end - end - def show + redirect_to @account.accountable end - def edit - @account.accountable.build_address if @account.accountable.is_a?(Property) && @account.accountable.address.blank? + def list + render layout: false end def update @@ -44,18 +31,6 @@ def update redirect_back_or_to account_path(@account), notice: t(".success") end - def create - @account = Current.family - .accounts - .create_with_optional_start_balance! \ - attributes: account_params.except(:start_date, :start_balance), - start_date: account_params[:start_date], - start_balance: account_params[:start_balance] - @account.sync_later - - redirect_back_or_to account_path(@account), notice: t(".success") - end - def destroy @account.destroy! redirect_to accounts_path, notice: t(".success") @@ -79,6 +54,8 @@ def set_account end def account_params - params.require(:account).permit(:name, :accountable_type, :mode, :balance, :start_date, :start_balance, :currency, :subtype, :is_active, :institution_id) + params.require(:account).permit( + :name, :balance, :currency, :is_active, :institution_id + ) end end diff --git a/app/controllers/concerns/filterable.rb b/app/controllers/concerns/filterable.rb deleted file mode 100644 index 4fe42f45fab..00000000000 --- a/app/controllers/concerns/filterable.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Filterable - extend ActiveSupport::Concern - - included do - before_action :set_period - end - - private - - def set_period - @period = Period.find_by_name(params[:period]) - if @period.nil? - start_date = params[:start_date].presence&.to_date - end_date = params[:end_date].presence&.to_date - if start_date.is_a?(Date) && end_date.is_a?(Date) && start_date <= end_date - @period = Period.new(name: "custom", date_range: start_date..end_date) - else - params[:period] = "last_30_days" - @period = Period.find_by_name(params[:period]) - end - end - end -end diff --git a/app/controllers/credit_cards_controller.rb b/app/controllers/credit_cards_controller.rb index bb416ce78c1..6560d6ac8d4 100644 --- a/app/controllers/credit_cards_controller.rb +++ b/app/controllers/credit_cards_controller.rb @@ -1,33 +1,34 @@ class CreditCardsController < ApplicationController - before_action :set_account, only: :update + before_action :set_account, only: [ :update, :show ] - def create - account = Current.family - .accounts - .create_with_optional_start_balance! \ - attributes: account_params.except(:start_date, :start_balance), - start_date: account_params[:start_date], - start_balance: account_params[:start_balance] + def new + @account = Current.family.accounts.credit_cards.build( + currency: Current.family.currency + ) + end + + def show + end - account.sync_later + def create + account = Current.family.accounts.create_and_sync(credit_card_params) redirect_to account, notice: t(".success") end def update - @account.update_with_sync!(account_params) + @account.update_with_sync!(credit_card_params) redirect_to @account, notice: t(".success") end private - def set_account - @account = Current.family.accounts.find(params[:id]) + @account = Current.family.accounts.credit_cards.find_by(accountable_id: params[:id]) end - def account_params - params.require(:account) + def credit_card_params + params.require(:credit_card) .permit( - :name, :balance, :institution_id, :mode, :start_date, :start_balance, :currency, :accountable_type, + :name, :balance, :institution_id, :currency, :accountable_type, accountable_attributes: [ :id, :available_credit, diff --git a/app/controllers/cryptos_controller.rb b/app/controllers/cryptos_controller.rb new file mode 100644 index 00000000000..bfa62ae6e7d --- /dev/null +++ b/app/controllers/cryptos_controller.rb @@ -0,0 +1,33 @@ +class CryptosController < AccountsController + before_action :set_account, only: [ :update, :show ] + + def new + @account = Current.family.accounts.cryptos.build( + currency: Current.family.currency, + ) + end + + def show + end + + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(account_params) + redirect_to @account, notice: t(".success") + end + + private + def set_account + @account = Current.family.accounts.cryptos.find_by(accountable_id: params[:id]) + end + + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :accountable_type + ) + end +end diff --git a/app/controllers/depositories_controller.rb b/app/controllers/depositories_controller.rb index 83bdb834a8f..34f6030044f 100644 --- a/app/controllers/depositories_controller.rb +++ b/app/controllers/depositories_controller.rb @@ -1,5 +1,5 @@ class DepositoriesController < AccountsController - before_action :set_account, only: [ :update ] + before_action :set_account, only: [ :show, :update ] def new @account = Current.family.accounts.depositories.build( @@ -7,15 +7,16 @@ def new ) end + def show + end + def create - @account = Current.family.accounts.create!( - depository_params.merge(accountable: Depository.new) - ) + @account = Current.family.accounts.create_and_sync(account_params) redirect_to @account, notice: t(".success") end def update - @account.update_with_sync!(depository_params) + @account.update_with_sync!(account_params) redirect_to @account, notice: t(".success") end @@ -24,9 +25,9 @@ def set_account @account = Current.family.accounts.depositories.find_by(accountable_id: params[:id]) end - def depository_params - params.require(:depository).permit( - :name, :balance, :subtype, :currency + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :accountable_type ) end end diff --git a/app/controllers/investments_controller.rb b/app/controllers/investments_controller.rb new file mode 100644 index 00000000000..bef805857dc --- /dev/null +++ b/app/controllers/investments_controller.rb @@ -0,0 +1,33 @@ +class InvestmentsController < AccountsController + before_action :set_account, only: [ :update, :show ] + + def new + @account = Current.family.accounts.investments.build( + currency: Current.family.currency, + ) + end + + def show + end + + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(account_params) + redirect_to @account, notice: t(".success") + end + + private + def set_account + @account = Current.family.accounts.investments.find_by(accountable_id: params[:id]) + end + + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :accountable_type + ) + end +end diff --git a/app/controllers/loans_controller.rb b/app/controllers/loans_controller.rb index 1b704290d54..a616834d8d1 100644 --- a/app/controllers/loans_controller.rb +++ b/app/controllers/loans_controller.rb @@ -1,15 +1,17 @@ class LoansController < ApplicationController - before_action :set_account, only: :update + before_action :set_account, only: [ :update, :show ] - def create - account = Current.family - .accounts - .create_with_optional_start_balance! \ - attributes: account_params.except(:start_date, :start_balance), - start_date: account_params[:start_date], - start_balance: account_params[:start_balance] + def new + @account = Current.family.accounts.loans.build( + currency: Current.family.currency + ) + end - account.sync_later + def show + end + + def create + account = Current.family.accounts.create_and_sync(account_params) redirect_to account, notice: t(".success") end @@ -21,13 +23,13 @@ def update private def set_account - @account = Current.family.accounts.find(params[:id]) + @account = Current.family.accounts.loans.find_by(accountable_id: params[:id]) end def account_params params.require(:account) .permit( - :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type, + :name, :balance, :institution_id, :currency, :accountable_type, accountable_attributes: [ :id, :rate_type, diff --git a/app/controllers/other_assets_controller.rb b/app/controllers/other_assets_controller.rb new file mode 100644 index 00000000000..29a1cd26a9e --- /dev/null +++ b/app/controllers/other_assets_controller.rb @@ -0,0 +1,33 @@ +class OtherAssetsController < AccountsController + before_action :set_account, only: [ :update, :show ] + + def new + @account = Current.family.accounts.other_assets.build( + currency: Current.family.currency, + ) + end + + def show + end + + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(account_params) + redirect_to @account, notice: t(".success") + end + + private + def set_account + @account = Current.family.accounts.other_assets.find_by(accountable_id: params[:id]) + end + + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :accountable_type + ) + end +end diff --git a/app/controllers/other_liabilities_controller.rb b/app/controllers/other_liabilities_controller.rb new file mode 100644 index 00000000000..99873e95ec6 --- /dev/null +++ b/app/controllers/other_liabilities_controller.rb @@ -0,0 +1,33 @@ +class OtherLiabilitiesController < AccountsController + before_action :set_account, only: [ :update, :show ] + + def new + @account = Current.family.accounts.other_liabilities.build( + currency: Current.family.currency, + ) + end + + def show + end + + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(account_params) + redirect_to @account, notice: t(".success") + end + + private + def set_account + @account = Current.family.accounts.other_liabilities.find_by(accountable_id: params[:id]) + end + + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :accountable_type + ) + end +end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index f495d465c64..9af9d6630d0 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -2,9 +2,8 @@ class PagesController < ApplicationController skip_before_action :authenticate_user!, only: %i[early_access] layout :with_sidebar, except: %i[early_access] - include Filterable - def dashboard + @period = Period.from_param(params[:period]) snapshot = Current.family.snapshot(@period) @net_worth_series = snapshot[:net_worth_series] @asset_series = snapshot[:asset_series] diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb index e37344d4462..1f9de726326 100644 --- a/app/controllers/properties_controller.rb +++ b/app/controllers/properties_controller.rb @@ -1,15 +1,17 @@ class PropertiesController < ApplicationController - before_action :set_account, only: :update + before_action :set_account, only: [ :update, :show ] - def create - account = Current.family - .accounts - .create_with_optional_start_balance! \ - attributes: account_params.except(:start_date, :start_balance), - start_date: account_params[:start_date], - start_balance: account_params[:start_balance] + def new + @account = Current.family.accounts.properties.build( + currency: Current.family.currency + ) + end - account.sync_later + def show + end + + def create + account = Current.family.accounts.create_and_sync(account_params) redirect_to account, notice: t(".success") end @@ -21,13 +23,13 @@ def update private def set_account - @account = Current.family.accounts.find(params[:id]) + @account = Current.family.accounts.properties.find_by(accountable_id: params[:id]) end def account_params params.require(:account) .permit( - :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type, + :name, :balance, :institution_id, :currency, :accountable_type, accountable_attributes: [ :id, :year_built, diff --git a/app/controllers/vehicles_controller.rb b/app/controllers/vehicles_controller.rb index fe41a42fedc..39dad23a605 100644 --- a/app/controllers/vehicles_controller.rb +++ b/app/controllers/vehicles_controller.rb @@ -1,16 +1,18 @@ class VehiclesController < ApplicationController - before_action :set_account, only: :update + before_action :set_account, only: [ :update, :show ] - def create - account = Current.family - .accounts - .create_with_optional_start_balance! \ - attributes: account_params.except(:start_date, :start_balance), - start_date: account_params[:start_date], - start_balance: account_params[:start_balance] + def new + @account = Current.family.accounts.vehicles.build( + currency: Current.family.currency + ) + end + + def show + end - account.sync_later - redirect_to account, notice: t(".success") + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") end def update @@ -21,13 +23,13 @@ def update private def set_account - @account = Current.family.accounts.find(params[:id]) + @account = Current.family.accounts.vehicles.find_by(accountable_id: params[:id]) end def account_params params.require(:account) .permit( - :name, :balance, :institution_id, :start_date, :mode, :start_balance, :currency, :accountable_type, + :name, :balance, :institution_id, :currency, :accountable_type, accountable_attributes: [ :id, :make, diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 924558eb6ff..c5fb5b7705f 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -3,6 +3,29 @@ def new_accountable_path(type) "/#{type.model_name.plural}/new" end + def period_label(period) + return "since account creation" if period.date_range.begin.nil? + start_date, end_date = period.date_range.first, period.date_range.last + + return "Starting from #{start_date.strftime('%b %d, %Y')}" if end_date.nil? + return "Ending at #{end_date.strftime('%b %d, %Y')}" if start_date.nil? + + days_apart = (end_date - start_date).to_i + + case days_apart + when 1 + "vs. yesterday" + when 7 + "vs. last week" + when 30, 31 + "vs. last month" + when 365, 366 + "vs. last year" + else + "from #{start_date.strftime('%b %d, %Y')} to #{end_date.strftime('%b %d, %Y')}" + end + end + def permitted_accountable_partial(account, name = nil) permitted_names = %w[tooltip header tabs form] folder = account.accountable_type.underscore diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ca83e38d730..f1194764e63 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -122,29 +122,6 @@ def trend_styles(trend) { bg_class: bg_class, text_class: text_class, symbol: symbol, icon: icon } end - def period_label(period) - return "since account creation" if period.date_range.begin.nil? - start_date, end_date = period.date_range.first, period.date_range.last - - return "Starting from #{start_date.strftime('%b %d, %Y')}" if end_date.nil? - return "Ending at #{end_date.strftime('%b %d, %Y')}" if start_date.nil? - - days_apart = (end_date - start_date).to_i - - case days_apart - when 1 - "vs. yesterday" - when 7 - "vs. last week" - when 30, 31 - "vs. last month" - when 365, 366 - "vs. last year" - else - "from #{start_date.strftime('%b %d, %Y')} to #{end_date.strftime('%b %d, %Y')}" - end - end - # Wrapper around I18n.l to support custom date formats def format_date(object, format = :default, options = {}) date = object.to_date diff --git a/app/javascript/controllers/bulk_select_controller.js b/app/javascript/controllers/bulk_select_controller.js index 104d2aa65bb..023e97dad98 100644 --- a/app/javascript/controllers/bulk_select_controller.js +++ b/app/javascript/controllers/bulk_select_controller.js @@ -10,7 +10,8 @@ export default class extends Controller { "bulkEditDrawerTitle", ]; static values = { - resource: String, + singularLabel: String, + pluralLabel: String, selectedIds: { type: Array, default: [] }, }; @@ -132,9 +133,11 @@ export default class extends Controller { } _pluralizedResourceName() { - return `${this.resourceValue}${ - this.selectedIdsValue.length === 1 ? "" : "s" - }`; + if (this.selectedIdsValue.length === 1) { + return this.singularLabelValue; + } + + return this.pluralLabelValue; } _updateGroups() { diff --git a/app/javascript/controllers/time_series_chart_controller.js b/app/javascript/controllers/time_series_chart_controller.js index 7660f3f4abf..ebd0e3fa136 100644 --- a/app/javascript/controllers/time_series_chart_controller.js +++ b/app/javascript/controllers/time_series_chart_controller.js @@ -542,7 +542,7 @@ export default class extends Controller { return d3 .scaleLinear() - .rangeRound([this._d3ContainerHeight, 0]) + .rangeRound([this._d3ContainerHeight - 30, 0]) .domain([dataMin - padding, dataMax + padding]); } } diff --git a/app/models/account.rb b/app/models/account.rb index f75ca9f5144..2e9ca1e30c1 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -58,29 +58,30 @@ def by_group(period: Period.all, currency: Money.default_currency.iso_code) grouped_accounts end - def create_with_optional_start_balance!(attributes:, start_date: nil, start_balance: nil) - transaction do - attributes[:accountable_attributes] ||= {} # Ensure accountable is created - account = new(attributes) + def create_and_sync(attributes) + attributes[:accountable_attributes] ||= {} # Ensure accountable is created, even if empty + account = new(attributes) - # Always initialize an account with a valuation entry to begin tracking value history - account.entries.build \ + transaction do + # Create 2 valuations for new accounts to establish a value history for users to see + account.entries.build( date: Date.current, amount: account.balance, currency: account.currency, entryable: Account::Valuation.new - - if start_date.present? && start_balance.present? - account.entries.build \ - date: start_date, - amount: start_balance, - currency: account.currency, - entryable: Account::Valuation.new - end + ) + account.entries.build( + date: 1.day.ago.to_date, + amount: 0, + currency: account.currency, + entryable: Account::Valuation.new + ) account.save! - account end + + account.sync_later + account end end diff --git a/app/models/period.rb b/app/models/period.rb index 4a8a3ffa89b..4a1e876234a 100644 --- a/app/models/period.rb +++ b/app/models/period.rb @@ -1,12 +1,18 @@ class Period attr_reader :name, :date_range - def self.find_by_name(name) - INDEX[name] - end + class << self + def from_param(param) + find_by_name(param) || self.last_30_days + end - def self.names - INDEX.keys.sort + def find_by_name(name) + INDEX[name] + end + + def names + INDEX.keys.sort + end end def initialize(name: "custom", date_range:) diff --git a/app/views/account/entries/_selection_bar.html.erb b/app/views/account/entries/_selection_bar.html.erb new file mode 100644 index 00000000000..f4f7208e49b --- /dev/null +++ b/app/views/account/entries/_selection_bar.html.erb @@ -0,0 +1,15 @@ +
+
+ <%= check_box_tag "entry_selection", 1, true, class: "maybe-checkbox maybe-checkbox--dark", data: { action: "bulk-select#deselectAll" } %> + +

+
+ +
+ <%= form_with url: bulk_delete_transactions_path, data: { turbo_confirm: true, turbo_frame: "_top" } do %> + + <% end %> +
+
diff --git a/app/views/account/entries/index.html.erb b/app/views/account/entries/index.html.erb new file mode 100644 index 00000000000..f4668463083 --- /dev/null +++ b/app/views/account/entries/index.html.erb @@ -0,0 +1,85 @@ +<%= turbo_frame_tag dom_id(@account, "entries") do %> +
+
+ <%= tag.h2 t(".title"), class: "font-medium text-lg" %> +
+ + +
+
+ +
+ <%= form_with url: account_entries_path(@account), + id: "entries-search", + scope: :q, + method: :get, + data: { controller: "auto-submit-form" } do |form| %> +
+
+
+ <%= lucide_icon("search", class: "w-5 h-5 text-gray-500") %> + <%= form.text_field :search, + placeholder: "Search entries by name", + value: @q[:search], + class: "form-field__input placeholder:text-sm placeholder:text-gray-500", + "data-auto-submit-form-target": "auto" %> +
+
+
+ <% end %> +
+ + <%= tag.div id: dom_id(@account, "entries_bulk_select"), + data: { + controller: "bulk-select", + bulk_select_singular_label_value: t(".entry"), + bulk_select_plural_label_value: t(".entries") + } do %> + + +
+
+ <%= check_box_tag "selection_entry", + class: "maybe-checkbox maybe-checkbox--light", + data: { action: "bulk-select#togglePageSelection" } %> +

<%= t(".date") %>

+
+ <%= tag.p t(".amount"), class: "col-span-2 justify-self-end" %> + <%= tag.p t(".balance"), class: "col-span-2 justify-self-end" %> +
+ +
+
+ <% if @entries.any? %> +
+ <%= entries_by_date(@entries) do |entries| %> + <%= render entries %> + <% end %> +
+ <% else %> +

<%= t(".no_entries") %>

+ <% end %> +
+ +
+ <%= render "pagination", pagy: @pagy %> +
+
+ <% end %> +
+<% end %> diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb index d250a38fb96..24d7df2944b 100644 --- a/app/views/accounts/show.html.erb +++ b/app/views/accounts/show.html.erb @@ -1,6 +1,7 @@ <%= turbo_stream_from @account %> -<% series = @account.series(period: @period) %> +<% period = Period.from_param(params[:period]) %> +<% series = @account.series(period: period) %> <% trend = series.trend %> <%= tag.div id: dom_id(@account), class: "space-y-4" do %> @@ -45,17 +46,17 @@ <%= tag.span "(#{trend.percent}%)", style: "color: #{trend.color}" %> <% end %> - <%= tag.span period_label(@period), class: "text-gray-500" %> + <%= tag.span period_label(period), class: "text-gray-500" %>
<%= form_with url: account_path(@account), method: :get, data: { controller: "auto-submit-form" } do |form| %> - <%= period_select form: form, selected: @period.name %> + <%= period_select form: form, selected: period.name %> <% end %>
- <%= render "shared/line_chart", series: @account.series(period: @period) %> + <%= render "shared/line_chart", series: series %>
diff --git a/app/views/accounts/show/_chart.html.erb b/app/views/accounts/show/_chart.html.erb new file mode 100644 index 00000000000..ae68eb1377f --- /dev/null +++ b/app/views/accounts/show/_chart.html.erb @@ -0,0 +1,7 @@ +<%# locals: (account:) %> + +<% period = Period.from_param(params[:period]) %> + +
+ <%= render "shared/line_chart", series: account.series(period: period) %> +
diff --git a/app/views/accounts/show/_chart_header.html.erb b/app/views/accounts/show/_chart_header.html.erb new file mode 100644 index 00000000000..c3ea40d3af9 --- /dev/null +++ b/app/views/accounts/show/_chart_header.html.erb @@ -0,0 +1,31 @@ +<%# locals: (account:, title: nil, tooltip: nil) %> + +<% period = Period.from_param(params[:period]) %> +<% series = account.series(period: period) %> +<% trend = series.trend %> + +
+
+
+ <%= tag.p title || t(".balance"), class: "text-sm font-medium text-gray-500" %> + <%= tooltip %> +
+ + <%= tag.p format_money(account.value), class: "text-gray-900 text-3xl font-medium" %> + +
+ <% if trend.direction.flat? %> + <%= tag.span t(".no_change"), class: "text-gray-500" %> + <% else %> + <%= tag.span format_money(trend.value), style: "color: #{trend.color}" %> + <%= tag.span "(#{trend.percent}%)", style: "color: #{trend.color}" %> + <% end %> + + <%= tag.span period_label(period), class: "text-gray-500" %> +
+
+ + <%= form_with url: request.path, method: :get, data: { controller: "auto-submit-form" } do |form| %> + <%= period_select form: form, selected: period.name %> + <% end %> +
\ No newline at end of file diff --git a/app/views/accounts/show/_header.html.erb b/app/views/accounts/show/_header.html.erb new file mode 100644 index 00000000000..a1905c00e43 --- /dev/null +++ b/app/views/accounts/show/_header.html.erb @@ -0,0 +1,31 @@ +<%# locals: (account:) %> + +
+
+ <% content = yield %> + + <% if content.present? %> + <%= content %> + <% else %> +
+ <%= render "accounts/logo", account: account %> + +
+

<%= account.name %>

+
+
+ <% end %> + +
+ <%= button_to sync_account_path(@account), method: :post, class: "flex items-center gap-2", title: "Sync Account" do %> + <%= lucide_icon "refresh-cw", class: "w-4 h-4 text-gray-500 hover:text-gray-400" %> + <% end %> + + <%= render "menu", account: @account %> +
+
+ + <% if account.highest_priority_issue %> + <%= render partial: "issues/issue", locals: { issue: account.highest_priority_issue } %> + <% end %> +
\ No newline at end of file diff --git a/app/views/accounts/summary.html.erb b/app/views/accounts/summary.html.erb index db9ab322cc3..bd6ccb5e256 100644 --- a/app/views/accounts/summary.html.erb +++ b/app/views/accounts/summary.html.erb @@ -1,3 +1,5 @@ +<% period = Period.from_param(params[:period]) %> +
<%= render "header" %> @@ -7,7 +9,7 @@
<%= render partial: "shared/value_heading", locals: { label: "Assets", - period: @period, + period: period, value: Current.family.assets, trend: @asset_series.trend } %> @@ -23,7 +25,7 @@
<%= render partial: "shared/value_heading", locals: { label: "Liabilities", - period: @period, + period: period, size: "md", value: Current.family.liabilities, trend: @liability_series.trend @@ -46,7 +48,7 @@

<%= t(".new") %>

<% end %> <%= form_with url: summary_accounts_path, method: :get, data: { controller: "auto-submit-form" } do |form| %> - <%= period_select form: form, selected: @period.name %> + <%= period_select form: form, selected: period.name %> <% end %>
@@ -71,7 +73,7 @@

<%= t(".new") %>

<% end %> <%= form_with url: summary_accounts_path, method: :get, data: { controller: "auto-submit-form" } do |form| %> - <%= period_select form: form, selected: @period.name %> + <%= period_select form: form, selected: period.name %> <% end %>
diff --git a/app/views/credit_cards/_form.html.erb b/app/views/credit_cards/_form.html.erb new file mode 100644 index 00000000000..d5a21997007 --- /dev/null +++ b/app/views/credit_cards/_form.html.erb @@ -0,0 +1,68 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: credit_cards_path, + scope: :credit_card, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> + +
+
+ +
+ <%= f.fields_for :accountable do |credit_card_form| %> +
+ <%= credit_card_form.number_field :available_credit, + label: t(".available_credit"), + placeholder: t(".available_credit_placeholder"), + min: 0 %> +
+ +
+ <%= credit_card_form.number_field :minimum_payment, + label: t(".minimum_payment"), + placeholder: t(".minimum_payment_placeholder"), + min: 0 %> + <%= credit_card_form.number_field :apr, + label: t(".apr"), + placeholder: t(".apr_placeholder"), + min: 0, + step: 0.01 %> +
+ +
+ <%= credit_card_form.date_field :expiration_date, + label: t(".expiration_date") %> + <%= credit_card_form.number_field :annual_fee, + label: t(".annual_fee"), + placeholder: t(".annual_fee_placeholder"), + min: 0 %> +
+ <% end %> +
+
+
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/credit_cards/new.html.erb b/app/views/credit_cards/new.html.erb new file mode 100644 index 00000000000..eac1198870a --- /dev/null +++ b/app/views/credit_cards/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "credit_cards/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/credit_cards/show.html.erb b/app/views/credit_cards/show.html.erb new file mode 100644 index 00000000000..b917cdf59f7 --- /dev/null +++ b/app/views/credit_cards/show.html.erb @@ -0,0 +1,4 @@ +
+ Credit Card Show View +
+ \ No newline at end of file diff --git a/app/views/cryptos/_form.html.erb b/app/views/cryptos/_form.html.erb new file mode 100644 index 00000000000..3e7dc197151 --- /dev/null +++ b/app/views/cryptos/_form.html.erb @@ -0,0 +1,36 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: cryptos_path, + scope: :crypto, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.select :subtype, + [["Bitcoin", "bitcoin"], ["Ethereum", "ethereum"], ["Other", "other"]], + { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> +
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/cryptos/new.html.erb b/app/views/cryptos/new.html.erb new file mode 100644 index 00000000000..c9ee3c7b93f --- /dev/null +++ b/app/views/cryptos/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "cryptos/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/cryptos/show.html.erb b/app/views/cryptos/show.html.erb new file mode 100644 index 00000000000..04672322b65 --- /dev/null +++ b/app/views/cryptos/show.html.erb @@ -0,0 +1,4 @@ +
+ Crypto Show View +
+ \ No newline at end of file diff --git a/app/views/depositories/show.html.erb b/app/views/depositories/show.html.erb new file mode 100644 index 00000000000..64af6041c55 --- /dev/null +++ b/app/views/depositories/show.html.erb @@ -0,0 +1,16 @@ +<%= turbo_stream_from @account %> + +<%= tag.div id: dom_id(@account), class: "space-y-4" do %> + <%= render "accounts/show/header", account: @account %> + +
+ <%= render "accounts/show/chart_header", account: @account %> + <%= render "accounts/show/chart", account: @account %> +
+ +
+ <%= turbo_frame_tag dom_id(@account, :entries), src: account_entries_path(@account) do %> + <%= render "account/entries/loading" %> + <% end %> +
+<% end %> diff --git a/app/views/investments/_form.html.erb b/app/views/investments/_form.html.erb new file mode 100644 index 00000000000..3f7e02baa46 --- /dev/null +++ b/app/views/investments/_form.html.erb @@ -0,0 +1,36 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: investments_path, + scope: :investment, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.select :subtype, + Investment::SUBTYPES, + { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> +
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/investments/new.html.erb b/app/views/investments/new.html.erb new file mode 100644 index 00000000000..f9d003f6b17 --- /dev/null +++ b/app/views/investments/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "investments/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/investments/show.html.erb b/app/views/investments/show.html.erb new file mode 100644 index 00000000000..b926d425708 --- /dev/null +++ b/app/views/investments/show.html.erb @@ -0,0 +1,4 @@ +
+ Investment Show View +
+ \ No newline at end of file diff --git a/app/views/loans/_form.html.erb b/app/views/loans/_form.html.erb new file mode 100644 index 00000000000..adc8ced45fe --- /dev/null +++ b/app/views/loans/_form.html.erb @@ -0,0 +1,57 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: loans_path, + scope: :loan, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> + +
+
+ +
+ <%= f.fields_for :accountable do |loan_form| %> +
+ <%= loan_form.number_field :interest_rate, + label: t(".interest_rate"), + placeholder: t(".interest_rate_placeholder"), + min: 0, + step: 0.01 %> + <%= loan_form.select :rate_type, + [["Fixed", "fixed"], ["Variable", "variable"], ["Adjustable", "adjustable"]], + { label: t(".rate_type") } %> +
+ +
+ <%= loan_form.number_field :term_months, + label: t(".term_months"), + placeholder: t(".term_months_placeholder") %> +
+ <% end %> +
+
+
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/loans/new.html.erb b/app/views/loans/new.html.erb new file mode 100644 index 00000000000..1502ba4191a --- /dev/null +++ b/app/views/loans/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "loans/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/loans/show.html.erb b/app/views/loans/show.html.erb new file mode 100644 index 00000000000..041d501ce3b --- /dev/null +++ b/app/views/loans/show.html.erb @@ -0,0 +1,4 @@ +
+ Loan Show View +
+ \ No newline at end of file diff --git a/app/views/other_assets/_form.html.erb b/app/views/other_assets/_form.html.erb new file mode 100644 index 00000000000..5896a400647 --- /dev/null +++ b/app/views/other_assets/_form.html.erb @@ -0,0 +1,36 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: other_assets_path, + scope: :other_asset, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.select :subtype, + [["Other", "other"]], + { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> +
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/other_assets/new.html.erb b/app/views/other_assets/new.html.erb new file mode 100644 index 00000000000..d4135fbacb5 --- /dev/null +++ b/app/views/other_assets/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "other_assets/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/other_assets/show.html.erb b/app/views/other_assets/show.html.erb new file mode 100644 index 00000000000..869803506a7 --- /dev/null +++ b/app/views/other_assets/show.html.erb @@ -0,0 +1,4 @@ +
+ Other Asset Show View +
+ \ No newline at end of file diff --git a/app/views/other_liabilities/_form.html.erb b/app/views/other_liabilities/_form.html.erb new file mode 100644 index 00000000000..4c5c7dd51f1 --- /dev/null +++ b/app/views/other_liabilities/_form.html.erb @@ -0,0 +1,36 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: other_liabilities_path, + scope: :other_liability, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.select :subtype, + [["Other", "other"]], + { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> +
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/other_liabilities/new.html.erb b/app/views/other_liabilities/new.html.erb new file mode 100644 index 00000000000..75a76513657 --- /dev/null +++ b/app/views/other_liabilities/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "other_liabilities/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/other_liabilities/show.html.erb b/app/views/other_liabilities/show.html.erb new file mode 100644 index 00000000000..95046fca363 --- /dev/null +++ b/app/views/other_liabilities/show.html.erb @@ -0,0 +1,4 @@ +
+ Other Liability Show View +
+ \ No newline at end of file diff --git a/app/views/properties/_form.html.erb b/app/views/properties/_form.html.erb new file mode 100644 index 00000000000..143398e8f25 --- /dev/null +++ b/app/views/properties/_form.html.erb @@ -0,0 +1,79 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: properties_path, + scope: :property, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> + +
+
+ +
+ <%= f.fields_for :accountable do |property_form| %> +
+ <%= property_form.number_field :year_built, + label: t(".year_built"), + placeholder: t(".year_built_placeholder"), + min: 1800, + max: Time.current.year %> +
+ +
+ <%= property_form.number_field :area_value, + label: t(".area"), + placeholder: t(".area_placeholder"), + min: 0 %> + <%= property_form.select :area_unit, + [["Square Feet", "sqft"], ["Square Meters", "sqm"]], + { label: t(".area_unit") } %> +
+ + <%= property_form.fields_for :address do |address_form| %> + <%= address_form.text_field :line1, + label: t(".address_line1"), + placeholder: t(".address_line1_placeholder") %> + <%= address_form.text_field :line2, + label: t(".address_line2"), + placeholder: t(".address_line2_placeholder") %> + <%= address_form.text_field :locality, + label: t(".locality"), + placeholder: t(".locality_placeholder") %> + <%= address_form.text_field :region, + label: t(".region"), + placeholder: t(".region_placeholder") %> + <%= address_form.text_field :postal_code, + label: t(".postal_code"), + placeholder: t(".postal_code_placeholder") %> + <%= address_form.text_field :country, + label: t(".country"), + placeholder: t(".country_placeholder") %> + <% end %> + <% end %> +
+
+
+ + <%= f.submit %> +<% end %> diff --git a/app/views/properties/new.html.erb b/app/views/properties/new.html.erb new file mode 100644 index 00000000000..d6b18b2fe29 --- /dev/null +++ b/app/views/properties/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "properties/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/properties/show.html.erb b/app/views/properties/show.html.erb new file mode 100644 index 00000000000..3a08f7c515b --- /dev/null +++ b/app/views/properties/show.html.erb @@ -0,0 +1,4 @@ +
+ Property Show View +
+ \ No newline at end of file diff --git a/app/views/vehicles/_form.html.erb b/app/views/vehicles/_form.html.erb new file mode 100644 index 00000000000..9e91ef63037 --- /dev/null +++ b/app/views/vehicles/_form.html.erb @@ -0,0 +1,64 @@ +<%# locals: (account:) %> + +<%= styled_form_with model: account, + url: vehicles_path, + scope: :vehicle, + class: "flex flex-col gap-4 justify-between grow", + data: { turbo: false } do |f| %> +
+ <%= f.hidden_field :accountable_type %> + + <%= f.text_field :name, + placeholder: t(".name_placeholder"), + required: "required", + label: t(".name_label") %> + + <% if account.new_record? %> + <%= f.hidden_field :institution_id %> + <% else %> + <%= f.collection_select :institution_id, + Current.family.institutions.alphabetically, + :id, :name, + { include_blank: t(".ungrouped"), label: t(".institution") } %> + <% end %> + + <%= f.money_field :balance, + label: t(".balance"), + required: true, + default_currency: Current.family.currency %> + +
+
+ +
+ <%= f.fields_for :accountable do |vehicle_form| %> +
+ <%= vehicle_form.text_field :make, + label: t(".make"), + placeholder: t(".make_placeholder") %> + <%= vehicle_form.text_field :model, + label: t(".model"), + placeholder: t(".model_placeholder") %> +
+ +
+ <%= vehicle_form.number_field :year, + label: t(".year"), + placeholder: t(".year_placeholder"), + min: 1900, + max: Time.current.year + 1 %> + <%= vehicle_form.number_field :mileage_value, + label: t(".mileage"), + placeholder: t(".mileage_placeholder"), + min: 0 %> + <%= vehicle_form.select :mileage_unit, + [["Miles", "mi"], ["Kilometers", "km"]], + { label: t(".mileage_unit") } %> +
+ <% end %> +
+
+
+ + <%= f.submit %> +<% end %> \ No newline at end of file diff --git a/app/views/vehicles/new.html.erb b/app/views/vehicles/new.html.erb new file mode 100644 index 00000000000..a1d378c6d08 --- /dev/null +++ b/app/views/vehicles/new.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".title") do %> + <%= render "vehicles/form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/vehicles/show.html.erb b/app/views/vehicles/show.html.erb new file mode 100644 index 00000000000..b3a6bb672ae --- /dev/null +++ b/app/views/vehicles/show.html.erb @@ -0,0 +1,4 @@ +
+ Vehicle Show View +
+ \ No newline at end of file diff --git a/config/locales/views/account/entries/en.yml b/config/locales/views/account/entries/en.yml index ca0d6e8c8dd..a56db392c3d 100644 --- a/config/locales/views/account/entries/en.yml +++ b/config/locales/views/account/entries/en.yml @@ -2,6 +2,10 @@ en: account: entries: + index: + title: Activity + entry: entry + entries: entries destroy: success: Entry deleted empty: diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index b220fbf83e6..5310073f33e 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -1,17 +1,5 @@ --- en: - depositories: - create: - success: Depository account created - update: - success: Depository account updated - new: - title: Enter account balance - form: - name_placeholder: Chase checking account - name_label: Account name - balance: Current balance - subtype_prompt: Select account type accounts: account: has_issues: Issue detected. @@ -49,8 +37,7 @@ en: tooltip: cash: Cash holdings: Holdings - total_value_tooltip: The total value is the sum of cash balance and your - holdings value, minus margin loans. + total_value_tooltip: The total value is the sum of cash balance and your holdings value, minus margin loans. loan: form: interest_rate: Interest rate @@ -137,9 +124,7 @@ en: 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_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 @@ -152,11 +137,7 @@ en: other_accounts: Other accounts menu: 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_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 import: Import transactions @@ -180,24 +161,12 @@ 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. + no_liabilities_description: Add a liability either via connection, importing or entering manually. sync_all: success: Successfully queued accounts for syncing. sync_all_button: sync: Sync all update: success: Account updated - credit_cards: - create: - success: Credit card created successfully - update: - success: Credit card updated successfully - loans: - create: - success: Loan created successfully - update: - success: Loan updated successfully diff --git a/config/locales/views/credit_cards/en.yml b/config/locales/views/credit_cards/en.yml new file mode 100644 index 00000000000..63d6a75a8a7 --- /dev/null +++ b/config/locales/views/credit_cards/en.yml @@ -0,0 +1,22 @@ +--- +en: + credit_cards: + create: + success: Credit card account created + update: + success: Credit card account updated + new: + title: Enter credit card details + form: + name_placeholder: Chase Sapphire + name_label: Card name + balance: Current balance + 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' \ No newline at end of file diff --git a/config/locales/views/cryptos/en.yml b/config/locales/views/cryptos/en.yml new file mode 100644 index 00000000000..0b17ba0953d --- /dev/null +++ b/config/locales/views/cryptos/en.yml @@ -0,0 +1,15 @@ +--- +en: + cryptos: + create: + success: Crypto account created + update: + success: Crypto account updated + new: + title: Enter account balance + form: + name_placeholder: Bitcoin wallet + name_label: Account name + balance: Current balance + subtype_prompt: Select crypto type + none: None \ No newline at end of file diff --git a/config/locales/views/depositories/en.yml b/config/locales/views/depositories/en.yml new file mode 100644 index 00000000000..2962c3a3728 --- /dev/null +++ b/config/locales/views/depositories/en.yml @@ -0,0 +1,14 @@ +--- +en: + depositories: + create: + success: Depository account created + update: + success: Depository account updated + new: + title: Enter account balance + form: + name_placeholder: Chase checking account + name_label: Account name + balance: Current balance + subtype_prompt: Select account type \ No newline at end of file diff --git a/config/locales/views/investments/en.yml b/config/locales/views/investments/en.yml new file mode 100644 index 00000000000..98664a453db --- /dev/null +++ b/config/locales/views/investments/en.yml @@ -0,0 +1,15 @@ +--- +en: + investments: + create: + success: Investment account created + update: + success: Investment account updated + new: + title: Enter account balance + form: + name_placeholder: Vanguard brokerage account + name_label: Account name + balance: Current balance + subtype_prompt: Select investment type + none: None \ No newline at end of file diff --git a/config/locales/views/loans/en.yml b/config/locales/views/loans/en.yml new file mode 100644 index 00000000000..ccd0af8bc12 --- /dev/null +++ b/config/locales/views/loans/en.yml @@ -0,0 +1,18 @@ +--- +en: + loans: + create: + success: Loan account created + update: + success: Loan account updated + new: + title: Enter loan details + form: + name_placeholder: Home mortgage + name_label: Loan name + balance: Current balance + interest_rate: Interest rate + interest_rate_placeholder: '5.25' + rate_type: Rate type + term_months: Term (months) + term_months_placeholder: '360' \ No newline at end of file diff --git a/config/locales/views/other_assets/en.yml b/config/locales/views/other_assets/en.yml new file mode 100644 index 00000000000..65fecc9dfcd --- /dev/null +++ b/config/locales/views/other_assets/en.yml @@ -0,0 +1,15 @@ +--- +en: + other_assets: + create: + success: Other asset account created + update: + success: Other asset account updated + new: + title: Enter asset details + form: + name_placeholder: Art collection + name_label: Asset name + balance: Current value + subtype_prompt: Select asset type + none: None \ No newline at end of file diff --git a/config/locales/views/other_liabilities/en.yml b/config/locales/views/other_liabilities/en.yml new file mode 100644 index 00000000000..0057280a3e7 --- /dev/null +++ b/config/locales/views/other_liabilities/en.yml @@ -0,0 +1,15 @@ +--- +en: + other_liabilities: + create: + success: Other liability account created + update: + success: Other liability account updated + new: + title: Enter liability details + form: + name_placeholder: Personal loan + name_label: Liability name + balance: Current balance + subtype_prompt: Select liability type + none: None \ No newline at end of file diff --git a/config/locales/views/properties/en.yml b/config/locales/views/properties/en.yml index a59f2f24f63..38ef1328eef 100644 --- a/config/locales/views/properties/en.yml +++ b/config/locales/views/properties/en.yml @@ -2,6 +2,29 @@ en: properties: create: - success: Property created successfully + success: Property account created update: - success: Property updated successfully + success: Property account updated + new: + title: Enter property details + form: + name_placeholder: Primary residence + name_label: Property name + balance: Current value + year_built: Year built + year_built_placeholder: "2000" + area: Living area + area_placeholder: "2000" + area_unit: Unit of measurement + address_line1: Street address + address_line1_placeholder: "123 Main St" + address_line2: Apartment/Suite + address_line2_placeholder: "Apt 4B" + locality: City + locality_placeholder: "San Francisco" + region: State/Province + region_placeholder: "CA" + postal_code: ZIP/Postal code + postal_code_placeholder: "94105" + country: Country + country_placeholder: "US" \ No newline at end of file diff --git a/config/locales/views/vehicles/en.yml b/config/locales/views/vehicles/en.yml index 73e0b8e57b0..18e38d3c3a9 100644 --- a/config/locales/views/vehicles/en.yml +++ b/config/locales/views/vehicles/en.yml @@ -2,6 +2,21 @@ en: vehicles: create: - success: Vehicle created successfully + success: Vehicle account created update: - success: Vehicle updated successfully + success: Vehicle account updated + new: + title: Enter vehicle details + form: + name_placeholder: Family car + name_label: Vehicle name + balance: Current value + make: Make + make_placeholder: Toyota + mileage: Mileage + mileage_placeholder: "15000" + mileage_unit: Unit + model: Model + model_placeholder: Camry + year: Year + year_placeholder: "2023" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 812e6eca514..30796ccd27f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,7 @@ resources :mappings, only: :update, module: :import end - resources :accounts do + resources :accounts, only: %i[index show new edit update destroy] do collection do get :summary get :list @@ -81,15 +81,19 @@ get :securities, on: :collection end - resources :entries, only: %i[edit update show destroy] + resources :entries, only: %i[index edit update show destroy] end end - resources :depositories, only: %i[new create update] - resources :properties, only: %i[create update] - resources :vehicles, only: %i[create update] - resources :credit_cards, only: %i[create update] - resources :loans, only: %i[create update] + resources :depositories, only: %i[new show create update] + resources :investments, only: %i[new show create update] + resources :properties, only: %i[new show create update] + resources :vehicles, only: %i[new show create update] + resources :credit_cards, only: %i[new show create update] + resources :loans, only: %i[new show create update] + resources :cryptos, only: %i[new show create update] + resources :other_assets, only: %i[new show create update] + resources :other_liabilities, only: %i[new show create update] resources :transactions, only: %i[index new create] do collection do diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb index 09e64c093e4..79e433fa48a 100644 --- a/test/controllers/accounts_controller_test.rb +++ b/test/controllers/accounts_controller_test.rb @@ -20,8 +20,8 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest assert_response :ok end - test "show" do - get account_path(@account) + test "edit" do + get edit_account_path(@account) assert_response :ok end @@ -79,42 +79,4 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest assert_enqueued_with job: AccountSyncJob assert_equal "Account updated", flash[:notice] end - - test "should create an account" do - assert_difference [ "Account.count", "Account::Valuation.count", "Account::Entry.count" ], 1 do - post accounts_path, params: { - account: { - name: "Test", - accountable_type: "Depository", - balance: 200, - currency: "USD", - subtype: "checking", - institution_id: institutions(:chase).id - } - } - - assert_equal "New account created successfully", flash[:notice] - assert_redirected_to account_url(Account.order(:created_at).last) - end - end - - test "can add optional start date and balance to an account on create" do - assert_difference -> { Account.count } => 1, -> { Account::Valuation.count } => 2 do - post accounts_path, params: { - account: { - name: "Test", - accountable_type: "Depository", - balance: 200, - currency: "USD", - subtype: "checking", - institution_id: institutions(:chase).id, - start_balance: 100, - start_date: 10.days.ago - } - } - - assert_equal "New account created successfully", flash[:notice] - assert_redirected_to account_url(Account.order(:created_at).last) - end - end end diff --git a/test/controllers/credit_cards_controller_test.rb b/test/controllers/credit_cards_controller_test.rb index d8f6772c4f3..c2c872258b1 100644 --- a/test/controllers/credit_cards_controller_test.rb +++ b/test/controllers/credit_cards_controller_test.rb @@ -3,7 +3,17 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest setup do sign_in @user = users(:family_admin) - @account = accounts(:credit_card) + @credit_card = credit_cards(:one) + end + + test "new" do + get new_credit_card_path + assert_response :success + end + + test "show" do + get credit_card_url(@credit_card) + assert_response :success end test "creates credit card" do @@ -12,13 +22,11 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest -> { Account::Valuation.count } => 2, -> { Account::Entry.count } => 2 do post credit_cards_path, params: { - account: { + credit_card: { name: "New Credit Card", balance: 1000, currency: "USD", accountable_type: "CreditCard", - start_date: 1.month.ago.to_date, - start_balance: 0, accountable_attributes: { available_credit: 5000, minimum_payment: 25, @@ -42,20 +50,20 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest assert_equal 99, created_account.credit_card.annual_fee assert_redirected_to account_path(created_account) - assert_equal "Credit card created successfully", flash[:notice] + assert_equal "Credit card account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates credit card" do assert_no_difference [ "Account.count", "CreditCard.count" ] do - patch credit_card_path(@account), params: { - account: { + patch credit_card_path(@credit_card), params: { + credit_card: { name: "Updated Credit Card", balance: 2000, currency: "USD", accountable_type: "CreditCard", accountable_attributes: { - id: @account.accountable_id, + id: @credit_card.id, available_credit: 6000, minimum_payment: 50, apr: 14.99, @@ -66,18 +74,18 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest } end - @account.reload + @credit_card.reload - assert_equal "Updated Credit Card", @account.name - assert_equal 2000, @account.balance - assert_equal 6000, @account.credit_card.available_credit - assert_equal 50, @account.credit_card.minimum_payment - assert_equal 14.99, @account.credit_card.apr - assert_equal 3.years.from_now.to_date, @account.credit_card.expiration_date - assert_equal 0, @account.credit_card.annual_fee + assert_equal "Updated Credit Card", @credit_card.account.name + assert_equal 2000, @credit_card.account.balance + assert_equal 6000, @credit_card.available_credit + assert_equal 50, @credit_card.minimum_payment + assert_equal 14.99, @credit_card.apr + assert_equal 3.years.from_now.to_date, @credit_card.expiration_date + assert_equal 0, @credit_card.annual_fee - assert_redirected_to account_path(@account) - assert_equal "Credit card updated successfully", flash[:notice] + assert_redirected_to account_path(@credit_card.account) + assert_equal "Credit card account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end end diff --git a/test/controllers/cryptos_controller_test.rb b/test/controllers/cryptos_controller_test.rb new file mode 100644 index 00000000000..0a820e08198 --- /dev/null +++ b/test/controllers/cryptos_controller_test.rb @@ -0,0 +1,51 @@ +require "test_helper" + +class CryptosControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @crypto = cryptos(:one) + end + + test "new" do + get new_crypto_url + assert_response :success + end + + test "show" do + get crypto_url(@crypto) + assert_response :success + end + + test "create" do + assert_difference [ "Account.count", "Crypto.count" ], 1 do + post cryptos_url, params: { + account: { + accountable_type: "Crypto", + name: "New crypto", + balance: 10000, + currency: "USD", + subtype: "bitcoin" + } + } + end + + assert_redirected_to Account.order(:created_at).last + assert_equal "Crypto account created", flash[:notice] + end + + test "update" do + assert_no_difference [ "Account.count", "Crypto.count" ] do + patch crypto_url(@crypto), params: { + account: { + name: "Updated name", + balance: 10000, + currency: "USD", + subtype: "bitcoin" + } + } + end + + assert_redirected_to @crypto.account + assert_equal "Crypto account updated", flash[:notice] + end +end diff --git a/test/controllers/depositories_controller_test.rb b/test/controllers/depositories_controller_test.rb index 8b91df9b769..fe8eb98f369 100644 --- a/test/controllers/depositories_controller_test.rb +++ b/test/controllers/depositories_controller_test.rb @@ -11,10 +11,16 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "show" do + get depository_url(@depository) + assert_response :success + end + test "create" do assert_difference [ "Account.count", "Depository.count" ], 1 do post depositories_url, params: { - depository: { + account: { + accountable_type: "Depository", name: "New depository", balance: 10000, currency: "USD", @@ -30,7 +36,7 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest test "update" do assert_no_difference [ "Account.count", "Depository.count" ] do patch depository_url(@depository), params: { - depository: { + account: { name: "Updated name", balance: 10000, currency: "USD", @@ -39,7 +45,7 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to @depository + assert_redirected_to @depository.account assert_equal "Depository account updated", flash[:notice] end end diff --git a/test/controllers/investments_controller_test.rb b/test/controllers/investments_controller_test.rb new file mode 100644 index 00000000000..0bd8cecba1b --- /dev/null +++ b/test/controllers/investments_controller_test.rb @@ -0,0 +1,51 @@ +require "test_helper" + +class InvestmentsControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @investment = investments(:one) + end + + test "new" do + get new_investment_url + assert_response :success + end + + test "show" do + get investment_url(@investment) + assert_response :success + end + + test "create" do + assert_difference [ "Account.count", "Investment.count" ], 1 do + post investments_url, params: { + account: { + accountable_type: "Investment", + name: "New investment", + balance: 50000, + currency: "USD", + subtype: "brokerage" + } + } + end + + assert_redirected_to Account.order(:created_at).last + assert_equal "Investment account created", flash[:notice] + end + + test "update" do + assert_no_difference [ "Account.count", "Investment.count" ] do + patch investment_url(@investment), params: { + account: { + name: "Updated name", + balance: 50000, + currency: "USD", + subtype: "brokerage" + } + } + end + + assert_redirected_to @investment.account + assert_equal "Investment account updated", flash[:notice] + end +end diff --git a/test/controllers/loans_controller_test.rb b/test/controllers/loans_controller_test.rb index 3ec9efc0b95..940c732cbed 100644 --- a/test/controllers/loans_controller_test.rb +++ b/test/controllers/loans_controller_test.rb @@ -3,7 +3,17 @@ class LoansControllerTest < ActionDispatch::IntegrationTest setup do sign_in @user = users(:family_admin) - @account = accounts(:loan) + @loan = loans(:one) + end + + test "new" do + get new_loan_path + assert_response :success + end + + test "show" do + get loan_url(@loan) + assert_response :success end test "creates loan" do @@ -17,8 +27,6 @@ class LoansControllerTest < ActionDispatch::IntegrationTest balance: 50000, currency: "USD", accountable_type: "Loan", - start_date: 1.month.ago.to_date, - start_balance: 50000, accountable_attributes: { interest_rate: 5.5, term_months: 60, @@ -38,20 +46,20 @@ class LoansControllerTest < ActionDispatch::IntegrationTest assert_equal "fixed", created_account.loan.rate_type assert_redirected_to account_path(created_account) - assert_equal "Loan created successfully", flash[:notice] + assert_equal "Loan account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates loan" do assert_no_difference [ "Account.count", "Loan.count" ] do - patch loan_path(@account), params: { + patch loan_path(@loan), params: { account: { name: "Updated Loan", balance: 45000, currency: "USD", accountable_type: "Loan", accountable_attributes: { - id: @account.accountable_id, + id: @loan.id, interest_rate: 4.5, term_months: 48, rate_type: "fixed" @@ -60,16 +68,16 @@ class LoansControllerTest < ActionDispatch::IntegrationTest } end - @account.reload + @loan.reload - assert_equal "Updated Loan", @account.name - assert_equal 45000, @account.balance - assert_equal 4.5, @account.loan.interest_rate - assert_equal 48, @account.loan.term_months - assert_equal "fixed", @account.loan.rate_type + assert_equal "Updated Loan", @loan.account.name + assert_equal 45000, @loan.account.balance + assert_equal 4.5, @loan.interest_rate + assert_equal 48, @loan.term_months + assert_equal "fixed", @loan.rate_type - assert_redirected_to account_path(@account) - assert_equal "Loan updated successfully", flash[:notice] + assert_redirected_to account_path(@loan.account) + assert_equal "Loan account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end end diff --git a/test/controllers/other_assets_controller_test.rb b/test/controllers/other_assets_controller_test.rb new file mode 100644 index 00000000000..a973cbe0878 --- /dev/null +++ b/test/controllers/other_assets_controller_test.rb @@ -0,0 +1,51 @@ +require "test_helper" + +class OtherAssetsControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @other_asset = other_assets(:one) + end + + test "new" do + get new_other_asset_url + assert_response :success + end + + test "show" do + get other_asset_url(@other_asset) + assert_response :success + end + + test "create" do + assert_difference [ "Account.count", "OtherAsset.count" ], 1 do + post other_assets_url, params: { + account: { + accountable_type: "OtherAsset", + name: "New other asset", + balance: 5000, + currency: "USD", + subtype: "other" + } + } + end + + assert_redirected_to Account.order(:created_at).last + assert_equal "Other asset account created", flash[:notice] + end + + test "update" do + assert_no_difference [ "Account.count", "OtherAsset.count" ] do + patch other_asset_url(@other_asset), params: { + account: { + name: "Updated name", + balance: 5000, + currency: "USD", + subtype: "other" + } + } + end + + assert_redirected_to @other_asset.account + assert_equal "Other asset account updated", flash[:notice] + end +end diff --git a/test/controllers/other_liabilities_controller_test.rb b/test/controllers/other_liabilities_controller_test.rb new file mode 100644 index 00000000000..09bc27c78e2 --- /dev/null +++ b/test/controllers/other_liabilities_controller_test.rb @@ -0,0 +1,51 @@ +require "test_helper" + +class OtherLiabilitiesControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @other_liability = other_liabilities(:one) + end + + test "new" do + get new_other_liability_url + assert_response :success + end + + test "show" do + get other_liability_url(@other_liability) + assert_response :success + end + + test "create" do + assert_difference [ "Account.count", "OtherLiability.count" ], 1 do + post other_liabilities_url, params: { + account: { + accountable_type: "OtherLiability", + name: "New other liability", + balance: 15000, + currency: "USD", + subtype: "other" + } + } + end + + assert_redirected_to Account.order(:created_at).last + assert_equal "Other liability account created", flash[:notice] + end + + test "update" do + assert_no_difference [ "Account.count", "OtherLiability.count" ] do + patch other_liability_url(@other_liability), params: { + account: { + name: "Updated name", + balance: 15000, + currency: "USD", + subtype: "other" + } + } + end + + assert_redirected_to @other_liability.account + assert_equal "Other liability account updated", flash[:notice] + end +end diff --git a/test/controllers/properties_controller_test.rb b/test/controllers/properties_controller_test.rb index 1e017eed307..6eb4ea77c1d 100644 --- a/test/controllers/properties_controller_test.rb +++ b/test/controllers/properties_controller_test.rb @@ -3,7 +3,17 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest setup do sign_in @user = users(:family_admin) - @account = accounts(:property) + @property = properties(:one) + end + + test "new" do + get new_property_path + assert_response :success + end + + test "show" do + get property_url(@property) + assert_response :success end test "creates property" do @@ -17,8 +27,6 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest balance: 500000, currency: "USD", accountable_type: "Property", - start_date: 3.years.ago.to_date, - start_balance: 450000, accountable_attributes: { year_built: 2002, area_value: 1000, @@ -42,20 +50,20 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest assert created_account.property.address.line1.present? assert_redirected_to account_path(created_account) - assert_equal "Property created successfully", flash[:notice] + assert_equal "Property account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates property" do assert_no_difference [ "Account.count", "Property.count" ] do - patch property_path(@account), params: { + patch property_path(@property), params: { account: { name: "Updated Property", balance: 500000, currency: "USD", accountable_type: "Property", accountable_attributes: { - id: @account.accountable_id, + id: @property.id, year_built: 2002, area_value: 1000, area_unit: "sqft", @@ -72,8 +80,8 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@account) - assert_equal "Property updated successfully", flash[:notice] + assert_redirected_to account_path(@property.account) + assert_equal "Property account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end end diff --git a/test/controllers/vehicles_controller_test.rb b/test/controllers/vehicles_controller_test.rb index 6908f969167..6cd9d2e7195 100644 --- a/test/controllers/vehicles_controller_test.rb +++ b/test/controllers/vehicles_controller_test.rb @@ -3,7 +3,17 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest setup do sign_in @user = users(:family_admin) - @account = accounts(:vehicle) + @vehicle = vehicles(:one) + end + + test "new" do + get new_vehicle_path + assert_response :success + end + + test "show" do + get vehicle_url(@vehicle) + assert_response :success end test "creates vehicle" do @@ -17,8 +27,6 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest balance: 30000, currency: "USD", accountable_type: "Vehicle", - start_date: 1.year.ago.to_date, - start_balance: 35000, accountable_attributes: { make: "Toyota", model: "Camry", @@ -39,20 +47,20 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest assert_equal "mi", created_account.vehicle.mileage_unit assert_redirected_to account_path(created_account) - assert_equal "Vehicle created successfully", flash[:notice] + assert_equal "Vehicle account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates vehicle" do assert_no_difference [ "Account.count", "Vehicle.count" ] do - patch vehicle_path(@account), params: { + patch vehicle_path(@vehicle), params: { account: { name: "Updated Vehicle", balance: 28000, currency: "USD", accountable_type: "Vehicle", accountable_attributes: { - id: @account.accountable_id, + id: @vehicle.id, make: "Honda", model: "Accord", year: 2021, @@ -64,8 +72,8 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@account) - assert_equal "Vehicle updated successfully", flash[:notice] + assert_redirected_to account_path(@vehicle.account) + assert_equal "Vehicle account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end end diff --git a/test/fixtures/accounts.yml b/test/fixtures/accounts.yml index eeb616f3da3..5c33a1efccd 100644 --- a/test/fixtures/accounts.yml +++ b/test/fixtures/accounts.yml @@ -63,3 +63,11 @@ vehicle: currency: USD accountable_type: Vehicle accountable: one + +crypto: + family: dylan_family + name: Bitcoin + balance: 10000 + currency: USD + accountable_type: Crypto + accountable: one From e1cf4ed57e684a22a79d3daae3333a777c0964bf Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Fri, 1 Nov 2024 08:56:03 -0400 Subject: [PATCH 03/19] Entry partials, checkpoint --- app/controllers/account/entries_controller.rb | 7 +- .../account/transactions_controller.rb | 5 +- .../account/transfers_controller.rb | 13 ++- app/helpers/account/entries_helper.rb | 34 +------ app/models/account/entry.rb | 21 ----- app/models/account/trade.rb | 6 ++ app/models/account/transaction.rb | 4 + app/models/account/valuation.rb | 40 +++++++++ app/models/time_series/trend.rb | 12 ++- .../account/entries/_entry_group.html.erb | 6 +- app/views/account/entries/index.html.erb | 10 +-- app/views/account/trades/_trade.html.erb | 6 +- .../transactions/_feed_transaction.html.erb | 90 +++++++++++++++++++ .../transactions/_transaction.html.erb | 6 +- app/views/account/transfers/show.html.erb | 3 + .../account/valuations/_valuation.html.erb | 63 ++++++------- app/views/account/valuations/new.html.erb | 5 +- app/views/account/valuations/show.html.erb | 84 ++++++++++++++++- app/views/pages/dashboard.html.erb | 5 +- app/views/transactions/index.html.erb | 5 +- .../locales/views/account/valuations/en.yml | 16 ++++ config/routes.rb | 2 +- 22 files changed, 325 insertions(+), 118 deletions(-) create mode 100644 app/views/account/transactions/_feed_transaction.html.erb create mode 100644 app/views/account/transfers/show.html.erb diff --git a/app/controllers/account/entries_controller.rb b/app/controllers/account/entries_controller.rb index 2985e655621..d78cb62cb23 100644 --- a/app/controllers/account/entries_controller.rb +++ b/app/controllers/account/entries_controller.rb @@ -14,8 +14,11 @@ def edit end def update + prev_amount = @entry.amount + prev_date = @entry.date + @entry.update!(entry_params) - @entry.sync_account_later + @entry.sync_account_later if prev_amount != @entry.amount || prev_date != @entry.date respond_to do |format| format.html { redirect_to account_entry_path(@account, @entry), notice: t(".success") } @@ -48,7 +51,7 @@ def set_entry end def entry_params - params.require(:account_entry).permit(:name, :date, :amount, :currency) + params.require(:account_entry).permit(:name, :date, :amount, :currency, :notes) end def search_params diff --git a/app/controllers/account/transactions_controller.rb b/app/controllers/account/transactions_controller.rb index 2e3073e613d..d3a36613446 100644 --- a/app/controllers/account/transactions_controller.rb +++ b/app/controllers/account/transactions_controller.rb @@ -12,7 +12,11 @@ def index end def update + prev_amount = @entry.amount + prev_date = @entry.date + @entry.update!(entry_params) + @entry.sync_account_later if prev_amount != @entry.amount || prev_date != @entry.date respond_to do |format| format.html { redirect_to account_entry_path(@account, @entry), notice: t(".success") } @@ -21,7 +25,6 @@ def update end private - def set_account @account = Current.family.accounts.find(params[:account_id]) end diff --git a/app/controllers/account/transfers_controller.rb b/app/controllers/account/transfers_controller.rb index c8fd487709a..9f7079c21b0 100644 --- a/app/controllers/account/transfers_controller.rb +++ b/app/controllers/account/transfers_controller.rb @@ -1,12 +1,15 @@ class Account::TransfersController < ApplicationController layout :with_sidebar - before_action :set_transfer, only: :destroy + before_action :set_transfer, only: %i[destroy show] def new @transfer = Account::Transfer.new end + def show + end + def create from_account = Current.family.accounts.find(transfer_params[:from_account_id]) to_account = Current.family.accounts.find(transfer_params[:to_account_id]) @@ -36,7 +39,13 @@ def destroy private def set_transfer - @transfer = Account::Transfer.find(params[:id]) + record = Account::Transfer.find(params[:id]) + + unless record.entries.all? { |entry| Current.family.accounts.include?(entry.account) } + raise ActiveRecord::RecordNotFound + end + + @transfer = record end def transfer_params diff --git a/app/helpers/account/entries_helper.rb b/app/helpers/account/entries_helper.rb index 0f2aff52366..e6cf570ab66 100644 --- a/app/helpers/account/entries_helper.rb +++ b/app/helpers/account/entries_helper.rb @@ -12,43 +12,13 @@ def transfer_entries(entries) transfers.map(&:transfer).uniq end - def entry_icon(entry, is_oldest: false) - if is_oldest - "keyboard" - elsif entry.trend.direction.up? - "arrow-up" - elsif entry.trend.direction.down? - "arrow-down" - else - "minus" - end - end - - def entry_style(entry, is_oldest: false) - color = is_oldest ? "#D444F1" : entry.trend.color - - mixed_hex_styles(color) - end - - def entry_name(entry) - if entry.account_trade? - trade = entry.account_trade - prefix = trade.sell? ? "Sell " : "Buy " - generated = prefix + "#{trade.qty.abs} shares of #{trade.security.ticker}" - name = entry.name || generated - name - else - entry.name || "Transaction" - end - end - - def entries_by_date(entries, selectable: true) + def entries_by_date(entries, selectable: true, totals: false) entries.group_by(&:date).map do |date, grouped_entries| content = capture do yield grouped_entries end - render partial: "account/entries/entry_group", locals: { date:, entries: grouped_entries, content:, selectable: } + render partial: "account/entries/entry_group", locals: { date:, entries: grouped_entries, content:, selectable:, totals: } end.join.html_safe end diff --git a/app/models/account/entry.rb b/app/models/account/entry.rb index e04756f1b90..1f6df70fe3f 100644 --- a/app/models/account/entry.rb +++ b/app/models/account/entry.rb @@ -46,24 +46,10 @@ def outflow? amount > 0 && account_transaction? end - def first_of_type? - first_entry = account - .entries - .where("entryable_type = ?", entryable_type) - .order(:date) - .first - - first_entry&.id == id - end - def entryable_name_short entryable_type.demodulize.underscore end - def trend - @trend ||= create_trend - end - class << self # arbitrary cutoff date to avoid expensive sync operations def min_supported_date @@ -216,11 +202,4 @@ def previous_entry .order(date: :desc) .first end - - def create_trend - TimeSeries::Trend.new \ - current: amount_money, - previous: previous_entry&.amount_money, - favorable_direction: account.favorable_direction - end end diff --git a/app/models/account/trade.rb b/app/models/account/trade.rb index a594ee169e2..17e0b070826 100644 --- a/app/models/account/trade.rb +++ b/app/models/account/trade.rb @@ -26,6 +26,12 @@ def buy? qty > 0 end + def name + prefix = sell? ? "Sell " : "Buy " + generated = prefix + "#{qty.abs} shares of #{security.ticker}" + entry.name || generated + end + def unrealized_gain_loss return nil if sell? current_price = security.current_price diff --git a/app/models/account/transaction.rb b/app/models/account/transaction.rb index 52a0f9bd78a..370664828ba 100644 --- a/app/models/account/transaction.rb +++ b/app/models/account/transaction.rb @@ -48,6 +48,10 @@ def searchable_keys end end + def name + entry.name || "(no description)" + end + private def previous_transaction_date self.account diff --git a/app/models/account/valuation.rb b/app/models/account/valuation.rb index 93ebf5ffb1f..77a276bc858 100644 --- a/app/models/account/valuation.rb +++ b/app/models/account/valuation.rb @@ -10,4 +10,44 @@ def requires_search?(_params) false end end + + def name + oldest? ? "Initial balance" : entry.name || "Balance update" + end + + def trend + @trend ||= create_trend + end + + def icon + oldest? ? "plus" : trend.icon + end + + def color + oldest? ? "#D444F1" : trend.color + end + + private + def oldest? + @oldest ||= account.entries.where("date < ?", entry.date).empty? + end + + def account + @account ||= entry.account + end + + def create_trend + TimeSeries::Trend.new( + current: entry.amount_money, + previous: prior_balance&.balance_money, + favorable_direction: account.favorable_direction + ) + end + + def prior_balance + @prior_balance ||= account.balances + .where("date < ?", entry.date) + .order(date: :desc) + .first + end end diff --git a/app/models/time_series/trend.rb b/app/models/time_series/trend.rb index b93db2bd67d..c6638cbe62c 100644 --- a/app/models/time_series/trend.rb +++ b/app/models/time_series/trend.rb @@ -35,9 +35,19 @@ def color end end + def icon + if direction.flat? + "minus" + elsif direction.up? + "arrow-up" + else + "arrow-down" + end + end + def value if previous.nil? - current.is_a?(Money) ? Money.new(0) : 0 + current.is_a?(Money) ? Money.new(0, current.currency) : 0 else current - previous end diff --git a/app/views/account/entries/_entry_group.html.erb b/app/views/account/entries/_entry_group.html.erb index 11489c2a792..a58d0f15130 100644 --- a/app/views/account/entries/_entry_group.html.erb +++ b/app/views/account/entries/_entry_group.html.erb @@ -1,4 +1,4 @@ -<%# locals: (date:, entries:, content:, selectable:) %> +<%# locals: (date:, entries:, content:, selectable:, totals: false) %>
@@ -16,7 +16,9 @@

- <%= totals_by_currency(collection: entries, money_method: :amount_money, negate: true) %> + <% if totals %> + <%= totals_by_currency(collection: entries, money_method: :amount_money, negate: true) %> + <% end %>
<%= content %> diff --git a/app/views/account/entries/index.html.erb b/app/views/account/entries/index.html.erb index f4668463083..7d7326762cf 100644 --- a/app/views/account/entries/index.html.erb +++ b/app/views/account/entries/index.html.erb @@ -8,12 +8,12 @@ <%= tag.span t(".new") %> <%= f.submit %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/investments/_holdings_tab.html.erb b/app/views/investments/_holdings_tab.html.erb index 1fca12773df..c61c3a17609 100644 --- a/app/views/investments/_holdings_tab.html.erb +++ b/app/views/investments/_holdings_tab.html.erb @@ -2,4 +2,4 @@ <%= turbo_frame_tag dom_id(account, :holdings), src: account_holdings_path(account) do %> <%= render "account/entries/loading" %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/investments/_value_tooltip.html.erb b/app/views/investments/_value_tooltip.html.erb index 7ad78dd768a..c624afbc1b9 100644 --- a/app/views/investments/_value_tooltip.html.erb +++ b/app/views/investments/_value_tooltip.html.erb @@ -23,4 +23,4 @@
- \ No newline at end of file + diff --git a/app/views/investments/new.html.erb b/app/views/investments/new.html.erb index f9d003f6b17..120dbe1807e 100644 --- a/app/views/investments/new.html.erb +++ b/app/views/investments/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "investments/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/investments/show.html.erb b/app/views/investments/show.html.erb index da189c48794..2259d7296b9 100644 --- a/app/views/investments/show.html.erb +++ b/app/views/investments/show.html.erb @@ -5,13 +5,12 @@ <%= render "accounts/show/chart", account: @account, - title: t(".chart"), + title: t(".chart_title"), tooltip: render( "investments/value_tooltip", value: @account.value, cash: @account.balance_money - ) - %> + ) %>
<%= render "accounts/show/tabs", account: @account, tabs: [ @@ -20,4 +19,4 @@ { key: "cash", contents: render("investments/cash_tab", account: @account) } ] %>
-<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/loans/_form.html.erb b/app/views/loans/_form.html.erb index adc8ced45fe..bc578555983 100644 --- a/app/views/loans/_form.html.erb +++ b/app/views/loans/_form.html.erb @@ -54,4 +54,4 @@ <%= f.submit %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/loans/new.html.erb b/app/views/loans/new.html.erb index 1502ba4191a..7dd32ff01eb 100644 --- a/app/views/loans/new.html.erb +++ b/app/views/loans/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "loans/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/other_assets/_form.html.erb b/app/views/other_assets/_form.html.erb index 5896a400647..be20086d0c1 100644 --- a/app/views/other_assets/_form.html.erb +++ b/app/views/other_assets/_form.html.erb @@ -33,4 +33,4 @@ <%= f.submit %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/other_assets/new.html.erb b/app/views/other_assets/new.html.erb index d4135fbacb5..789f3ec6008 100644 --- a/app/views/other_assets/new.html.erb +++ b/app/views/other_assets/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "other_assets/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/other_liabilities/_form.html.erb b/app/views/other_liabilities/_form.html.erb index 4c5c7dd51f1..a8ea5705378 100644 --- a/app/views/other_liabilities/_form.html.erb +++ b/app/views/other_liabilities/_form.html.erb @@ -33,4 +33,4 @@ <%= f.submit %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/other_liabilities/new.html.erb b/app/views/other_liabilities/new.html.erb index 75a76513657..a39f0b63f38 100644 --- a/app/views/other_liabilities/new.html.erb +++ b/app/views/other_liabilities/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "other_liabilities/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/properties/_overview.html.erb b/app/views/properties/_overview.html.erb index 5905452b420..4a832c172f2 100644 --- a/app/views/properties/_overview.html.erb +++ b/app/views/properties/_overview.html.erb @@ -30,4 +30,4 @@
<%= link_to "Edit account details", edit_property_path(account.property), class: "btn btn--ghost", data: { turbo_frame: :modal } %> -
\ No newline at end of file + diff --git a/app/views/properties/new.html.erb b/app/views/properties/new.html.erb index d6b18b2fe29..07012f41f19 100644 --- a/app/views/properties/new.html.erb +++ b/app/views/properties/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "properties/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/vehicles/_form.html.erb b/app/views/vehicles/_form.html.erb index 9e91ef63037..149a2340646 100644 --- a/app/views/vehicles/_form.html.erb +++ b/app/views/vehicles/_form.html.erb @@ -61,4 +61,4 @@ <%= f.submit %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/vehicles/new.html.erb b/app/views/vehicles/new.html.erb index a1d378c6d08..db423fb317a 100644 --- a/app/views/vehicles/new.html.erb +++ b/app/views/vehicles/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> <%= render "vehicles/form", account: @account %> -<% end %> \ No newline at end of file +<% end %> diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 78648c48283..1d1d9957013 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -23,74 +23,6 @@ ], "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, @@ -106,7 +38,7 @@ "type": "controller", "class": "PagesController", "method": "changelog", - "line": 36, + "line": 35, "file": "app/controllers/pages_controller.rb", "rendered": { "name": "pages/changelog", @@ -125,40 +57,6 @@ ], "note": "" }, - { - "warning_type": "Dynamic Render Path", - "warning_code": 15, - "fingerprint": "c5c512a13c34c9696024bd4e2367a657a5c140b5b6a0f5c352e9b69965f63e1b", - "check_name": "Render", - "message": "Render path contains parameter value", - "file": "app/views/accounts/show.html.erb", - "line": 63, - "link": "https://brakemanscanner.org/docs/warning_types/dynamic_render_path/", - "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": 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, @@ -194,6 +92,6 @@ "note": "" } ], - "updated": "2024-10-17 11:30:15 -0400", - "brakeman_version": "6.2.1" + "updated": "2024-11-02 08:12:55 -0400", + "brakeman_version": "6.2.2" } diff --git a/config/locales/views/account/entries/en.yml b/config/locales/views/account/entries/en.yml index a56db392c3d..b4b4cb93c58 100644 --- a/config/locales/views/account/entries/en.yml +++ b/config/locales/views/account/entries/en.yml @@ -2,15 +2,22 @@ en: account: entries: - index: - title: Activity - entry: entry - entries: entries destroy: success: Entry deleted empty: description: Try adding an entry, editing filters or refining your search title: No entries found + index: + amount: Amount + balance: Balance + date: Date + entries: entries + entry: entry + new: New + new_balance: New balance + new_transaction: New transaction + no_entries: No entries yet + title: Activity loading: loading: Loading entries... update: diff --git a/config/locales/views/account/transactions/en.yml b/config/locales/views/account/transactions/en.yml index 561c58580a1..81a88210412 100644 --- a/config/locales/views/account/transactions/en.yml +++ b/config/locales/views/account/transactions/en.yml @@ -35,9 +35,5 @@ en: overview: Overview settings: Settings tags_label: Tags - transaction: - remove_transfer: Remove transfer - remove_transfer_body: This will remove the transfer from this transaction - remove_transfer_confirm: Confirm update: success: Transaction updated successfully. diff --git a/config/locales/views/account/transfers/en.yml b/config/locales/views/account/transfers/en.yml index f7cfd574712..7728d764c6b 100644 --- a/config/locales/views/account/transfers/en.yml +++ b/config/locales/views/account/transfers/en.yml @@ -2,14 +2,6 @@ en: account: transfers: - show: - delete: Delete - delete_title: Delete transfer? - delete_subtitle: This permanently deletes both of the transactions related to the transfer. This cannot be undone. - exclude_title: Exclude transfer - exclude_subtitle: This excludes the transfer from any in-app features or analytics. - note_label: Notes - note_placeholder: Add a note to this transfer create: success: Transfer created destroy: @@ -26,8 +18,21 @@ en: transfer: Transfer new: title: New transfer - transfer: - remove_body: This will NOT delete the underlying transactions. It will just - remove the transfer. - remove_confirm: Confirm - remove_title: Remove transfer? + show: + delete: Delete + delete_subtitle: This permanently deletes both of the transactions related + to the transfer. This cannot be undone. + delete_title: Delete transfer? + details: Details + exclude_subtitle: This excludes the transfer from any in-app features or analytics. + exclude_title: Exclude transfer + note_label: Notes + note_placeholder: Add a note to this transfer + overview: Overview + settings: Settings + transfer_toggle: + remove_transfer: Remove transfer + remove_transfer_body: This will remove the transfer from this transaction + remove_transfer_confirm: Confirm + update: + success: Transfer updated diff --git a/config/locales/views/account/valuations/en.yml b/config/locales/views/account/valuations/en.yml index 32ec1f66afc..1062d1238a0 100644 --- a/config/locales/views/account/valuations/en.yml +++ b/config/locales/views/account/valuations/en.yml @@ -2,8 +2,6 @@ en: account: valuations: - new: - title: New balance create: success: Valuation created successfully. form: @@ -15,29 +13,19 @@ en: no_valuations: No valuations for this account yet valuations: Value value: value - valuation: - confirm_accept: Delete entry - confirm_body_html: "

Deleting this entry will remove it from the account’s - history which will impact different parts of your account. This includes - the net worth and account graphs.


The only way you’ll be able - to add this entry back is by re-entering it manually via a new entry.

" - confirm_title: Delete Entry? - delete_entry: Delete entry - edit_entry: Edit entry - no_change: No change - start_balance: Starting balance - value_update: Value update + new: + title: New balance show: + amount: Amount balance: Balance - overview: Overview + date_label: Date + delete: Delete + delete_subtitle: This action cannot be undone + delete_title: Delete Entry details: Details - settings: Settings name_label: Name name_placeholder: Enter a name for this entry - date_label: Date - amount: Amount note_label: Notes note_placeholder: Add any additional details about this entry - delete_title: Delete Entry - delete_subtitle: This action cannot be undone - delete: Delete + overview: Overview + settings: Settings diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index 5310073f33e..bea250e927e 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -6,95 +6,6 @@ en: troubleshoot: Troubleshoot account_list: new_account: New %{type} - accountables: - credit_card: - form: - 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' - overview: - amount_owed: Amount Owed - annual_fee: Annual Fee - apr: APR - available_credit: Available Credit - expiration_date: Expiration Date - minimum_payment: Minimum Payment - unknown: Unknown - depository: - 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: - 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 - not_applicable: N/A - original_principal: Original Principal - remaining_principal: Remaining Principal - term: Term - type: Type - unknown: Unknown - property: - 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 - purchase_price: Purchase Price - trend: Trend - unknown: Unknown - year_built: Year Built - vehicle: - 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 - mileage: Mileage - purchase_price: Purchase Price - trend: Trend - unknown: Unknown - year: Year - create: - success: New account created successfully destroy: success: Account deleted successfully edit: @@ -107,63 +18,77 @@ en: accountable_type: Account type balance: Today's balance institution: Financial institution - mode: Value tracking mode - mode_prompt: Select a mode name_label: Account name name_placeholder: Example account name type_prompt: Select a type ungrouped: "(none)" - header: - accounts: Accounts - manage: Manage accounts - new: New account index: accounts: Accounts add_institution: Add institution + 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_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 - menu: - 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 - import: Import transactions new: - container: - manual_entry: Enter account balance - connected_entry: Link account (coming soon) - title: What would you like to add? + form: + accountable_type: Account type + balance: Today's balance + institution: Financial institution + name_label: Account name + name_placeholder: Example account name + type_prompt: Select a type + ungrouped: "(none)" method_selector: + connected_entry: Link account (coming soon) + manual_entry: Enter account balance title: How would you like to add it? + title: What would you like to add? show: cash: Cash + chart: + balance: Balance + no_change: no change + owed: Owed holdings: Holdings - no_change: No change + menu: + 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 + import: Import transactions overview: Overview - total_owed: Total Owed - total_value: Total Value trades: Transactions transactions: Transactions value: Value summary: - new: New + header: + accounts: Accounts + manage: Manage accounts + new: New account + new: New account 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. + no_liabilities_description: Add a liability either via connection, importing + or entering manually. sync_all: success: Successfully queued accounts for syncing. sync_all_button: diff --git a/config/locales/views/credit_cards/en.yml b/config/locales/views/credit_cards/en.yml index 63d6a75a8a7..31b65802f14 100644 --- a/config/locales/views/credit_cards/en.yml +++ b/config/locales/views/credit_cards/en.yml @@ -3,20 +3,30 @@ en: credit_cards: create: success: Credit card account created - update: - success: Credit card account updated - new: - title: Enter credit card details form: - name_placeholder: Chase Sapphire - name_label: Card name - balance: Current balance annual_fee: Annual fee annual_fee_placeholder: '99' apr: APR apr_placeholder: '15.99' available_credit: Available credit available_credit_placeholder: '10000' + balance: Current balance expiration_date: Expiration date + institution: Institution minimum_payment: Minimum payment - minimum_payment_placeholder: '100' \ No newline at end of file + minimum_payment_placeholder: '100' + name_label: Card name + name_placeholder: Chase Sapphire + ungrouped: "(none)" + new: + title: Enter credit card details + overview: + amount_owed: Amount Owed + annual_fee: Annual Fee + apr: APR + available_credit: Available Credit + expiration_date: Expiration Date + minimum_payment: Minimum Payment + unknown: Unknown + update: + success: Credit card account updated diff --git a/config/locales/views/cryptos/en.yml b/config/locales/views/cryptos/en.yml index 0b17ba0953d..bc4ea2a4733 100644 --- a/config/locales/views/cryptos/en.yml +++ b/config/locales/views/cryptos/en.yml @@ -3,13 +3,15 @@ en: cryptos: create: success: Crypto account created - update: - success: Crypto account updated - new: - title: Enter account balance form: - name_placeholder: Bitcoin wallet - name_label: Account name balance: Current balance + institution: Institution + name_label: Account name + name_placeholder: Bitcoin wallet + none: None subtype_prompt: Select crypto type - none: None \ No newline at end of file + ungrouped: "(none)" + new: + title: Enter account balance + update: + success: Crypto account updated diff --git a/config/locales/views/depositories/en.yml b/config/locales/views/depositories/en.yml index 2962c3a3728..e67767f0721 100644 --- a/config/locales/views/depositories/en.yml +++ b/config/locales/views/depositories/en.yml @@ -3,12 +3,15 @@ en: depositories: create: success: Depository account created - update: - success: Depository account updated - new: - title: Enter account balance form: - name_placeholder: Chase checking account - name_label: Account name balance: Current balance - subtype_prompt: Select account type \ No newline at end of file + institution: Institution + name_label: Account name + name_placeholder: Chase checking account + none: None + subtype_prompt: Select account type + ungrouped: "(none)" + new: + title: Enter account balance + update: + success: Depository account updated diff --git a/config/locales/views/investments/en.yml b/config/locales/views/investments/en.yml index 98664a453db..e8036b81e8d 100644 --- a/config/locales/views/investments/en.yml +++ b/config/locales/views/investments/en.yml @@ -3,13 +3,22 @@ en: investments: create: success: Investment account created - update: - success: Investment account updated - new: - title: Enter account balance form: - name_placeholder: Vanguard brokerage account - name_label: Account name balance: Current balance + institution: Institution + name_label: Account name + name_placeholder: Vanguard brokerage account + none: None subtype_prompt: Select investment type - none: None \ No newline at end of file + ungrouped: "(none)" + new: + title: Enter account balance + show: + chart_title: Total value + update: + success: Investment account updated + value_tooltip: + cash: Cash + holdings: Holdings + total_value_tooltip: The total value is the sum of cash balance and your holdings + value, minus margin loans. diff --git a/config/locales/views/loans/en.yml b/config/locales/views/loans/en.yml index ccd0af8bc12..f76fb50301e 100644 --- a/config/locales/views/loans/en.yml +++ b/config/locales/views/loans/en.yml @@ -3,16 +3,27 @@ en: loans: create: success: Loan account created - update: - success: Loan account updated - new: - title: Enter loan details form: - name_placeholder: Home mortgage - name_label: Loan name balance: Current balance + institution: Institution interest_rate: Interest rate interest_rate_placeholder: '5.25' + name_label: Loan name + name_placeholder: Home mortgage rate_type: Rate type term_months: Term (months) - term_months_placeholder: '360' \ No newline at end of file + term_months_placeholder: '360' + ungrouped: "(none)" + new: + title: Enter loan details + overview: + interest_rate: Interest Rate + monthly_payment: Monthly Payment + not_applicable: N/A + original_principal: Original Principal + remaining_principal: Remaining Principal + term: Term + type: Type + unknown: Unknown + update: + success: Loan account updated diff --git a/config/locales/views/other_assets/en.yml b/config/locales/views/other_assets/en.yml index 65fecc9dfcd..6196258f67a 100644 --- a/config/locales/views/other_assets/en.yml +++ b/config/locales/views/other_assets/en.yml @@ -3,13 +3,15 @@ en: other_assets: create: success: Other asset account created - update: - success: Other asset account updated - new: - title: Enter asset details form: - name_placeholder: Art collection - name_label: Asset name balance: Current value + institution: Institution + name_label: Asset name + name_placeholder: Art collection + none: None subtype_prompt: Select asset type - none: None \ No newline at end of file + ungrouped: "(none)" + new: + title: Enter asset details + update: + success: Other asset account updated diff --git a/config/locales/views/other_liabilities/en.yml b/config/locales/views/other_liabilities/en.yml index 0057280a3e7..6d3be9039a2 100644 --- a/config/locales/views/other_liabilities/en.yml +++ b/config/locales/views/other_liabilities/en.yml @@ -3,13 +3,15 @@ en: other_liabilities: create: success: Other liability account created - update: - success: Other liability account updated - new: - title: Enter liability details form: - name_placeholder: Personal loan - name_label: Liability name balance: Current balance + institution: Institution + name_label: Liability name + name_placeholder: Personal loan + none: None subtype_prompt: Select liability type - none: None \ No newline at end of file + ungrouped: "(none)" + new: + title: Enter liability details + update: + success: Other liability account updated diff --git a/config/locales/views/properties/en.yml b/config/locales/views/properties/en.yml index 38ef1328eef..67a3e391180 100644 --- a/config/locales/views/properties/en.yml +++ b/config/locales/views/properties/en.yml @@ -3,28 +3,37 @@ en: properties: create: success: Property account created - update: - success: Property account updated - new: - title: Enter property details form: - name_placeholder: Primary residence - name_label: Property name - balance: Current value - year_built: Year built - year_built_placeholder: "2000" - area: Living area - area_placeholder: "2000" - area_unit: Unit of measurement address_line1: Street address - address_line1_placeholder: "123 Main St" + address_line1_placeholder: 123 Main St address_line2: Apartment/Suite - address_line2_placeholder: "Apt 4B" + address_line2_placeholder: Apt 4B + area: Living area + area_placeholder: '2000' + area_unit: Unit of measurement + balance: Current value + country: Country + country_placeholder: US + institution: Institution locality: City - locality_placeholder: "San Francisco" - region: State/Province - region_placeholder: "CA" + locality_placeholder: San Francisco + name_label: Property name + name_placeholder: Primary residence postal_code: ZIP/Postal code - postal_code_placeholder: "94105" - country: Country - country_placeholder: "US" \ No newline at end of file + postal_code_placeholder: '94105' + region: State/Province + region_placeholder: CA + ungrouped: "(none)" + year_built: Year built + year_built_placeholder: '2000' + new: + title: Enter property details + overview: + living_area: Living Area + market_value: Market Value + purchase_price: Purchase Price + trend: Trend + unknown: Unknown + year_built: Year Built + update: + success: Property account updated diff --git a/config/locales/views/vehicles/en.yml b/config/locales/views/vehicles/en.yml index 18e38d3c3a9..cbfb7906cdc 100644 --- a/config/locales/views/vehicles/en.yml +++ b/config/locales/views/vehicles/en.yml @@ -3,20 +3,30 @@ en: vehicles: create: success: Vehicle account created - update: - success: Vehicle account updated - new: - title: Enter vehicle details form: - name_placeholder: Family car - name_label: Vehicle name balance: Current value + institution: Institution make: Make make_placeholder: Toyota mileage: Mileage - mileage_placeholder: "15000" + mileage_placeholder: '15000' mileage_unit: Unit model: Model model_placeholder: Camry + name_label: Vehicle name + name_placeholder: Family car + ungrouped: "(none)" year: Year - year_placeholder: "2023" \ No newline at end of file + year_placeholder: '2023' + new: + title: Enter vehicle details + overview: + current_price: Current Price + make_model: Make & Model + mileage: Mileage + purchase_price: Purchase Price + trend: Trend + unknown: Unknown + year: Year + update: + success: Vehicle account updated From e64d62a5112dfc9732da2fc4cc33a6e6807dd576 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Sat, 2 Nov 2024 11:08:52 -0400 Subject: [PATCH 09/19] Account actions concern --- app/controllers/account/trades_controller.rb | 4 +- .../account/valuations_controller.rb | 2 +- app/controllers/accounts_controller.rb | 16 +++++- app/controllers/concerns/account_actions.rb | 51 +++++++++++++++++ app/controllers/credit_cards_controller.rb | 52 ++++------------- app/controllers/cryptos_controller.rb | 36 +----------- app/controllers/depositories_controller.rb | 36 +----------- app/controllers/investments_controller.rb | 36 +----------- app/controllers/loans_controller.rb | 44 ++------------- app/controllers/other_assets_controller.rb | 36 +----------- .../other_liabilities_controller.rb | 36 +----------- app/controllers/properties_controller.rb | 46 ++------------- app/controllers/transactions_controller.rb | 2 +- app/controllers/vehicles_controller.rb | 46 ++------------- app/helpers/accounts_helper.rb | 56 ------------------- app/models/account/transfer.rb | 12 +++- app/models/depository.rb | 5 ++ .../account/transfers/_account_logos.html.erb | 11 ++-- app/views/accounts/_account_list.html.erb | 2 +- app/views/accounts/_form.html.erb | 18 +++--- app/views/accounts/edit.html.erb | 3 - app/views/accounts/show.html.erb | 0 app/views/accounts/show/_loading.html.erb | 3 + app/views/accounts/show/_menu.html.erb | 4 +- app/views/accounts/show/_template.html.erb | 36 ++++++------ app/views/credit_cards/edit.html.erb | 3 + app/views/cryptos/edit.html.erb | 3 + app/views/depositories/_form.html.erb | 37 ++---------- app/views/depositories/edit.html.erb | 3 + app/views/investments/_form.html.erb | 35 +----------- app/views/investments/edit.html.erb | 3 + app/views/investments/new.html.erb | 2 +- app/views/investments/show.html.erb | 22 ++++---- app/views/loans/edit.html.erb | 3 + app/views/other_assets/edit.html.erb | 3 + app/views/other_liabilities/edit.html.erb | 3 + app/views/properties/edit.html.erb | 3 + app/views/vehicles/edit.html.erb | 3 + config/locales/views/accounts/en.yml | 3 + config/locales/views/credit_cards/en.yml | 2 + config/locales/views/cryptos/en.yml | 2 + config/locales/views/depositories/en.yml | 2 + config/locales/views/investments/en.yml | 2 + config/locales/views/loans/en.yml | 2 + config/locales/views/other_assets/en.yml | 2 + config/locales/views/other_liabilities/en.yml | 2 + config/locales/views/properties/en.yml | 2 + config/locales/views/vehicles/en.yml | 2 + config/routes.rb | 2 +- .../credit_cards_controller_test.rb | 9 ++- test/controllers/cryptos_controller_test.rb | 5 ++ .../depositories_controller_test.rb | 7 +++ .../investments_controller_test.rb | 5 ++ test/controllers/loans_controller_test.rb | 5 ++ .../other_liabilities_controller_test.rb | 5 ++ .../controllers/properties_controller_test.rb | 5 ++ test/controllers/vehicles_controller_test.rb | 5 ++ 57 files changed, 267 insertions(+), 518 deletions(-) create mode 100644 app/controllers/concerns/account_actions.rb create mode 100644 app/views/accounts/show.html.erb create mode 100644 app/views/accounts/show/_loading.html.erb create mode 100644 app/views/credit_cards/edit.html.erb create mode 100644 app/views/cryptos/edit.html.erb create mode 100644 app/views/depositories/edit.html.erb create mode 100644 app/views/investments/edit.html.erb create mode 100644 app/views/loans/edit.html.erb create mode 100644 app/views/other_assets/edit.html.erb create mode 100644 app/views/other_liabilities/edit.html.erb create mode 100644 app/views/properties/edit.html.erb create mode 100644 app/views/vehicles/edit.html.erb diff --git a/app/controllers/account/trades_controller.rb b/app/controllers/account/trades_controller.rb index 0b8bc99d3da..e0897c9f22f 100644 --- a/app/controllers/account/trades_controller.rb +++ b/app/controllers/account/trades_controller.rb @@ -17,10 +17,10 @@ def create if entry = @builder.save entry.sync_account_later - redirect_to account_path(@account), notice: t(".success") + redirect_to @account, notice: t(".success") else flash[:alert] = t(".failure") - redirect_back_or_to account_path(@account) + redirect_back_or_to @account end end diff --git a/app/controllers/account/valuations_controller.rb b/app/controllers/account/valuations_controller.rb index e3015bde2b7..893a31f7a47 100644 --- a/app/controllers/account/valuations_controller.rb +++ b/app/controllers/account/valuations_controller.rb @@ -15,7 +15,7 @@ def create redirect_back_or_to account_valuations_path(@account), notice: t(".success") else flash[:alert] = @entry.errors.full_messages.to_sentence - redirect_to account_path(@account) + redirect_to @account.accountable end end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 52d9c5e6a34..1dfbdac060b 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,7 +1,7 @@ class AccountsController < ApplicationController layout :with_sidebar - before_action :set_account, only: %i[edit destroy sync update] + before_action :set_account, only: %i[edit show destroy sync update] def index @institutions = Current.family.institutions @@ -22,9 +22,17 @@ def list render layout: false end + def show + render accountable_view_path(:show) + end + + def edit + render accountable_view_path(:edit) + end + def update @account.update_with_sync!(account_params) - redirect_back_or_to @account.accountable, notice: t(".success") + redirect_back_or_to @account, notice: t(".success") end def destroy @@ -45,6 +53,10 @@ def sync_all private + def accountable_view_path(action) + @account.accountable.class.name.underscore.pluralize + "/" + action.to_s + end + def set_account @account = Current.family.accounts.find(params[:id]) end diff --git a/app/controllers/concerns/account_actions.rb b/app/controllers/concerns/account_actions.rb new file mode 100644 index 00000000000..4948869780b --- /dev/null +++ b/app/controllers/concerns/account_actions.rb @@ -0,0 +1,51 @@ +module AccountActions + extend ActiveSupport::Concern + + included do + layout :with_sidebar + before_action :set_account, only: [ :show, :edit, :update ] + end + + class_methods do + def permitted_accountable_attributes(*attrs) + @permitted_accountable_attributes = attrs if attrs.any? + @permitted_accountable_attributes ||= [ :id ] + end + end + + def new + @account = Current.family.accounts.build( + currency: Current.family.currency, + accountable_type: accountable_type, + ) + end + + def show + end + + def create + @account = Current.family.accounts.create_and_sync(account_params) + redirect_to @account, notice: t(".success") + end + + def update + @account.update_with_sync!(account_params) + redirect_to @account, notice: t(".success") + end + + private + def accountable_type + controller_name.classify.constantize + end + + def set_account + @account = Current.family.accounts.find_by(accountable_type: accountable_type.to_s, accountable_id: params[:id]) + end + + def account_params + params.require(:account).permit( + :name, :balance, :subtype, :currency, :institution_id, :accountable_type, + accountable_attributes: self.class.permitted_accountable_attributes + ) + end +end diff --git a/app/controllers/credit_cards_controller.rb b/app/controllers/credit_cards_controller.rb index d80bbcf4619..9bd2e93e3ce 100644 --- a/app/controllers/credit_cards_controller.rb +++ b/app/controllers/credit_cards_controller.rb @@ -1,44 +1,12 @@ class CreditCardsController < ApplicationController - layout :with_sidebar - - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.credit_cards.build( - currency: Current.family.currency - ) - end - - def show - end - - def create - account = Current.family.accounts.create_and_sync(credit_card_params) - redirect_to account, notice: t(".success") - end - - def update - @account.update_with_sync!(credit_card_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.credit_cards.find_by(accountable_id: params[:id]) - end - - def credit_card_params - params.require(:credit_card) - .permit( - :name, :balance, :institution_id, :currency, :accountable_type, - accountable_attributes: [ - :id, - :available_credit, - :minimum_payment, - :apr, - :annual_fee, - :expiration_date - ] - ) - end + include AccountActions + + permitted_accountable_attributes( + :id, + :available_credit, + :minimum_payment, + :apr, + :annual_fee, + :expiration_date + ) end diff --git a/app/controllers/cryptos_controller.rb b/app/controllers/cryptos_controller.rb index 2ce92c8ef63..fd1be847a58 100644 --- a/app/controllers/cryptos_controller.rb +++ b/app/controllers/cryptos_controller.rb @@ -1,35 +1,3 @@ -class CryptosController < AccountsController - layout :with_sidebar - - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.cryptos.build( - currency: Current.family.currency, - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.cryptos.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account).permit( - :name, :balance, :subtype, :currency, :accountable_type - ) - end +class CryptosController < ApplicationController + include AccountActions end diff --git a/app/controllers/depositories_controller.rb b/app/controllers/depositories_controller.rb index 38923a7c9fc..b11d6f40ca0 100644 --- a/app/controllers/depositories_controller.rb +++ b/app/controllers/depositories_controller.rb @@ -1,35 +1,3 @@ -class DepositoriesController < AccountsController - layout :with_sidebar - - before_action :set_account, only: [ :show, :update ] - - def new - @account = Current.family.accounts.depositories.build( - currency: Current.family.currency, - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.depositories.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account).permit( - :name, :balance, :subtype, :currency, :accountable_type - ) - end +class DepositoriesController < ApplicationController + include AccountActions end diff --git a/app/controllers/investments_controller.rb b/app/controllers/investments_controller.rb index 4a3fc426eaf..38cb8f489ed 100644 --- a/app/controllers/investments_controller.rb +++ b/app/controllers/investments_controller.rb @@ -1,35 +1,3 @@ -class InvestmentsController < AccountsController - layout :with_sidebar - - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.investments.build( - currency: Current.family.currency, - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.investments.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account).permit( - :name, :balance, :subtype, :currency, :accountable_type - ) - end +class InvestmentsController < ApplicationController + include AccountActions end diff --git a/app/controllers/loans_controller.rb b/app/controllers/loans_controller.rb index d1bc46528b4..b7eadbc07fa 100644 --- a/app/controllers/loans_controller.rb +++ b/app/controllers/loans_controller.rb @@ -1,43 +1,7 @@ class LoansController < ApplicationController - layout :with_sidebar + include AccountActions - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.loans.build( - currency: Current.family.currency - ) - end - - def show - end - - def create - account = Current.family.accounts.create_and_sync(account_params) - redirect_to account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - - def set_account - @account = Current.family.accounts.loans.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account) - .permit( - :name, :balance, :institution_id, :currency, :accountable_type, - accountable_attributes: [ - :id, - :rate_type, - :interest_rate, - :term_months - ] - ) - end + permitted_accountable_attributes( + :id, :rate_type, :interest_rate, :term_months + ) end diff --git a/app/controllers/other_assets_controller.rb b/app/controllers/other_assets_controller.rb index 5c731041e5e..836a11e7561 100644 --- a/app/controllers/other_assets_controller.rb +++ b/app/controllers/other_assets_controller.rb @@ -1,35 +1,3 @@ -class OtherAssetsController < AccountsController - layout :with_sidebar - - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.other_assets.build( - currency: Current.family.currency, - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.other_assets.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account).permit( - :name, :balance, :subtype, :currency, :accountable_type - ) - end +class OtherAssetsController < ApplicationController + include AccountActions end diff --git a/app/controllers/other_liabilities_controller.rb b/app/controllers/other_liabilities_controller.rb index 1c463dc83b6..77fdc0e04ea 100644 --- a/app/controllers/other_liabilities_controller.rb +++ b/app/controllers/other_liabilities_controller.rb @@ -1,35 +1,3 @@ -class OtherLiabilitiesController < AccountsController - layout :with_sidebar - - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.other_liabilities.build( - currency: Current.family.currency, - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - def set_account - @account = Current.family.accounts.other_liabilities.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account).permit( - :name, :balance, :subtype, :currency, :accountable_type - ) - end +class OtherLiabilitiesController < ApplicationController + include AccountActions end diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb index b48de72b4b5..72dbed0b4d7 100644 --- a/app/controllers/properties_controller.rb +++ b/app/controllers/properties_controller.rb @@ -1,44 +1,8 @@ class PropertiesController < ApplicationController - layout :with_sidebar + include AccountActions - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.properties.build( - currency: Current.family.currency - ) - end - - def show - end - - def create - account = Current.family.accounts.create_and_sync(account_params) - redirect_to account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - - def set_account - @account = Current.family.accounts.properties.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account) - .permit( - :name, :balance, :institution_id, :currency, :accountable_type, - accountable_attributes: [ - :id, - :year_built, - :area_unit, - :area_value, - address_attributes: [ :line1, :line2, :locality, :region, :country, :postal_code ] - ] - ) - end + permitted_accountable_attributes( + :id, :year_built, :area_unit, :area_value, + address_attributes: [ :line1, :line2, :locality, :region, :country, :postal_code ] + ) end diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index ed8f579dc53..6360bd19d17 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -32,7 +32,7 @@ def create .create!(transaction_entry_params.merge(amount: amount)) @entry.sync_account_later - redirect_back_or_to account_path(@entry.account), notice: t(".success") + redirect_back_or_to @entry.account, notice: t(".success") end def bulk_delete diff --git a/app/controllers/vehicles_controller.rb b/app/controllers/vehicles_controller.rb index 11134c3b49b..2376095d1ec 100644 --- a/app/controllers/vehicles_controller.rb +++ b/app/controllers/vehicles_controller.rb @@ -1,45 +1,7 @@ class VehiclesController < ApplicationController - layout :with_sidebar + include AccountActions - before_action :set_account, only: [ :update, :show ] - - def new - @account = Current.family.accounts.vehicles.build( - currency: Current.family.currency - ) - end - - def show - end - - def create - @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") - end - - def update - @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") - end - - private - - def set_account - @account = Current.family.accounts.vehicles.find_by(accountable_id: params[:id]) - end - - def account_params - params.require(:account) - .permit( - :name, :balance, :institution_id, :currency, :accountable_type, - accountable_attributes: [ - :id, - :make, - :model, - :year, - :mileage_value, - :mileage_unit - ] - ) - end + permitted_accountable_attributes( + :id, :make, :model, :year, :mileage_value, :mileage_unit + ) end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 2c9206f18b5..1f3291de1e9 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -66,62 +66,6 @@ def accountable_color(accountable_type) class_mapping(accountable_type)[:hex] end - # Eventually, we'll have an accountable form for each type of accountable, so - # this helper is a convenience for now to reuse common logic in the accounts controller - def new_account_form_url(account) - case account.accountable_type - when "Property" - properties_path - when "Vehicle" - vehicles_path - when "Loan" - loans_path - when "CreditCard" - credit_cards_path - else - accounts_path - end - end - - def edit_account_form_url(account) - case account.accountable_type - when "Property" - property_path(account) - when "Vehicle" - vehicle_path(account) - when "Loan" - loan_path(account) - when "CreditCard" - credit_card_path(account) - else - account_path(account) - end - end - - def account_tabs(account) - overview_tab = { key: "overview", label: t("accounts.show.overview"), path: account_path(account, tab: "overview"), partial_path: "accounts/overview" } - holdings_tab = { key: "holdings", label: t("accounts.show.holdings"), path: account_path(account, tab: "holdings"), route: account_holdings_path(account) } - cash_tab = { key: "cash", label: t("accounts.show.cash"), path: account_path(account, tab: "cash"), route: account_cashes_path(account) } - value_tab = { key: "valuations", label: t("accounts.show.value"), path: account_path(account, tab: "valuations"), route: account_valuations_path(account) } - transactions_tab = { key: "transactions", label: t("accounts.show.transactions"), path: account_path(account, tab: "transactions"), route: account_transactions_path(account) } - trades_tab = { key: "trades", label: t("accounts.show.trades"), path: account_path(account, tab: "trades"), route: account_trades_path(account) } - - return [ value_tab ] if account.other_asset? || account.other_liability? - return [ overview_tab, value_tab ] if account.property? || account.vehicle? - return [ holdings_tab, cash_tab, trades_tab, value_tab ] if account.investment? - return [ overview_tab, value_tab, transactions_tab ] if account.loan? || account.credit_card? - - [ value_tab, transactions_tab ] - end - - def selected_account_tab(account) - available_tabs = account_tabs(account) - - tab = available_tabs.find { |tab| tab[:key] == params[:tab] } - - tab || available_tabs.first - end - def account_groups(period: nil) assets, liabilities = Current.family.accounts.by_group(currency: Current.family.currency, period: period || Period.last_30_days).values_at(:assets, :liabilities) [ assets.children.sort_by(&:name), liabilities.children.sort_by(&:name) ].flatten diff --git a/app/models/account/transfer.rb b/app/models/account/transfer.rb index d66a29019b6..ec464003586 100644 --- a/app/models/account/transfer.rb +++ b/app/models/account/transfer.rb @@ -13,17 +13,25 @@ def amount_money end def from_name - outflow_transaction&.account&.name || I18n.t("account/transfer.from_fallback_name") + from_account&.name || I18n.t("account/transfer.from_fallback_name") end def to_name - inflow_transaction&.account&.name || I18n.t("account/transfer.to_fallback_name") + to_account&.name || I18n.t("account/transfer.to_fallback_name") end def name I18n.t("account/transfer.name", from_account: from_name, to_account: to_name) end + def from_account + outflow_transaction&.account + end + + def to_account + inflow_transaction&.account + end + def inflow_transaction entries.find { |e| e.inflow? } end diff --git a/app/models/depository.rb b/app/models/depository.rb index b6408bdd142..3b818f437b7 100644 --- a/app/models/depository.rb +++ b/app/models/depository.rb @@ -1,6 +1,11 @@ class Depository < ApplicationRecord include Accountable + SUBTYPES = [ + [ "Checking", "checking" ], + [ "Savings", "savings" ] + ].freeze + def color "#875BF7" end diff --git a/app/views/account/transfers/_account_logos.html.erb b/app/views/account/transfers/_account_logos.html.erb index c3c4a91d468..7db8b197c38 100644 --- a/app/views/account/transfers/_account_logos.html.erb +++ b/app/views/account/transfers/_account_logos.html.erb @@ -1,27 +1,24 @@ <%# locals: (transfer:, outflow: false) %> -<% from_account = transfer.outflow_transaction.account %> -<% to_account = transfer.inflow_transaction.account %> -
<% if outflow %> - <%= link_to account_path(transfer.outflow_transaction.account), class: "hover:opacity-90" do %> + <%= link_to transfer.from_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.from_name[0].upcase, size: "sm") %> <% end %> <%= lucide_icon "arrow-right", class: "text-gray-500 w-4 h-4" %> - <%= link_to account_path(transfer.inflow_transaction.account), class: "hover:opacity-90" do %> + <%= link_to transfer.to_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.to_name[0].upcase, size: "sm") %> <% end %> <% else %> - <%= link_to account_path(transfer.inflow_transaction.account), class: "hover:opacity-90" do %> + <%= link_to transfer.to_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.to_name[0].upcase, size: "sm") %> <% end %> <%= lucide_icon "arrow-left", class: "text-gray-500 w-4 h-4" %> - <%= link_to account_path(transfer.outflow_transaction.account), class: "hover:opacity-90" do %> + <%= link_to transfer.from_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.from_name[0].upcase, size: "sm") %> <% end %> <% end %> diff --git a/app/views/accounts/_account_list.html.erb b/app/views/accounts/_account_list.html.erb index dcdbbe8f956..821256c1d37 100644 --- a/app/views/accounts/_account_list.html.erb +++ b/app/views/accounts/_account_list.html.erb @@ -29,7 +29,7 @@ <% group.children.sort_by(&:name).each do |account_value_node| %> <% account = account_value_node.original %> - <%= link_to account.accountable, class: "flex items-center w-full gap-3 px-3 py-2 mb-1 hover:bg-gray-100 rounded-[10px]" do %> + <%= link_to account, class: "flex items-center w-full gap-3 px-3 py-2 mb-1 hover:bg-gray-100 rounded-[10px]" do %> <%= render "accounts/logo", account: account, size: "sm" %>

<%= account_value_node.name %>

diff --git a/app/views/accounts/_form.html.erb b/app/views/accounts/_form.html.erb index e85448e018f..3c758f11e09 100644 --- a/app/views/accounts/_form.html.erb +++ b/app/views/accounts/_form.html.erb @@ -1,22 +1,20 @@ <%# locals: (account:, url:) %> -<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %> +<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow" do |form| %>
- <%= 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") %> + <%= form.hidden_field :accountable_type %> <% if account.new_record? %> - <%= f.hidden_field :institution_id %> + <%= form.hidden_field :institution_id %> <% else %> - <%= f.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %> + <%= form.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %> <% end %> - <%= f.money_field :balance, label: t(".balance"), required: true, default_currency: Current.family.currency %> + <%= form.text_field :name, placeholder: t(".name_placeholder"), required: "required", label: t(".name_label") %> + <%= form.money_field :balance, label: t(".balance"), required: true, default_currency: Current.family.currency %> - <% if account.accountable %> - <%= render permitted_accountable_partial(account, "form"), f: f %> - <% end %> + <%= yield form %>
- <%= f.submit %> + <%= form.submit %> <% end %> diff --git a/app/views/accounts/edit.html.erb b/app/views/accounts/edit.html.erb index 26eff37d042..e69de29bb2d 100644 --- a/app/views/accounts/edit.html.erb +++ b/app/views/accounts/edit.html.erb @@ -1,3 +0,0 @@ -<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: edit_account_form_url(@account) %> -<% end %> diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/views/accounts/show/_loading.html.erb b/app/views/accounts/show/_loading.html.erb new file mode 100644 index 00000000000..c6adbdfdf0e --- /dev/null +++ b/app/views/accounts/show/_loading.html.erb @@ -0,0 +1,3 @@ +
+

Loading account...

+
\ No newline at end of file diff --git a/app/views/accounts/show/_menu.html.erb b/app/views/accounts/show/_menu.html.erb index 24bd51dc5f0..8ba7673aaa1 100644 --- a/app/views/accounts/show/_menu.html.erb +++ b/app/views/accounts/show/_menu.html.erb @@ -2,7 +2,7 @@ <%= contextual_menu do %>
- <%= link_to edit_polymorphic_path(account.accountable), + <%= link_to edit_account_path(account), data: { turbo_frame: :modal }, class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %> <%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %> @@ -17,7 +17,7 @@ <%= t(".import") %> <% end %> - <%= button_to polymorphic_path(account.accountable), + <%= button_to account, method: :delete, class: "block w-full py-2 px-3 space-x-2 text-red-600 hover:bg-red-50 flex items-center rounded-lg", data: { diff --git a/app/views/accounts/show/_template.html.erb b/app/views/accounts/show/_template.html.erb index 3291251a1d4..7d17e80c560 100644 --- a/app/views/accounts/show/_template.html.erb +++ b/app/views/accounts/show/_template.html.erb @@ -2,24 +2,26 @@ <%= turbo_stream_from account %> -<%= tag.div id: dom_id(account), class: "space-y-4" do %> - <% if header.present? %> - <%= header %> - <% else %> - <%= render "accounts/show/header", account: account %> - <% end %> - - <% if chart.present? %> - <%= chart %> - <% else %> - <%= render "accounts/show/chart", account: account %> - <% end %> +<%= turbo_frame_tag dom_id(account) do %> + <%= tag.div class: "space-y-4" do %> + <% if header.present? %> + <%= header %> + <% else %> + <%= render "accounts/show/header", account: account %> + <% end %> -
- <% if tabs.present? %> - <%= tabs %> + <% if chart.present? %> + <%= chart %> <% else %> - <%= render "accounts/show/activity", account: account %> + <%= render "accounts/show/chart", account: account %> <% end %> -
+ +
+ <% if tabs.present? %> + <%= tabs %> + <% else %> + <%= render "accounts/show/activity", account: account %> + <% end %> +
+ <% end %> <% end %> diff --git a/app/views/credit_cards/edit.html.erb b/app/views/credit_cards/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/credit_cards/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/cryptos/edit.html.erb b/app/views/cryptos/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/cryptos/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/depositories/_form.html.erb b/app/views/depositories/_form.html.erb index e28564dd336..40af60940fa 100644 --- a/app/views/depositories/_form.html.erb +++ b/app/views/depositories/_form.html.erb @@ -1,36 +1,7 @@ <%# locals: (account:) %> -<%= styled_form_with model: account, - url: depositories_path, - scope: :depository, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.select :subtype, - [["Checking", "checking"], ["Savings", "savings"]], +<%= render "accounts/form", account: account, url: depositories_path do |form| %> + <%= form.select :subtype, + Depository::SUBTYPES, { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> -
- - <%= f.submit %> -<% end %> +<% end %> \ No newline at end of file diff --git a/app/views/depositories/edit.html.erb b/app/views/depositories/edit.html.erb new file mode 100644 index 00000000000..58e242fa713 --- /dev/null +++ b/app/views/depositories/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/investments/_form.html.erb b/app/views/investments/_form.html.erb index d59a7ed6d40..1223715c55e 100644 --- a/app/views/investments/_form.html.erb +++ b/app/views/investments/_form.html.erb @@ -1,36 +1,7 @@ -<%# locals: (account:) %> +<%# locals: (account:, url:) %> -<%= styled_form_with model: account, - url: investments_path, - scope: :investment, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.select :subtype, +<%= render "accounts/form", account: account, url: url do |form| %> + <%= form.select :subtype, Investment::SUBTYPES, { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> -
- - <%= f.submit %> <% end %> diff --git a/app/views/investments/edit.html.erb b/app/views/investments/edit.html.erb new file mode 100644 index 00000000000..60f09d999ab --- /dev/null +++ b/app/views/investments/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "investments/form", account: @account, url: investment_path(@account.accountable) %> +<% end %> \ No newline at end of file diff --git a/app/views/investments/new.html.erb b/app/views/investments/new.html.erb index 120dbe1807e..8d7c636d9f1 100644 --- a/app/views/investments/new.html.erb +++ b/app/views/investments/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "investments/form", account: @account %> + <%= render "investments/form", account: @account, url: investments_path %> <% end %> diff --git a/app/views/investments/show.html.erb b/app/views/investments/show.html.erb index 2259d7296b9..9984844b0c2 100644 --- a/app/views/investments/show.html.erb +++ b/app/views/investments/show.html.erb @@ -1,9 +1,10 @@ <%= turbo_stream_from @account %> -<%= tag.div id: dom_id(@account), class: "space-y-4" do %> - <%= render "accounts/show/header", account: @account %> +<%= turbo_frame_tag dom_id(@account) do %> + <%= tag.div class: "space-y-4" do %> + <%= render "accounts/show/header", account: @account %> - <%= render "accounts/show/chart", + <%= render "accounts/show/chart", account: @account, title: t(".chart_title"), tooltip: render( @@ -12,11 +13,12 @@ cash: @account.balance_money ) %> -
- <%= render "accounts/show/tabs", account: @account, tabs: [ - { key: "activity", contents: render("accounts/show/activity", account: @account) }, - { key: "holdings", contents: render("investments/holdings_tab", account: @account) }, - { key: "cash", contents: render("investments/cash_tab", account: @account) } - ] %> -
+
+ <%= render "accounts/show/tabs", account: @account, tabs: [ + { key: "activity", contents: render("accounts/show/activity", account: @account) }, + { key: "holdings", contents: render("investments/holdings_tab", account: @account) }, + { key: "cash", contents: render("investments/cash_tab", account: @account) } + ] %> +
+ <% end %> <% end %> diff --git a/app/views/loans/edit.html.erb b/app/views/loans/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/loans/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/other_assets/edit.html.erb b/app/views/other_assets/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/other_assets/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/other_liabilities/edit.html.erb b/app/views/other_liabilities/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/other_liabilities/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/properties/edit.html.erb b/app/views/properties/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/properties/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/app/views/vehicles/edit.html.erb b/app/views/vehicles/edit.html.erb new file mode 100644 index 00000000000..90bab27493c --- /dev/null +++ b/app/views/vehicles/edit.html.erb @@ -0,0 +1,3 @@ +<%= modal_form_wrapper title: t(".edit", account: @account.name) do %> + <%= render "form", account: @account %> +<% end %> \ No newline at end of file diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index bea250e927e..e6219ad9ff4 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -22,6 +22,9 @@ en: name_placeholder: Example account name type_prompt: Select a type ungrouped: "(none)" + subtype_prompt: Select a subtype + none: None + subtype: Subtype index: accounts: Accounts add_institution: Add institution diff --git a/config/locales/views/credit_cards/en.yml b/config/locales/views/credit_cards/en.yml index 31b65802f14..05a9f66386f 100644 --- a/config/locales/views/credit_cards/en.yml +++ b/config/locales/views/credit_cards/en.yml @@ -30,3 +30,5 @@ en: unknown: Unknown update: success: Credit card account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/cryptos/en.yml b/config/locales/views/cryptos/en.yml index bc4ea2a4733..dcda0bdacfc 100644 --- a/config/locales/views/cryptos/en.yml +++ b/config/locales/views/cryptos/en.yml @@ -15,3 +15,5 @@ en: title: Enter account balance update: success: Crypto account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/depositories/en.yml b/config/locales/views/depositories/en.yml index e67767f0721..0718c7d043c 100644 --- a/config/locales/views/depositories/en.yml +++ b/config/locales/views/depositories/en.yml @@ -15,3 +15,5 @@ en: title: Enter account balance update: success: Depository account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/investments/en.yml b/config/locales/views/investments/en.yml index e8036b81e8d..6f7e26e37e5 100644 --- a/config/locales/views/investments/en.yml +++ b/config/locales/views/investments/en.yml @@ -22,3 +22,5 @@ en: holdings: Holdings total_value_tooltip: The total value is the sum of cash balance and your holdings value, minus margin loans. + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/loans/en.yml b/config/locales/views/loans/en.yml index f76fb50301e..0f4185a88c9 100644 --- a/config/locales/views/loans/en.yml +++ b/config/locales/views/loans/en.yml @@ -27,3 +27,5 @@ en: unknown: Unknown update: success: Loan account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/other_assets/en.yml b/config/locales/views/other_assets/en.yml index 6196258f67a..97af8393735 100644 --- a/config/locales/views/other_assets/en.yml +++ b/config/locales/views/other_assets/en.yml @@ -15,3 +15,5 @@ en: title: Enter asset details update: success: Other asset account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/other_liabilities/en.yml b/config/locales/views/other_liabilities/en.yml index 6d3be9039a2..cfde86a71e1 100644 --- a/config/locales/views/other_liabilities/en.yml +++ b/config/locales/views/other_liabilities/en.yml @@ -15,3 +15,5 @@ en: title: Enter liability details update: success: Other liability account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/properties/en.yml b/config/locales/views/properties/en.yml index 67a3e391180..07661c66f80 100644 --- a/config/locales/views/properties/en.yml +++ b/config/locales/views/properties/en.yml @@ -37,3 +37,5 @@ en: year_built: Year Built update: success: Property account updated + edit: + edit: "Edit %{account}" diff --git a/config/locales/views/vehicles/en.yml b/config/locales/views/vehicles/en.yml index cbfb7906cdc..b141e613cfe 100644 --- a/config/locales/views/vehicles/en.yml +++ b/config/locales/views/vehicles/en.yml @@ -30,3 +30,5 @@ en: year: Year update: success: Vehicle account updated + edit: + edit: "Edit %{account}" diff --git a/config/routes.rb b/config/routes.rb index d2f3f6b1413..da2955f0750 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,7 @@ resources :mappings, only: :update, module: :import end - resources :accounts, only: %i[index new update destroy] do + resources :accounts, only: %i[index show edit new update destroy] do collection do get :summary get :list diff --git a/test/controllers/credit_cards_controller_test.rb b/test/controllers/credit_cards_controller_test.rb index c2c872258b1..136cfe72b92 100644 --- a/test/controllers/credit_cards_controller_test.rb +++ b/test/controllers/credit_cards_controller_test.rb @@ -11,6 +11,11 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_credit_card_path(@credit_card) + assert_response :success + end + test "show" do get credit_card_url(@credit_card) assert_response :success @@ -22,7 +27,7 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest -> { Account::Valuation.count } => 2, -> { Account::Entry.count } => 2 do post credit_cards_path, params: { - credit_card: { + account: { name: "New Credit Card", balance: 1000, currency: "USD", @@ -57,7 +62,7 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest test "updates credit card" do assert_no_difference [ "Account.count", "CreditCard.count" ] do patch credit_card_path(@credit_card), params: { - credit_card: { + account: { name: "Updated Credit Card", balance: 2000, currency: "USD", diff --git a/test/controllers/cryptos_controller_test.rb b/test/controllers/cryptos_controller_test.rb index 0a820e08198..9c3ce8dddd3 100644 --- a/test/controllers/cryptos_controller_test.rb +++ b/test/controllers/cryptos_controller_test.rb @@ -11,6 +11,11 @@ class CryptosControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_crypto_url(@crypto) + assert_response :success + end + test "show" do get crypto_url(@crypto) assert_response :success diff --git a/test/controllers/depositories_controller_test.rb b/test/controllers/depositories_controller_test.rb index fe8eb98f369..5af3791c8eb 100644 --- a/test/controllers/depositories_controller_test.rb +++ b/test/controllers/depositories_controller_test.rb @@ -11,6 +11,11 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_depository_url(@depository) + assert_response :success + end + test "show" do get depository_url(@depository) assert_response :success @@ -21,6 +26,7 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest post depositories_url, params: { account: { accountable_type: "Depository", + institution_id: institutions(:chase).id, name: "New depository", balance: 10000, currency: "USD", @@ -37,6 +43,7 @@ class DepositoriesControllerTest < ActionDispatch::IntegrationTest assert_no_difference [ "Account.count", "Depository.count" ] do patch depository_url(@depository), params: { account: { + institution_id: institutions(:chase).id, name: "Updated name", balance: 10000, currency: "USD", diff --git a/test/controllers/investments_controller_test.rb b/test/controllers/investments_controller_test.rb index 0bd8cecba1b..43f3487e567 100644 --- a/test/controllers/investments_controller_test.rb +++ b/test/controllers/investments_controller_test.rb @@ -11,6 +11,11 @@ class InvestmentsControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_investment_url(@investment) + assert_response :success + end + test "show" do get investment_url(@investment) assert_response :success diff --git a/test/controllers/loans_controller_test.rb b/test/controllers/loans_controller_test.rb index 940c732cbed..e125e4d5611 100644 --- a/test/controllers/loans_controller_test.rb +++ b/test/controllers/loans_controller_test.rb @@ -11,6 +11,11 @@ class LoansControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_loan_path(@loan) + assert_response :success + end + test "show" do get loan_url(@loan) assert_response :success diff --git a/test/controllers/other_liabilities_controller_test.rb b/test/controllers/other_liabilities_controller_test.rb index 09bc27c78e2..0a35a841656 100644 --- a/test/controllers/other_liabilities_controller_test.rb +++ b/test/controllers/other_liabilities_controller_test.rb @@ -11,6 +11,11 @@ class OtherLiabilitiesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_other_liability_url(@other_liability) + assert_response :success + end + test "show" do get other_liability_url(@other_liability) assert_response :success diff --git a/test/controllers/properties_controller_test.rb b/test/controllers/properties_controller_test.rb index 6eb4ea77c1d..31e25ba367a 100644 --- a/test/controllers/properties_controller_test.rb +++ b/test/controllers/properties_controller_test.rb @@ -11,6 +11,11 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_property_url(@property) + assert_response :success + end + test "show" do get property_url(@property) assert_response :success diff --git a/test/controllers/vehicles_controller_test.rb b/test/controllers/vehicles_controller_test.rb index 6cd9d2e7195..0dc1d2e1c2a 100644 --- a/test/controllers/vehicles_controller_test.rb +++ b/test/controllers/vehicles_controller_test.rb @@ -11,6 +11,11 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "edit" do + get edit_vehicle_path(@vehicle) + assert_response :success + end + test "show" do get vehicle_url(@vehicle) assert_response :success From ad5d7bdaaa4c352f6c81d7c37d79ff59bc9239db Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Sat, 2 Nov 2024 12:20:47 -0400 Subject: [PATCH 10/19] Finalize forms, get account system tests passing --- app/controllers/accounts_controller.rb | 15 +-- app/controllers/concerns/account_actions.rb | 9 +- app/controllers/properties_controller.rb | 13 ++ app/helpers/accounts_helper.rb | 8 ++ app/views/account/entries/index.html.erb | 65 ++++----- app/views/accounts/_form.html.erb | 2 +- .../accounts/new/_method_selector.html.erb | 4 +- app/views/credit_cards/_form.html.erb | 95 +++++-------- app/views/credit_cards/edit.html.erb | 2 +- app/views/credit_cards/new.html.erb | 2 +- app/views/cryptos/_form.html.erb | 37 +----- app/views/cryptos/edit.html.erb | 2 +- app/views/cryptos/new.html.erb | 2 +- app/views/depositories/_form.html.erb | 4 +- app/views/depositories/edit.html.erb | 2 +- app/views/depositories/new.html.erb | 2 +- app/views/loans/_form.html.erb | 75 +++-------- app/views/loans/edit.html.erb | 2 +- app/views/loans/new.html.erb | 2 +- app/views/other_assets/_form.html.erb | 37 +----- app/views/other_assets/edit.html.erb | 4 +- app/views/other_assets/new.html.erb | 2 +- app/views/other_liabilities/_form.html.erb | 37 +----- app/views/other_liabilities/edit.html.erb | 2 +- app/views/other_liabilities/new.html.erb | 2 +- app/views/properties/_form.html.erb | 125 +++++++----------- app/views/properties/edit.html.erb | 2 +- app/views/properties/new.html.erb | 2 +- app/views/vehicles/_form.html.erb | 89 ++++--------- app/views/vehicles/edit.html.erb | 2 +- app/views/vehicles/new.html.erb | 2 +- config/locales/views/properties/en.yml | 2 + config/routes.rb | 2 +- test/system/accounts_test.rb | 22 ++- 34 files changed, 236 insertions(+), 439 deletions(-) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 1dfbdac060b..dca48cdca03 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,7 +1,7 @@ class AccountsController < ApplicationController layout :with_sidebar - before_action :set_account, only: %i[edit show destroy sync update] + before_action :set_account, only: %i[destroy sync update] def index @institutions = Current.family.institutions @@ -22,14 +22,6 @@ def list render layout: false end - def show - render accountable_view_path(:show) - end - - def edit - render accountable_view_path(:edit) - end - def update @account.update_with_sync!(account_params) redirect_back_or_to @account, notice: t(".success") @@ -52,11 +44,6 @@ def sync_all end private - - def accountable_view_path(action) - @account.accountable.class.name.underscore.pluralize + "/" + action.to_s - end - def set_account @account = Current.family.accounts.find(params[:id]) end diff --git a/app/controllers/concerns/account_actions.rb b/app/controllers/concerns/account_actions.rb index 4948869780b..3a1f3a067a6 100644 --- a/app/controllers/concerns/account_actions.rb +++ b/app/controllers/concerns/account_actions.rb @@ -16,21 +16,24 @@ def permitted_accountable_attributes(*attrs) def new @account = Current.family.accounts.build( currency: Current.family.currency, - accountable_type: accountable_type, + accountable: accountable_type.new, ) end def show end + def edit + end + def create @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account, notice: t(".success") + redirect_to @account.accountable, notice: t(".success") end def update @account.update_with_sync!(account_params) - redirect_to @account, notice: t(".success") + redirect_to @account.accountable, notice: t(".success") end private diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb index 72dbed0b4d7..73151a45c25 100644 --- a/app/controllers/properties_controller.rb +++ b/app/controllers/properties_controller.rb @@ -5,4 +5,17 @@ class PropertiesController < ApplicationController :id, :year_built, :area_unit, :area_value, address_attributes: [ :line1, :line2, :locality, :region, :country, :postal_code ] ) + + def new + @account = Current.family.accounts.build( + currency: Current.family.currency, + accountable: Property.new( + address: Address.new + ) + ) + end + + def edit + @account.accountable.address ||= Address.new + end end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 1f3291de1e9..b297151d85c 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -1,4 +1,12 @@ module AccountsHelper + def edit_account_path(account, options = {}) + edit_polymorphic_path(account.accountable, options) + end + + def account_path(account, options = {}) + polymorphic_path(account.accountable, options) + end + def new_accountable_path(type) klass = Accountable.from_type(type) "/#{klass.model_name.plural}/new" diff --git a/app/views/account/entries/index.html.erb b/app/views/account/entries/index.html.erb index ab7e36aca53..54abbf8f18f 100644 --- a/app/views/account/entries/index.html.erb +++ b/app/views/account/entries/index.html.erb @@ -21,65 +21,68 @@
-
- <%= form_with url: account_entries_path(@account), + <% if @entries.empty? %> +

<%= t(".no_entries") %>

+ <% else %> + +
+ <%= form_with url: account_entries_path(@account), id: "entries-search", scope: :q, method: :get, data: { controller: "auto-submit-form" } do |form| %> -
-
-
- <%= lucide_icon("search", class: "w-5 h-5 text-gray-500") %> - <%= form.search_field :search, +
+
+
+ <%= lucide_icon("search", class: "w-5 h-5 text-gray-500") %> + <%= form.search_field :search, placeholder: "Search entries by name", value: @q[:search], class: "form-field__input placeholder:text-sm placeholder:text-gray-500", "data-auto-submit-form-target": "auto" %> +
-
- <% end %> -
+ <% end %> +
- <%= tag.div id: dom_id(@account, "entries_bulk_select"), + <%= tag.div id: dom_id(@account, "entries_bulk_select"), data: { controller: "bulk-select", bulk_select_singular_label_value: t(".entry"), bulk_select_plural_label_value: t(".entries") } do %> - + -
-
- <%= check_box_tag "selection_entry", +
+
+ <%= check_box_tag "selection_entry", class: "maybe-checkbox maybe-checkbox--light", data: { action: "bulk-select#togglePageSelection" } %> -

<%= t(".date") %>

+

<%= t(".date") %>

+
+ <%= tag.p t(".amount"), class: "col-span-2 justify-self-end" %> + <%= tag.p t(".balance"), class: "col-span-2 justify-self-end" %>
- <%= tag.p t(".amount"), class: "col-span-2 justify-self-end" %> - <%= tag.p t(".balance"), class: "col-span-2 justify-self-end" %> -
-
-
- <% if @entries.any? %> +
+
+
<%= entries_by_date(@entries) do |entries| %> <%= render entries, show_balance: true, origin: "account" %> <% end %>
- <% else %> -

<%= t(".no_entries") %>

- <% end %> -
-
- <%= render "pagination", pagy: @pagy %> +
+ +
+ <%= render "pagination", pagy: @pagy %> +
-
+ <% end %> <% end %>
<% end %> diff --git a/app/views/accounts/_form.html.erb b/app/views/accounts/_form.html.erb index 3c758f11e09..17b8c3e7cf3 100644 --- a/app/views/accounts/_form.html.erb +++ b/app/views/accounts/_form.html.erb @@ -1,6 +1,6 @@ <%# locals: (account:, url:) %> -<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow" do |form| %> +<%= styled_form_with model: account, url: url, scope: :account, data: { turbo: false }, class: "flex flex-col gap-4 justify-between grow" do |form| %>
<%= form.hidden_field :accountable_type %> diff --git a/app/views/accounts/new/_method_selector.html.erb b/app/views/accounts/new/_method_selector.html.erb index fb6cc79defe..2760ff4f457 100644 --- a/app/views/accounts/new/_method_selector.html.erb +++ b/app/views/accounts/new/_method_selector.html.erb @@ -6,14 +6,14 @@ <%= lucide_icon("keyboard", class: "text-gray-500 w-5 h-5") %> - <%= t(".manual_entry") %> + <%= t("accounts.new.method_selector.manual_entry") %> <% end %> <%= lucide_icon("link-2", class: "text-gray-500 w-5 h-5") %> - <%= t(".connected_entry") %> + <%= t("accounts.new.method_selector.connected_entry") %>
<% end %> diff --git a/app/views/credit_cards/_form.html.erb b/app/views/credit_cards/_form.html.erb index 9f76c3e71bd..ff9e7582f28 100644 --- a/app/views/credit_cards/_form.html.erb +++ b/app/views/credit_cards/_form.html.erb @@ -1,68 +1,37 @@ -<%# locals: (account:) %> - -<%= styled_form_with model: account, - url: credit_cards_path, - scope: :credit_card, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> - -
-
- -
- <%= f.fields_for :accountable do |credit_card_form| %> -
- <%= credit_card_form.number_field :available_credit, - label: t(".available_credit"), - placeholder: t(".available_credit_placeholder"), - min: 0 %> -
+<%# locals: (account:, url:) %> + +<%= render "accounts/form", account: account, url: url do |form| %> +
+ +
+ <%= form.fields_for :accountable do |credit_card_form| %> +
+ <%= credit_card_form.number_field :available_credit, + label: t("credit_cards.form.available_credit"), + placeholder: t("credit_cards.form.available_credit_placeholder"), + min: 0 %> +
-
- <%= credit_card_form.number_field :minimum_payment, - label: t(".minimum_payment"), - placeholder: t(".minimum_payment_placeholder"), - min: 0 %> - <%= credit_card_form.number_field :apr, - label: t(".apr"), - placeholder: t(".apr_placeholder"), - min: 0, - step: 0.01 %> -
+
+ <%= credit_card_form.number_field :minimum_payment, + label: t("credit_cards.form.minimum_payment"), + placeholder: t("credit_cards.form.minimum_payment_placeholder"), + min: 0 %> + <%= credit_card_form.number_field :apr, + label: t("credit_cards.form.apr"), + placeholder: t("credit_cards.form.apr_placeholder"), + min: 0, + step: 0.01 %> +
-
- <%= credit_card_form.date_field :expiration_date, - label: t(".expiration_date") %> - <%= credit_card_form.number_field :annual_fee, - label: t(".annual_fee"), - placeholder: t(".annual_fee_placeholder"), - min: 0 %> -
- <% end %> +
+ <%= credit_card_form.date_field :expiration_date, + label: t("credit_cards.form.expiration_date") %> + <%= credit_card_form.number_field :annual_fee, + label: t("credit_cards.form.annual_fee"), + placeholder: t("credit_cards.form.annual_fee_placeholder"), + min: 0 %>
-
+ <% end %>
- - <%= f.submit %> <% end %> diff --git a/app/views/credit_cards/edit.html.erb b/app/views/credit_cards/edit.html.erb index 90bab27493c..4276aab56ea 100644 --- a/app/views/credit_cards/edit.html.erb +++ b/app/views/credit_cards/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: credit_card_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/credit_cards/new.html.erb b/app/views/credit_cards/new.html.erb index 8115dd14a93..b843973b6f2 100644 --- a/app/views/credit_cards/new.html.erb +++ b/app/views/credit_cards/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "credit_cards/form", account: @account %> + <%= render "credit_cards/form", account: @account, url: credit_cards_path %> <% end %> diff --git a/app/views/cryptos/_form.html.erb b/app/views/cryptos/_form.html.erb index 1729d5883f1..aa16d76baf4 100644 --- a/app/views/cryptos/_form.html.erb +++ b/app/views/cryptos/_form.html.erb @@ -1,36 +1,3 @@ -<%# locals: (account:) %> +<%# locals: (account:, url:) %> -<%= styled_form_with model: account, - url: cryptos_path, - scope: :crypto, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.select :subtype, - [["Bitcoin", "bitcoin"], ["Ethereum", "ethereum"], ["Other", "other"]], - { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> -
- - <%= f.submit %> -<% end %> +<%= render "accounts/form", account: account, url: url %> \ No newline at end of file diff --git a/app/views/cryptos/edit.html.erb b/app/views/cryptos/edit.html.erb index 90bab27493c..4c6190bf905 100644 --- a/app/views/cryptos/edit.html.erb +++ b/app/views/cryptos/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: crypto_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/cryptos/new.html.erb b/app/views/cryptos/new.html.erb index a535c5a906a..62c73227a2e 100644 --- a/app/views/cryptos/new.html.erb +++ b/app/views/cryptos/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "cryptos/form", account: @account %> + <%= render "cryptos/form", account: @account, url: cryptos_path %> <% end %> diff --git a/app/views/depositories/_form.html.erb b/app/views/depositories/_form.html.erb index 40af60940fa..c6a28fbc0da 100644 --- a/app/views/depositories/_form.html.erb +++ b/app/views/depositories/_form.html.erb @@ -1,6 +1,6 @@ -<%# locals: (account:) %> +<%# locals: (account:, url:) %> -<%= render "accounts/form", account: account, url: depositories_path do |form| %> +<%= render "accounts/form", account: account, url: url do |form| %> <%= form.select :subtype, Depository::SUBTYPES, { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> diff --git a/app/views/depositories/edit.html.erb b/app/views/depositories/edit.html.erb index 58e242fa713..906a5ba0be4 100644 --- a/app/views/depositories/edit.html.erb +++ b/app/views/depositories/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: depository_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/depositories/new.html.erb b/app/views/depositories/new.html.erb index cd7b7da8f68..dc50ac26db5 100644 --- a/app/views/depositories/new.html.erb +++ b/app/views/depositories/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "depositories/form", account: @account %> + <%= render "depositories/form", account: @account, url: depositories_path %> <% end %> diff --git a/app/views/loans/_form.html.erb b/app/views/loans/_form.html.erb index bc578555983..bfadda90cf6 100644 --- a/app/views/loans/_form.html.erb +++ b/app/views/loans/_form.html.erb @@ -1,57 +1,26 @@ -<%# locals: (account:) %> - -<%= styled_form_with model: account, - url: loans_path, - scope: :loan, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> - -
-
- -
- <%= f.fields_for :accountable do |loan_form| %> -
- <%= loan_form.number_field :interest_rate, - label: t(".interest_rate"), - placeholder: t(".interest_rate_placeholder"), - min: 0, - step: 0.01 %> - <%= loan_form.select :rate_type, - [["Fixed", "fixed"], ["Variable", "variable"], ["Adjustable", "adjustable"]], - { label: t(".rate_type") } %> -
+<%# locals: (account:, url:) %> + +<%= render "accounts/form", account: account, url: url do |form| %> +
+ +
+ <%= form.fields_for :accountable do |loan_form| %> +
+ <%= loan_form.number_field :interest_rate, + label: t("loans.form.interest_rate"), + placeholder: t("loans.form.interest_rate_placeholder"), + min: 0, + step: 0.01 %> + <%= loan_form.select :rate_type, + [["Fixed", "fixed"], ["Variable", "variable"], ["Adjustable", "adjustable"]], + { label: t("loans.form.rate_type") } %> +
-
- <%= loan_form.number_field :term_months, - label: t(".term_months"), - placeholder: t(".term_months_placeholder") %> -
- <% end %> +
+ <%= loan_form.number_field :term_months, + label: t("loans.form.term_months"), + placeholder: t("loans.form.term_months_placeholder") %>
-
+ <% end %>
- - <%= f.submit %> <% end %> diff --git a/app/views/loans/edit.html.erb b/app/views/loans/edit.html.erb index 90bab27493c..f2065d6225e 100644 --- a/app/views/loans/edit.html.erb +++ b/app/views/loans/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: loan_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/loans/new.html.erb b/app/views/loans/new.html.erb index 7dd32ff01eb..2e3696988d5 100644 --- a/app/views/loans/new.html.erb +++ b/app/views/loans/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "loans/form", account: @account %> + <%= render "loans/form", account: @account, url: loans_path %> <% end %> diff --git a/app/views/other_assets/_form.html.erb b/app/views/other_assets/_form.html.erb index be20086d0c1..aa16d76baf4 100644 --- a/app/views/other_assets/_form.html.erb +++ b/app/views/other_assets/_form.html.erb @@ -1,36 +1,3 @@ -<%# locals: (account:) %> +<%# locals: (account:, url:) %> -<%= styled_form_with model: account, - url: other_assets_path, - scope: :other_asset, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.select :subtype, - [["Other", "other"]], - { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> -
- - <%= f.submit %> -<% end %> +<%= render "accounts/form", account: account, url: url %> \ No newline at end of file diff --git a/app/views/other_assets/edit.html.erb b/app/views/other_assets/edit.html.erb index 90bab27493c..dacfec55785 100644 --- a/app/views/other_assets/edit.html.erb +++ b/app/views/other_assets/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> -<% end %> \ No newline at end of file + <%= render "other_assets/form", account: @account, url: other_asset_path(@account.accountable) %> +<% end %> diff --git a/app/views/other_assets/new.html.erb b/app/views/other_assets/new.html.erb index 789f3ec6008..90adfdd5457 100644 --- a/app/views/other_assets/new.html.erb +++ b/app/views/other_assets/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "other_assets/form", account: @account %> + <%= render "other_assets/form", account: @account, url: other_assets_path %> <% end %> diff --git a/app/views/other_liabilities/_form.html.erb b/app/views/other_liabilities/_form.html.erb index a8ea5705378..8895b27abe6 100644 --- a/app/views/other_liabilities/_form.html.erb +++ b/app/views/other_liabilities/_form.html.erb @@ -1,36 +1,3 @@ -<%# locals: (account:) %> +<%# locals: (account:, url:) %> -<%= styled_form_with model: account, - url: other_liabilities_path, - scope: :other_liability, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.select :subtype, - [["Other", "other"]], - { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> -
- - <%= f.submit %> -<% end %> +<%= render "accounts/form", account: account, url: url %> diff --git a/app/views/other_liabilities/edit.html.erb b/app/views/other_liabilities/edit.html.erb index 90bab27493c..720e4329ecd 100644 --- a/app/views/other_liabilities/edit.html.erb +++ b/app/views/other_liabilities/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: other_liability_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/other_liabilities/new.html.erb b/app/views/other_liabilities/new.html.erb index a39f0b63f38..a7e7bcb50ea 100644 --- a/app/views/other_liabilities/new.html.erb +++ b/app/views/other_liabilities/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "other_liabilities/form", account: @account %> + <%= render "other_liabilities/form", account: @account, url: other_liabilities_path %> <% end %> diff --git a/app/views/properties/_form.html.erb b/app/views/properties/_form.html.erb index 143398e8f25..59cb5232c2d 100644 --- a/app/views/properties/_form.html.erb +++ b/app/views/properties/_form.html.erb @@ -1,79 +1,54 @@ -<%# locals: (account:) %> - -<%= styled_form_with model: account, - url: properties_path, - scope: :property, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> +<%# locals: (account:, url:) %> + +<%= render "accounts/form", account: account, url: url do |form| %> + <%= form.select :subtype, + Depository::SUBTYPES, + { label: true, prompt: t("properties.form.subtype_prompt"), include_blank: t("properties.form.none") } %> + +
+ +
+ <%= form.fields_for :accountable do |property_form| %> +
+ <%= property_form.number_field :year_built, + label: t("properties.form.year_built"), + placeholder: t("properties.form.year_built_placeholder"), + min: 1800, + max: Time.current.year %> +
- <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> +
+ <%= property_form.number_field :area_value, + label: t("properties.form.area"), + placeholder: t("properties.form.area_placeholder"), + min: 0 %> + <%= property_form.select :area_unit, + [["Square Feet", "sqft"], ["Square Meters", "sqm"]], + { label: t("properties.form.area_unit") } %> +
- <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> + <%= property_form.fields_for :address do |address_form| %> + <%= address_form.text_field :line1, + label: t("properties.form.address_line1"), + placeholder: t("properties.form.address_line1_placeholder") %> +
+ <%= address_form.text_field :locality, + label: t("properties.form.locality"), + placeholder: t("properties.form.locality_placeholder") %> + <%= address_form.text_field :region, + label: t("properties.form.region"), + placeholder: t("properties.form.region_placeholder") %> +
+ +
+ <%= address_form.text_field :postal_code, + label: t("properties.form.postal_code"), + placeholder: t("properties.form.postal_code_placeholder") %> + <%= address_form.text_field :country, + label: t("properties.form.country"), + placeholder: t("properties.form.country_placeholder") %> +
+ <% end %> <% end %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> - -
-
- -
- <%= f.fields_for :accountable do |property_form| %> -
- <%= property_form.number_field :year_built, - label: t(".year_built"), - placeholder: t(".year_built_placeholder"), - min: 1800, - max: Time.current.year %> -
- -
- <%= property_form.number_field :area_value, - label: t(".area"), - placeholder: t(".area_placeholder"), - min: 0 %> - <%= property_form.select :area_unit, - [["Square Feet", "sqft"], ["Square Meters", "sqm"]], - { label: t(".area_unit") } %> -
- - <%= property_form.fields_for :address do |address_form| %> - <%= address_form.text_field :line1, - label: t(".address_line1"), - placeholder: t(".address_line1_placeholder") %> - <%= address_form.text_field :line2, - label: t(".address_line2"), - placeholder: t(".address_line2_placeholder") %> - <%= address_form.text_field :locality, - label: t(".locality"), - placeholder: t(".locality_placeholder") %> - <%= address_form.text_field :region, - label: t(".region"), - placeholder: t(".region_placeholder") %> - <%= address_form.text_field :postal_code, - label: t(".postal_code"), - placeholder: t(".postal_code_placeholder") %> - <%= address_form.text_field :country, - label: t(".country"), - placeholder: t(".country_placeholder") %> - <% end %> - <% end %> -
-
- - <%= f.submit %> -<% end %> +<% end %> \ No newline at end of file diff --git a/app/views/properties/edit.html.erb b/app/views/properties/edit.html.erb index 90bab27493c..93dc41c60db 100644 --- a/app/views/properties/edit.html.erb +++ b/app/views/properties/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: property_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/properties/new.html.erb b/app/views/properties/new.html.erb index 07012f41f19..204da56e35a 100644 --- a/app/views/properties/new.html.erb +++ b/app/views/properties/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "properties/form", account: @account %> + <%= render "properties/form", account: @account, url: properties_path %> <% end %> diff --git a/app/views/vehicles/_form.html.erb b/app/views/vehicles/_form.html.erb index 149a2340646..97dd7944292 100644 --- a/app/views/vehicles/_form.html.erb +++ b/app/views/vehicles/_form.html.erb @@ -1,64 +1,33 @@ -<%# locals: (account:) %> - -<%= styled_form_with model: account, - url: vehicles_path, - scope: :vehicle, - class: "flex flex-col gap-4 justify-between grow", - data: { turbo: false } do |f| %> -
- <%= f.hidden_field :accountable_type %> - - <%= f.text_field :name, - placeholder: t(".name_placeholder"), - required: "required", - label: t(".name_label") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, - Current.family.institutions.alphabetically, - :id, :name, - { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.money_field :balance, - label: t(".balance"), - required: true, - default_currency: Current.family.currency %> - -
-
- -
- <%= f.fields_for :accountable do |vehicle_form| %> -
- <%= vehicle_form.text_field :make, - label: t(".make"), - placeholder: t(".make_placeholder") %> - <%= vehicle_form.text_field :model, - label: t(".model"), - placeholder: t(".model_placeholder") %> -
+<%# locals: (account:, url:) %> + +<%= render "accounts/form", account: account, url: url do |form| %> +
+ +
+ <%= form.fields_for :accountable do |vehicle_form| %> +
+ <%= vehicle_form.text_field :make, + label: t("vehicles.form.make"), + placeholder: t("vehicles.form.make_placeholder") %> + <%= vehicle_form.text_field :model, + label: t("vehicles.form.model"), + placeholder: t("vehicles.form.model_placeholder") %> +
-
- <%= vehicle_form.number_field :year, - label: t(".year"), - placeholder: t(".year_placeholder"), - min: 1900, - max: Time.current.year + 1 %> - <%= vehicle_form.number_field :mileage_value, - label: t(".mileage"), - placeholder: t(".mileage_placeholder"), - min: 0 %> - <%= vehicle_form.select :mileage_unit, - [["Miles", "mi"], ["Kilometers", "km"]], - { label: t(".mileage_unit") } %> -
- <% end %> +
+ <%= vehicle_form.number_field :year, + label: t("vehicles.form.year"), + placeholder: t("vehicles.form.year_placeholder"), + min: 1900, + max: Time.current.year + 1 %> + <%= vehicle_form.number_field :mileage_value, + label: t("vehicles.form.mileage"), + placeholder: t("vehicles.form.mileage_placeholder"), + min: 0 %> + <%= vehicle_form.select :mileage_unit, + [["Miles", "mi"], ["Kilometers", "km"]], + { label: t("vehicles.form.mileage_unit") } %>
-
+ <% end %>
- - <%= f.submit %> <% end %> diff --git a/app/views/vehicles/edit.html.erb b/app/views/vehicles/edit.html.erb index 90bab27493c..00fe5b56cd3 100644 --- a/app/views/vehicles/edit.html.erb +++ b/app/views/vehicles/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account %> + <%= render "form", account: @account, url: vehicle_path(@account.accountable) %> <% end %> \ No newline at end of file diff --git a/app/views/vehicles/new.html.erb b/app/views/vehicles/new.html.erb index db423fb317a..ba2acba4660 100644 --- a/app/views/vehicles/new.html.erb +++ b/app/views/vehicles/new.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".title") do %> - <%= render "vehicles/form", account: @account %> + <%= render "vehicles/form", account: @account, url: vehicles_path %> <% end %> diff --git a/config/locales/views/properties/en.yml b/config/locales/views/properties/en.yml index 07661c66f80..c76bf84552d 100644 --- a/config/locales/views/properties/en.yml +++ b/config/locales/views/properties/en.yml @@ -4,6 +4,8 @@ en: create: success: Property account created form: + test1: Test 1 is working + test2: Test 2 is working address_line1: Street address address_line1_placeholder: 123 Main St address_line2: Apartment/Suite diff --git a/config/routes.rb b/config/routes.rb index da2955f0750..d2f3f6b1413 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,7 @@ resources :mappings, only: :update, module: :import end - resources :accounts, only: %i[index show edit new update destroy] do + resources :accounts, only: %i[index new update destroy] do collection do get :summary get :list diff --git a/test/system/accounts_test.rb b/test/system/accounts_test.rb index b7b6d18e305..9583fe48071 100644 --- a/test/system/accounts_test.rb +++ b/test/system/accounts_test.rb @@ -23,12 +23,11 @@ class AccountsTest < ApplicationSystemTestCase test "can create property account" do assert_account_created "Property" do fill_in "Year built", with: 2005 - fill_in "Area value", with: 2250 - fill_in "Address line 1", with: "123 Main St" - fill_in "Address line 2", with: "Apt 4B" + fill_in "Living area", with: 2250 + fill_in "Street address", with: "123 Main St" fill_in "City", with: "San Francisco" - fill_in "State", with: "CA" - fill_in "Postal code", with: "94101" + fill_in "State/Province", with: "CA" + fill_in "ZIP/Postal code", with: "94101" fill_in "Country", with: "US" end end @@ -80,14 +79,16 @@ def open_new_account_modal end def assert_account_created(accountable_type, &block) - click_link "Enter account manually" + click_link humanized_accountable(accountable_type) + click_link "Enter account balance" account_name = "[system test] #{accountable_type} Account" - select accountable_type.titleize, from: "Account type" - fill_in "Account name", with: account_name + fill_in "Account name*", with: account_name fill_in "account[balance]", with: 100.99 + yield if block_given? + click_button "Create Account" find("details", text: humanized_accountable(accountable_type)).click @@ -97,17 +98,14 @@ def assert_account_created(accountable_type, &block) assert_text account_name created_account = Account.order(:created_at).last - created_account.update!(mode: "transactions") - visit account_url(created_account) + visit polymorphic_path(created_account.accountable) within "header" do find('button[data-menu-target="button"]').click click_on "Edit" end - yield if block_given? - fill_in "Account name", with: "Updated account name" click_button "Update Account" assert_selector "h2", text: "Updated account name" From e274219f8b155fb06be223aa980d6194983a8e85 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Sat, 2 Nov 2024 15:00:18 -0400 Subject: [PATCH 11/19] Get tests passing --- app/controllers/account/trades_controller.rb | 4 +- app/controllers/concerns/account_actions.rb | 5 +- ...hange_rate_provider_missings_controller.rb | 5 +- app/controllers/properties_controller.rb | 3 +- app/helpers/accounts_helper.rb | 6 +- app/views/account/entries/index.html.erb | 2 +- .../transactions/_transaction.html.erb | 2 +- app/views/accounts/_account.html.erb | 2 +- app/views/accounts/_account_list.html.erb | 2 +- app/views/accounts/_account_type.html.erb | 4 +- app/views/accounts/_empty.html.erb | 2 +- app/views/accounts/index.html.erb | 2 +- app/views/accounts/new.html.erb | 20 ++--- app/views/accounts/show/_loading.html.erb | 2 +- app/views/accounts/show/_menu.html.erb | 2 +- app/views/accounts/summary.html.erb | 4 +- app/views/accounts/summary/_header.html.erb | 2 +- app/views/credit_cards/edit.html.erb | 2 +- app/views/cryptos/_form.html.erb | 2 +- app/views/cryptos/edit.html.erb | 2 +- app/views/depositories/_form.html.erb | 2 +- app/views/depositories/edit.html.erb | 2 +- app/views/investments/edit.html.erb | 2 +- app/views/layouts/_sidebar.html.erb | 4 +- app/views/loans/edit.html.erb | 2 +- app/views/other_assets/_form.html.erb | 2 +- app/views/other_liabilities/edit.html.erb | 2 +- app/views/pages/dashboard.html.erb | 2 +- app/views/properties/_form.html.erb | 2 +- app/views/properties/edit.html.erb | 2 +- .../shared/_no_account_empty_state.html.erb | 2 +- app/views/transactions/index.html.erb | 3 +- app/views/vehicles/edit.html.erb | 2 +- config/i18n-tasks.yml | 6 +- config/locales/views/accounts/en.yml | 13 --- config/locales/views/credit_cards/en.yml | 9 +- config/locales/views/cryptos/en.yml | 12 +-- config/locales/views/depositories/en.yml | 9 +- config/locales/views/investments/en.yml | 9 +- config/locales/views/loans/en.yml | 9 +- config/locales/views/other_assets/en.yml | 12 +-- config/locales/views/other_liabilities/en.yml | 12 +-- config/locales/views/properties/en.yml | 15 +--- config/locales/views/transactions/en.yml | 1 + config/locales/views/vehicles/en.yml | 9 +- config/routes.rb | 2 +- .../account/trades_controller_test.rb | 12 +-- .../account/transfers_controller_test.rb | 2 +- .../account/valuations_controller_test.rb | 2 +- test/controllers/accounts_controller_test.rb | 49 ----------- .../credit_cards_controller_test.rb | 45 ++++------ test/controllers/cryptos_controller_test.rb | 52 +----------- .../depositories_controller_test.rb | 54 +----------- .../impersonation_sessions_controller_test.rb | 2 +- .../investments_controller_test.rb | 52 +----------- ..._rate_provider_missings_controller_test.rb | 2 +- test/controllers/loans_controller_test.rb | 41 ++++----- .../other_assets_controller_test.rb | 47 +---------- .../other_liabilities_controller_test.rb | 52 +----------- .../controllers/properties_controller_test.rb | 33 +++----- test/controllers/vehicles_controller_test.rb | 39 +++------ .../account_actions_interface_test.rb | 84 +++++++++++++++++++ test/system/trades_test.rb | 7 +- test/system/transactions_test.rb | 6 +- test/system/transfers_test.rb | 3 +- 65 files changed, 252 insertions(+), 554 deletions(-) create mode 100644 test/interfaces/account_actions_interface_test.rb diff --git a/app/controllers/account/trades_controller.rb b/app/controllers/account/trades_controller.rb index e0897c9f22f..f043913a244 100644 --- a/app/controllers/account/trades_controller.rb +++ b/app/controllers/account/trades_controller.rb @@ -17,10 +17,10 @@ def create if entry = @builder.save entry.sync_account_later - redirect_to @account, notice: t(".success") + redirect_to @account.accountable, notice: t(".success") else flash[:alert] = t(".failure") - redirect_back_or_to @account + redirect_back_or_to @account.accountable end end diff --git a/app/controllers/concerns/account_actions.rb b/app/controllers/concerns/account_actions.rb index 3a1f3a067a6..82573390fff 100644 --- a/app/controllers/concerns/account_actions.rb +++ b/app/controllers/concerns/account_actions.rb @@ -17,6 +17,7 @@ def new @account = Current.family.accounts.build( currency: Current.family.currency, accountable: accountable_type.new, + institution_id: params[:institution_id] ) end @@ -28,12 +29,12 @@ def edit def create @account = Current.family.accounts.create_and_sync(account_params) - redirect_to @account.accountable, notice: t(".success") + redirect_back_or_to @account.accountable, notice: t(".success") end def update @account.update_with_sync!(account_params) - redirect_to @account.accountable, notice: t(".success") + redirect_back_or_to @account.accountable, notice: t(".success") end private diff --git a/app/controllers/issue/exchange_rate_provider_missings_controller.rb b/app/controllers/issue/exchange_rate_provider_missings_controller.rb index 91cac7f5cba..e3224ef81c4 100644 --- a/app/controllers/issue/exchange_rate_provider_missings_controller.rb +++ b/app/controllers/issue/exchange_rate_provider_missings_controller.rb @@ -3,8 +3,9 @@ class Issue::ExchangeRateProviderMissingsController < ApplicationController def update Setting.synth_api_key = exchange_rate_params[:synth_api_key] - @issue.issuable.sync_later - redirect_back_or_to account_path(@issue.issuable) + account = @issue.issuable + account.sync_later + redirect_back_or_to account.accountable end private diff --git a/app/controllers/properties_controller.rb b/app/controllers/properties_controller.rb index 73151a45c25..9daa7bd9d25 100644 --- a/app/controllers/properties_controller.rb +++ b/app/controllers/properties_controller.rb @@ -11,7 +11,8 @@ def new currency: Current.family.currency, accountable: Property.new( address: Address.new - ) + ), + institution_id: params[:institution_id] ) end diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index b297151d85c..0f63728170c 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -7,9 +7,11 @@ def account_path(account, options = {}) polymorphic_path(account.accountable, options) end - def new_accountable_path(type) + def new_accountable_path(type, institution_id: nil) klass = Accountable.from_type(type) - "/#{klass.model_name.plural}/new" + path = "/#{klass.model_name.plural}/new" + path += "?institution_id=#{institution_id}" if institution_id.present? + path end def period_label(period) diff --git a/app/views/account/entries/index.html.erb b/app/views/account/entries/index.html.erb index 54abbf8f18f..a3ab1eb172e 100644 --- a/app/views/account/entries/index.html.erb +++ b/app/views/account/entries/index.html.erb @@ -13,7 +13,7 @@ <%= tag.span t(".new_balance"), class: "text-sm" %> <% end %> - <%= link_to new_transaction_path(account_id: @account.id), data: { turbo_frame: :modal }, class: "block p-2 rounded-lg hover:bg-gray-50 flex items-center gap-2" do %> + <%= link_to @account.investment? ? new_account_trade_path(@account) : new_transaction_path(account_id: @account.id), data: { turbo_frame: :modal }, class: "block p-2 rounded-lg hover:bg-gray-50 flex items-center gap-2" do %> <%= lucide_icon("credit-card", class: "text-gray-500 w-5 h-5") %> <%= tag.span t(".new_transaction"), class: "text-sm" %> <% end %> diff --git a/app/views/account/transactions/_transaction.html.erb b/app/views/account/transactions/_transaction.html.erb index 3c6b7ef8d6d..80afbaea59c 100644 --- a/app/views/account/transactions/_transaction.html.erb +++ b/app/views/account/transactions/_transaction.html.erb @@ -52,7 +52,7 @@ <%= tag.p account.name %> <% else %> <%= link_to account.name, - account_path(account, tab: "transactions"), + polymorphic_path(account.accountable, tab: "transactions"), data: { turbo_frame: "_top" }, class: "hover:underline" %> <% end %> diff --git a/app/views/accounts/_account.html.erb b/app/views/accounts/_account.html.erb index e8627e69eb2..2debcd3d3d1 100644 --- a/app/views/accounts/_account.html.erb +++ b/app/views/accounts/_account.html.erb @@ -16,7 +16,7 @@ <% end %>
- <%= link_to edit_account_path(account), data: { turbo_frame: :modal }, class: "group-hover/account:flex hidden hover:opacity-80 items-center justify-center" do %> + <%= link_to edit_polymorphic_path(account.accountable), data: { turbo_frame: :modal }, class: "group-hover/account:flex hidden hover:opacity-80 items-center justify-center" do %> <%= lucide_icon "pencil-line", class: "w-4 h-4 text-gray-500" %> <% end %>
diff --git a/app/views/accounts/_account_list.html.erb b/app/views/accounts/_account_list.html.erb index 821256c1d37..922c3373483 100644 --- a/app/views/accounts/_account_list.html.erb +++ b/app/views/accounts/_account_list.html.erb @@ -61,7 +61,7 @@
<% end %> <% end %> - <%= link_to new_account_path(step: "method", type: type.name.demodulize), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path(type: type.name.demodulize), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5") %> <%= t(".new_account", type: type.model_name.human.downcase) %> <% end %> diff --git a/app/views/accounts/_account_type.html.erb b/app/views/accounts/_account_type.html.erb index 5d6a00ba962..8c2b86bf8a8 100644 --- a/app/views/accounts/_account_type.html.erb +++ b/app/views/accounts/_account_type.html.erb @@ -1,6 +1,6 @@ -<%# locals: (accountable:) %> +<%# locals: (accountable:, institution_id: nil) %> -<%= link_to new_account_path(type: accountable.class), +<%= link_to new_account_path(type: accountable.class, institution_id: institution_id), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-alpha-black-25 hover:bg-alpha-black-25 border border-transparent block px-2 rounded-lg p-2" do %> <%= lucide_icon(accountable.icon, style: "color: #{accountable.color}", class: "w-5 h-5") %> diff --git a/app/views/accounts/_empty.html.erb b/app/views/accounts/_empty.html.erb index 68c6431622b..e938c863d57 100644 --- a/app/views/accounts/_empty.html.erb +++ b/app/views/accounts/_empty.html.erb @@ -3,7 +3,7 @@ <%= tag.p t(".no_accounts"), class: "text-gray-900 mb-1 font-medium" %> <%= tag.p t(".empty_message"), class: "text-gray-500 mb-4" %> - <%= link_to new_account_path(step: "method"), class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, class: "w-fit flex text-white text-sm font-medium items-center gap-1 bg-gray-900 rounded-lg p-2 pr-3", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5") %> <%= t(".new_account") %> <% end %> diff --git a/app/views/accounts/index.html.erb b/app/views/accounts/index.html.erb index 50d4446d6ab..a53f33a0e98 100644 --- a/app/views/accounts/index.html.erb +++ b/app/views/accounts/index.html.erb @@ -20,7 +20,7 @@ <%= render "sync_all_button" %> - <%= link_to new_account_path(step: "method"), + <%= link_to new_account_path, data: { turbo_frame: "modal" }, class: "btn btn--primary flex items-center gap-1" do %> <%= lucide_icon("plus", class: "w-5 h-5") %> diff --git a/app/views/accounts/new.html.erb b/app/views/accounts/new.html.erb index 0abf5267e7d..38143f88daf 100644 --- a/app/views/accounts/new.html.erb +++ b/app/views/accounts/new.html.erb @@ -1,17 +1,17 @@ <% if params[:type].present? %> - <%= render "accounts/new/method_selector", path: new_accountable_path(params[:type]) %> + <%= render "accounts/new/method_selector", path: new_accountable_path(params[:type], institution_id: params[:institution_id]) %> <% else %> <%= render layout: "accounts/new/container", locals: { title: t(".title") } do %>
- <%= render "account_type", accountable: Depository.new %> - <%= render "account_type", accountable: Investment.new %> - <%= render "account_type", accountable: Crypto.new %> - <%= render "account_type", accountable: Property.new %> - <%= render "account_type", accountable: Vehicle.new %> - <%= render "account_type", accountable: CreditCard.new %> - <%= render "account_type", accountable: Loan.new %> - <%= render "account_type", accountable: OtherAsset.new %> - <%= render "account_type", accountable: OtherLiability.new %> + <%= render "account_type", accountable: Depository.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: Investment.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: Crypto.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: Property.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: Vehicle.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: CreditCard.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: Loan.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: OtherAsset.new, institution_id: params[:institution_id] %> + <%= render "account_type", accountable: OtherLiability.new, institution_id: params[:institution_id] %>
<% end %> <% end %> diff --git a/app/views/accounts/show/_loading.html.erb b/app/views/accounts/show/_loading.html.erb index c6adbdfdf0e..a4254988bbc 100644 --- a/app/views/accounts/show/_loading.html.erb +++ b/app/views/accounts/show/_loading.html.erb @@ -1,3 +1,3 @@

Loading account...

-
\ No newline at end of file +
diff --git a/app/views/accounts/show/_menu.html.erb b/app/views/accounts/show/_menu.html.erb index 8ba7673aaa1..bbd9b01e001 100644 --- a/app/views/accounts/show/_menu.html.erb +++ b/app/views/accounts/show/_menu.html.erb @@ -2,7 +2,7 @@ <%= contextual_menu do %>
- <%= link_to edit_account_path(account), + <%= link_to edit_polymorphic_path(account.accountable), data: { turbo_frame: :modal }, class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %> <%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %> diff --git a/app/views/accounts/summary.html.erb b/app/views/accounts/summary.html.erb index d957e0ab4b5..0894ee34eb8 100644 --- a/app/views/accounts/summary.html.erb +++ b/app/views/accounts/summary.html.erb @@ -43,7 +43,7 @@

Assets

- <%= link_to new_account_path(step: "method"), class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>

<%= t(".new") %>

<% end %> @@ -68,7 +68,7 @@

Liabilities

- <%= link_to new_account_path(step: "method"), class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, class: "btn btn--secondary flex items-center gap-1", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %>

<%= t(".new") %>

<% end %> diff --git a/app/views/accounts/summary/_header.html.erb b/app/views/accounts/summary/_header.html.erb index 348fc9b980c..f8c8eb3e557 100644 --- a/app/views/accounts/summary/_header.html.erb +++ b/app/views/accounts/summary/_header.html.erb @@ -13,7 +13,7 @@ <% end %> - <%= link_to new_account_path(step: "method"), class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %> + <%= link_to new_account_path, class: "rounded-lg bg-gray-900 text-white flex items-center gap-1 justify-center hover:bg-gray-700 px-3 py-2", data: { turbo_frame: :modal } do %> <%= lucide_icon("plus", class: "w-5 h-5") %>

<%= t(".new") %>

<% end %> diff --git a/app/views/credit_cards/edit.html.erb b/app/views/credit_cards/edit.html.erb index 4276aab56ea..25c6458c64d 100644 --- a/app/views/credit_cards/edit.html.erb +++ b/app/views/credit_cards/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: credit_card_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/cryptos/_form.html.erb b/app/views/cryptos/_form.html.erb index aa16d76baf4..8895b27abe6 100644 --- a/app/views/cryptos/_form.html.erb +++ b/app/views/cryptos/_form.html.erb @@ -1,3 +1,3 @@ <%# locals: (account:, url:) %> -<%= render "accounts/form", account: account, url: url %> \ No newline at end of file +<%= render "accounts/form", account: account, url: url %> diff --git a/app/views/cryptos/edit.html.erb b/app/views/cryptos/edit.html.erb index 4c6190bf905..751939569fb 100644 --- a/app/views/cryptos/edit.html.erb +++ b/app/views/cryptos/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: crypto_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/depositories/_form.html.erb b/app/views/depositories/_form.html.erb index c6a28fbc0da..bf88ec5a544 100644 --- a/app/views/depositories/_form.html.erb +++ b/app/views/depositories/_form.html.erb @@ -4,4 +4,4 @@ <%= form.select :subtype, Depository::SUBTYPES, { label: true, prompt: t(".subtype_prompt"), include_blank: t(".none") } %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/depositories/edit.html.erb b/app/views/depositories/edit.html.erb index 906a5ba0be4..37ada5eaa6b 100644 --- a/app/views/depositories/edit.html.erb +++ b/app/views/depositories/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: depository_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/investments/edit.html.erb b/app/views/investments/edit.html.erb index 60f09d999ab..aaa76b2b90a 100644 --- a/app/views/investments/edit.html.erb +++ b/app/views/investments/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "investments/form", account: @account, url: investment_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/layouts/_sidebar.html.erb b/app/views/layouts/_sidebar.html.erb index 8c997673b86..c274dc75b8d 100644 --- a/app/views/layouts/_sidebar.html.erb +++ b/app/views/layouts/_sidebar.html.erb @@ -95,7 +95,7 @@ <%= period_select form: form, selected: "last_30_days", classes: "w-full border-none pl-2 pr-7 text-xs bg-transparent gap-1 cursor-pointer font-semibold tracking-wide focus:outline-none focus:ring-0" %> <% end %>
- <%= link_to new_account_path(step: "method"), id: "sidebar-new-account", class: "block hover:bg-gray-100 font-semibold text-gray-900 flex items-center rounded p-1", title: t(".new_account"), data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, id: "sidebar-new-account", class: "block hover:bg-gray-100 font-semibold text-gray-900 flex items-center rounded p-1", title: t(".new_account"), data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5 text-gray-500") %> <% end %>
@@ -106,7 +106,7 @@ <%= render "accounts/account_list", group: group %> <% end %> <% else %> - <%= link_to new_account_path(step: "method"), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5") %> <%= tag.p t(".new_account") %> <% end %> diff --git a/app/views/loans/edit.html.erb b/app/views/loans/edit.html.erb index f2065d6225e..c039900329b 100644 --- a/app/views/loans/edit.html.erb +++ b/app/views/loans/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: loan_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/other_assets/_form.html.erb b/app/views/other_assets/_form.html.erb index aa16d76baf4..8895b27abe6 100644 --- a/app/views/other_assets/_form.html.erb +++ b/app/views/other_assets/_form.html.erb @@ -1,3 +1,3 @@ <%# locals: (account:, url:) %> -<%= render "accounts/form", account: account, url: url %> \ No newline at end of file +<%= render "accounts/form", account: account, url: url %> diff --git a/app/views/other_liabilities/edit.html.erb b/app/views/other_liabilities/edit.html.erb index 720e4329ecd..9fd7d68b4dd 100644 --- a/app/views/other_liabilities/edit.html.erb +++ b/app/views/other_liabilities/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: other_liability_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/pages/dashboard.html.erb b/app/views/pages/dashboard.html.erb index 87d181bcd9f..666cf509821 100644 --- a/app/views/pages/dashboard.html.erb +++ b/app/views/pages/dashboard.html.erb @@ -17,7 +17,7 @@
<% end %> - <%= link_to new_account_path(step: "method"), class: "flex items-center gap-1 btn btn--primary", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, class: "flex items-center gap-1 btn btn--primary", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5") %> <%= t(".new") %> <% end %> diff --git a/app/views/properties/_form.html.erb b/app/views/properties/_form.html.erb index 59cb5232c2d..2d03684bfd3 100644 --- a/app/views/properties/_form.html.erb +++ b/app/views/properties/_form.html.erb @@ -51,4 +51,4 @@ <% end %> <% end %>
-<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/properties/edit.html.erb b/app/views/properties/edit.html.erb index 93dc41c60db..e55052ff9c2 100644 --- a/app/views/properties/edit.html.erb +++ b/app/views/properties/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: property_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/shared/_no_account_empty_state.html.erb b/app/views/shared/_no_account_empty_state.html.erb index b4eda59760f..cfb79003039 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(step: "method"), class: "btn btn--primary flex items-center gap-1", data: { turbo_frame: "modal" } do %> + <%= link_to new_account_path, 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/app/views/transactions/index.html.erb b/app/views/transactions/index.html.erb index b17ecf7e291..c2663da36d8 100644 --- a/app/views/transactions/index.html.erb +++ b/app/views/transactions/index.html.erb @@ -5,7 +5,8 @@
" + data-bulk-select-singular-label-value="<%= t(".transaction") %>" + data-bulk-select-plural-label-value="<%= t(".transactions") %>" class="overflow-y-auto flex flex-col bg-white rounded-xl border border-alpha-black-25 shadow-xs p-4"> <%= render "transactions/searches/search" %> diff --git a/app/views/vehicles/edit.html.erb b/app/views/vehicles/edit.html.erb index 00fe5b56cd3..947ceaa481b 100644 --- a/app/views/vehicles/edit.html.erb +++ b/app/views/vehicles/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> <%= render "form", account: @account, url: vehicle_path(@account.accountable) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index f7627158b48..c13e0eeba87 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -12,6 +12,7 @@ search: - app/ relative_roots: - app/controllers + - app/controllers/concerns - app/helpers - app/mailers - app/presenters @@ -25,6 +26,8 @@ search: - app/assets/fonts - app/assets/videos - app/assets/builds +ignore_missing: + - 'account_actions.{create,update}.success' ignore_unused: - 'activerecord.attributes.*' # i18n-tasks does not detect these on forms, forms validations (https://github.com/glebm/i18n-tasks/blob/0b4b483c82664f26c5696fb0f6aa1297356e4683/templates/config/i18n-tasks.yml#L146) - 'activerecord.models.*' # i18n-tasks does not detect use in dynamic model names (e.g. object.model_name.human) @@ -40,4 +43,5 @@ ignore_unused: - 'number.*' - 'errors.*' - 'helpers.*' - - 'support.*' \ No newline at end of file + - 'support.*' + - '{credit_cards,cryptos,depositories,other_assets,other_liabilities,loans,vehicles,properties,investments}.{create,update}.success' \ No newline at end of file diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index e6219ad9ff4..a237cd330db 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -8,23 +8,16 @@ en: new_account: New %{type} 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: - accountable_type: Account type balance: Today's balance institution: Financial institution name_label: Account name name_placeholder: Example account name - type_prompt: Select a type ungrouped: "(none)" - subtype_prompt: Select a subtype - none: None - subtype: Subtype index: accounts: Accounts add_institution: Add institution @@ -60,12 +53,10 @@ en: title: How would you like to add it? title: What would you like to add? show: - cash: Cash chart: balance: Balance no_change: no change owed: Owed - holdings: Holdings menu: confirm_accept: Delete "%{name}" confirm_body_html: "

By deleting this account, you will erase its value @@ -76,10 +67,6 @@ en: confirm_title: Delete account? edit: Edit import: Import transactions - overview: Overview - trades: Transactions - transactions: Transactions - value: Value summary: header: accounts: Accounts diff --git a/config/locales/views/credit_cards/en.yml b/config/locales/views/credit_cards/en.yml index 05a9f66386f..c9e1dcb64f1 100644 --- a/config/locales/views/credit_cards/en.yml +++ b/config/locales/views/credit_cards/en.yml @@ -3,6 +3,8 @@ en: credit_cards: create: success: Credit card account created + edit: + edit: Edit %{account} form: annual_fee: Annual fee annual_fee_placeholder: '99' @@ -10,14 +12,9 @@ en: apr_placeholder: '15.99' available_credit: Available credit available_credit_placeholder: '10000' - balance: Current balance expiration_date: Expiration date - institution: Institution minimum_payment: Minimum payment minimum_payment_placeholder: '100' - name_label: Card name - name_placeholder: Chase Sapphire - ungrouped: "(none)" new: title: Enter credit card details overview: @@ -30,5 +27,3 @@ en: unknown: Unknown update: success: Credit card account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/cryptos/en.yml b/config/locales/views/cryptos/en.yml index dcda0bdacfc..45a8252774a 100644 --- a/config/locales/views/cryptos/en.yml +++ b/config/locales/views/cryptos/en.yml @@ -3,17 +3,9 @@ en: cryptos: create: success: Crypto account created - form: - balance: Current balance - institution: Institution - name_label: Account name - name_placeholder: Bitcoin wallet - none: None - subtype_prompt: Select crypto type - ungrouped: "(none)" + edit: + edit: Edit %{account} new: title: Enter account balance update: success: Crypto account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/depositories/en.yml b/config/locales/views/depositories/en.yml index 0718c7d043c..a51b858d0cc 100644 --- a/config/locales/views/depositories/en.yml +++ b/config/locales/views/depositories/en.yml @@ -3,17 +3,12 @@ en: depositories: create: success: Depository account created + edit: + edit: Edit %{account} form: - balance: Current balance - institution: Institution - name_label: Account name - name_placeholder: Chase checking account none: None subtype_prompt: Select account type - ungrouped: "(none)" new: title: Enter account balance update: success: Depository account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/investments/en.yml b/config/locales/views/investments/en.yml index 6f7e26e37e5..e7bb9c4daa5 100644 --- a/config/locales/views/investments/en.yml +++ b/config/locales/views/investments/en.yml @@ -3,14 +3,11 @@ en: investments: create: success: Investment account created + edit: + edit: Edit %{account} form: - balance: Current balance - institution: Institution - name_label: Account name - name_placeholder: Vanguard brokerage account none: None subtype_prompt: Select investment type - ungrouped: "(none)" new: title: Enter account balance show: @@ -22,5 +19,3 @@ en: holdings: Holdings total_value_tooltip: The total value is the sum of cash balance and your holdings value, minus margin loans. - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/loans/en.yml b/config/locales/views/loans/en.yml index 0f4185a88c9..46cbca238a9 100644 --- a/config/locales/views/loans/en.yml +++ b/config/locales/views/loans/en.yml @@ -3,17 +3,14 @@ en: loans: create: success: Loan account created + edit: + edit: Edit %{account} form: - balance: Current balance - institution: Institution interest_rate: Interest rate interest_rate_placeholder: '5.25' - name_label: Loan name - name_placeholder: Home mortgage rate_type: Rate type term_months: Term (months) term_months_placeholder: '360' - ungrouped: "(none)" new: title: Enter loan details overview: @@ -27,5 +24,3 @@ en: unknown: Unknown update: success: Loan account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/other_assets/en.yml b/config/locales/views/other_assets/en.yml index 97af8393735..7ef3a8f9392 100644 --- a/config/locales/views/other_assets/en.yml +++ b/config/locales/views/other_assets/en.yml @@ -3,17 +3,9 @@ en: other_assets: create: success: Other asset account created - form: - balance: Current value - institution: Institution - name_label: Asset name - name_placeholder: Art collection - none: None - subtype_prompt: Select asset type - ungrouped: "(none)" + edit: + edit: Edit %{account} new: title: Enter asset details update: success: Other asset account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/other_liabilities/en.yml b/config/locales/views/other_liabilities/en.yml index cfde86a71e1..f6471188f04 100644 --- a/config/locales/views/other_liabilities/en.yml +++ b/config/locales/views/other_liabilities/en.yml @@ -3,17 +3,9 @@ en: other_liabilities: create: success: Other liability account created - form: - balance: Current balance - institution: Institution - name_label: Liability name - name_placeholder: Personal loan - none: None - subtype_prompt: Select liability type - ungrouped: "(none)" + edit: + edit: Edit %{account} new: title: Enter liability details update: success: Other liability account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/properties/en.yml b/config/locales/views/properties/en.yml index c76bf84552d..f27b5a9ef6d 100644 --- a/config/locales/views/properties/en.yml +++ b/config/locales/views/properties/en.yml @@ -3,29 +3,24 @@ en: properties: create: success: Property account created + edit: + edit: Edit %{account} form: - test1: Test 1 is working - test2: Test 2 is working address_line1: Street address address_line1_placeholder: 123 Main St - address_line2: Apartment/Suite - address_line2_placeholder: Apt 4B area: Living area area_placeholder: '2000' area_unit: Unit of measurement - balance: Current value country: Country country_placeholder: US - institution: Institution locality: City locality_placeholder: San Francisco - name_label: Property name - name_placeholder: Primary residence + none: None postal_code: ZIP/Postal code postal_code_placeholder: '94105' region: State/Province region_placeholder: CA - ungrouped: "(none)" + subtype_prompt: Select property type year_built: Year built year_built_placeholder: '2000' new: @@ -39,5 +34,3 @@ en: year_built: Year Built update: success: Property account updated - edit: - edit: "Edit %{account}" diff --git a/config/locales/views/transactions/en.yml b/config/locales/views/transactions/en.yml index 7b7189e8185..c0533bb4b25 100644 --- a/config/locales/views/transactions/en.yml +++ b/config/locales/views/transactions/en.yml @@ -40,6 +40,7 @@ en: import: Import index: transaction: transaction + transactions: transactions mark_transfers: success: Marked as transfer new: diff --git a/config/locales/views/vehicles/en.yml b/config/locales/views/vehicles/en.yml index b141e613cfe..c41e811011f 100644 --- a/config/locales/views/vehicles/en.yml +++ b/config/locales/views/vehicles/en.yml @@ -3,9 +3,9 @@ en: vehicles: create: success: Vehicle account created + edit: + edit: Edit %{account} form: - balance: Current value - institution: Institution make: Make make_placeholder: Toyota mileage: Mileage @@ -13,9 +13,6 @@ en: mileage_unit: Unit model: Model model_placeholder: Camry - name_label: Vehicle name - name_placeholder: Family car - ungrouped: "(none)" year: Year year_placeholder: '2023' new: @@ -30,5 +27,3 @@ en: year: Year update: success: Vehicle account updated - edit: - edit: "Edit %{account}" diff --git a/config/routes.rb b/config/routes.rb index d2f3f6b1413..9944967a452 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -60,7 +60,7 @@ resources :mappings, only: :update, module: :import end - resources :accounts, only: %i[index new update destroy] do + resources :accounts, only: %i[index new destroy] do collection do get :summary get :list diff --git a/test/controllers/account/trades_controller_test.rb b/test/controllers/account/trades_controller_test.rb index b9c7285224c..a89e70c9a23 100644 --- a/test/controllers/account/trades_controller_test.rb +++ b/test/controllers/account/trades_controller_test.rb @@ -32,7 +32,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end test "creates withdrawal entry" do @@ -51,7 +51,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end test "deposit and withdrawal has optional transfer account" do @@ -71,7 +71,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.amount.positive? assert created_entry.marked_as_transfer - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end test "creates interest entry" do @@ -88,7 +88,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest created_entry = Account::Entry.order(created_at: :desc).first assert created_entry.amount.negative? - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end test "creates trade buy entry" do @@ -110,7 +110,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.account_trade.qty.positive? assert_equal "Transaction created successfully.", flash[:notice] assert_enqueued_with job: AccountSyncJob - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end test "creates trade sell entry" do @@ -133,6 +133,6 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.account_trade.qty.negative? assert_equal "Transaction created successfully.", flash[:notice] assert_enqueued_with job: AccountSyncJob - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end end diff --git a/test/controllers/account/transfers_controller_test.rb b/test/controllers/account/transfers_controller_test.rb index 06289fd5a55..671147e0a13 100644 --- a/test/controllers/account/transfers_controller_test.rb +++ b/test/controllers/account/transfers_controller_test.rb @@ -26,7 +26,7 @@ class Account::TransfersControllerTest < ActionDispatch::IntegrationTest end test "can destroy transfer" do - assert_difference -> { Account::Transfer.count } => -1, -> { Account::Transaction.count } => 0 do + assert_difference -> { Account::Transfer.count } => -1, -> { Account::Transaction.count } => -2 do delete account_transfer_url(account_transfers(:one)) end end diff --git a/test/controllers/account/valuations_controller_test.rb b/test/controllers/account/valuations_controller_test.rb index 0523a19e34b..b200f37d174 100644 --- a/test/controllers/account/valuations_controller_test.rb +++ b/test/controllers/account/valuations_controller_test.rb @@ -45,6 +45,6 @@ class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest end assert_equal "Date has already been taken", flash[:alert] - assert_redirected_to account_path(@entry.account) + assert_redirected_to @entry.account.accountable end end diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb index 79e433fa48a..18ff5c7d8c5 100644 --- a/test/controllers/accounts_controller_test.rb +++ b/test/controllers/accounts_controller_test.rb @@ -20,11 +20,6 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest assert_response :ok end - test "edit" do - get edit_account_path(@account) - assert_response :ok - end - test "can sync an account" do post sync_account_path(@account) assert_response :no_content @@ -35,48 +30,4 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest assert_redirected_to accounts_url assert_equal "Successfully queued accounts for syncing.", flash[:notice] end - - test "should update account" do - patch account_url(@account), params: { - account: { - name: "Updated name", - is_active: "0", - institution_id: institutions(:chase).id - } - } - - assert_redirected_to account_url(@account) - assert_enqueued_with job: AccountSyncJob - assert_equal "Account updated", flash[:notice] - end - - test "updates account balance by creating new valuation" do - assert_difference [ "Account::Entry.count", "Account::Valuation.count" ], 1 do - patch account_url(@account), params: { - account: { - balance: 10000 - } - } - end - - assert_redirected_to account_url(@account) - assert_enqueued_with job: AccountSyncJob - assert_equal "Account updated", flash[:notice] - end - - test "updates account balance by editing existing valuation for today" do - @account.entries.create! date: Date.current, amount: 6000, currency: "USD", entryable: Account::Valuation.new - - assert_no_difference [ "Account::Entry.count", "Account::Valuation.count" ] do - patch account_url(@account), params: { - account: { - balance: 10000 - } - } - end - - assert_redirected_to account_url(@account) - assert_enqueued_with job: AccountSyncJob - assert_equal "Account updated", flash[:notice] - end end diff --git a/test/controllers/credit_cards_controller_test.rb b/test/controllers/credit_cards_controller_test.rb index 136cfe72b92..d5abd4dec41 100644 --- a/test/controllers/credit_cards_controller_test.rb +++ b/test/controllers/credit_cards_controller_test.rb @@ -1,27 +1,14 @@ require "test_helper" class CreditCardsControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @credit_card = credit_cards(:one) - end - - test "new" do - get new_credit_card_path - assert_response :success - end - - test "edit" do - get edit_credit_card_path(@credit_card) - assert_response :success - end - - test "show" do - get credit_card_url(@credit_card) - assert_response :success + @accountable = @credit_card = credit_cards(:one) end - test "creates credit card" do + test "creates with credit card details" do assert_difference -> { Account.count } => 1, -> { CreditCard.count } => 1, -> { Account::Valuation.count } => 2, @@ -43,23 +30,23 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest } end - created_account = Account.order(:created_at).last + created_cc = CreditCard.order(:created_at).last - assert_equal "New Credit Card", created_account.name - assert_equal 1000, created_account.balance - assert_equal "USD", created_account.currency - assert_equal 5000, created_account.credit_card.available_credit - assert_equal 25, created_account.credit_card.minimum_payment - assert_equal 15.99, created_account.credit_card.apr - assert_equal 2.years.from_now.to_date, created_account.credit_card.expiration_date - assert_equal 99, created_account.credit_card.annual_fee + assert_equal "New Credit Card", created_cc.account.name + assert_equal 1000, created_cc.account.balance + assert_equal "USD", created_cc.account.currency + assert_equal 5000, created_cc.available_credit + assert_equal 25, created_cc.minimum_payment + assert_equal 15.99, created_cc.apr + assert_equal 2.years.from_now.to_date, created_cc.expiration_date + assert_equal 99, created_cc.annual_fee - assert_redirected_to account_path(created_account) + assert_redirected_to created_cc assert_equal "Credit card account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end - test "updates credit card" do + test "updates with credit card details" do assert_no_difference [ "Account.count", "CreditCard.count" ] do patch credit_card_path(@credit_card), params: { account: { @@ -89,7 +76,7 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest assert_equal 3.years.from_now.to_date, @credit_card.expiration_date assert_equal 0, @credit_card.annual_fee - assert_redirected_to account_path(@credit_card.account) + assert_redirected_to @credit_card assert_equal "Credit card account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/cryptos_controller_test.rb b/test/controllers/cryptos_controller_test.rb index 9c3ce8dddd3..b349ee693ea 100644 --- a/test/controllers/cryptos_controller_test.rb +++ b/test/controllers/cryptos_controller_test.rb @@ -1,56 +1,10 @@ require "test_helper" class CryptosControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @crypto = cryptos(:one) - end - - test "new" do - get new_crypto_url - assert_response :success - end - - test "edit" do - get edit_crypto_url(@crypto) - assert_response :success - end - - test "show" do - get crypto_url(@crypto) - assert_response :success - end - - test "create" do - assert_difference [ "Account.count", "Crypto.count" ], 1 do - post cryptos_url, params: { - account: { - accountable_type: "Crypto", - name: "New crypto", - balance: 10000, - currency: "USD", - subtype: "bitcoin" - } - } - end - - assert_redirected_to Account.order(:created_at).last - assert_equal "Crypto account created", flash[:notice] - end - - test "update" do - assert_no_difference [ "Account.count", "Crypto.count" ] do - patch crypto_url(@crypto), params: { - account: { - name: "Updated name", - balance: 10000, - currency: "USD", - subtype: "bitcoin" - } - } - end - - assert_redirected_to @crypto.account - assert_equal "Crypto account updated", flash[:notice] + @accountable = @crypto = cryptos(:one) end end diff --git a/test/controllers/depositories_controller_test.rb b/test/controllers/depositories_controller_test.rb index 5af3791c8eb..0c52fb7bc87 100644 --- a/test/controllers/depositories_controller_test.rb +++ b/test/controllers/depositories_controller_test.rb @@ -1,58 +1,10 @@ require "test_helper" class DepositoriesControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @depository = depositories(:one) - end - - test "new" do - get new_depository_url - assert_response :success - end - - test "edit" do - get edit_depository_url(@depository) - assert_response :success - end - - test "show" do - get depository_url(@depository) - assert_response :success - end - - test "create" do - assert_difference [ "Account.count", "Depository.count" ], 1 do - post depositories_url, params: { - account: { - accountable_type: "Depository", - institution_id: institutions(:chase).id, - name: "New depository", - balance: 10000, - currency: "USD", - subtype: "checking" - } - } - end - - assert_redirected_to Account.order(:created_at).last - assert_equal "Depository account created", flash[:notice] - end - - test "update" do - assert_no_difference [ "Account.count", "Depository.count" ] do - patch depository_url(@depository), params: { - account: { - institution_id: institutions(:chase).id, - name: "Updated name", - balance: 10000, - currency: "USD", - subtype: "checking" - } - } - end - - assert_redirected_to @depository.account - assert_equal "Depository account updated", flash[:notice] + @accountable = @depository = depositories(:one) end end diff --git a/test/controllers/impersonation_sessions_controller_test.rb b/test/controllers/impersonation_sessions_controller_test.rb index 65fe4bf5622..d21f69100cf 100644 --- a/test/controllers/impersonation_sessions_controller_test.rb +++ b/test/controllers/impersonation_sessions_controller_test.rb @@ -11,7 +11,7 @@ class ImpersonationSessionsControllerTest < ActionDispatch::IntegrationTest assert_difference "impersonator_session.logs.count", 2 do get root_path - get account_path(impersonated.family.accounts.first) + get polymorphic_path(impersonated.family.accounts.first.accountable) end end diff --git a/test/controllers/investments_controller_test.rb b/test/controllers/investments_controller_test.rb index 43f3487e567..5c908ed5c89 100644 --- a/test/controllers/investments_controller_test.rb +++ b/test/controllers/investments_controller_test.rb @@ -1,56 +1,10 @@ require "test_helper" class InvestmentsControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @investment = investments(:one) - end - - test "new" do - get new_investment_url - assert_response :success - end - - test "edit" do - get edit_investment_url(@investment) - assert_response :success - end - - test "show" do - get investment_url(@investment) - assert_response :success - end - - test "create" do - assert_difference [ "Account.count", "Investment.count" ], 1 do - post investments_url, params: { - account: { - accountable_type: "Investment", - name: "New investment", - balance: 50000, - currency: "USD", - subtype: "brokerage" - } - } - end - - assert_redirected_to Account.order(:created_at).last - assert_equal "Investment account created", flash[:notice] - end - - test "update" do - assert_no_difference [ "Account.count", "Investment.count" ] do - patch investment_url(@investment), params: { - account: { - name: "Updated name", - balance: 50000, - currency: "USD", - subtype: "brokerage" - } - } - end - - assert_redirected_to @investment.account - assert_equal "Investment account updated", flash[:notice] + @accountable = @investment = investments(:one) end end diff --git a/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb b/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb index 10cb6f1a099..4bee1bbfe78 100644 --- a/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb +++ b/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb @@ -14,6 +14,6 @@ class Issue::ExchangeRateProviderMissingsControllerTest < ActionDispatch::Integr } assert_enqueued_with job: AccountSyncJob - assert_redirected_to account_url(@issue.issuable) + assert_redirected_to @issue.issuable.accountable end end diff --git a/test/controllers/loans_controller_test.rb b/test/controllers/loans_controller_test.rb index e125e4d5611..d9d4666e9ff 100644 --- a/test/controllers/loans_controller_test.rb +++ b/test/controllers/loans_controller_test.rb @@ -1,27 +1,14 @@ require "test_helper" class LoansControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @loan = loans(:one) - end - - test "new" do - get new_loan_path - assert_response :success - end - - test "edit" do - get edit_loan_path(@loan) - assert_response :success - end - - test "show" do - get loan_url(@loan) - assert_response :success + @accountable = @loan = loans(:one) end - test "creates loan" do + test "creates with loan details" do assert_difference -> { Account.count } => 1, -> { Loan.count } => 1, -> { Account::Valuation.count } => 2, @@ -41,21 +28,21 @@ class LoansControllerTest < ActionDispatch::IntegrationTest } end - created_account = Account.order(:created_at).last + created_loan = Loan.order(:created_at).last - assert_equal "New Loan", created_account.name - assert_equal 50000, created_account.balance - assert_equal "USD", created_account.currency - assert_equal 5.5, created_account.loan.interest_rate - assert_equal 60, created_account.loan.term_months - assert_equal "fixed", created_account.loan.rate_type + assert_equal "New Loan", created_loan.account.name + assert_equal 50000, created_loan.account.balance + assert_equal "USD", created_loan.account.currency + assert_equal 5.5, created_loan.interest_rate + assert_equal 60, created_loan.term_months + assert_equal "fixed", created_loan.rate_type - assert_redirected_to account_path(created_account) + assert_redirected_to created_loan assert_equal "Loan account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end - test "updates loan" do + test "updates with loan details" do assert_no_difference [ "Account.count", "Loan.count" ] do patch loan_path(@loan), params: { account: { @@ -81,7 +68,7 @@ class LoansControllerTest < ActionDispatch::IntegrationTest assert_equal 48, @loan.term_months assert_equal "fixed", @loan.rate_type - assert_redirected_to account_path(@loan.account) + assert_redirected_to @loan assert_equal "Loan account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/other_assets_controller_test.rb b/test/controllers/other_assets_controller_test.rb index a973cbe0878..6bb176cc1d3 100644 --- a/test/controllers/other_assets_controller_test.rb +++ b/test/controllers/other_assets_controller_test.rb @@ -1,51 +1,10 @@ require "test_helper" class OtherAssetsControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @other_asset = other_assets(:one) - end - - test "new" do - get new_other_asset_url - assert_response :success - end - - test "show" do - get other_asset_url(@other_asset) - assert_response :success - end - - test "create" do - assert_difference [ "Account.count", "OtherAsset.count" ], 1 do - post other_assets_url, params: { - account: { - accountable_type: "OtherAsset", - name: "New other asset", - balance: 5000, - currency: "USD", - subtype: "other" - } - } - end - - assert_redirected_to Account.order(:created_at).last - assert_equal "Other asset account created", flash[:notice] - end - - test "update" do - assert_no_difference [ "Account.count", "OtherAsset.count" ] do - patch other_asset_url(@other_asset), params: { - account: { - name: "Updated name", - balance: 5000, - currency: "USD", - subtype: "other" - } - } - end - - assert_redirected_to @other_asset.account - assert_equal "Other asset account updated", flash[:notice] + @accountable = @other_asset = other_assets(:one) end end diff --git a/test/controllers/other_liabilities_controller_test.rb b/test/controllers/other_liabilities_controller_test.rb index 0a35a841656..0a3cc68d85e 100644 --- a/test/controllers/other_liabilities_controller_test.rb +++ b/test/controllers/other_liabilities_controller_test.rb @@ -1,56 +1,10 @@ require "test_helper" class OtherLiabilitiesControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @other_liability = other_liabilities(:one) - end - - test "new" do - get new_other_liability_url - assert_response :success - end - - test "edit" do - get edit_other_liability_url(@other_liability) - assert_response :success - end - - test "show" do - get other_liability_url(@other_liability) - assert_response :success - end - - test "create" do - assert_difference [ "Account.count", "OtherLiability.count" ], 1 do - post other_liabilities_url, params: { - account: { - accountable_type: "OtherLiability", - name: "New other liability", - balance: 15000, - currency: "USD", - subtype: "other" - } - } - end - - assert_redirected_to Account.order(:created_at).last - assert_equal "Other liability account created", flash[:notice] - end - - test "update" do - assert_no_difference [ "Account.count", "OtherLiability.count" ] do - patch other_liability_url(@other_liability), params: { - account: { - name: "Updated name", - balance: 15000, - currency: "USD", - subtype: "other" - } - } - end - - assert_redirected_to @other_liability.account - assert_equal "Other liability account updated", flash[:notice] + @accountable = @other_liability = other_liabilities(:one) end end diff --git a/test/controllers/properties_controller_test.rb b/test/controllers/properties_controller_test.rb index 31e25ba367a..0324f760c0b 100644 --- a/test/controllers/properties_controller_test.rb +++ b/test/controllers/properties_controller_test.rb @@ -1,27 +1,14 @@ require "test_helper" class PropertiesControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @property = properties(:one) - end - - test "new" do - get new_property_path - assert_response :success - end - - test "edit" do - get edit_property_url(@property) - assert_response :success - end - - test "show" do - get property_url(@property) - assert_response :success + @accountable = @property = properties(:one) end - test "creates property" do + test "creates with property details" do assert_difference -> { Account.count } => 1, -> { Property.count } => 1, -> { Account::Valuation.count } => 2, @@ -49,17 +36,17 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest } end - created_account = Account.order(:created_at).last + created_property = Property.order(:created_at).last - assert created_account.property.year_built.present? - assert created_account.property.address.line1.present? + assert created_property.year_built.present? + assert created_property.address.line1.present? - assert_redirected_to account_path(created_account) + assert_redirected_to created_property assert_equal "Property account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end - test "updates property" do + test "updates with property details" do assert_no_difference [ "Account.count", "Property.count" ] do patch property_path(@property), params: { account: { @@ -85,7 +72,7 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@property.account) + assert_redirected_to @property assert_equal "Property account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/vehicles_controller_test.rb b/test/controllers/vehicles_controller_test.rb index 0dc1d2e1c2a..7488d2ecee9 100644 --- a/test/controllers/vehicles_controller_test.rb +++ b/test/controllers/vehicles_controller_test.rb @@ -1,27 +1,14 @@ require "test_helper" class VehiclesControllerTest < ActionDispatch::IntegrationTest + include AccountActionsInterfaceTest + setup do sign_in @user = users(:family_admin) - @vehicle = vehicles(:one) - end - - test "new" do - get new_vehicle_path - assert_response :success - end - - test "edit" do - get edit_vehicle_path(@vehicle) - assert_response :success - end - - test "show" do - get vehicle_url(@vehicle) - assert_response :success + @accountable = @vehicle = vehicles(:one) end - test "creates vehicle" do + test "creates with vehicle details" do assert_difference -> { Account.count } => 1, -> { Vehicle.count } => 1, -> { Account::Valuation.count } => 2, @@ -43,20 +30,20 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest } end - created_account = Account.order(:created_at).last + created_vehicle = Vehicle.order(:created_at).last - assert_equal "Toyota", created_account.vehicle.make - assert_equal "Camry", created_account.vehicle.model - assert_equal 2020, created_account.vehicle.year - assert_equal 15000, created_account.vehicle.mileage_value - assert_equal "mi", created_account.vehicle.mileage_unit + assert_equal "Toyota", created_vehicle.make + assert_equal "Camry", created_vehicle.model + assert_equal 2020, created_vehicle.year + assert_equal 15000, created_vehicle.mileage_value + assert_equal "mi", created_vehicle.mileage_unit - assert_redirected_to account_path(created_account) + assert_redirected_to created_vehicle assert_equal "Vehicle account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end - test "updates vehicle" do + test "updates with vehicle details" do assert_no_difference [ "Account.count", "Vehicle.count" ] do patch vehicle_path(@vehicle), params: { account: { @@ -77,7 +64,7 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to account_path(@vehicle.account) + assert_redirected_to @vehicle assert_equal "Vehicle account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/interfaces/account_actions_interface_test.rb b/test/interfaces/account_actions_interface_test.rb new file mode 100644 index 00000000000..52f98027f6b --- /dev/null +++ b/test/interfaces/account_actions_interface_test.rb @@ -0,0 +1,84 @@ +require "test_helper" + +module AccountActionsInterfaceTest + extend ActiveSupport::Testing::Declarative + + test "shows new form" do + get new_polymorphic_url(@accountable) + assert_response :success + end + + test "shows edit form" do + get edit_polymorphic_url(@accountable) + assert_response :success + end + + test "renders accountable page" do + get polymorphic_url(@accountable) + assert_response :success + end + + test "updates basic account balances" do + assert_no_difference [ "Account.count", "@accountable.class.count" ] do + patch polymorphic_url(@accountable), params: { + account: { + institution_id: institutions(:chase).id, + name: "Updated name", + balance: 10000, + currency: "USD" + } + } + end + + assert_redirected_to @accountable + assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + end + + test "creates with basic attributes" do + assert_difference [ "Account.count", "@accountable.class.count" ], 1 do + post "/#{@accountable.class.model_name.collection}", params: { + account: { + accountable_type: @accountable.class.name, + institution_id: institutions(:chase).id, + name: "New accountable", + balance: 10000, + currency: "USD", + subtype: "checking" + } + } + end + + assert_redirected_to @accountable.class.order(:created_at).last + assert_equal "#{@accountable.class.model_name.human} account created", flash[:notice] + end + + test "updates account balance by creating new valuation" do + assert_difference [ "Account::Entry.count", "Account::Valuation.count" ], 1 do + patch polymorphic_url(@accountable), params: { + account: { + balance: 10000 + } + } + end + + assert_redirected_to @accountable + assert_enqueued_with job: AccountSyncJob + assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + end + + test "updates account balance by editing existing valuation for today" do + @accountable.account.entries.create! date: Date.current, amount: 6000, currency: "USD", entryable: Account::Valuation.new + + assert_no_difference [ "Account::Entry.count", "Account::Valuation.count" ] do + patch polymorphic_url(@accountable), params: { + account: { + balance: 10000 + } + } + end + + assert_redirected_to @accountable + assert_enqueued_with job: AccountSyncJob + assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + end +end diff --git a/test/system/trades_test.rb b/test/system/trades_test.rb index c9539276970..5d2fbec0252 100644 --- a/test/system/trades_test.rb +++ b/test/system/trades_test.rb @@ -66,15 +66,16 @@ class TradesTest < ApplicationSystemTestCase private def open_new_trade_modal - click_link "new_trade_account_#{@account.id}" + click_on "New" + click_on "New transaction" end def within_trades(&block) - within "#" + dom_id(@account, "trades"), &block + within "#" + dom_id(@account, "entries"), &block end def visit_account_trades - visit account_url(@account, tab: "transactions") + visit polymorphic_path(@account.accountable) end def select_combobox_option(text) diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb index 622f0b81d25..7e13cb77a40 100644 --- a/test/system/transactions_test.rb +++ b/test/system/transactions_test.rb @@ -182,15 +182,13 @@ class TransactionsTest < ApplicationSystemTestCase 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) + visit polymorphic_path(investment_account.accountable) + click_on "New" click_on "New transaction" select "Deposit", from: "Type" fill_in "Date", with: transfer_date fill_in "account_entry[amount]", with: 175.25 click_button "Add transaction" - within "#account_" + investment_account.id do - click_on "Transactions" - end within "#entry-group-" + transfer_date.to_s do assert_text "175.25" end diff --git a/test/system/transfers_test.rb b/test/system/transfers_test.rb index 1fc72fa50f1..601a50f8f9f 100644 --- a/test/system/transfers_test.rb +++ b/test/system/transfers_test.rb @@ -55,7 +55,8 @@ class TransfersTest < ApplicationSystemTestCase click_on "Mark as transfers" within "#entry-group-" + transfer_date.to_s do - assert_text "Transfer from" + assert_text "Outflow" + assert_text "Inflow" end end From 2ad17b75e9983dd94eab55bb85165123e6dd8710 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Sat, 2 Nov 2024 15:03:48 -0400 Subject: [PATCH 12/19] Lint, rubocop, schema updates --- .../invitation_mailer/invite_email.html.erb | 4 +- app/views/invitations/new.html.erb | 4 +- app/views/registrations/new.html.erb | 6 +- app/views/settings/profiles/show.html.erb | 6 +- config/brakeman.ignore | 106 +----------------- db/schema.rb | 2 +- 6 files changed, 13 insertions(+), 115 deletions(-) diff --git a/app/views/invitation_mailer/invite_email.html.erb b/app/views/invitation_mailer/invite_email.html.erb index c57be0a9492..04a70291403 100644 --- a/app/views/invitation_mailer/invite_email.html.erb +++ b/app/views/invitation_mailer/invite_email.html.erb @@ -1,11 +1,11 @@

<%= t(".greeting") %>

- <%= t(".body", + <%= t(".body", inviter: @invitation.inviter.display_name, family: @invitation.family.name).html_safe %>

<%= link_to t(".accept_button"), @accept_url, class: "button" %> - \ No newline at end of file + diff --git a/app/views/invitations/new.html.erb b/app/views/invitations/new.html.erb index 5b6a455062e..5d50e516054 100644 --- a/app/views/invitations/new.html.erb +++ b/app/views/invitations/new.html.erb @@ -1,6 +1,6 @@ <%= modal_form_wrapper title: t(".title"), subtitle: t(".subtitle") do %> <%= styled_form_with model: @invitation, class: "space-y-4", data: { turbo: false } do |form| %> - <%= form.email_field :email, + <%= form.email_field :email, required: true, placeholder: t(".email_placeholder"), label: t(".email_label") %> @@ -17,4 +17,4 @@ <%= form.submit t(".submit"), class: "bg-gray-900 text-white rounded-lg px-4 py-2 w-full" %>
<% end %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/registrations/new.html.erb b/app/views/registrations/new.html.erb index 6ad1f066e07..1c0f3fe79c8 100644 --- a/app/views/registrations/new.html.erb +++ b/app/views/registrations/new.html.erb @@ -10,7 +10,7 @@ <% elsif @invitation %>

- <%= t(".invitation_message", + <%= t(".invitation_message", inviter: @invitation.inviter.display_name, role: t(".role_#{@invitation.role}")) %>

@@ -18,8 +18,8 @@ <% end %> <%= styled_form_with model: @user, url: registration_path, class: "space-y-4" do |form| %> - <%= form.email_field :email, - autofocus: false, + <%= form.email_field :email, + autofocus: false, autocomplete: "email", required: "required", placeholder: "you@example.com", diff --git a/app/views/settings/profiles/show.html.erb b/app/views/settings/profiles/show.html.erb index dde691a2de4..b3e5a84d5aa 100644 --- a/app/views/settings/profiles/show.html.erb +++ b/app/views/settings/profiles/show.html.erb @@ -63,9 +63,9 @@

<%= t(".invitation_link") %>

-
<% else %>
- <%= render "categories/menu", transaction: transaction %> + <%= render "categories/menu", transaction: transaction, origin: origin %>
<% unless show_balance %> @@ -52,7 +52,7 @@ <%= tag.p account.name %> <% else %> <%= link_to account.name, - polymorphic_path(account.accountable, tab: "transactions"), + account_path(account, tab: "transactions"), data: { turbo_frame: "_top" }, class: "hover:underline" %> <% end %> diff --git a/app/views/account/transfers/_account_logos.html.erb b/app/views/account/transfers/_account_logos.html.erb index 7db8b197c38..2d668e3313e 100644 --- a/app/views/account/transfers/_account_logos.html.erb +++ b/app/views/account/transfers/_account_logos.html.erb @@ -2,23 +2,23 @@
<% if outflow %> - <%= link_to transfer.from_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> + <%= link_to transfer.from_account, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.from_name[0].upcase, size: "sm") %> <% end %> <%= lucide_icon "arrow-right", class: "text-gray-500 w-4 h-4" %> - <%= link_to transfer.to_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> + <%= link_to transfer.to_account, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.to_name[0].upcase, size: "sm") %> <% end %> <% else %> - <%= link_to transfer.to_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> + <%= link_to transfer.to_account, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.to_name[0].upcase, size: "sm") %> <% end %> <%= lucide_icon "arrow-left", class: "text-gray-500 w-4 h-4" %> - <%= link_to transfer.from_account&.accountable, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> + <%= link_to transfer.from_account, data: { turbo_frame: :_top }, class: "hover:opacity-90" do %> <%= circle_logo(transfer.from_name[0].upcase, size: "sm") %> <% end %> <% end %> diff --git a/app/views/accounts/_account.html.erb b/app/views/accounts/_account.html.erb index 2debcd3d3d1..e8627e69eb2 100644 --- a/app/views/accounts/_account.html.erb +++ b/app/views/accounts/_account.html.erb @@ -16,7 +16,7 @@ <% end %>
- <%= link_to edit_polymorphic_path(account.accountable), data: { turbo_frame: :modal }, class: "group-hover/account:flex hidden hover:opacity-80 items-center justify-center" do %> + <%= link_to edit_account_path(account), data: { turbo_frame: :modal }, class: "group-hover/account:flex hidden hover:opacity-80 items-center justify-center" do %> <%= lucide_icon "pencil-line", class: "w-4 h-4 text-gray-500" %> <% end %>
diff --git a/app/views/accounts/_account_type.html.erb b/app/views/accounts/_account_type.html.erb index 8c2b86bf8a8..bd7f71829e7 100644 --- a/app/views/accounts/_account_type.html.erb +++ b/app/views/accounts/_account_type.html.erb @@ -1,6 +1,6 @@ -<%# locals: (accountable:, institution_id: nil) %> +<%# locals: (accountable:) %> -<%= link_to new_account_path(type: accountable.class, institution_id: institution_id), +<%= link_to new_polymorphic_path(accountable, institution_id: params[:institution_id], step: "method_select"), class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-alpha-black-25 hover:bg-alpha-black-25 border border-transparent block px-2 rounded-lg p-2" do %> <%= lucide_icon(accountable.icon, style: "color: #{accountable.color}", class: "w-5 h-5") %> diff --git a/app/views/accounts/edit.html.erb b/app/views/accounts/edit.html.erb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/views/accounts/new.html.erb b/app/views/accounts/new.html.erb index 38143f88daf..cc2636646ff 100644 --- a/app/views/accounts/new.html.erb +++ b/app/views/accounts/new.html.erb @@ -1,17 +1,13 @@ -<% if params[:type].present? %> - <%= render "accounts/new/method_selector", path: new_accountable_path(params[:type], institution_id: params[:institution_id]) %> -<% else %> - <%= render layout: "accounts/new/container", locals: { title: t(".title") } do %> -
- <%= render "account_type", accountable: Depository.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: Investment.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: Crypto.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: Property.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: Vehicle.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: CreditCard.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: Loan.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: OtherAsset.new, institution_id: params[:institution_id] %> - <%= render "account_type", accountable: OtherLiability.new, institution_id: params[:institution_id] %> -
- <% end %> +<%= render layout: "accounts/new/container", locals: { title: t(".title") } do %> +
+ <%= render "account_type", accountable: Depository.new %> + <%= render "account_type", accountable: Investment.new %> + <%= render "account_type", accountable: Crypto.new %> + <%= render "account_type", accountable: Property.new %> + <%= render "account_type", accountable: Vehicle.new %> + <%= render "account_type", accountable: CreditCard.new %> + <%= render "account_type", accountable: Loan.new %> + <%= render "account_type", accountable: OtherAsset.new %> + <%= render "account_type", accountable: OtherLiability.new %> +
<% end %> diff --git a/app/views/accounts/new/_form.html.erb b/app/views/accounts/new/_form.html.erb deleted file mode 100644 index 9b7991b79ba..00000000000 --- a/app/views/accounts/new/_form.html.erb +++ /dev/null @@ -1,20 +0,0 @@ -<%= styled_form_with model: account, url: url, scope: :account, class: "flex flex-col gap-4 justify-between grow", data: { turbo: false } do |f| %> -
- <%= 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") %> - - <% if account.new_record? %> - <%= f.hidden_field :institution_id %> - <% else %> - <%= f.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %> - <% end %> - - <%= f.money_field :balance, label: t(".balance"), required: true, default_currency: Current.family.currency %> - - <% if account.accountable %> - <%= render permitted_accountable_partial(account, "form"), f: f %> - <% end %> -
- - <%= f.submit %> -<% end %> diff --git a/app/views/accounts/show.html.erb b/app/views/accounts/show.html.erb deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/views/accounts/show/_menu.html.erb b/app/views/accounts/show/_menu.html.erb index bbd9b01e001..8ba7673aaa1 100644 --- a/app/views/accounts/show/_menu.html.erb +++ b/app/views/accounts/show/_menu.html.erb @@ -2,7 +2,7 @@ <%= contextual_menu do %>
- <%= link_to edit_polymorphic_path(account.accountable), + <%= link_to edit_account_path(account), data: { turbo_frame: :modal }, class: "block w-full py-2 px-3 space-x-2 text-gray-900 hover:bg-gray-50 flex items-center rounded-lg" do %> <%= lucide_icon "pencil-line", class: "w-5 h-5 text-gray-500" %> diff --git a/app/views/accounts/show/_tab.html.erb b/app/views/accounts/show/_tab.html.erb index 476c066c177..4ddd0e6ef4d 100644 --- a/app/views/accounts/show/_tab.html.erb +++ b/app/views/accounts/show/_tab.html.erb @@ -1,7 +1,7 @@ <%# locals: (account:, key:, is_selected:) %> <%= link_to key.titleize, - polymorphic_path(account.accountable, tab: key), + account_path(account, tab: key), class: [ "px-2 py-1.5 rounded-md border border-transparent", "bg-white shadow-xs border-alpha-black-50": is_selected diff --git a/app/views/categories/_menu.html.erb b/app/views/categories/_menu.html.erb index 6c632596c46..9235a581d70 100644 --- a/app/views/categories/_menu.html.erb +++ b/app/views/categories/_menu.html.erb @@ -1,11 +1,11 @@ -<%# locals: (transaction:) %> +<%# locals: (transaction:, origin: nil) %>

diff --git a/app/views/credit_cards/edit.html.erb b/app/views/credit_cards/edit.html.erb index 25c6458c64d..fc97a7a8f06 100644 --- a/app/views/credit_cards/edit.html.erb +++ b/app/views/credit_cards/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: credit_card_path(@account.accountable) %> + <%= render "form", account: @account, url: credit_card_path(@account) %> <% end %> diff --git a/app/views/credit_cards/new.html.erb b/app/views/credit_cards/new.html.erb index b843973b6f2..7af664eec97 100644 --- a/app/views/credit_cards/new.html.erb +++ b/app/views/credit_cards/new.html.erb @@ -1,3 +1,7 @@ -<%= modal_form_wrapper title: t(".title") do %> - <%= render "credit_cards/form", account: @account, url: credit_cards_path %> +<% if params[:step] == "method_select" %> + <%= render "accounts/new/method_selector", path: new_credit_card_path(institution_id: params[:institution_id]) %> +<% else %> + <%= modal_form_wrapper title: t(".title") do %> + <%= render "credit_cards/form", account: @account, url: credit_cards_path %> + <% end %> <% end %> diff --git a/app/views/cryptos/edit.html.erb b/app/views/cryptos/edit.html.erb index 751939569fb..5f5b49812c0 100644 --- a/app/views/cryptos/edit.html.erb +++ b/app/views/cryptos/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: crypto_path(@account.accountable) %> + <%= render "form", account: @account, url: crypto_path(@account) %> <% end %> diff --git a/app/views/cryptos/new.html.erb b/app/views/cryptos/new.html.erb index 62c73227a2e..b23cdee5a47 100644 --- a/app/views/cryptos/new.html.erb +++ b/app/views/cryptos/new.html.erb @@ -1,3 +1,7 @@ -<%= modal_form_wrapper title: t(".title") do %> - <%= render "cryptos/form", account: @account, url: cryptos_path %> +<% if params[:step] == "method_select" %> + <%= render "accounts/new/method_selector", path: new_crypto_path(institution_id: params[:institution_id]) %> +<% else %> + <%= modal_form_wrapper title: t(".title") do %> + <%= render "cryptos/form", account: @account, url: cryptos_path %> + <% end %> <% end %> diff --git a/app/views/depositories/edit.html.erb b/app/views/depositories/edit.html.erb index 37ada5eaa6b..0c61040d6c4 100644 --- a/app/views/depositories/edit.html.erb +++ b/app/views/depositories/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: depository_path(@account.accountable) %> + <%= render "form", account: @account, url: depository_path(@account) %> <% end %> diff --git a/app/views/depositories/new.html.erb b/app/views/depositories/new.html.erb index dc50ac26db5..18172788c91 100644 --- a/app/views/depositories/new.html.erb +++ b/app/views/depositories/new.html.erb @@ -1,3 +1,7 @@ -<%= modal_form_wrapper title: t(".title") do %> - <%= render "depositories/form", account: @account, url: depositories_path %> +<% if params[:step] == "method_select" %> + <%= render "accounts/new/method_selector", path: new_depository_path(institution_id: params[:institution_id]) %> +<% else %> + <%= modal_form_wrapper title: t(".title") do %> + <%= render "depositories/form", account: @account, url: depositories_path %> + <% end %> <% end %> diff --git a/app/views/investments/edit.html.erb b/app/views/investments/edit.html.erb index aaa76b2b90a..c91d9eb2457 100644 --- a/app/views/investments/edit.html.erb +++ b/app/views/investments/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "investments/form", account: @account, url: investment_path(@account.accountable) %> + <%= render "investments/form", account: @account, url: investment_path(@account) %> <% end %> diff --git a/app/views/investments/new.html.erb b/app/views/investments/new.html.erb index 8d7c636d9f1..57bc247f38d 100644 --- a/app/views/investments/new.html.erb +++ b/app/views/investments/new.html.erb @@ -1,3 +1,7 @@ -<%= modal_form_wrapper title: t(".title") do %> - <%= render "investments/form", account: @account, url: investments_path %> +<% if params[:step] == "method_select" %> + <%= render "accounts/new/method_selector", path: new_investment_path(institution_id: params[:institution_id]) %> +<% else %> + <%= modal_form_wrapper title: t(".title") do %> + <%= render "investments/form", account: @account, url: investments_path %> + <% end %> <% end %> diff --git a/app/views/loans/edit.html.erb b/app/views/loans/edit.html.erb index c039900329b..5fb3b13e326 100644 --- a/app/views/loans/edit.html.erb +++ b/app/views/loans/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: loan_path(@account.accountable) %> + <%= render "form", account: @account, url: loan_path(@account) %> <% end %> diff --git a/app/views/loans/new.html.erb b/app/views/loans/new.html.erb index 2e3696988d5..4fd4ca7ec44 100644 --- a/app/views/loans/new.html.erb +++ b/app/views/loans/new.html.erb @@ -1,3 +1,7 @@ -<%= modal_form_wrapper title: t(".title") do %> - <%= render "loans/form", account: @account, url: loans_path %> +<% if params[:step] == "method_select" %> + <%= render "accounts/new/method_selector", path: new_loan_path(institution_id: params[:institution_id]) %> +<% else %> + <%= modal_form_wrapper title: t(".title") do %> + <%= render "loans/form", account: @account, url: loans_path %> + <% end %> <% end %> diff --git a/app/views/other_assets/edit.html.erb b/app/views/other_assets/edit.html.erb index dacfec55785..4c38d223086 100644 --- a/app/views/other_assets/edit.html.erb +++ b/app/views/other_assets/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "other_assets/form", account: @account, url: other_asset_path(@account.accountable) %> + <%= render "other_assets/form", account: @account, url: other_asset_path(@account) %> <% end %> diff --git a/app/views/other_liabilities/edit.html.erb b/app/views/other_liabilities/edit.html.erb index 9fd7d68b4dd..4473faffe00 100644 --- a/app/views/other_liabilities/edit.html.erb +++ b/app/views/other_liabilities/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: other_liability_path(@account.accountable) %> + <%= render "form", account: @account, url: other_liability_path(@account) %> <% end %> diff --git a/app/views/properties/edit.html.erb b/app/views/properties/edit.html.erb index e55052ff9c2..187208b6d9f 100644 --- a/app/views/properties/edit.html.erb +++ b/app/views/properties/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: property_path(@account.accountable) %> + <%= render "form", account: @account, url: property_path(@account) %> <% end %> diff --git a/app/views/vehicles/edit.html.erb b/app/views/vehicles/edit.html.erb index 947ceaa481b..a64715f1b95 100644 --- a/app/views/vehicles/edit.html.erb +++ b/app/views/vehicles/edit.html.erb @@ -1,3 +1,3 @@ <%= modal_form_wrapper title: t(".edit", account: @account.name) do %> - <%= render "form", account: @account, url: vehicle_path(@account.accountable) %> + <%= render "form", account: @account, url: vehicle_path(@account) %> <% end %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index c13e0eeba87..169d497223b 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -27,7 +27,7 @@ search: - app/assets/videos - app/assets/builds ignore_missing: - - 'account_actions.{create,update}.success' + - 'accountable_resource.{create,update}.success' ignore_unused: - 'activerecord.attributes.*' # i18n-tasks does not detect these on forms, forms validations (https://github.com/glebm/i18n-tasks/blob/0b4b483c82664f26c5696fb0f6aa1297356e4683/templates/config/i18n-tasks.yml#L146) - 'activerecord.models.*' # i18n-tasks does not detect use in dynamic model names (e.g. object.model_name.human) diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index a237cd330db..7284349120f 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -38,15 +38,7 @@ en: institutionless_accounts: other_accounts: Other accounts new_account: New account - new: - form: - accountable_type: Account type - balance: Today's balance - institution: Financial institution - name_label: Account name - name_placeholder: Example account name - type_prompt: Select a type - ungrouped: "(none)" + new: method_selector: connected_entry: Link account (coming soon) manual_entry: Enter account balance diff --git a/config/routes.rb b/config/routes.rb index 791d4594408..3806fa1fcbd 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -85,6 +85,15 @@ end end + # Convenience routes for polymorphic paths + # Example: account_path(Account.new(accountable: Depository.new)) => /depositories/123 + direct :account do |model| + route_for model.accountable_name, model + end + direct :edit_account do |model| + route_for "edit_#{model.accountable_name}", model + end + resources :depositories, only: %i[new show create edit update] resources :investments, only: %i[new show create edit update] resources :properties, only: %i[new show create edit update] diff --git a/test/controllers/account/trades_controller_test.rb b/test/controllers/account/trades_controller_test.rb index a89e70c9a23..f45e1b4b673 100644 --- a/test/controllers/account/trades_controller_test.rb +++ b/test/controllers/account/trades_controller_test.rb @@ -32,7 +32,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end test "creates withdrawal entry" do @@ -51,7 +51,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end test "deposit and withdrawal has optional transfer account" do @@ -71,7 +71,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.amount.positive? assert created_entry.marked_as_transfer - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end test "creates interest entry" do @@ -88,7 +88,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest created_entry = Account::Entry.order(created_at: :desc).first assert created_entry.amount.negative? - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end test "creates trade buy entry" do @@ -110,7 +110,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.account_trade.qty.positive? assert_equal "Transaction created successfully.", flash[:notice] assert_enqueued_with job: AccountSyncJob - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end test "creates trade sell entry" do @@ -133,6 +133,6 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest assert created_entry.account_trade.qty.negative? assert_equal "Transaction created successfully.", flash[:notice] assert_enqueued_with job: AccountSyncJob - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end end diff --git a/test/controllers/account/valuations_controller_test.rb b/test/controllers/account/valuations_controller_test.rb index b200f37d174..eed2a33fe71 100644 --- a/test/controllers/account/valuations_controller_test.rb +++ b/test/controllers/account/valuations_controller_test.rb @@ -45,6 +45,6 @@ class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest end assert_equal "Date has already been taken", flash[:alert] - assert_redirected_to @entry.account.accountable + assert_redirected_to @entry.account end end diff --git a/test/controllers/credit_cards_controller_test.rb b/test/controllers/credit_cards_controller_test.rb index d5abd4dec41..dfd1b5b6787 100644 --- a/test/controllers/credit_cards_controller_test.rb +++ b/test/controllers/credit_cards_controller_test.rb @@ -1,11 +1,11 @@ require "test_helper" class CreditCardsControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @credit_card = credit_cards(:one) + @account = accounts(:credit_card) end test "creates with credit card details" do @@ -30,32 +30,32 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest } end - created_cc = CreditCard.order(:created_at).last + created_account = Account.order(:created_at).last - assert_equal "New Credit Card", created_cc.account.name - assert_equal 1000, created_cc.account.balance - assert_equal "USD", created_cc.account.currency - assert_equal 5000, created_cc.available_credit - assert_equal 25, created_cc.minimum_payment - assert_equal 15.99, created_cc.apr - assert_equal 2.years.from_now.to_date, created_cc.expiration_date - assert_equal 99, created_cc.annual_fee + assert_equal "New Credit Card", created_account.name + assert_equal 1000, created_account.balance + assert_equal "USD", created_account.currency + assert_equal 5000, created_account.accountable.available_credit + assert_equal 25, created_account.accountable.minimum_payment + assert_equal 15.99, created_account.accountable.apr + assert_equal 2.years.from_now.to_date, created_account.accountable.expiration_date + assert_equal 99, created_account.accountable.annual_fee - assert_redirected_to created_cc + assert_redirected_to created_account assert_equal "Credit card account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates with credit card details" do assert_no_difference [ "Account.count", "CreditCard.count" ] do - patch credit_card_path(@credit_card), params: { + patch account_path(@account), params: { account: { name: "Updated Credit Card", balance: 2000, currency: "USD", accountable_type: "CreditCard", accountable_attributes: { - id: @credit_card.id, + id: @account.accountable_id, available_credit: 6000, minimum_payment: 50, apr: 14.99, @@ -66,17 +66,17 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest } end - @credit_card.reload + @account.reload - assert_equal "Updated Credit Card", @credit_card.account.name - assert_equal 2000, @credit_card.account.balance - assert_equal 6000, @credit_card.available_credit - assert_equal 50, @credit_card.minimum_payment - assert_equal 14.99, @credit_card.apr - assert_equal 3.years.from_now.to_date, @credit_card.expiration_date - assert_equal 0, @credit_card.annual_fee + assert_equal "Updated Credit Card", @account.name + assert_equal 2000, @account.balance + assert_equal 6000, @account.accountable.available_credit + assert_equal 50, @account.accountable.minimum_payment + assert_equal 14.99, @account.accountable.apr + assert_equal 3.years.from_now.to_date, @account.accountable.expiration_date + assert_equal 0, @account.accountable.annual_fee - assert_redirected_to @credit_card + assert_redirected_to @account assert_equal "Credit card account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/cryptos_controller_test.rb b/test/controllers/cryptos_controller_test.rb index b349ee693ea..c0a9d1b205c 100644 --- a/test/controllers/cryptos_controller_test.rb +++ b/test/controllers/cryptos_controller_test.rb @@ -1,10 +1,10 @@ require "test_helper" class CryptosControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @crypto = cryptos(:one) + @account = accounts(:crypto) end end diff --git a/test/controllers/depositories_controller_test.rb b/test/controllers/depositories_controller_test.rb index 0c52fb7bc87..3c6e443a5b5 100644 --- a/test/controllers/depositories_controller_test.rb +++ b/test/controllers/depositories_controller_test.rb @@ -1,10 +1,10 @@ require "test_helper" class DepositoriesControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @depository = depositories(:one) + @account = accounts(:depository) end end diff --git a/test/controllers/impersonation_sessions_controller_test.rb b/test/controllers/impersonation_sessions_controller_test.rb index d21f69100cf..65fe4bf5622 100644 --- a/test/controllers/impersonation_sessions_controller_test.rb +++ b/test/controllers/impersonation_sessions_controller_test.rb @@ -11,7 +11,7 @@ class ImpersonationSessionsControllerTest < ActionDispatch::IntegrationTest assert_difference "impersonator_session.logs.count", 2 do get root_path - get polymorphic_path(impersonated.family.accounts.first.accountable) + get account_path(impersonated.family.accounts.first) end end diff --git a/test/controllers/investments_controller_test.rb b/test/controllers/investments_controller_test.rb index 5c908ed5c89..e9caf260ffd 100644 --- a/test/controllers/investments_controller_test.rb +++ b/test/controllers/investments_controller_test.rb @@ -1,10 +1,10 @@ require "test_helper" class InvestmentsControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @investment = investments(:one) + @account = accounts(:investment) end end diff --git a/test/controllers/invitations_controller_test.rb b/test/controllers/invitations_controller_test.rb index d6bdcacbe70..b6b7edbe630 100644 --- a/test/controllers/invitations_controller_test.rb +++ b/test/controllers/invitations_controller_test.rb @@ -57,7 +57,7 @@ class InvitationsControllerTest < ActionDispatch::IntegrationTest } end - invitation = Invitation.last + invitation = Invitation.order(created_at: :desc).first assert_equal "admin", invitation.role assert_equal @user.family, invitation.family assert_equal @user, invitation.inviter diff --git a/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb b/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb index 4bee1bbfe78..01d48ce3fd3 100644 --- a/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb +++ b/test/controllers/issue/exchange_rate_provider_missings_controller_test.rb @@ -14,6 +14,6 @@ class Issue::ExchangeRateProviderMissingsControllerTest < ActionDispatch::Integr } assert_enqueued_with job: AccountSyncJob - assert_redirected_to @issue.issuable.accountable + assert_redirected_to @issue.issuable end end diff --git a/test/controllers/loans_controller_test.rb b/test/controllers/loans_controller_test.rb index d9d4666e9ff..7df26b81dc7 100644 --- a/test/controllers/loans_controller_test.rb +++ b/test/controllers/loans_controller_test.rb @@ -1,11 +1,11 @@ require "test_helper" class LoansControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @loan = loans(:one) + @account = accounts(:loan) end test "creates with loan details" do @@ -28,30 +28,30 @@ class LoansControllerTest < ActionDispatch::IntegrationTest } end - created_loan = Loan.order(:created_at).last + created_account = Account.order(:created_at).last - assert_equal "New Loan", created_loan.account.name - assert_equal 50000, created_loan.account.balance - assert_equal "USD", created_loan.account.currency - assert_equal 5.5, created_loan.interest_rate - assert_equal 60, created_loan.term_months - assert_equal "fixed", created_loan.rate_type + assert_equal "New Loan", created_account.name + assert_equal 50000, created_account.balance + assert_equal "USD", created_account.currency + assert_equal 5.5, created_account.accountable.interest_rate + assert_equal 60, created_account.accountable.term_months + assert_equal "fixed", created_account.accountable.rate_type - assert_redirected_to created_loan + assert_redirected_to created_account assert_equal "Loan account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates with loan details" do assert_no_difference [ "Account.count", "Loan.count" ] do - patch loan_path(@loan), params: { + patch account_path(@account), params: { account: { name: "Updated Loan", balance: 45000, currency: "USD", accountable_type: "Loan", accountable_attributes: { - id: @loan.id, + id: @account.accountable_id, interest_rate: 4.5, term_months: 48, rate_type: "fixed" @@ -60,15 +60,15 @@ class LoansControllerTest < ActionDispatch::IntegrationTest } end - @loan.reload + @account.reload - assert_equal "Updated Loan", @loan.account.name - assert_equal 45000, @loan.account.balance - assert_equal 4.5, @loan.interest_rate - assert_equal 48, @loan.term_months - assert_equal "fixed", @loan.rate_type + assert_equal "Updated Loan", @account.name + assert_equal 45000, @account.balance + assert_equal 4.5, @account.accountable.interest_rate + assert_equal 48, @account.accountable.term_months + assert_equal "fixed", @account.accountable.rate_type - assert_redirected_to @loan + assert_redirected_to @account assert_equal "Loan account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/other_assets_controller_test.rb b/test/controllers/other_assets_controller_test.rb index 6bb176cc1d3..3a10fda05ea 100644 --- a/test/controllers/other_assets_controller_test.rb +++ b/test/controllers/other_assets_controller_test.rb @@ -1,10 +1,10 @@ require "test_helper" class OtherAssetsControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @other_asset = other_assets(:one) + @account = accounts(:other_asset) end end diff --git a/test/controllers/other_liabilities_controller_test.rb b/test/controllers/other_liabilities_controller_test.rb index 0a3cc68d85e..ef6ac6468e9 100644 --- a/test/controllers/other_liabilities_controller_test.rb +++ b/test/controllers/other_liabilities_controller_test.rb @@ -1,10 +1,10 @@ require "test_helper" class OtherLiabilitiesControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @other_liability = other_liabilities(:one) + @account = accounts(:other_liability) end end diff --git a/test/controllers/properties_controller_test.rb b/test/controllers/properties_controller_test.rb index 0324f760c0b..4641206088a 100644 --- a/test/controllers/properties_controller_test.rb +++ b/test/controllers/properties_controller_test.rb @@ -1,11 +1,11 @@ require "test_helper" class PropertiesControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @property = properties(:one) + @account = accounts(:property) end test "creates with property details" do @@ -36,26 +36,26 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest } end - created_property = Property.order(:created_at).last + created_account = Account.order(:created_at).last - assert created_property.year_built.present? - assert created_property.address.line1.present? + assert created_account.accountable.year_built.present? + assert created_account.accountable.address.line1.present? - assert_redirected_to created_property + assert_redirected_to created_account assert_equal "Property account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates with property details" do assert_no_difference [ "Account.count", "Property.count" ] do - patch property_path(@property), params: { + patch account_path(@account), params: { account: { name: "Updated Property", balance: 500000, currency: "USD", accountable_type: "Property", accountable_attributes: { - id: @property.id, + id: @account.accountable_id, year_built: 2002, area_value: 1000, area_unit: "sqft", @@ -72,7 +72,7 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to @property + assert_redirected_to @account assert_equal "Property account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/controllers/vehicles_controller_test.rb b/test/controllers/vehicles_controller_test.rb index 7488d2ecee9..00df8f36e09 100644 --- a/test/controllers/vehicles_controller_test.rb +++ b/test/controllers/vehicles_controller_test.rb @@ -1,11 +1,11 @@ require "test_helper" class VehiclesControllerTest < ActionDispatch::IntegrationTest - include AccountActionsInterfaceTest + include AccountableResourceInterfaceTest setup do sign_in @user = users(:family_admin) - @accountable = @vehicle = vehicles(:one) + @account = accounts(:vehicle) end test "creates with vehicle details" do @@ -30,29 +30,29 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest } end - created_vehicle = Vehicle.order(:created_at).last + created_account = Account.order(:created_at).last - assert_equal "Toyota", created_vehicle.make - assert_equal "Camry", created_vehicle.model - assert_equal 2020, created_vehicle.year - assert_equal 15000, created_vehicle.mileage_value - assert_equal "mi", created_vehicle.mileage_unit + assert_equal "Toyota", created_account.accountable.make + assert_equal "Camry", created_account.accountable.model + assert_equal 2020, created_account.accountable.year + assert_equal 15000, created_account.accountable.mileage_value + assert_equal "mi", created_account.accountable.mileage_unit - assert_redirected_to created_vehicle + assert_redirected_to created_account assert_equal "Vehicle account created", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end test "updates with vehicle details" do assert_no_difference [ "Account.count", "Vehicle.count" ] do - patch vehicle_path(@vehicle), params: { + patch account_path(@account), params: { account: { name: "Updated Vehicle", balance: 28000, currency: "USD", accountable_type: "Vehicle", accountable_attributes: { - id: @vehicle.id, + id: @account.accountable_id, make: "Honda", model: "Accord", year: 2021, @@ -64,7 +64,7 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest } end - assert_redirected_to @vehicle + assert_redirected_to @account assert_equal "Vehicle account updated", flash[:notice] assert_enqueued_with(job: AccountSyncJob) end diff --git a/test/interfaces/account_actions_interface_test.rb b/test/interfaces/accountable_resource_interface_test.rb similarity index 51% rename from test/interfaces/account_actions_interface_test.rb rename to test/interfaces/accountable_resource_interface_test.rb index 52f98027f6b..de3f3c3e8e2 100644 --- a/test/interfaces/account_actions_interface_test.rb +++ b/test/interfaces/accountable_resource_interface_test.rb @@ -1,26 +1,26 @@ require "test_helper" -module AccountActionsInterfaceTest +module AccountableResourceInterfaceTest extend ActiveSupport::Testing::Declarative test "shows new form" do - get new_polymorphic_url(@accountable) + get new_polymorphic_url(@account.accountable) assert_response :success end test "shows edit form" do - get edit_polymorphic_url(@accountable) + get edit_account_url(@account) assert_response :success end test "renders accountable page" do - get polymorphic_url(@accountable) + get account_url(@account) assert_response :success end test "updates basic account balances" do - assert_no_difference [ "Account.count", "@accountable.class.count" ] do - patch polymorphic_url(@accountable), params: { + assert_no_difference [ "Account.count", "@account.accountable_class.count" ] do + patch account_url(@account), params: { account: { institution_id: institutions(:chase).id, name: "Updated name", @@ -30,15 +30,15 @@ module AccountActionsInterfaceTest } end - assert_redirected_to @accountable - assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + assert_redirected_to @account + assert_equal "#{@account.accountable_name.humanize} account updated", flash[:notice] end test "creates with basic attributes" do - assert_difference [ "Account.count", "@accountable.class.count" ], 1 do - post "/#{@accountable.class.model_name.collection}", params: { + assert_difference [ "Account.count", "@account.accountable_class.count" ], 1 do + post "/#{@account.accountable_name.pluralize}", params: { account: { - accountable_type: @accountable.class.name, + accountable_type: @account.accountable_class, institution_id: institutions(:chase).id, name: "New accountable", balance: 10000, @@ -48,37 +48,37 @@ module AccountActionsInterfaceTest } end - assert_redirected_to @accountable.class.order(:created_at).last - assert_equal "#{@accountable.class.model_name.human} account created", flash[:notice] + assert_redirected_to Account.order(:created_at).last + assert_equal "#{@account.accountable_name.humanize} account created", flash[:notice] end test "updates account balance by creating new valuation" do assert_difference [ "Account::Entry.count", "Account::Valuation.count" ], 1 do - patch polymorphic_url(@accountable), params: { + patch account_url(@account), params: { account: { balance: 10000 } } end - assert_redirected_to @accountable + assert_redirected_to @account assert_enqueued_with job: AccountSyncJob - assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + assert_equal "#{@account.accountable_name.humanize} account updated", flash[:notice] end test "updates account balance by editing existing valuation for today" do - @accountable.account.entries.create! date: Date.current, amount: 6000, currency: "USD", entryable: Account::Valuation.new + @account.entries.create! date: Date.current, amount: 6000, currency: "USD", entryable: Account::Valuation.new assert_no_difference [ "Account::Entry.count", "Account::Valuation.count" ] do - patch polymorphic_url(@accountable), params: { + patch account_url(@account), params: { account: { balance: 10000 } } end - assert_redirected_to @accountable + assert_redirected_to @account assert_enqueued_with job: AccountSyncJob - assert_equal "#{@accountable.class.model_name.human} account updated", flash[:notice] + assert_equal "#{@account.accountable_name.humanize} account updated", flash[:notice] end end diff --git a/test/system/accounts_test.rb b/test/system/accounts_test.rb index 9583fe48071..d7b4211d628 100644 --- a/test/system/accounts_test.rb +++ b/test/system/accounts_test.rb @@ -99,7 +99,7 @@ def assert_account_created(accountable_type, &block) created_account = Account.order(:created_at).last - visit polymorphic_path(created_account.accountable) + visit account_url(created_account) within "header" do find('button[data-menu-target="button"]').click diff --git a/test/system/trades_test.rb b/test/system/trades_test.rb index 5d2fbec0252..1ab111db8ed 100644 --- a/test/system/trades_test.rb +++ b/test/system/trades_test.rb @@ -75,7 +75,7 @@ def within_trades(&block) end def visit_account_trades - visit polymorphic_path(@account.accountable) + visit account_path(@account) end def select_combobox_option(text) diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb index 7e13cb77a40..e51c81835b4 100644 --- a/test/system/transactions_test.rb +++ b/test/system/transactions_test.rb @@ -182,7 +182,7 @@ class TransactionsTest < ApplicationSystemTestCase 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 polymorphic_path(investment_account.accountable) + visit account_url(investment_account) click_on "New" click_on "New transaction" select "Deposit", from: "Type" From 05df4255be9dc8016a8042cdbf48d07e5186a893 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Mon, 4 Nov 2024 09:42:04 -0500 Subject: [PATCH 14/19] Fix broken routes --- app/views/accounts/_account_list.html.erb | 2 +- app/views/accounts/show/_header.html.erb | 7 +++++-- app/views/credit_cards/_overview.html.erb | 2 +- app/views/investments/show.html.erb | 4 ++-- app/views/loans/_overview.html.erb | 2 +- app/views/properties/_overview.html.erb | 2 +- app/views/properties/show.html.erb | 1 + app/views/vehicles/_overview.html.erb | 2 +- config/routes.rb | 8 ++++---- 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/app/views/accounts/_account_list.html.erb b/app/views/accounts/_account_list.html.erb index 922c3373483..d183d9759d4 100644 --- a/app/views/accounts/_account_list.html.erb +++ b/app/views/accounts/_account_list.html.erb @@ -61,7 +61,7 @@
<% end %> <% end %> - <%= link_to new_account_path(type: type.name.demodulize), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> + <%= link_to new_polymorphic_path(type, step: "method_select"), class: "flex items-center min-h-10 gap-4 px-3 py-2 mb-1 text-gray-500 text-sm font-medium rounded-[10px] hover:bg-gray-100", data: { turbo_frame: "modal" } do %> <%= lucide_icon("plus", class: "w-5 h-5") %> <%= t(".new_account", type: type.model_name.human.downcase) %> <% end %> diff --git a/app/views/accounts/show/_header.html.erb b/app/views/accounts/show/_header.html.erb index df556994355..c41f2d482c4 100644 --- a/app/views/accounts/show/_header.html.erb +++ b/app/views/accounts/show/_header.html.erb @@ -1,4 +1,4 @@ -<%# locals: (account:) %> +<%# locals: (account:, title: nil, subtitle: nil) %>
@@ -11,7 +11,10 @@ <%= render "accounts/logo", account: account %>
-

<%= account.name %>

+

<%= title || account.name %>

+ <% if subtitle.present? %> +

<%= subtitle %>

+ <% end %>
<% end %> diff --git a/app/views/credit_cards/_overview.html.erb b/app/views/credit_cards/_overview.html.erb index acea8cd66d4..85ce6527725 100644 --- a/app/views/credit_cards/_overview.html.erb +++ b/app/views/credit_cards/_overview.html.erb @@ -27,5 +27,5 @@
- <%= link_to "Edit account details", edit_credit_card_path(account.credit_card), class: "btn btn--ghost", data: { turbo_frame: :modal } %> + <%= link_to "Edit account details", edit_credit_card_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
diff --git a/app/views/investments/show.html.erb b/app/views/investments/show.html.erb index 9984844b0c2..4833badd520 100644 --- a/app/views/investments/show.html.erb +++ b/app/views/investments/show.html.erb @@ -17,8 +17,8 @@ <%= render "accounts/show/tabs", account: @account, tabs: [ { key: "activity", contents: render("accounts/show/activity", account: @account) }, { key: "holdings", contents: render("investments/holdings_tab", account: @account) }, - { key: "cash", contents: render("investments/cash_tab", account: @account) } - ] %> + { key: "cash", contents: render("investments/cash_tab", account: @account) } + ] %>
<% end %> <% end %> diff --git a/app/views/loans/_overview.html.erb b/app/views/loans/_overview.html.erb index a3fa77fb6f4..db6824fb53c 100644 --- a/app/views/loans/_overview.html.erb +++ b/app/views/loans/_overview.html.erb @@ -45,5 +45,5 @@
- <%= link_to "Edit loan details", edit_loan_path(account.loan), class: "btn btn--ghost", data: { turbo_frame: :modal } %> + <%= link_to "Edit loan details", edit_loan_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
diff --git a/app/views/properties/_overview.html.erb b/app/views/properties/_overview.html.erb index 4a832c172f2..95d42c8ea5c 100644 --- a/app/views/properties/_overview.html.erb +++ b/app/views/properties/_overview.html.erb @@ -29,5 +29,5 @@
- <%= link_to "Edit account details", edit_property_path(account.property), class: "btn btn--ghost", data: { turbo_frame: :modal } %> + <%= link_to "Edit account details", edit_property_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
diff --git a/app/views/properties/show.html.erb b/app/views/properties/show.html.erb index a4e23827b26..24d421471d2 100644 --- a/app/views/properties/show.html.erb +++ b/app/views/properties/show.html.erb @@ -1,5 +1,6 @@ <%= render "accounts/show/template", account: @account, + header: render("accounts/show/header", account: @account, subtitle: @account.property.address), tabs: render("accounts/show/tabs", account: @account, tabs: [ { key: "overview", contents: render("properties/overview", account: @account) }, { key: "activity", contents: render("accounts/show/activity", account: @account) } diff --git a/app/views/vehicles/_overview.html.erb b/app/views/vehicles/_overview.html.erb index 71cf00d3067..ab08ae211bc 100644 --- a/app/views/vehicles/_overview.html.erb +++ b/app/views/vehicles/_overview.html.erb @@ -33,5 +33,5 @@
- <%= link_to "Edit account details", edit_vehicle_path(account.vehicle), class: "btn btn--ghost", data: { turbo_frame: :modal } %> + <%= link_to "Edit account details", edit_vehicle_path(account), class: "btn btn--ghost", data: { turbo_frame: :modal } %>
diff --git a/config/routes.rb b/config/routes.rb index 3806fa1fcbd..113d5b72b4b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -87,11 +87,11 @@ # Convenience routes for polymorphic paths # Example: account_path(Account.new(accountable: Depository.new)) => /depositories/123 - direct :account do |model| - route_for model.accountable_name, model + direct :account do |model, options| + route_for model.accountable_name, model, options end - direct :edit_account do |model| - route_for "edit_#{model.accountable_name}", model + direct :edit_account do |model, options| + route_for "edit_#{model.accountable_name}", model, options end resources :depositories, only: %i[new show create edit update] From 9eec5c8e1c448b7ffa23c885d81ce3ffba93304a Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Mon, 4 Nov 2024 09:48:57 -0500 Subject: [PATCH 15/19] Add import option for adding accounts --- app/views/accounts/new.html.erb | 9 +++++++++ config/locales/views/accounts/en.yml | 1 + 2 files changed, 10 insertions(+) diff --git a/app/views/accounts/new.html.erb b/app/views/accounts/new.html.erb index cc2636646ff..935882b9ed5 100644 --- a/app/views/accounts/new.html.erb +++ b/app/views/accounts/new.html.erb @@ -9,5 +9,14 @@ <%= render "account_type", accountable: Loan.new %> <%= render "account_type", accountable: OtherAsset.new %> <%= render "account_type", accountable: OtherLiability.new %> + + <%= button_to imports_path(import: { type: "AccountImport" }), + data: { turbo_frame: :_top }, + class: "flex items-center gap-4 w-full text-center focus:outline-none focus:bg-alpha-black-25 hover:bg-alpha-black-25 border border-transparent block px-2 rounded-lg p-2" do %> + + <%= lucide_icon("download", style: "color: #F79009", class: "w-5 h-5") %> + + <%= t("accounts.new.import_accounts") %> + <% end %>
<% end %> diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index 7284349120f..07621766fb9 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -43,6 +43,7 @@ en: connected_entry: Link account (coming soon) manual_entry: Enter account balance title: How would you like to add it? + import_accounts: Import accounts title: What would you like to add? show: chart: From f46dc0b75ea4b72dc90499ed837a6652287c3cb5 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Mon, 4 Nov 2024 10:03:46 -0500 Subject: [PATCH 16/19] Fix system test --- app/views/settings/profiles/show.html.erb | 1 + config/locales/views/accounts/en.yml | 2 +- test/system/accounts_test.rb | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/settings/profiles/show.html.erb b/app/views/settings/profiles/show.html.erb index b3e5a84d5aa..c21775d6e67 100644 --- a/app/views/settings/profiles/show.html.erb +++ b/app/views/settings/profiles/show.html.erb @@ -65,6 +65,7 @@