Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Export User Transactions in CSV and upload to Active Storage or send as attachment in email #rails
# frozen_string_literal: true
# app/services/export_services/export_transaction_service.rb
# Example:
# ExportServices::ExportTransactionService.new({ user: User,last}).call
# ExportServices::ExportTransactionService.new({ user: User.last, from_date: '2022-01-01', to_date: '2022-09-01'}).call
module ExportServices
# ExportTransactionService
class ExportTransactionService
# initialize the service with user, from_date and to_date and setting transactions accordingly
def initialize(params) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@user = params[:user]
@from_date = params[:from_date] ? params[:from_date].to_date : 10.years.ago # -Infinity
@to_date = params[:to_date] ? params[:to_date].to_date : Time.zone.now
@transactions = @user.transactions.where(transaction_date: @from_date..@to_date)
.joins(:account, :category).kept.order(transaction_date: :desc)
end
# service work when call method is called
def call
return if @transactions.length.zero?
generate_csv_file
# export_to_storage
send_email
end
# This method creates a temp CSV file and fills data based on initialized transactions
def generate_csv_file # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
@tempfile = Tempfile.new(["export_#{Time.zone.now.strftime('%Y%m%d%H%M%S')}_#{@user.id}", '.csv']).tap do |file|
CSV.open(file, 'wb') do |csv|
# CSV Header Row
csv << %w[Date Description Type Amount Currency Category Account]
# CSV Rows, each row representing a transaction
@transactions.find_each do |transaction|
csv << [
transaction.transaction_date.to_date.to_s,
transaction.description,
transaction.transaction_type == 'income' ? 'Income' : 'Expense',
transaction.value.to_f.round(2),
transaction.account.currency.code,
transaction.category.name,
transaction.account.name,
]
end
end
end
end
# Thios method adds the tempfile to ActiveStorage and hence to S3 service if attached
# I have attached s3 to production environment
# returns url of the uploaded CSV File
def export_to_storage # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
# Document Model `has_attached_file :doc` and `user has_many :documents` and `document belongs_to :user`
document = Document.new(user: @user)
document.doc.attach(
io: @tempfile,
filename: @tempfile.path.split('/').last,
content_type: 'application/csv'
)
document.save!
@file_url = if Rails.env.production?
# returns s3 public url
Rails.application.routes.url_helpers.rails_public_blob_url(@document.doc)
else
# return local url
Rails.application.routes.url_helpers.rails_blob_url(@document.doc)
end
end
# This method sends email with temp file attached
# https://gist.github.com/sulmanweb/eab697301cf8209572c5a95af6543b3a
# https://sulmanweb.com/send-emails-using-sendgrid-sdk-for-ruby-on-rails-using-dynamic-sendgrid-email-templates/
def send_email # rubocop:disable Metrics/MethodLength
EmailJob.new.perform(
@user.id,
{ name: @user.name },
ENV.fetch('EXPORT_TEMPLATE', nil),
[
{
file: @tempfile.path,
type: 'application/csv',
name: @tempfile.path.split('/').last,
content_id: 'export_file'
}
]
)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment