diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index 00bc8f0da..a1441439a 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -5,7 +5,11 @@ class TransactionsController < ApplicationController before_action :store_params!, only: :index def new + prefill_params_from_duplicate! super + apply_duplicate_attributes! + @income_categories = Current.family.categories.incomes.alphabetically + @expense_categories = Current.family.categories.expenses.alphabetically @categories = Current.family.categories.alphabetically end @@ -306,6 +310,35 @@ class TransactionsController < ApplicationController end private + def duplicate_source + return @duplicate_source if defined?(@duplicate_source) + @duplicate_source = if params[:duplicate_entry_id].present? + source = Current.family.entries.find_by(id: params[:duplicate_entry_id]) + source if source&.transaction? + end + end + + def prefill_params_from_duplicate! + return unless duplicate_source + params[:nature] ||= duplicate_source.amount.negative? ? "inflow" : "outflow" + params[:account_id] ||= duplicate_source.account_id.to_s + end + + def apply_duplicate_attributes! + return unless duplicate_source + @entry.assign_attributes( + name: duplicate_source.name, + amount: duplicate_source.amount.abs, + currency: duplicate_source.currency, + notes: duplicate_source.notes + ) + @entry.entryable.assign_attributes( + category_id: duplicate_source.entryable.category_id, + merchant_id: duplicate_source.entryable.merchant_id + ) + @entry.entryable.tag_ids = duplicate_source.entryable.tag_ids + end + def set_entry_for_unlock transaction = Current.family.transactions.find(params[:id]) @entry = transaction.entry diff --git a/app/javascript/controllers/bulk_select_controller.js b/app/javascript/controllers/bulk_select_controller.js index 0851da7ad..271b6a0f5 100644 --- a/app/javascript/controllers/bulk_select_controller.js +++ b/app/javascript/controllers/bulk_select_controller.js @@ -8,6 +8,7 @@ export default class extends Controller { "selectionBar", "selectionBarText", "bulkEditDrawerHeader", + "duplicateLink", ]; static values = { singularLabel: String, @@ -135,6 +136,18 @@ export default class extends Controller { this.selectionBarTarget.classList.toggle("hidden", count === 0); this.selectionBarTarget.querySelector("input[type='checkbox']").checked = count > 0; + + if (this.hasDuplicateLinkTarget) { + this.duplicateLinkTarget.classList.toggle("hidden", count !== 1); + if (count === 1) { + const url = new URL( + this.duplicateLinkTarget.href, + window.location.origin, + ); + url.searchParams.set("duplicate_entry_id", this.selectedIdsValue[0]); + this.duplicateLinkTarget.href = url.toString(); + } + } } _pluralizedResourceName() { diff --git a/app/views/transactions/_form.html.erb b/app/views/transactions/_form.html.erb index 063fe394b..2717dd57c 100644 --- a/app/views/transactions/_form.html.erb +++ b/app/views/transactions/_form.html.erb @@ -30,6 +30,11 @@ <%= render DS::Disclosure.new(title: t(".details")) do %> <%= f.fields_for :entryable do |ef| %> + <%= ef.collection_select :merchant_id, + Current.family.available_merchants.alphabetically, + :id, :name, + { include_blank: t(".none"), + label: t(".merchant_label") } %> <%= ef.select :tag_ids, Current.family.tags.alphabetically.pluck(:name, :id), { diff --git a/app/views/transactions/_selection_bar.html.erb b/app/views/transactions/_selection_bar.html.erb index 062b442ad..bfec49418 100644 --- a/app/views/transactions/_selection_bar.html.erb +++ b/app/views/transactions/_selection_bar.html.erb @@ -7,9 +7,20 @@