From bddaab019243488b0a981763f0fbd72cd6911dd8 Mon Sep 17 00:00:00 2001 From: Zach Gollwitzer Date: Thu, 20 Jun 2024 13:32:44 -0400 Subject: [PATCH] Account namespace updates: part 4 (transfers, singular namespacing) (#896) * Move Transfer to Account namespace * Fix partial resolution due to namespacing plurality * Make category and tag controllers consistent with namespacing convention * Update stale partial reference --- .../{accounts => account}/logos_controller.rb | 2 +- .../{ => account}/transfers_controller.rb | 15 ++-- .../deletions_controller.rb | 2 +- .../dropdowns_controller.rb | 2 +- .../{tags => tag}/deletions_controller.rb | 2 +- .../rows_controller.rb | 2 +- .../transaction/rules_controller.rb | 6 ++ .../transactions/rules_controller.rb | 6 -- app/models/{ => account}/transfer.rb | 2 +- app/models/transaction.rb | 4 +- .../{accounts => account}/logos/show.svg.erb | 0 .../{ => account}/transfers/_form.html.erb | 2 +- .../transfers/_transfer.html.erb | 2 +- .../{ => account}/transfers/new.html.erb | 0 .../_credit_card.html.erb | 0 .../_crypto.html.erb | 0 .../_depository.html.erb | 0 .../_investment.html.erb | 0 .../{account => accountables}/_loan.html.erb | 0 .../_other_asset.html.erb | 0 .../_other_liability.html.erb | 0 .../_property.html.erb | 0 .../_vehicle.html.erb | 0 app/views/accounts/new.html.erb | 2 +- .../deletions/new.html.erb | 0 .../dropdowns/_row.html.erb | 0 .../dropdowns/show.html.erb | 2 +- .../{tags => tag}/deletions/new.html.erb | 0 .../rows/show.html.erb | 0 .../rules/index.html.erb | 0 app/views/transactions/_date_group.html.erb | 2 +- app/views/transactions/_form.html.erb | 2 +- .../transactions/_selection_bar.html.erb | 2 +- config/locales/views/account/transfers/en.yml | 28 +++++++ config/locales/views/categories/en.yml | 21 ----- .../locales/views/category/deletions/en.yml | 15 ++++ .../locales/views/category/dropdowns/en.yml | 12 +++ config/locales/views/tag/deletions/en.yml | 15 ++++ config/locales/views/tags/en.yml | 12 --- config/locales/views/transfers/en.yml | 27 ------ config/routes.rb | 34 ++++---- .../20240620125026_rename_transfer_table.rb | 5 ++ db/schema.rb | 14 ++-- .../transfers_controller_test.rb | 14 ++-- .../deletions_controller_test.rb | 2 +- .../deletions_controller_test.rb | 2 +- test/fixtures/{ => account}/transfers.yml | 0 test/fixtures/accounts.yml | 2 +- test/models/transfer_test.rb | 12 +-- test/system/transfers_test.rb | 82 +++++++++++++++++++ 50 files changed, 227 insertions(+), 127 deletions(-) rename app/controllers/{accounts => account}/logos_controller.rb (74%) rename app/controllers/{ => account}/transfers_controller.rb (59%) rename app/controllers/{categories => category}/deletions_controller.rb (90%) rename app/controllers/{categories => category}/dropdowns_controller.rb (88%) rename app/controllers/{tags => tag}/deletions_controller.rb (89%) rename app/controllers/{transactions => transaction}/rows_controller.rb (87%) create mode 100644 app/controllers/transaction/rules_controller.rb delete mode 100644 app/controllers/transactions/rules_controller.rb rename app/models/{ => account}/transfer.rb (97%) rename app/views/{accounts => account}/logos/show.svg.erb (100%) rename app/views/{ => account}/transfers/_form.html.erb (96%) rename app/views/{ => account}/transfers/_transfer.html.erb (96%) rename app/views/{ => account}/transfers/new.html.erb (100%) rename app/views/accounts/{account => accountables}/_credit_card.html.erb (100%) rename app/views/accounts/{account => accountables}/_crypto.html.erb (100%) rename app/views/accounts/{account => accountables}/_depository.html.erb (100%) rename app/views/accounts/{account => accountables}/_investment.html.erb (100%) rename app/views/accounts/{account => accountables}/_loan.html.erb (100%) rename app/views/accounts/{account => accountables}/_other_asset.html.erb (100%) rename app/views/accounts/{account => accountables}/_other_liability.html.erb (100%) rename app/views/accounts/{account => accountables}/_property.html.erb (100%) rename app/views/accounts/{account => accountables}/_vehicle.html.erb (100%) rename app/views/{categories => category}/deletions/new.html.erb (100%) rename app/views/{categories => category}/dropdowns/_row.html.erb (100%) rename app/views/{categories => category}/dropdowns/show.html.erb (96%) rename app/views/{tags => tag}/deletions/new.html.erb (100%) rename app/views/{transactions => transaction}/rows/show.html.erb (100%) rename app/views/{transactions => transaction}/rules/index.html.erb (100%) create mode 100644 config/locales/views/account/transfers/en.yml create mode 100644 config/locales/views/category/deletions/en.yml create mode 100644 config/locales/views/category/dropdowns/en.yml create mode 100644 config/locales/views/tag/deletions/en.yml delete mode 100644 config/locales/views/transfers/en.yml create mode 100644 db/migrate/20240620125026_rename_transfer_table.rb rename test/controllers/{ => account}/transfers_controller_test.rb (53%) rename test/controllers/{categories => category}/deletions_controller_test.rb (93%) rename test/controllers/{tags => tag}/deletions_controller_test.rb (93%) rename test/fixtures/{ => account}/transfers.yml (100%) create mode 100644 test/system/transfers_test.rb diff --git a/app/controllers/accounts/logos_controller.rb b/app/controllers/account/logos_controller.rb similarity index 74% rename from app/controllers/accounts/logos_controller.rb rename to app/controllers/account/logos_controller.rb index 8e8c5092..dd56e665 100644 --- a/app/controllers/accounts/logos_controller.rb +++ b/app/controllers/account/logos_controller.rb @@ -1,4 +1,4 @@ -class Accounts::LogosController < ApplicationController +class Account::LogosController < ApplicationController def show @account = Current.family.accounts.find(params[:account_id]) render_placeholder diff --git a/app/controllers/transfers_controller.rb b/app/controllers/account/transfers_controller.rb similarity index 59% rename from app/controllers/transfers_controller.rb rename to app/controllers/account/transfers_controller.rb index 6e231a88..13a7ea8b 100644 --- a/app/controllers/transfers_controller.rb +++ b/app/controllers/account/transfers_controller.rb @@ -1,17 +1,17 @@ -class TransfersController < ApplicationController +class Account::TransfersController < ApplicationController layout "with_sidebar" before_action :set_transfer, only: :destroy def new - @transfer = Transfer.new + @transfer = Account::Transfer.new 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]) - @transfer = Transfer.build_from_accounts from_account, to_account, \ + @transfer = Account::Transfer.build_from_accounts from_account, to_account, \ date: transfer_params[:date], amount: transfer_params[:amount].to_d, currency: transfer_params[:currency], @@ -20,7 +20,10 @@ class TransfersController < ApplicationController if @transfer.save redirect_to transactions_path, notice: t(".success") else - render :new, status: :unprocessable_entity + # TODO: this is not an ideal way to handle errors and should eventually be improved. + # See: https://github.com/hotwired/turbo-rails/pull/367 + flash[:error] = @transfer.errors.full_messages.to_sentence + redirect_to transactions_path end end @@ -32,10 +35,10 @@ class TransfersController < ApplicationController private def set_transfer - @transfer = Transfer.find(params[:id]) + @transfer = Account::Transfer.find(params[:id]) end def transfer_params - params.require(:transfer).permit(:from_account_id, :to_account_id, :amount, :currency, :date, :name) + params.require(:account_transfer).permit(:from_account_id, :to_account_id, :amount, :currency, :date, :name) end end diff --git a/app/controllers/categories/deletions_controller.rb b/app/controllers/category/deletions_controller.rb similarity index 90% rename from app/controllers/categories/deletions_controller.rb rename to app/controllers/category/deletions_controller.rb index 678823f2..96ff4c47 100644 --- a/app/controllers/categories/deletions_controller.rb +++ b/app/controllers/category/deletions_controller.rb @@ -1,4 +1,4 @@ -class Categories::DeletionsController < ApplicationController +class Category::DeletionsController < ApplicationController layout "with_sidebar" before_action :set_category diff --git a/app/controllers/categories/dropdowns_controller.rb b/app/controllers/category/dropdowns_controller.rb similarity index 88% rename from app/controllers/categories/dropdowns_controller.rb rename to app/controllers/category/dropdowns_controller.rb index 3da1bfe6..ef2322e4 100644 --- a/app/controllers/categories/dropdowns_controller.rb +++ b/app/controllers/category/dropdowns_controller.rb @@ -1,4 +1,4 @@ -class Categories::DropdownsController < ApplicationController +class Category::DropdownsController < ApplicationController before_action :set_from_params def show diff --git a/app/controllers/tags/deletions_controller.rb b/app/controllers/tag/deletions_controller.rb similarity index 89% rename from app/controllers/tags/deletions_controller.rb rename to app/controllers/tag/deletions_controller.rb index 8916ce74..19183c57 100644 --- a/app/controllers/tags/deletions_controller.rb +++ b/app/controllers/tag/deletions_controller.rb @@ -1,4 +1,4 @@ -class Tags::DeletionsController < ApplicationController +class Tag::DeletionsController < ApplicationController layout "with_sidebar" before_action :set_tag diff --git a/app/controllers/transactions/rows_controller.rb b/app/controllers/transaction/rows_controller.rb similarity index 87% rename from app/controllers/transactions/rows_controller.rb rename to app/controllers/transaction/rows_controller.rb index 159e75a9..08f081b9 100644 --- a/app/controllers/transactions/rows_controller.rb +++ b/app/controllers/transaction/rows_controller.rb @@ -1,4 +1,4 @@ -class Transactions::RowsController < ApplicationController +class Transaction::RowsController < ApplicationController before_action :set_transaction, only: %i[ show update ] def show diff --git a/app/controllers/transaction/rules_controller.rb b/app/controllers/transaction/rules_controller.rb new file mode 100644 index 00000000..7c7b157a --- /dev/null +++ b/app/controllers/transaction/rules_controller.rb @@ -0,0 +1,6 @@ +class Transaction::RulesController < ApplicationController + layout "with_sidebar" + + def index + end +end diff --git a/app/controllers/transactions/rules_controller.rb b/app/controllers/transactions/rules_controller.rb deleted file mode 100644 index 3c1db811..00000000 --- a/app/controllers/transactions/rules_controller.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Transactions::RulesController < ApplicationController - layout "with_sidebar" - - def index - end -end diff --git a/app/models/transfer.rb b/app/models/account/transfer.rb similarity index 97% rename from app/models/transfer.rb rename to app/models/account/transfer.rb index bb3778fb..9a3aeb4c 100644 --- a/app/models/transfer.rb +++ b/app/models/account/transfer.rb @@ -1,4 +1,4 @@ -class Transfer < ApplicationRecord +class Account::Transfer < ApplicationRecord has_many :transactions, dependent: :nullify validate :transaction_count, :from_different_accounts, :net_zero_flows, :all_transactions_marked diff --git a/app/models/transaction.rb b/app/models/transaction.rb index 1657873a..bad2aaf6 100644 --- a/app/models/transaction.rb +++ b/app/models/transaction.rb @@ -4,7 +4,7 @@ class Transaction < ApplicationRecord monetize :amount belongs_to :account - belongs_to :transfer, optional: true + belongs_to :transfer, optional: true, class_name: "Account::Transfer" belongs_to :category, optional: true belongs_to :merchant, optional: true has_many :taggings, as: :taggable, dependent: :destroy @@ -70,7 +70,7 @@ class Transaction < ApplicationRecord update_all marked_as_transfer: true # Attempt to "auto match" and save a transfer if 2 transactions selected - Transfer.new(transactions: all).save if all.count == 2 + Account::Transfer.new(transactions: all).save if all.count == 2 end def daily_totals(transactions, period: Period.last_30_days, currency: Current.family.currency) diff --git a/app/views/accounts/logos/show.svg.erb b/app/views/account/logos/show.svg.erb similarity index 100% rename from app/views/accounts/logos/show.svg.erb rename to app/views/account/logos/show.svg.erb diff --git a/app/views/transfers/_form.html.erb b/app/views/account/transfers/_form.html.erb similarity index 96% rename from app/views/transfers/_form.html.erb rename to app/views/account/transfers/_form.html.erb index 0a8cfcd1..e8cdd61e 100644 --- a/app/views/transfers/_form.html.erb +++ b/app/views/account/transfers/_form.html.erb @@ -1,4 +1,4 @@ -<%= form_with model: transfer do |f| %> +<%= form_with model: transfer, data: { turbo_frame: "_top" } do |f| %>
<%= link_to new_transaction_path(nature: "expense"), data: { turbo_frame: :modal }, class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400" do %> diff --git a/app/views/transfers/_transfer.html.erb b/app/views/account/transfers/_transfer.html.erb similarity index 96% rename from app/views/transfers/_transfer.html.erb rename to app/views/account/transfers/_transfer.html.erb index fae63dae..f0e0c857 100644 --- a/app/views/transfers/_transfer.html.erb +++ b/app/views/account/transfers/_transfer.html.erb @@ -2,7 +2,7 @@
- <%= button_to transfer_path(transfer), + <%= button_to account_transfer_path(transfer), method: :delete, class: "flex items-center group/transfer", data: { diff --git a/app/views/transfers/new.html.erb b/app/views/account/transfers/new.html.erb similarity index 100% rename from app/views/transfers/new.html.erb rename to app/views/account/transfers/new.html.erb diff --git a/app/views/accounts/account/_credit_card.html.erb b/app/views/accounts/accountables/_credit_card.html.erb similarity index 100% rename from app/views/accounts/account/_credit_card.html.erb rename to app/views/accounts/accountables/_credit_card.html.erb diff --git a/app/views/accounts/account/_crypto.html.erb b/app/views/accounts/accountables/_crypto.html.erb similarity index 100% rename from app/views/accounts/account/_crypto.html.erb rename to app/views/accounts/accountables/_crypto.html.erb diff --git a/app/views/accounts/account/_depository.html.erb b/app/views/accounts/accountables/_depository.html.erb similarity index 100% rename from app/views/accounts/account/_depository.html.erb rename to app/views/accounts/accountables/_depository.html.erb diff --git a/app/views/accounts/account/_investment.html.erb b/app/views/accounts/accountables/_investment.html.erb similarity index 100% rename from app/views/accounts/account/_investment.html.erb rename to app/views/accounts/accountables/_investment.html.erb diff --git a/app/views/accounts/account/_loan.html.erb b/app/views/accounts/accountables/_loan.html.erb similarity index 100% rename from app/views/accounts/account/_loan.html.erb rename to app/views/accounts/accountables/_loan.html.erb diff --git a/app/views/accounts/account/_other_asset.html.erb b/app/views/accounts/accountables/_other_asset.html.erb similarity index 100% rename from app/views/accounts/account/_other_asset.html.erb rename to app/views/accounts/accountables/_other_asset.html.erb diff --git a/app/views/accounts/account/_other_liability.html.erb b/app/views/accounts/accountables/_other_liability.html.erb similarity index 100% rename from app/views/accounts/account/_other_liability.html.erb rename to app/views/accounts/accountables/_other_liability.html.erb diff --git a/app/views/accounts/account/_property.html.erb b/app/views/accounts/accountables/_property.html.erb similarity index 100% rename from app/views/accounts/account/_property.html.erb rename to app/views/accounts/accountables/_property.html.erb diff --git a/app/views/accounts/account/_vehicle.html.erb b/app/views/accounts/accountables/_vehicle.html.erb similarity index 100% rename from app/views/accounts/account/_vehicle.html.erb rename to app/views/accounts/accountables/_vehicle.html.erb diff --git a/app/views/accounts/new.html.erb b/app/views/accounts/new.html.erb index 6bb0430e..878cafc0 100644 --- a/app/views/accounts/new.html.erb +++ b/app/views/accounts/new.html.erb @@ -78,7 +78,7 @@ <%= f.hidden_field :accountable_type %> <%= f.text_field :name, placeholder: t(".name.placeholder"), required: "required", label: t(".name.label"), autofocus: true %> <%= f.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %> - <%= render "accounts/account/#{permitted_accountable_partial(@account.accountable_type)}", f: f %> + <%= render "accounts/accountables/#{permitted_accountable_partial(@account.accountable_type)}", f: f %> <%= f.money_field :balance_money, label: t(".balance"), required: "required" %>
diff --git a/app/views/categories/deletions/new.html.erb b/app/views/category/deletions/new.html.erb similarity index 100% rename from app/views/categories/deletions/new.html.erb rename to app/views/category/deletions/new.html.erb diff --git a/app/views/categories/dropdowns/_row.html.erb b/app/views/category/dropdowns/_row.html.erb similarity index 100% rename from app/views/categories/dropdowns/_row.html.erb rename to app/views/category/dropdowns/_row.html.erb diff --git a/app/views/categories/dropdowns/show.html.erb b/app/views/category/dropdowns/show.html.erb similarity index 96% rename from app/views/categories/dropdowns/show.html.erb rename to app/views/category/dropdowns/show.html.erb index 098e00e8..0ddfd1ec 100644 --- a/app/views/categories/dropdowns/show.html.erb +++ b/app/views/category/dropdowns/show.html.erb @@ -11,7 +11,7 @@ <%= t(".no_categories") %>
<% @categories.each do |category| %> - <%= render partial: "categories/dropdowns/row", locals: { category: } %> + <%= render partial: "category/dropdowns/row", locals: { category: } %> <% end %>

diff --git a/app/views/tags/deletions/new.html.erb b/app/views/tag/deletions/new.html.erb similarity index 100% rename from app/views/tags/deletions/new.html.erb rename to app/views/tag/deletions/new.html.erb diff --git a/app/views/transactions/rows/show.html.erb b/app/views/transaction/rows/show.html.erb similarity index 100% rename from app/views/transactions/rows/show.html.erb rename to app/views/transaction/rows/show.html.erb diff --git a/app/views/transactions/rules/index.html.erb b/app/views/transaction/rules/index.html.erb similarity index 100% rename from app/views/transactions/rules/index.html.erb rename to app/views/transaction/rules/index.html.erb diff --git a/app/views/transactions/_date_group.html.erb b/app/views/transactions/_date_group.html.erb index 7ec9be4b..80de9bd9 100644 --- a/app/views/transactions/_date_group.html.erb +++ b/app/views/transactions/_date_group.html.erb @@ -1,5 +1,5 @@ <%# locals: (date:, group:) %> -
+
<%= check_box_tag "#{date}_transactions_selection", diff --git a/app/views/transactions/_form.html.erb b/app/views/transactions/_form.html.erb index 4839772e..575e9fc6 100644 --- a/app/views/transactions/_form.html.erb +++ b/app/views/transactions/_form.html.erb @@ -3,7 +3,7 @@
<%= radio_tab_tag form: f, name: :nature, value: :expense, label: t(".expense"), icon: "minus-circle", checked: params[:nature] == "expense" || params[:nature].nil? %> <%= radio_tab_tag form: f, name: :nature, value: :income, label: t(".income"), icon: "plus-circle", checked: params[:nature] == "income" %> - <%= link_to new_transfer_path, data: { turbo_frame: :modal }, class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400 group-has-[:checked]:bg-white group-has-[:checked]:text-gray-800 group-has-[:checked]:shadow-sm" do %> + <%= link_to new_account_transfer_path, data: { turbo_frame: :modal }, class: "flex px-4 py-1 rounded-lg items-center space-x-2 justify-center text-gray-400 group-has-[:checked]:bg-white group-has-[:checked]:text-gray-800 group-has-[:checked]:shadow-sm" do %> <%= lucide_icon "arrow-right-left", class: "w-5 h-5" %> <%= tag.span t(".transfer") %> <% end %> diff --git a/app/views/transactions/_selection_bar.html.erb b/app/views/transactions/_selection_bar.html.erb index d03ca5f3..3def43bb 100644 --- a/app/views/transactions/_selection_bar.html.erb +++ b/app/views/transactions/_selection_bar.html.erb @@ -18,7 +18,7 @@ accept: t(".mark_transfers_confirm"), } } do |f| %> - <% end %> diff --git a/config/locales/views/account/transfers/en.yml b/config/locales/views/account/transfers/en.yml new file mode 100644 index 00000000..4ae3701b --- /dev/null +++ b/config/locales/views/account/transfers/en.yml @@ -0,0 +1,28 @@ +--- +en: + account: + transfers: + create: + success: Transfer created + destroy: + success: Transfer removed + form: + amount: Amount + date: Date + description: Description + description_placeholder: Transfer from Checking to Savings + expense: Expense + from: From + income: Income + select_account: Select account + submit: Create transfer + to: To + 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? + transfer_name: Transfer from %{from_account} to %{to_account} diff --git a/config/locales/views/categories/en.yml b/config/locales/views/categories/en.yml index 9451094a..3da3ab1e 100644 --- a/config/locales/views/categories/en.yml +++ b/config/locales/views/categories/en.yml @@ -3,27 +3,6 @@ en: categories: create: success: New transaction category created successfully - deletions: - create: - success: Transaction category deleted successfully - new: - category: Category - delete_and_leave_uncategorized: Delete "%{category_name}" and leave uncategorized - delete_and_recategorize: Delete "%{category_name}" and assign new category - delete_category: Delete category? - explanation: By deleting this category, every transaction that has the "%{category_name}" - category will be uncategorized. Instead of leaving them uncategorized, you - can also assign a new category below. - replacement_category_prompt: Select category - dropdowns: - row: - delete: Delete category - edit: Edit category - show: - add_new: Add new - clear: Clear - no_categories: No categories found - search_placeholder: Search edit: edit: Edit category form: diff --git a/config/locales/views/category/deletions/en.yml b/config/locales/views/category/deletions/en.yml new file mode 100644 index 00000000..3568374e --- /dev/null +++ b/config/locales/views/category/deletions/en.yml @@ -0,0 +1,15 @@ +--- +en: + category: + deletions: + create: + success: Transaction category deleted successfully + new: + category: Category + delete_and_leave_uncategorized: Delete "%{category_name}" and leave uncategorized + delete_and_recategorize: Delete "%{category_name}" and assign new category + delete_category: Delete category? + explanation: By deleting this category, every transaction that has the "%{category_name}" + category will be uncategorized. Instead of leaving them uncategorized, you + can also assign a new category below. + replacement_category_prompt: Select category diff --git a/config/locales/views/category/dropdowns/en.yml b/config/locales/views/category/dropdowns/en.yml new file mode 100644 index 00000000..5b9e8248 --- /dev/null +++ b/config/locales/views/category/dropdowns/en.yml @@ -0,0 +1,12 @@ +--- +en: + category: + dropdowns: + row: + delete: Delete category + edit: Edit category + show: + add_new: Add new + clear: Clear + no_categories: No categories found + search_placeholder: Search diff --git a/config/locales/views/tag/deletions/en.yml b/config/locales/views/tag/deletions/en.yml new file mode 100644 index 00000000..c69ec8d5 --- /dev/null +++ b/config/locales/views/tag/deletions/en.yml @@ -0,0 +1,15 @@ +--- +en: + tag: + deletions: + create: + deleted: Tag deleted + new: + delete_and_leave_uncategorized: Delete "%{tag_name}" + delete_and_recategorize: Delete "%{tag_name}" and assign new tag + delete_tag: Delete tag? + explanation: "%{tag_name} will be removed from transactions and other taggable + entities. Instead of leaving them untagged, you can also assign a new tag + below." + replacement_tag_prompt: Select tag + tag: Tag diff --git a/config/locales/views/tags/en.yml b/config/locales/views/tags/en.yml index 506c41a3..a2cc464f 100644 --- a/config/locales/views/tags/en.yml +++ b/config/locales/views/tags/en.yml @@ -3,18 +3,6 @@ en: tags: create: created: Tag created - deletions: - create: - deleted: Tag deleted - new: - delete_and_leave_uncategorized: Delete "%{tag_name}" - delete_and_recategorize: Delete "%{tag_name}" and assign new tag - delete_tag: Delete tag? - explanation: "%{tag_name} will be removed from transactions and other taggable - entities. Instead of leaving them untagged, you can also assign a new tag - below." - replacement_tag_prompt: Select tag - tag: Tag edit: edit: Edit tag form: diff --git a/config/locales/views/transfers/en.yml b/config/locales/views/transfers/en.yml deleted file mode 100644 index 79b842a2..00000000 --- a/config/locales/views/transfers/en.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -en: - transfers: - create: - success: Transfer created - destroy: - success: Transfer removed - form: - amount: Amount - date: Date - description: Description - description_placeholder: Transfer from Checking to Savings - expense: Expense - from: From - income: Income - select_account: Select account - submit: Create transfer - to: To - 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? - transfer_name: Transfer from %{from_account} to %{to_account} diff --git a/config/routes.rb b/config/routes.rb index a6026f2e..2f57f282 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,18 +38,24 @@ Rails.application.routes.draw do end resources :tags, except: %i[ show destroy ] do - resources :deletions, only: %i[ new create ], module: :tags + resources :deletions, only: %i[ new create ], module: :tag + end + + namespace :category do + resource :dropdown, only: :show end resources :categories do - resources :deletions, only: %i[ new create ], module: :categories - collection do - resource :dropdown, only: :show, module: :categories, as: :category_dropdown - end + resources :deletions, only: %i[ new create ], module: :category end resources :merchants, only: %i[ index new create edit update destroy ] + namespace :transaction do + resources :rows, only: %i[ show update ] + resources :rules, only: %i[ index ] + end + resources :transactions do collection do post "bulk_delete" @@ -57,17 +63,14 @@ Rails.application.routes.draw do post "bulk_update" post "mark_transfers" post "unmark_transfers" - - scope module: :transactions, as: :transaction do - resources :rows, only: %i[ show update ] - resources :rules, only: %i[ index ] - end end end - resources :transfers, only: %i[ new create destroy ] + namespace :account do + resources :transfers, only: %i[ new create destroy ] + end - resources :accounts, shallow: true do + resources :accounts do collection do get :summary get :list @@ -77,11 +80,8 @@ Rails.application.routes.draw do post :sync end - scope module: :accounts do - resource :logo, only: :show - end - - resources :valuations + resource :logo, only: :show, module: :account + resources :valuations, shallow: true end resources :institutions, except: %i[ index show ] diff --git a/db/migrate/20240620125026_rename_transfer_table.rb b/db/migrate/20240620125026_rename_transfer_table.rb new file mode 100644 index 00000000..20bf619f --- /dev/null +++ b/db/migrate/20240620125026_rename_transfer_table.rb @@ -0,0 +1,5 @@ +class RenameTransferTable < ActiveRecord::Migration[7.2] + def change + rename_table :transfers, :account_transfers + end +end diff --git a/db/schema.rb b/db/schema.rb index b82ad346..f0f7d7d9 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_06_20_122201) do +ActiveRecord::Schema[7.2].define(version: 2024_06_20_125026) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -32,6 +32,11 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_122201) do t.index ["account_id"], name: "index_account_balances_on_account_id" end + create_table "account_transfers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "accounts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "subtype" t.uuid "family_id", null: false @@ -313,11 +318,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_122201) do t.index ["transfer_id"], name: "index_transactions_on_transfer_id" end - create_table "transfers", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - create_table "users", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "family_id", null: false t.string "first_name" @@ -362,10 +362,10 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_122201) do add_foreign_key "merchants", "families" add_foreign_key "taggings", "tags" add_foreign_key "tags", "families" + add_foreign_key "transactions", "account_transfers", column: "transfer_id" add_foreign_key "transactions", "accounts", on_delete: :cascade add_foreign_key "transactions", "categories", on_delete: :nullify add_foreign_key "transactions", "merchants" - add_foreign_key "transactions", "transfers" add_foreign_key "users", "families" add_foreign_key "valuations", "accounts", on_delete: :cascade end diff --git a/test/controllers/transfers_controller_test.rb b/test/controllers/account/transfers_controller_test.rb similarity index 53% rename from test/controllers/transfers_controller_test.rb rename to test/controllers/account/transfers_controller_test.rb index 4a139f67..9ceb5a30 100644 --- a/test/controllers/transfers_controller_test.rb +++ b/test/controllers/account/transfers_controller_test.rb @@ -1,19 +1,19 @@ require "test_helper" -class TransfersControllerTest < ActionDispatch::IntegrationTest +class Account::TransfersControllerTest < ActionDispatch::IntegrationTest setup do sign_in users(:family_admin) end test "should get new" do - get new_transfer_url + get new_account_transfer_url assert_response :success end test "can create transfers" do - assert_difference "Transfer.count", 1 do - post transfers_url, params: { - transfer: { + assert_difference "Account::Transfer.count", 1 do + post account_transfers_url, params: { + account_transfer: { from_account_id: accounts(:checking).id, to_account_id: accounts(:savings).id, date: Date.current, @@ -26,8 +26,8 @@ class TransfersControllerTest < ActionDispatch::IntegrationTest end test "can destroy transfer" do - assert_difference -> { Transfer.count } => -1, -> { Transaction.count } => 0 do - delete transfer_url(transfers(:credit_card_payment)) + assert_difference -> { Account::Transfer.count } => -1, -> { Transaction.count } => 0 do + delete account_transfer_url(account_transfers(:credit_card_payment)) end end end diff --git a/test/controllers/categories/deletions_controller_test.rb b/test/controllers/category/deletions_controller_test.rb similarity index 93% rename from test/controllers/categories/deletions_controller_test.rb rename to test/controllers/category/deletions_controller_test.rb index a9b0caa8..c8bd3d37 100644 --- a/test/controllers/categories/deletions_controller_test.rb +++ b/test/controllers/category/deletions_controller_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class Categories::DeletionsControllerTest < ActionDispatch::IntegrationTest +class Category::DeletionsControllerTest < ActionDispatch::IntegrationTest setup do sign_in users(:family_admin) @category = categories(:food_and_drink) diff --git a/test/controllers/tags/deletions_controller_test.rb b/test/controllers/tag/deletions_controller_test.rb similarity index 93% rename from test/controllers/tags/deletions_controller_test.rb rename to test/controllers/tag/deletions_controller_test.rb index a176f5b5..57bf6df2 100644 --- a/test/controllers/tags/deletions_controller_test.rb +++ b/test/controllers/tag/deletions_controller_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class Tags::DeletionsControllerTest < ActionDispatch::IntegrationTest +class Tag::DeletionsControllerTest < ActionDispatch::IntegrationTest setup do sign_in @user = users(:family_admin) @user_tags = @user.family.tags diff --git a/test/fixtures/transfers.yml b/test/fixtures/account/transfers.yml similarity index 100% rename from test/fixtures/transfers.yml rename to test/fixtures/account/transfers.yml diff --git a/test/fixtures/accounts.yml b/test/fixtures/accounts.yml index 977a919e..25633c4e 100644 --- a/test/fixtures/accounts.yml +++ b/test/fixtures/accounts.yml @@ -22,7 +22,7 @@ checking: savings: family: dylan_family - name: Savings account with valuation overrides + name: Savings account balance: 19700 accountable_type: Depository accountable: depository_savings diff --git a/test/models/transfer_test.rb b/test/models/transfer_test.rb index 2d1b26cd..0ca4be91 100644 --- a/test/models/transfer_test.rb +++ b/test/models/transfer_test.rb @@ -8,14 +8,14 @@ class TransferTest < ActiveSupport::TestCase end test "transfer valid if it has inflow and outflow from different accounts for the same amount" do - transfer = Transfer.create! transactions: [ @inflow, @outflow ] + transfer = Account::Transfer.create! transactions: [ @inflow, @outflow ] assert transfer.valid? end test "transfer must have 2 transactions" do - invalid_transfer_1 = Transfer.new transactions: [ @outflow ] - invalid_transfer_2 = Transfer.new transactions: [ @inflow, @outflow, transactions(:savings_four) ] + invalid_transfer_1 = Account::Transfer.new transactions: [ @outflow ] + invalid_transfer_2 = Account::Transfer.new transactions: [ @inflow, @outflow, transactions(:savings_four) ] assert invalid_transfer_1.invalid? assert invalid_transfer_2.invalid? @@ -27,7 +27,7 @@ class TransferTest < ActiveSupport::TestCase outflow = account.transactions.create! date: Date.current, name: "Outflow", amount: 100 assert_raise ActiveRecord::RecordInvalid do - Transfer.create! transactions: [ inflow, outflow ] + Account::Transfer.create! transactions: [ inflow, outflow ] end end @@ -35,7 +35,7 @@ class TransferTest < ActiveSupport::TestCase @inflow.update! marked_as_transfer: false assert_raise ActiveRecord::RecordInvalid do - Transfer.create! transactions: [ @inflow, @outflow ] + Account::Transfer.create! transactions: [ @inflow, @outflow ] end end @@ -43,7 +43,7 @@ class TransferTest < ActiveSupport::TestCase @outflow.update! amount: 105 assert_raises ActiveRecord::RecordInvalid do - Transfer.create! transactions: [ @inflow, @outflow ] + Account::Transfer.create! transactions: [ @inflow, @outflow ] end end end diff --git a/test/system/transfers_test.rb b/test/system/transfers_test.rb new file mode 100644 index 00000000..4f70f101 --- /dev/null +++ b/test/system/transfers_test.rb @@ -0,0 +1,82 @@ +require "application_system_test_case" + +class TransfersTest < ApplicationSystemTestCase + setup do + sign_in @user = users(:family_admin) + visit transactions_url + end + + test "can create a transfer" do + checking_name = accounts(:checking).name + savings_name = accounts(:savings).name + transfer_date = Date.current + + click_on "New transaction" + + # Will navigate to different route in same modal + click_on "Transfer" + assert_text "New transfer" + + fill_in "Description", with: "Transfer txn name" + select checking_name, from: "From" + select savings_name, from: "To" + fill_in "account_transfer[amount]", with: 500 + fill_in "Date", with: transfer_date + click_button "Create transfer" + + within "#date-group-" + transfer_date.to_s do + transfer_name = "Transfer from #{checking_name} to #{savings_name}" + find("details", text: transfer_name).click + assert_text "Transfer txn name", count: 2 + end + end + + test "can match 2 transactions and create a transfer" do + transfer_date = Date.current + outflow = Transaction.create! name: "Outflow from savings account", date: transfer_date, account: accounts(:savings), amount: 100 + inflow = Transaction.create! name: "Inflow to checking account", date: transfer_date, account: accounts(:checking), amount: -100 + + visit transactions_url + + transaction_checkbox(inflow).check + transaction_checkbox(outflow).check + + bulk_transfer_action_button.click + + click_on "Mark as transfers" + + within "#date-group-" + transfer_date.to_s do + transfer_name = "Transfer from #{outflow.account.name} to #{inflow.account.name}" + find("details", text: transfer_name).click + assert_text inflow.name + assert_text outflow.name + end + end + + test "can mark a single transaction as a transfer" do + txn = @user.family.transactions.ordered.first + + within "#" + dom_id(txn) do + assert_text "Uncategorized" + end + + transaction_checkbox(txn).check + + bulk_transfer_action_button.click + click_on "Mark as transfers" + + within "#" + dom_id(txn) do + assert_no_text "Uncategorized" + end + end + + private + + def transaction_checkbox(transaction) + find("#" + dom_id(transaction, "selection")) + end + + def bulk_transfer_action_button + find("#bulk-transfer-btn") + end +end