diff --git a/app/controllers/organization_transfers_controller.rb b/app/controllers/organization_transfers_controller.rb new file mode 100644 index 00000000..f2a18e84 --- /dev/null +++ b/app/controllers/organization_transfers_controller.rb @@ -0,0 +1,58 @@ +class OrganizationTransfersController < ApplicationController + before_action :authenticate_user! + before_action :check_manager_role + before_action :set_organizations, only: [:new] + before_action :validate_alliance, only: [:new, :create] + + def new + @transfer = Transfer.new + end + + def create + @transfer = Transfer.new(transfer_params) + @transfer.source = current_organization.account + @transfer.destination = destination_organization.account + @transfer.post = nil + persister = ::Persister::TransferPersister.new(@transfer) + + if persister.save + redirect_to organization_path(destination_organization), + notice: t('organizations.transfers.create.success') + else + set_organizations + flash.now[:error] = t('organizations.transfers.create.error', error: @transfer.errors.full_messages.to_sentence) + render :new + end + end + + private + + def transfer_params + params.require(:transfer).permit(:amount, :hours, :minutes, :reason) + end + + def check_manager_role + unless current_user.manages?(current_organization) + redirect_to root_path, alert: t('organization_alliances.not_authorized') + end + end + + def set_organizations + @source_organization = current_organization + @destination_organization = destination_organization + end + + def destination_organization + @destination_organization ||= Organization.find(params[:destination_organization_id]) + rescue ActiveRecord::RecordNotFound + redirect_to organizations_path, alert: t('application.tips.user_not_found') + end + + def validate_alliance + alliance = current_organization.alliance_with(destination_organization) + unless alliance && alliance.accepted? + redirect_to organizations_path, + alert: t('transfers.cross_bank.no_alliance') + end + end +end diff --git a/app/controllers/transfers_controller.rb b/app/controllers/transfers_controller.rb index 12ae72f9..b10222da 100644 --- a/app/controllers/transfers_controller.rb +++ b/app/controllers/transfers_controller.rb @@ -72,6 +72,12 @@ def create_cross_bank_transfer(post) destination_organization = transfer_factory.destination_organization + unless current_organization.alliance_with(destination_organization)&.accepted? + redirect_back fallback_location: post, + alert: t('transfers.cross_bank.no_alliance') + return + end + @persisters = [] user_account = current_user.members.find_by(organization: current_organization).account @@ -93,8 +99,7 @@ def create_cross_bank_transfer(post) destination: destination_organization.account, amount: transfer_params[:amount], reason: post.description, - post: post, - is_cross_bank: true + post: post ) @persisters << ::Persister::TransferPersister.new(org_to_org_transfer) @@ -108,6 +113,9 @@ def create_cross_bank_transfer(post) post: post ) @persisters << ::Persister::TransferPersister.new(org_to_user_transfer) + else + redirect_back fallback_location: post, alert: t('transfers.cross_bank.error') + return end if persisters_saved? diff --git a/app/helpers/transfers_helper.rb b/app/helpers/transfers_helper.rb index 7e6cf20f..93d27f0c 100644 --- a/app/helpers/transfers_helper.rb +++ b/app/helpers/transfers_helper.rb @@ -22,4 +22,15 @@ def accounts_from_movements(transfer, with_links: false) end end end + + def is_bank_to_bank_transfer?(transfer) + return false unless transfer + + source_account = transfer.movements.find_by('amount < 0')&.account + destination_account = transfer.movements.find_by('amount > 0')&.account + + source_account&.accountable_type == 'Organization' && + destination_account&.accountable_type == 'Organization' && + transfer.post.nil? + end end diff --git a/app/models/transfer.rb b/app/models/transfer.rb index 8644b326..24c99402 100644 --- a/app/models/transfer.rb +++ b/app/models/transfer.rb @@ -11,7 +11,7 @@ # account, so the total sum of the system is zero # class Transfer < ApplicationRecord - attr_accessor :source, :destination, :amount, :hours, :minutes, :is_cross_bank, :meta + attr_accessor :source, :destination, :amount, :hours, :minutes belongs_to :post, optional: true has_many :movements, dependent: :destroy @@ -19,37 +19,12 @@ class Transfer < ApplicationRecord validates :amount, numericality: { greater_than: 0 } validate :different_source_and_destination - validate :validate_organizations_alliance, if: -> { is_cross_bank && meta.present? } after_create :make_movements def make_movements - if is_cross_bank && meta.present? - make_cross_bank_movements - else - movements.create(account: Account.find(source_id), amount: -amount.to_i, created_at: created_at) - movements.create(account: Account.find(destination_id), amount: amount.to_i, created_at: created_at) - end - end - - def make_cross_bank_movements - source_organization_id = meta[:source_organization_id] - destination_organization_id = meta[:destination_organization_id] - final_destination_user_id = meta[:final_destination_user_id] - - source_organization = Organization.find(source_organization_id) - destination_organization = Organization.find(destination_organization_id) - final_user = User.find(final_destination_user_id) - final_member = final_user.members.find_by(organization: destination_organization) - movements.create(account: Account.find(source_id), amount: -amount.to_i, created_at: created_at) - movements.create(account: source_organization.account, amount: amount.to_i, created_at: created_at) - - movements.create(account: source_organization.account, amount: -amount.to_i, created_at: created_at) - movements.create(account: destination_organization.account, amount: amount.to_i, created_at: created_at) - - movements.create(account: destination_organization.account, amount: -amount.to_i, created_at: created_at) - movements.create(account: final_member.account, amount: amount.to_i, created_at: created_at) + movements.create(account: Account.find(destination_id), amount: amount.to_i, created_at: created_at) end def source_id @@ -60,43 +35,10 @@ def destination_id destination.respond_to?(:id) ? destination.id : destination end + private + def different_source_and_destination return unless source == destination errors.add(:base, :same_account) end - - def cross_bank? - movements.count > 2 - end - - def related_account_for(movement) - return nil unless movement.transfer == self - - movements_in_order = movements.order(:id) - current_index = movements_in_order.index(movement) - return nil unless current_index - - if movement.amount > 0 && current_index > 0 - movements_in_order[current_index - 1].account - elsif movement.amount < 0 && current_index < movements_in_order.length - 1 - movements_in_order[current_index + 1].account - end - end - - private - - def validate_organizations_alliance - return unless meta[:source_organization_id] && meta[:destination_organization_id] - - source_org = Organization.find_by(id: meta[:source_organization_id]) - dest_org = Organization.find_by(id: meta[:destination_organization_id]) - - return unless source_org && dest_org - - alliance = source_org.alliance_with(dest_org) - - unless alliance && alliance.accepted? - errors.add(:base, :no_alliance_between_organizations) - end - end end diff --git a/app/models/transfer_factory.rb b/app/models/transfer_factory.rb index 95019e74..36464c0f 100644 --- a/app/models/transfer_factory.rb +++ b/app/models/transfer_factory.rb @@ -8,22 +8,14 @@ def initialize(current_organization, current_user, offer_id, destination_account end def offer - if offer_id.present? - Offer.find_by_id(offer_id) - end + @offer ||= Offer.find_by_id(offer_id) if offer_id.present? end def build_transfer - transfer = Transfer.new(source: source) + transfer = Transfer.new(source: source, destination: destination_account.id) - if cross_bank && offer && offer.organization != current_organization - transfer.destination = destination_account.id - transfer.post = offer - transfer.is_cross_bank = true - else - transfer.destination = destination_account.id - transfer.post = offer unless for_organization? - end + transfer.post = offer if (cross_bank && offer && offer.organization != current_organization) || + (offer && !for_organization?) transfer end @@ -63,7 +55,7 @@ def source end def for_organization? - destination_account.try(:accountable).class == Organization + destination_account&.accountable.is_a?(Organization) end def admin? diff --git a/app/views/organization_transfers/new.html.erb b/app/views/organization_transfers/new.html.erb new file mode 100644 index 00000000..946a2209 --- /dev/null +++ b/app/views/organization_transfers/new.html.erb @@ -0,0 +1,33 @@ +