Skip to content

Instantly share code, notes, and snippets.

@sulmanweb
Last active September 7, 2022 06:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sulmanweb/a3407dcc9cd7fddb42e251055d20f247 to your computer and use it in GitHub Desktop.
Save sulmanweb/a3407dcc9cd7fddb42e251055d20f247 to your computer and use it in GitHub Desktop.
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