Skip to content

Instantly share code, notes, and snippets.

@Pepan
Last active April 9, 2020 08:31
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 Pepan/00b557ef5dc17c39b8073af7d3cf71b7 to your computer and use it in GitHub Desktop.
Save Pepan/00b557ef5dc17c39b8073af7d3cf71b7 to your computer and use it in GitHub Desktop.
CSV hanlder
# lib/csv_handler.rb
require 'csv'
module CsvHandler
class Generator
def self.perform
file = CSV.generate do |csv|
yield csv
end
file.html_safe
end
end
class Handler
def self.call (template)
%{
CsvHandler::Generator.perform do |csv|
#{template.source}
end
}
end
end
end
# config/initializers/csv_handler.rb
ActionView::Template.register_template_handler :cbld, CsvHandler::Handler
# app/services/export/timesheet_details_service.rb
module Export
class TimesheetDetailsService
attr_reader :object, :time_range
def initialize(params)
@object = object_from params
@time_range = time_range_from params
end
def perform
@object.project_times.meaningful.where(day: @time_range).order(:day, :created_at)
end
private
def object_from(params)
Person.find params[:person_id]
rescue ActiveRecord::RecordNotFound
Project.find params[:project_id]
end
def time_range_from(params)
case params[:timeframe]
when 'Custom Range'
(params[:start_date].to_date..params[:end_date].to_date)
when 'This Week'
Date.today.all_week
when 'Last Week'
Date.today.last_week.all_week
when "#{I18n.l Date.today, format: :month} To Date"
(Date.today.beginning_of_month..Date.today)
when 'Entire Project'
((@object.plans.first.start_date - 4.months)..Date.today)
else # previous month
Date.today.prev_month.all_month
end
end
end
end
# app/controllers/export/timesheet_details_controller.rb
class Export::TimesheetDetailsController < ApplicationController
before_action :require_company_scope
before_action :verify_user
layout 'dashboard'
def create
@timesheet_details_service = Export::TimesheetDetailsService.new timesheet_params
@project_times = @timesheet_details_service.perform
headers['Content-Disposition'] = "attachment; filename=\"#{file_name_for @timesheet_details_service}\""
headers['Content-Type'] ||= 'text/csv'
render @timesheet_details_service.object.class.name.underscore
end
private
def timesheet_params
params.permit(:project_id, :person_id, :timeframe, :start_date, :end_date)
end
def file_name_for(service)
case service.object
when Person
"Timesheet Detail Export #{service.object.name} #{service.time_range.begin.strftime('%m/%d/%Y')} to #{service.time_range.end.strftime('%m/%d/%Y')}.csv"
when Project
"Timesheet Detail Export #{service.object.client.name} #{service.object.name} #{service.object.code} #{service.time_range.begin.strftime('%m/%d/%Y')} to #{service.time_range.end.strftime('%m/%d/%Y')}.csv"
else
raise StandardError::ArgumentError, service.object.class.name
end
end
end
# app/views/export/timesheet_details/person.csv.cbld
csv << ['Date', 'Project', 'Project Code', 'Contract Type', 'Client', 'Role', 'Status ', 'Actual Hours', 'Project Billable Rate', 'Revenue Earned', 'Notes']
@project_times.each do |project_time|
calculated_billing_rate = project_time.person.calculated_billing_rate(project_time.project_id)
csv << [
project_time.day,
project_time.project.name,
project_time.project.code,
export_contract_type(project_time.project.plans.first.try(:contract_type)),
project_time.project.client.name,
project_time.person_role.name,
project_time.person.status_short_display,
(project_time.minutes / 60.0).round(2),
calculated_billing_rate.to_i,
((project_time.minutes / 60.0) * calculated_billing_rate.to_f).round(0),
project_time.notes
]
end
# app/views/export/timesheet_details/project.csv.cbld
csv << ['Date', 'Project Code', 'Person', 'Person ID', 'Role', 'Status', 'Tracked Time ', 'Project Billable Rate', 'Revenue Earned', 'Notes']
@project_times.each do |project_time|
calculated_billing_rate = project_time.person.calculated_billing_rate(project_time.project_id)
csv << [
project_time.day,
project_time.project.code,
project_time.person.name,
project_time.person_id,
project_time.project.person_roles(project_time.person_id).map(&:name).join(', '),
project_time.person.status_short_display,
(project_time.minutes / 60.0).round(2),
calculated_billing_rate.to_i,
((project_time.minutes / 60.0) * calculated_billing_rate.to_f).round(0),
project_time.notes
]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment