Files
sure/app/controllers/transfers_controller.rb
soky srm 560c9fbff3 Family sharing (#1272)
* Initial account sharing changes

* Update schema.rb

* Update schema.rb

* Change sharing UI to modal

* UX fixes and sharing controls

* Scope include in finances better

* Update totals.rb

* Update totals.rb

* Scope reports to finance account scope

* Update impersonation_sessions_controller_test.rb

* Review fixes

* Update schema.rb

* Update show.html.erb

* FIX db validation

* Refine edit permissions

* Review items

* Review

* Review

* Add application level helper

* Critical review

* Address remaining review items

* Fix modals

* more scoping

* linter

* small UI fix

* Fix: Sync broadcasts push unscoped balance sheet to all users

* Update sync_complete_event.rb

 The fix removes the sidebar broadcasts (which rendered unscoped account groups using family.balance_sheet without user context)
  along with the now-unused sidebar_targets, account_group, and family_balance_sheet private methods.

  The sidebar will still update correctly — when the sync completes, Family::SyncCompleteEvent#broadcast fires family.broadcast_refresh, which triggers a
  morph-based page refresh for each user with their own authenticated session, rendering properly scoped sidebar content.
2026-03-25 10:50:23 +01:00

129 lines
4.2 KiB
Ruby

class TransfersController < ApplicationController
include StreamExtensions
before_action :set_transfer, only: %i[show destroy update]
def new
@transfer = Transfer.new
@from_account_id = params[:from_account_id]
@accounts = accessible_accounts
.alphabetically
.includes(
:account_providers,
logo_attachment: :blob
)
end
def show
@categories = Current.family.categories.alphabetically
end
def create
# Validate user has write access to both accounts
source_account = accessible_accounts.find(transfer_params[:from_account_id])
destination_account = accessible_accounts.find(transfer_params[:to_account_id])
unless source_account.permission_for(Current.user).in?([ :owner, :full_control ]) &&
destination_account.permission_for(Current.user).in?([ :owner, :full_control ])
respond_to do |format|
format.html { redirect_back_or_to transactions_path, alert: t("accounts.not_authorized") }
format.turbo_stream { stream_redirect_back_or_to(transactions_path, alert: t("accounts.not_authorized")) }
end
return
end
@transfer = Transfer::Creator.new(
family: Current.family,
source_account_id: source_account.id,
destination_account_id: destination_account.id,
date: Date.parse(transfer_params[:date]),
amount: transfer_params[:amount].to_d
).create
if @transfer.persisted?
success_message = "Transfer created"
respond_to do |format|
format.html { redirect_back_or_to transactions_path, notice: success_message }
format.turbo_stream { stream_redirect_back_or_to transactions_path, notice: success_message }
end
else
@from_account_id = transfer_params[:from_account_id]
render :new, status: :unprocessable_entity
end
end
def update
outflow_account = @transfer.outflow_transaction.entry.account
permission = outflow_account.permission_for(Current.user)
unless permission.in?([ :owner, :full_control ])
respond_to do |format|
format.html { redirect_back_or_to transactions_url, alert: t("accounts.not_authorized") }
format.turbo_stream { stream_redirect_back_or_to(transactions_url, alert: t("accounts.not_authorized")) }
end
return
end
Transfer.transaction do
update_transfer_status
update_transfer_details unless transfer_update_params[:status] == "rejected"
end
respond_to do |format|
format.html { redirect_back_or_to transactions_url, notice: t(".success") }
format.turbo_stream
end
end
def destroy
# Require write permission on at least the outflow account
outflow_account = @transfer.outflow_transaction.entry.account
permission = outflow_account.permission_for(Current.user)
unless permission.in?([ :owner, :full_control ])
respond_to do |format|
format.html { redirect_back_or_to transactions_url, alert: t("accounts.not_authorized") }
format.turbo_stream { stream_redirect_back_or_to(transactions_url, alert: t("accounts.not_authorized")) }
end
return
end
@transfer.destroy!
redirect_back_or_to transactions_url, notice: t(".success")
end
private
def set_transfer
# Finds the transfer and ensures the user has access to it
accessible_transaction_ids = Current.family.transactions
.joins(entry: :account)
.merge(Account.accessible_by(Current.user))
.select(:id)
@transfer = Transfer
.where(id: params[:id])
.where(inflow_transaction_id: accessible_transaction_ids)
.first!
end
def transfer_params
params.require(:transfer).permit(:from_account_id, :to_account_id, :amount, :date, :name, :excluded)
end
def transfer_update_params
params.require(:transfer).permit(:notes, :status, :category_id)
end
def update_transfer_status
if transfer_update_params[:status] == "rejected"
@transfer.reject!
elsif transfer_update_params[:status] == "confirmed"
@transfer.confirm!
end
end
def update_transfer_details
@transfer.outflow_transaction.update!(category_id: transfer_update_params[:category_id])
@transfer.update!(notes: transfer_update_params[:notes])
end
end