Skip to content

Commit

Permalink
[Feature] Transfers added to admin & import from csv (#723)
Browse files Browse the repository at this point in the history
  • Loading branch information
franpb14 authored Dec 30, 2023
1 parent 5d56ea6 commit de95e00
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
40 changes: 40 additions & 0 deletions app/admin/transfer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
ActiveAdmin.register Transfer do
action_item :upload_csv, only: :index do
link_to I18n.t("active_admin.users.upload_from_csv"), action: "upload_csv"
end

collection_action :upload_csv do
render "admin/csv/upload_csv"
end

collection_action :import_csv, method: :post do
errors = TransferImporter.call(params[:dump][:organization_id], params[:dump][:file])
flash[:error] = errors.join("<br/>").html_safe if errors.present?

redirect_to action: :index
end

index do
id_column
column :post
column :reason
column :source do |transfer|
acc = transfer.movements.find_by('amount < 0').account.accountable
acc.class.name == "Member" ? acc.user : acc
end
column :destination do |transfer|
acc = transfer.movements.find_by('amount > 0').account.accountable
acc.class.name == "Member" ? acc.user : acc
end
column :amount do |transfer|
transfer.movements.find_by('amount > 0').amount
end
column :created_at do |transfer|
l transfer.created_at.to_date, format: :long
end
column :organization do |transfer|
transfer.movements.first.account.organization
end
actions
end
end
78 changes: 78 additions & 0 deletions app/services/transfer_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Used in the Admin section to import transfers
# to a specific organization, from a CSV file.

require "csv"

class TransferImporter
Row = Struct.new(
:source_id,
:source_type,
:destination_id,
:destination_type,
:amount,
:created_at,
:reason,
:post_id
) do
def transfer_from_row(organization_id, errors)
source = find_account(source_id, source_type, organization_id, errors, 'source')
destination = find_account(destination_id, destination_type, organization_id, errors, 'destination')
return unless source && destination

Transfer.new(
source: source,
destination: destination,
amount: amount,
created_at: created_at,
reason: reason,
post_id: post_id,
)
end

private

def find_account(id, type, organization_id, errors, direction)
acc = if type.downcase == 'organization'
Organization.find(organization_id).account
else
Member.find_by(member_uid: id, organization_id: organization_id)&.account
end

unless acc
errors.push(account_id: id, errors: "#{direction}_id #{id} not found in organization #{organization_id}")
return false
end
acc
end
end

class << self
def call(organization_id, csv_data)
data = csv_data.read
errors = []

CSV.parse(data, headers: false) do |data_row|
row = Row.new(
data_row[0],
data_row[1],
data_row[2],
data_row[3],
data_row[4],
data_row[5],
data_row[6],
data_row[7]
)
process_row(row, organization_id, errors)
end

errors
end

def process_row(row, organization_id, errors)
transfer = row.transfer_from_row(organization_id, errors)
return if !transfer || transfer.save

errors.push(account_id: row.source_id, errors: transfer.errors.full_messages)
end
end
end

0 comments on commit de95e00

Please sign in to comment.