diff --git a/app/controllers/merchants_controller.rb b/app/controllers/merchants_controller.rb new file mode 100644 index 00000000..17c1343f --- /dev/null +++ b/app/controllers/merchants_controller.rb @@ -0,0 +1,41 @@ +class MerchantsController < ApplicationController + layout "with_sidebar" + + before_action :set_merchant, only: %i[ edit update destroy ] + + def index + @merchants = Current.family.merchants.alphabetically + end + + def new + @merchant = Merchant.new + end + + def create + Current.family.merchants.create!(merchant_params) + redirect_to merchants_path, notice: t(".success") + end + + def edit + end + + def update + @merchant.update!(merchant_params) + redirect_to merchants_path, notice: t(".success") + end + + def destroy + @merchant.destroy! + redirect_to merchants_path, notice: t(".success") + end + + private + + def set_merchant + @merchant = Current.family.merchants.find(params[:id]) + end + + def merchant_params + params.require(:merchant).permit(:name, :color) + end +end diff --git a/app/controllers/transactions/merchants_controller.rb b/app/controllers/transactions/merchants_controller.rb deleted file mode 100644 index 470953a5..00000000 --- a/app/controllers/transactions/merchants_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -class Transactions::MerchantsController < ApplicationController - layout "with_sidebar" - - before_action :set_merchant, only: %i[ edit update destroy ] - - def index - @merchants = Current.family.transaction_merchants.alphabetically - end - - def new - @merchant = Transaction::Merchant.new - end - - def create - Current.family.transaction_merchants.create!(merchant_params) - redirect_to transaction_merchants_path, notice: t(".success") - end - - def edit - end - - def update - @merchant.update!(merchant_params) - redirect_to transaction_merchants_path, notice: t(".success") - end - - def destroy - @merchant.destroy! - redirect_to transaction_merchants_path, notice: t(".success") - end - - private - - def set_merchant - @merchant = Current.family.transaction_merchants.find(params[:id]) - end - - def merchant_params - params.require(:transaction_merchant).permit(:name, :color) - end -end diff --git a/app/models/family.rb b/app/models/family.rb index a86980ff..1159fd87 100644 --- a/app/models/family.rb +++ b/app/models/family.rb @@ -6,7 +6,7 @@ class Family < ApplicationRecord has_many :transactions, through: :accounts has_many :imports, through: :accounts has_many :categories, dependent: :destroy - has_many :transaction_merchants, dependent: :destroy, class_name: "Transaction::Merchant" + has_many :merchants, dependent: :destroy def snapshot(period = Period.all) query = accounts.active.joins(:balances) diff --git a/app/models/transaction/merchant.rb b/app/models/merchant.rb similarity index 84% rename from app/models/transaction/merchant.rb rename to app/models/merchant.rb index 369ab916..5e657763 100644 --- a/app/models/transaction/merchant.rb +++ b/app/models/merchant.rb @@ -1,4 +1,4 @@ -class Transaction::Merchant < ApplicationRecord +class Merchant < ApplicationRecord has_many :transactions, dependent: :nullify belongs_to :family diff --git a/app/models/transaction.rb b/app/models/transaction.rb index 7f534839..1657873a 100644 --- a/app/models/transaction.rb +++ b/app/models/transaction.rb @@ -21,7 +21,7 @@ class Transaction < ApplicationRecord scope :with_categories, ->(categories) { joins(:category).where(categories: { name: categories }) } scope :with_accounts, ->(accounts) { joins(:account).where(accounts: { name: accounts }) } scope :with_account_ids, ->(account_ids) { joins(:account).where(accounts: { id: account_ids }) } - scope :with_merchants, ->(merchants) { joins(:merchant).where(transaction_merchants: { name: merchants }) } + scope :with_merchants, ->(merchants) { joins(:merchant).where(merchants: { name: merchants }) } scope :on_or_after_date, ->(date) { where("transactions.date >= ?", date) } scope :on_or_before_date, ->(date) { where("transactions.date <= ?", date) } scope :with_converted_amount, ->(currency = Current.family.currency) { diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index 29a2a12c..0cf2f577 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -23,6 +23,6 @@ diff --git a/app/views/transactions/merchants/_avatar.html.erb b/app/views/merchants/_avatar.html.erb similarity index 100% rename from app/views/transactions/merchants/_avatar.html.erb rename to app/views/merchants/_avatar.html.erb diff --git a/app/views/transactions/merchants/_form.html.erb b/app/views/merchants/_form.html.erb similarity index 72% rename from app/views/transactions/merchants/_form.html.erb rename to app/views/merchants/_form.html.erb index 68526568..aebeef4e 100644 --- a/app/views/transactions/merchants/_form.html.erb +++ b/app/views/merchants/_form.html.erb @@ -1,14 +1,14 @@ <% is_editing = @merchant.id.present? %>
- <%= form_with model: @merchant, url: is_editing ? transaction_merchant_path(@merchant) : transaction_merchants_path, method: is_editing ? :patch : :post, scope: :transaction_merchant, data: { turbo: false } do |f| %> + <%= form_with model: @merchant, url: is_editing ? merchant_path(@merchant) : merchants_path, method: is_editing ? :patch : :post, scope: :merchant, data: { turbo: false } do |f| %>
- <%= render partial: "transactions/merchants/avatar", locals: { merchant: } %> + <%= render partial: "merchants/avatar", locals: { merchant: } %>
-
+
<%= f.hidden_field :color, data: { select_target: "input", merchant_avatar_target: "color" } %>
    - <% Transaction::Merchant::COLORS.each do |color| %> + <% Merchant::COLORS.each do |color| %>
  • diff --git a/app/views/transactions/merchants/_list.html.erb b/app/views/merchants/_list.html.erb similarity index 89% rename from app/views/transactions/merchants/_list.html.erb rename to app/views/merchants/_list.html.erb index af4bca7b..35ac3e6d 100644 --- a/app/views/transactions/merchants/_list.html.erb +++ b/app/views/merchants/_list.html.erb @@ -2,7 +2,7 @@ <% merchants.each.with_index do |merchant, index| %>
    - <%= render partial: "transactions/merchants/avatar", locals: { merchant: } %> + <%= render partial: "merchants/avatar", locals: { merchant: } %>

    <%= merchant.name %>

    @@ -13,13 +13,13 @@ diff --git a/app/views/transactions/searches/filters/_merchant_filter.html.erb b/app/views/transactions/searches/filters/_merchant_filter.html.erb index 160dd15c..5faca04c 100644 --- a/app/views/transactions/searches/filters/_merchant_filter.html.erb +++ b/app/views/transactions/searches/filters/_merchant_filter.html.erb @@ -5,7 +5,7 @@ <%= lucide_icon("search", class: "w-5 h-5 text-gray-500 absolute inset-y-0 left-2 top-1/2 transform -translate-y-1/2") %>
    - <% Current.family.transaction_merchants.alphabetically.each do |merchant| %> + <% Current.family.merchants.alphabetically.each do |merchant| %>
    <%= form.check_box :merchants, { diff --git a/app/views/transactions/show.html.erb b/app/views/transactions/show.html.erb index fe49b650..e83e4c59 100644 --- a/app/views/transactions/show.html.erb +++ b/app/views/transactions/show.html.erb @@ -30,7 +30,7 @@ <% unless @transaction.marked_as_transfer %> <%= f.collection_select :category_id, Current.family.categories.alphabetically, :id, :name, { prompt: t(".category_placeholder"), label: t(".category_label"), class: "text-gray-400" }, "data-auto-submit-form-target": "auto" %> - <%= f.collection_select :merchant_id, Current.family.transaction_merchants.alphabetically, :id, :name, { prompt: t(".merchant_placeholder"), label: t(".merchant_label"), class: "text-gray-400" }, "data-auto-submit-form-target": "auto" %> + <%= f.collection_select :merchant_id, Current.family.merchants.alphabetically, :id, :name, { prompt: t(".merchant_placeholder"), label: t(".merchant_label"), class: "text-gray-400" }, "data-auto-submit-form-target": "auto" %> <% end %> <%= f.collection_select :account_id, Current.family.accounts.alphabetically, :id, :name, { prompt: t(".account_placeholder"), label: t(".account_label"), class: "text-gray-500" }, { class: "form-field__input cursor-not-allowed text-gray-400", disabled: "disabled" } %> diff --git a/config/locales/views/merchants/en.yml b/config/locales/views/merchants/en.yml new file mode 100644 index 00000000..e3f7247e --- /dev/null +++ b/config/locales/views/merchants/en.yml @@ -0,0 +1,29 @@ +--- +en: + merchants: + create: + success: New merchant created successfully + destroy: + success: Merchant deleted successfully + edit: + title: Edit merchant + form: + name_placeholder: Merchant name + submit_create: Add merchant + submit_edit: Update + index: + empty: No merchants yet + new_long: New merchant + new_short: New + title: Merchants + list: + confirm_accept: Delete merchant + confirm_body: Are you sure you want to delete this merchant? Removing this merchant + will unlink all associated transactions and may effect your reporting. + confirm_title: Delete merchant? + delete: Delete merchant + edit: Edit merchant + new: + title: New merchant + update: + success: Merchant updated successfully diff --git a/config/locales/views/transactions/en.yml b/config/locales/views/transactions/en.yml index b74298d4..78120fe9 100644 --- a/config/locales/views/transactions/en.yml +++ b/config/locales/views/transactions/en.yml @@ -50,33 +50,6 @@ en: transaction: transaction mark_transfers: success: Marked as transfer - merchants: - create: - success: New merchant created successfully - destroy: - success: Merchant deleted successfully - edit: - title: Edit merchant - form: - name_placeholder: Merchant name - submit_create: Add merchant - submit_edit: Update - index: - empty: No merchants yet - new_long: New merchant - new_short: New - title: Merchants - list: - confirm_accept: Delete merchant - confirm_body: Are you sure you want to delete this merchant? Removing this - merchant will unlink all associated transactions and may effect your reporting. - confirm_title: Delete merchant? - delete: Delete merchant - edit: Edit merchant - new: - title: New merchant - update: - success: Merchant updated successfully selection_bar: mark_transfers: Mark as transfers? mark_transfers_confirm: Mark as transfers diff --git a/config/routes.rb b/config/routes.rb index a1f98f7e..a6026f2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,6 +48,8 @@ Rails.application.routes.draw do end end + resources :merchants, only: %i[ index new create edit update destroy ] + resources :transactions do collection do post "bulk_delete" @@ -59,7 +61,6 @@ Rails.application.routes.draw do scope module: :transactions, as: :transaction do resources :rows, only: %i[ show update ] resources :rules, only: %i[ index ] - resources :merchants, only: %i[ index new create edit update destroy ] end end end diff --git a/db/migrate/20240620122201_rename_merchants_table.rb b/db/migrate/20240620122201_rename_merchants_table.rb new file mode 100644 index 00000000..f5fa770c --- /dev/null +++ b/db/migrate/20240620122201_rename_merchants_table.rb @@ -0,0 +1,5 @@ +class RenameMerchantsTable < ActiveRecord::Migration[7.2] + def change + rename_table :transaction_merchants, :merchants + end +end diff --git a/db/schema.rb b/db/schema.rb index 1a40956f..b82ad346 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_114307) do +ActiveRecord::Schema[7.2].define(version: 2024_06_20_122201) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -242,6 +242,15 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_114307) do t.datetime "updated_at", null: false end + create_table "merchants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "name", null: false + t.string "color", default: "#e99537", null: false + t.uuid "family_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["family_id"], name: "index_merchants_on_family_id" + end + create_table "other_assets", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -284,15 +293,6 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_114307) do t.index ["family_id"], name: "index_tags_on_family_id" end - create_table "transaction_merchants", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.string "name", null: false - t.string "color", default: "#e99537", null: false - t.uuid "family_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["family_id"], name: "index_transaction_merchants_on_family_id" - end - create_table "transactions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "name" t.date "date", null: false @@ -359,12 +359,12 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_114307) do add_foreign_key "categories", "families" add_foreign_key "imports", "accounts" add_foreign_key "institutions", "families" + add_foreign_key "merchants", "families" add_foreign_key "taggings", "tags" add_foreign_key "tags", "families" - add_foreign_key "transaction_merchants", "families" add_foreign_key "transactions", "accounts", on_delete: :cascade add_foreign_key "transactions", "categories", on_delete: :nullify - add_foreign_key "transactions", "transaction_merchants", column: "merchant_id" + add_foreign_key "transactions", "merchants" add_foreign_key "transactions", "transfers" add_foreign_key "users", "families" add_foreign_key "valuations", "accounts", on_delete: :cascade diff --git a/test/controllers/merchants_controller_test.rb b/test/controllers/merchants_controller_test.rb new file mode 100644 index 00000000..4f84bb0d --- /dev/null +++ b/test/controllers/merchants_controller_test.rb @@ -0,0 +1,39 @@ +require "test_helper" + +class MerchantsControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @merchant = merchants(:netflix) + end + + test "index" do + get merchants_path + assert_response :success + end + + test "new" do + get new_merchant_path + assert_response :success + end + + test "should create merchant" do + assert_difference("Merchant.count") do + post merchants_url, params: { merchant: { name: "new merchant", color: "#000000" } } + end + + assert_redirected_to merchants_path + end + + test "should update merchant" do + patch merchant_url(@merchant), params: { merchant: { name: "new name", color: "#000000" } } + assert_redirected_to merchants_path + end + + test "should destroy merchant" do + assert_difference("Merchant.count", -1) do + delete merchant_url(@merchant) + end + + assert_redirected_to merchants_path + end +end diff --git a/test/controllers/transactions/merchants_controller_test.rb b/test/controllers/transactions/merchants_controller_test.rb deleted file mode 100644 index fab1fd71..00000000 --- a/test/controllers/transactions/merchants_controller_test.rb +++ /dev/null @@ -1,39 +0,0 @@ -require "test_helper" - -class Transactions::MerchantsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in @user = users(:family_admin) - @merchant = transaction_merchants(:netflix) - end - - test "index" do - get transaction_merchants_path - assert_response :success - end - - test "new" do - get new_transaction_merchant_path - assert_response :success - end - - test "should create merchant" do - assert_difference("Transaction::Merchant.count") do - post transaction_merchants_url, params: { transaction_merchant: { name: "new merchant", color: "#000000" } } - end - - assert_redirected_to transaction_merchants_path - end - - test "should update merchant" do - patch transaction_merchant_url(@merchant), params: { transaction_merchant: { name: "new name", color: "#000000" } } - assert_redirected_to transaction_merchants_path - end - - test "should destroy merchant" do - assert_difference("Transaction::Merchant.count", -1) do - delete transaction_merchant_url(@merchant) - end - - assert_redirected_to transaction_merchants_path - end -end diff --git a/test/controllers/transactions_controller_test.rb b/test/controllers/transactions_controller_test.rb index b31fe159..7dbcde8d 100644 --- a/test/controllers/transactions_controller_test.rb +++ b/test/controllers/transactions_controller_test.rb @@ -160,7 +160,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest transaction.update! \ excluded: false, category_id: Category.first.id, - merchant_id: Transaction::Merchant.first.id, + merchant_id: Merchant.first.id, notes: "Starting note" end @@ -170,7 +170,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest transaction_ids: transactions.map(&:id), excluded: true, category_id: Category.second.id, - merchant_id: Transaction::Merchant.second.id, + merchant_id: Merchant.second.id, notes: "Updated note" } } @@ -182,7 +182,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest assert_equal Date.current, transaction.date assert transaction.excluded assert_equal Category.second, transaction.category - assert_equal Transaction::Merchant.second, transaction.merchant + assert_equal Merchant.second, transaction.merchant assert_equal "Updated note", transaction.notes end end diff --git a/test/fixtures/transaction/merchants.yml b/test/fixtures/merchants.yml similarity index 100% rename from test/fixtures/transaction/merchants.yml rename to test/fixtures/merchants.yml diff --git a/test/models/family_test.rb b/test/models/family_test.rb index 55218957..96eb2cdc 100644 --- a/test/models/family_test.rb +++ b/test/models/family_test.rb @@ -39,7 +39,7 @@ class FamilyTest < ActiveSupport::TestCase end test "should destroy dependent merchants" do - assert_difference("Transaction::Merchant.count", -@family.transaction_merchants.count) do + assert_difference("Merchant.count", -@family.merchants.count) do @family.destroy end end diff --git a/test/system/settings_test.rb b/test/system/settings_test.rb index e9be8a86..1c844ebd 100644 --- a/test/system/settings_test.rb +++ b/test/system/settings_test.rb @@ -13,7 +13,7 @@ class SettingsTest < ApplicationSystemTestCase [ "Accounts", "Accounts", accounts_path ], [ "Tags", "Tags", tags_path ], [ "Categories", "Categories", categories_path ], - [ "Merchants", "Merchants", transaction_merchants_path ], + [ "Merchants", "Merchants", merchants_path ], [ "Rules", "Rules", transaction_rules_path ], [ "Imports", "Imports", imports_path ], [ "What's New", "What's New", changelog_path ], diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb index f75edd76..097d8d8e 100644 --- a/test/system/transactions_test.rb +++ b/test/system/transactions_test.rb @@ -6,7 +6,7 @@ class TransactionsTest < ApplicationSystemTestCase @latest_transactions = @user.family.transactions.ordered.limit(20).to_a @test_category = @user.family.categories.create! name: "System Test Category" - @test_merchant = @user.family.transaction_merchants.create! name: "System Test Merchant" + @test_merchant = @user.family.merchants.create! name: "System Test Merchant" @target_txn = @user.family.accounts.first.transactions.create! \ name: "Oldest transaction", date: 10.years.ago.to_date,