Fixes #2594 - Wrong date format in Excel Exports of reporting download.
This commit is contained in:
parent
bd5170b731
commit
04d829c7e9
2 changed files with 101 additions and 41 deletions
|
@ -61,6 +61,8 @@ class ReportsController < ApplicationController
|
||||||
|
|
||||||
# get data
|
# get data
|
||||||
result = {}
|
result = {}
|
||||||
|
content = nil
|
||||||
|
filename = nil
|
||||||
get_params[:metric][:backend].each do |backend|
|
get_params[:metric][:backend].each do |backend|
|
||||||
next if params[:downloadBackendSelected] != backend[:name]
|
next if params[:downloadBackendSelected] != backend[:name]
|
||||||
|
|
||||||
|
@ -86,17 +88,21 @@ class ReportsController < ApplicationController
|
||||||
result = { count: 0, ticket_ids: [] } if result.nil?
|
result = { count: 0, ticket_ids: [] } if result.nil?
|
||||||
|
|
||||||
# generate sheet
|
# generate sheet
|
||||||
next if !params[:sheet]
|
if params[:sheet]
|
||||||
|
|
||||||
content = sheet(get_params[:profile], backend[:display], result)
|
content = sheet(get_params[:profile], backend[:display], result)
|
||||||
|
filename = "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls"
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if content
|
||||||
send_data(
|
send_data(
|
||||||
content,
|
content,
|
||||||
filename: "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls",
|
filename: filename,
|
||||||
type: 'application/vnd.ms-excel',
|
type: 'application/vnd.ms-excel',
|
||||||
disposition: 'attachment'
|
disposition: 'attachment'
|
||||||
)
|
)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
return if params[:sheet]
|
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
@ -172,24 +178,29 @@ class ReportsController < ApplicationController
|
||||||
|
|
||||||
def sheet(profile, title, result)
|
def sheet(profile, title, result)
|
||||||
|
|
||||||
|
params[:timezone] ||= Setting.get('timezone_default')
|
||||||
|
|
||||||
# Create a new Excel workbook
|
# Create a new Excel workbook
|
||||||
temp_file = Tempfile.new('time_tracking.xls')
|
temp_file = Tempfile.new('time_tracking.xls')
|
||||||
workbook = WriteExcel.new(temp_file)
|
workbook = WriteExcel.new(temp_file)
|
||||||
|
|
||||||
# Add a worksheet
|
# Add a worksheet
|
||||||
worksheet = workbook.add_worksheet
|
worksheet = workbook.add_worksheet
|
||||||
|
worksheet.set_row(0, 18)
|
||||||
worksheet.set_column(0, 0, 10)
|
worksheet.set_column(0, 0, 10)
|
||||||
worksheet.set_column(1, 1, 34)
|
worksheet.set_column(1, 1, 34)
|
||||||
worksheet.set_column(2, 2, 10)
|
worksheet.set_column(2, 2, 10)
|
||||||
worksheet.set_column(3, 3, 10)
|
worksheet.set_column(3, 3, 10)
|
||||||
worksheet.set_column(4, 8, 20)
|
worksheet.set_column(4, 8, 20)
|
||||||
|
worksheet.set_column(11, 0, 20)
|
||||||
|
worksheet.set_column(12, 0, 20)
|
||||||
|
worksheet.set_column(13, 0, 20)
|
||||||
|
|
||||||
# Add and define a format
|
# Add and define a format
|
||||||
format = workbook.add_format
|
format = workbook.add_format
|
||||||
format.set_bold
|
format.set_bold
|
||||||
format.set_size(14)
|
format.set_size(14)
|
||||||
format.set_color('black')
|
format.set_color('black')
|
||||||
worksheet.set_row(0, 0, 6)
|
|
||||||
|
|
||||||
# Write a formatted and unformatted string, row and column notation.
|
# Write a formatted and unformatted string, row and column notation.
|
||||||
worksheet.write_string(0, 0, "Tickets: #{profile.name} (#{title})", format)
|
worksheet.write_string(0, 0, "Tickets: #{profile.name} (#{title})", format)
|
||||||
|
@ -199,6 +210,14 @@ class ReportsController < ApplicationController
|
||||||
format_header.set_bg_color('gray')
|
format_header.set_bg_color('gray')
|
||||||
format_header.set_color('white')
|
format_header.set_color('white')
|
||||||
|
|
||||||
|
format_time = workbook.add_format(num_format: 'yyyy-mm-dd hh:mm:ss')
|
||||||
|
format_date = workbook.add_format(num_format: 'yyyy-mm-dd')
|
||||||
|
|
||||||
|
format_footer = workbook.add_format
|
||||||
|
format_footer.set_italic
|
||||||
|
format_footer.set_color('gray')
|
||||||
|
format_footer.set_size(8)
|
||||||
|
|
||||||
worksheet.write_string(2, 0, '#', format_header)
|
worksheet.write_string(2, 0, '#', format_header)
|
||||||
worksheet.write_string(2, 1, 'Title', format_header)
|
worksheet.write_string(2, 1, 'Title', format_header)
|
||||||
worksheet.write_string(2, 2, 'State', format_header)
|
worksheet.write_string(2, 2, 'State', format_header)
|
||||||
|
@ -213,6 +232,7 @@ class ReportsController < ApplicationController
|
||||||
worksheet.write_string(2, 11, 'Created at', format_header)
|
worksheet.write_string(2, 11, 'Created at', format_header)
|
||||||
worksheet.write_string(2, 12, 'Updated at', format_header)
|
worksheet.write_string(2, 12, 'Updated at', format_header)
|
||||||
worksheet.write_string(2, 13, 'Closed at', format_header)
|
worksheet.write_string(2, 13, 'Closed at', format_header)
|
||||||
|
|
||||||
# ObjectManager attributes
|
# ObjectManager attributes
|
||||||
header_column = 14
|
header_column = 14
|
||||||
# needs to be skipped
|
# needs to be skipped
|
||||||
|
@ -223,6 +243,7 @@ class ReportsController < ApplicationController
|
||||||
.pluck(:name, :display, :data_type, :data_option)
|
.pluck(:name, :display, :data_type, :data_option)
|
||||||
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
||||||
objects.each do |object|
|
objects.each do |object|
|
||||||
|
worksheet.set_column(header_column, 0, 16)
|
||||||
worksheet.write_string(2, header_column, object[:display].capitalize, format_header)
|
worksheet.write_string(2, header_column, object[:display].capitalize, format_header)
|
||||||
header_column += 1
|
header_column += 1
|
||||||
end
|
end
|
||||||
|
@ -243,9 +264,11 @@ class ReportsController < ApplicationController
|
||||||
worksheet.write_string(row, 8, ticket.create_article_type.name)
|
worksheet.write_string(row, 8, ticket.create_article_type.name)
|
||||||
worksheet.write_string(row, 9, ticket.create_article_sender.name)
|
worksheet.write_string(row, 9, ticket.create_article_sender.name)
|
||||||
worksheet.write_string(row, 10, ticket.tag_list.join(','))
|
worksheet.write_string(row, 10, ticket.tag_list.join(','))
|
||||||
worksheet.write_date_time(row, 11, ticket.created_at.to_time.iso8601)
|
|
||||||
worksheet.write_date_time(row, 12, ticket.updated_at.to_time.iso8601)
|
worksheet.write_date_time(row, 11, time_in_localtime_for_excel(ticket.created_at, params[:timezone]), format_time)
|
||||||
worksheet.write_date_time(row, 13, ticket.close_at.to_time.iso8601) if ticket.close_at.present?
|
worksheet.write_date_time(row, 12, time_in_localtime_for_excel(ticket.updated_at, params[:timezone]), format_time)
|
||||||
|
worksheet.write_date_time(row, 13, time_in_localtime_for_excel(ticket.close_at, params[:timezone]), format_time) if ticket.close_at.present?
|
||||||
|
|
||||||
# Object Manager attributes
|
# Object Manager attributes
|
||||||
column = 14
|
column = 14
|
||||||
# We already queried ObjectManager::Attributes, so we just use objects
|
# We already queried ObjectManager::Attributes, so we just use objects
|
||||||
|
@ -253,13 +276,20 @@ class ReportsController < ApplicationController
|
||||||
key = object[:name]
|
key = object[:name]
|
||||||
case object[:data_type]
|
case object[:data_type]
|
||||||
when 'boolean', 'select'
|
when 'boolean', 'select'
|
||||||
|
value = ticket.send(key.to_sym)
|
||||||
|
if object[:data_option] && object[:data_option]['options'] && object[:data_option]['options'][ticket.send(key.to_sym)]
|
||||||
value = object[:data_option]['options'][ticket.send(key.to_sym)]
|
value = object[:data_option]['options'][ticket.send(key.to_sym)]
|
||||||
|
end
|
||||||
worksheet.write_string(row, column, value)
|
worksheet.write_string(row, column, value)
|
||||||
when 'datetime', 'date'
|
when 'datetime'
|
||||||
worksheet.write_date_time(row, column, ticket.send(key.to_sym).to_time.iso8601) if ticket.send(key.to_sym).present?
|
worksheet.write_date_time(row, column, time_in_localtime_for_excel(ticket.send(key.to_sym), params[:timezone]), format_time) if ticket.send(key.to_sym).present?
|
||||||
|
when 'date'
|
||||||
|
worksheet.write_date_time(row, column, ticket.send(key.to_sym).to_s, format_date) if ticket.send(key.to_sym).present?
|
||||||
|
when 'integer'
|
||||||
|
worksheet.write_number(row, column, ticket.send(key.to_sym))
|
||||||
else
|
else
|
||||||
# for text, integer and tree select
|
# for text, integer and tree select
|
||||||
worksheet.write_string(row, column, ticket.send(key.to_sym))
|
worksheet.write_string(row, column, ticket.send(key.to_sym).to_s)
|
||||||
end
|
end
|
||||||
column += 1
|
column += 1
|
||||||
end
|
end
|
||||||
|
@ -268,6 +298,9 @@ class ReportsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
row += 2
|
||||||
|
worksheet.write_string(row, 0, "#{Translation.translate(current_user.locale, 'Timezone')}: #{params[:timezone]}", format_footer)
|
||||||
|
|
||||||
workbook.close
|
workbook.close
|
||||||
|
|
||||||
# read file again
|
# read file again
|
||||||
|
@ -277,4 +310,13 @@ class ReportsController < ApplicationController
|
||||||
contents
|
contents
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def time_in_localtime_for_excel(time, timezone)
|
||||||
|
return if time.blank?
|
||||||
|
|
||||||
|
if timezone.present?
|
||||||
|
offset = time.in_time_zone(timezone).utc_offset
|
||||||
|
time -= offset
|
||||||
|
end
|
||||||
|
time.utc.iso8601.to_s.sub(/Z$/, '')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -96,15 +96,15 @@ class TimeAccountingsController < ApplicationController
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Created at',
|
name: 'Created at',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Closed at',
|
name: 'Closed at',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Close Escalation At',
|
name: 'Close Escalation At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Close In Min',
|
name: 'Close In Min',
|
||||||
|
@ -116,11 +116,11 @@ class TimeAccountingsController < ApplicationController
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'First Response At',
|
name: 'First Response At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'First Response Escalation At',
|
name: 'First Response Escalation At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'First Response In Min',
|
name: 'First Response In Min',
|
||||||
|
@ -132,7 +132,7 @@ class TimeAccountingsController < ApplicationController
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Update Escalation At',
|
name: 'Update Escalation At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Update In Min',
|
name: 'Update In Min',
|
||||||
|
@ -144,15 +144,15 @@ class TimeAccountingsController < ApplicationController
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Last Contact At',
|
name: 'Last Contact At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Last Contact Agent At',
|
name: 'Last Contact Agent At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Last Contact Customer At',
|
name: 'Last Contact Customer At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Article Count',
|
name: 'Article Count',
|
||||||
|
@ -160,7 +160,7 @@ class TimeAccountingsController < ApplicationController
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Escalation At',
|
name: 'Escalation At',
|
||||||
width: 10,
|
width: 18,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
objects = ObjectManager::Attribute.where(editable: true,
|
objects = ObjectManager::Attribute.where(editable: true,
|
||||||
|
@ -170,18 +170,11 @@ class TimeAccountingsController < ApplicationController
|
||||||
.pluck(:name, :display, :data_type, :data_option)
|
.pluck(:name, :display, :data_type, :data_option)
|
||||||
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
.map { |name, display, data_type, data_option| { name: name, display: display, data_type: data_type, data_option: data_option } }
|
||||||
objects.each do |object|
|
objects.each do |object|
|
||||||
header.push({ name: object[:display], width: 10 })
|
header.push({ name: object[:display], width: 18 })
|
||||||
end
|
end
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
results.each do |row|
|
results.each do |row|
|
||||||
row[:ticket].each_key do |field|
|
|
||||||
next if row[:ticket][field].blank?
|
|
||||||
next if !row[:ticket][field].is_a?(ActiveSupport::TimeWithZone)
|
|
||||||
|
|
||||||
row[:ticket][field] = row[:ticket][field].iso8601
|
|
||||||
end
|
|
||||||
|
|
||||||
result_row = [
|
result_row = [
|
||||||
row[:ticket]['number'],
|
row[:ticket]['number'],
|
||||||
row[:ticket]['title'],
|
row[:ticket]['title'],
|
||||||
|
@ -209,19 +202,17 @@ class TimeAccountingsController < ApplicationController
|
||||||
row[:ticket]['escalation_at'],
|
row[:ticket]['escalation_at'],
|
||||||
]
|
]
|
||||||
|
|
||||||
# needed to get human values for boolean/select rather than true/false values
|
|
||||||
ticket = Ticket.lookup(id: row[:ticket]['id'])
|
|
||||||
|
|
||||||
# Object Manager attributes
|
# Object Manager attributes
|
||||||
# We already queried ObjectManager::Attributes, so we just use objects
|
# We already queried ObjectManager::Attributes, so we just use objects
|
||||||
objects.each do |object|
|
objects.each do |object|
|
||||||
key = object[:name]
|
key = object[:name]
|
||||||
case object[:data_type]
|
case object[:data_type]
|
||||||
when 'boolean', 'select'
|
when 'boolean', 'select'
|
||||||
value = object[:data_option]['options'][ticket.send(key.to_sym)]
|
value = row[:ticket][key]
|
||||||
|
if object[:data_option] && object[:data_option]['options'] && object[:data_option]['options'][row[:ticket][key]]
|
||||||
|
value = object[:data_option]['options'][row[:ticket][key]]
|
||||||
|
end
|
||||||
value.present? ? result_row.push(value) : result_row.push('')
|
value.present? ? result_row.push(value) : result_row.push('')
|
||||||
when 'datetime', 'date'
|
|
||||||
row[:ticket][key].present? ? result_row.push(row[:ticket][key].to_time.iso8601) : result_row.push('')
|
|
||||||
else
|
else
|
||||||
# for text, integer and tree select
|
# for text, integer and tree select
|
||||||
row[:ticket][key].present? ? result_row.push(row[:ticket][key]) : result_row.push('')
|
row[:ticket][key].present? ? result_row.push(row[:ticket][key]) : result_row.push('')
|
||||||
|
@ -400,6 +391,8 @@ class TimeAccountingsController < ApplicationController
|
||||||
|
|
||||||
def sheet(title, header, result)
|
def sheet(title, header, result)
|
||||||
|
|
||||||
|
params[:timezone] ||= Setting.get('timezone_default')
|
||||||
|
|
||||||
# Create a new Excel workbook
|
# Create a new Excel workbook
|
||||||
temp_file = Tempfile.new('time_tracking.xls')
|
temp_file = Tempfile.new('time_tracking.xls')
|
||||||
workbook = WriteExcel.new(temp_file)
|
workbook = WriteExcel.new(temp_file)
|
||||||
|
@ -412,7 +405,16 @@ class TimeAccountingsController < ApplicationController
|
||||||
format.set_bold
|
format.set_bold
|
||||||
format.set_size(14)
|
format.set_size(14)
|
||||||
format.set_color('black')
|
format.set_color('black')
|
||||||
worksheet.set_row(0, 0, header.count)
|
|
||||||
|
format_time = workbook.add_format(num_format: 'yyyy-mm-dd hh:mm:ss')
|
||||||
|
format_date = workbook.add_format(num_format: 'yyyy-mm-dd')
|
||||||
|
|
||||||
|
format_footer = workbook.add_format
|
||||||
|
format_footer.set_italic
|
||||||
|
format_footer.set_color('gray')
|
||||||
|
format_footer.set_size(8)
|
||||||
|
|
||||||
|
worksheet.set_row(0, 18, header.count)
|
||||||
|
|
||||||
# Write a formatted and unformatted string, row and column notation.
|
# Write a formatted and unformatted string, row and column notation.
|
||||||
worksheet.write_string(0, 0, title, format)
|
worksheet.write_string(0, 0, title, format)
|
||||||
|
@ -435,15 +437,22 @@ class TimeAccountingsController < ApplicationController
|
||||||
row_count += 1
|
row_count += 1
|
||||||
row_item_count = 0
|
row_item_count = 0
|
||||||
row.each do |item|
|
row.each do |item|
|
||||||
if item.acts_like?(:date)
|
if item.acts_like?(:time)
|
||||||
worksheet.write_date_time(row_count, row_item_count, item.to_time.iso8601)
|
worksheet.write_date_time(row_count, row_item_count, time_in_localtime_for_excel(item, params[:timezone]), format_time) if item.present?
|
||||||
|
elsif item.acts_like?(:date)
|
||||||
|
worksheet.write_date_time(row_count, row_item_count, item.to_s, format_date) if item.present?
|
||||||
|
elsif item.is_a?(Integer) || item.is_a?(Float)
|
||||||
|
worksheet.write_number(row_count, row_item_count, item)
|
||||||
else
|
else
|
||||||
worksheet.write_string(row_count, row_item_count, item)
|
worksheet.write_string(row_count, row_item_count, item.to_s)
|
||||||
end
|
end
|
||||||
row_item_count += 1
|
row_item_count += 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
row_count += 2
|
||||||
|
worksheet.write_string(row_count, 0, "#{Translation.translate(current_user.locale, 'Timezone')}: #{params[:timezone]}", format_footer)
|
||||||
|
|
||||||
workbook.close
|
workbook.close
|
||||||
|
|
||||||
# read file again
|
# read file again
|
||||||
|
@ -453,4 +462,13 @@ class TimeAccountingsController < ApplicationController
|
||||||
contents
|
contents
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def time_in_localtime_for_excel(time, timezone)
|
||||||
|
return if time.blank?
|
||||||
|
|
||||||
|
if timezone.present?
|
||||||
|
offset = time.in_time_zone(timezone).utc_offset
|
||||||
|
time -= offset
|
||||||
|
end
|
||||||
|
time.utc.iso8601.to_s.sub(/Z$/, '')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue