Fixes #2699 - Excel export of report or time accounting drops additional fields in row if integer field contain null/nil/undefined.

This commit is contained in:
Martin Edenhofer 2019-09-16 22:36:03 +02:00 committed by Thorsten Eckel
parent 2e3b7e07ad
commit ba2afc0c16
7 changed files with 391 additions and 454 deletions

View file

@ -61,7 +61,7 @@ class ReportsController < ApplicationController
# get data
result = {}
content = nil
excel = nil
filename = nil
get_params[:metric][:backend].each do |backend|
next if params[:downloadBackendSelected] != backend[:name]
@ -89,14 +89,19 @@ class ReportsController < ApplicationController
# generate sheet
if params[:sheet]
content = sheet(get_params[:profile], backend[:display], result)
excel = ExcelSheet::Ticket.new(
title: "#{get_params[:profile].name} (#{backend[:display]})",
ticket_ids: result[:ticket_ids],
timezone: params[:timezone],
locale: current_user.locale,
)
filename = "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls"
end
break
end
if content
if excel
send_data(
content,
excel.content,
filename: filename,
type: 'application/vnd.ms-excel',
disposition: 'attachment'
@ -176,148 +181,4 @@ class ReportsController < ApplicationController
}
end
def sheet(profile, title, result)
params[:timezone] ||= Setting.get('timezone_default')
# Create a new Excel workbook
temp_file = Tempfile.new('time_tracking.xls')
workbook = WriteExcel.new(temp_file)
# Add a worksheet
worksheet = workbook.add_worksheet
worksheet.set_row(0, 18)
worksheet.set_column(0, 0, 10)
worksheet.set_column(1, 1, 34)
worksheet.set_column(2, 2, 10)
worksheet.set_column(3, 3, 10)
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
format = workbook.add_format
format.set_bold
format.set_size(14)
format.set_color('black')
# Write a formatted and unformatted string, row and column notation.
worksheet.write_string(0, 0, "Tickets: #{profile.name} (#{title})", format)
format_header = workbook.add_format
format_header.set_italic
format_header.set_bg_color('gray')
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, 1, 'Title', format_header)
worksheet.write_string(2, 2, 'State', format_header)
worksheet.write_string(2, 3, 'Priority', format_header)
worksheet.write_string(2, 4, 'Group', format_header)
worksheet.write_string(2, 5, 'Owner', format_header)
worksheet.write_string(2, 6, 'Customer', format_header)
worksheet.write_string(2, 7, 'Organization', format_header)
worksheet.write_string(2, 8, 'Create Channel', format_header)
worksheet.write_string(2, 9, 'Sender', format_header)
worksheet.write_string(2, 10, 'Tags', format_header)
worksheet.write_string(2, 11, 'Created at', format_header)
worksheet.write_string(2, 12, 'Updated at', format_header)
worksheet.write_string(2, 13, 'Closed at', format_header)
# ObjectManager attributes
header_column = 14
# needs to be skipped
objects = ObjectManager::Attribute.where(editable: true,
active: true,
to_create: false,
object_lookup_id: ObjectLookup.lookup(name: 'Ticket').id)
.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 } }
objects.each do |object|
worksheet.set_column(header_column, 0, 16)
worksheet.write_string(2, header_column, object[:display].capitalize, format_header)
header_column += 1
end
row = 2
result[:ticket_ids].each do |ticket_id|
ticket = Ticket.lookup(id: ticket_id)
row += 1
worksheet.write_string(row, 0, ticket.number)
worksheet.write_string(row, 1, ticket.title)
worksheet.write_string(row, 2, ticket.state.name)
worksheet.write_string(row, 3, ticket.priority.name)
worksheet.write_string(row, 4, ticket.group.name)
worksheet.write_string(row, 5, ticket.owner.fullname)
worksheet.write_string(row, 6, ticket.customer.fullname)
worksheet.write_string(row, 7, ticket.try(:organization).try(: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, 10, ticket.tag_list.join(','))
worksheet.write_date_time(row, 11, time_in_localtime_for_excel(ticket.created_at, params[:timezone]), format_time)
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
column = 14
# We already queried ObjectManager::Attributes, so we just use objects
objects.each do |object|
key = object[:name]
case object[:data_type]
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)]
end
worksheet.write_string(row, column, value)
when 'datetime'
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
# for text, integer and tree select
worksheet.write_string(row, column, ticket.send(key.to_sym).to_s)
end
column += 1
end
rescue => e
Rails.logger.error "SKIP: #{e.message}"
end
row += 2
worksheet.write_string(row, 0, "#{Translation.translate(current_user.locale, 'Timezone')}: #{params[:timezone]}", format_footer)
workbook.close
# read file again
file = File.new(temp_file, 'r')
contents = file.read
file.close
contents
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
local_time = time.utc.iso8601.to_s.sub(/Z$/, '')
local_time.sub(/T/, ' ')
end
end

View file

@ -21,216 +21,79 @@ class TimeAccountingsController < ApplicationController
end
time_unit[record[0]][:time_unit] += record[1]
end
customers = {}
organizations = {}
agents = {}
results = []
time_unit.each do |ticket_id, local_time_unit|
ticket = Ticket.lookup(id: ticket_id)
next if !ticket
if !customers[ticket.customer_id]
customers[ticket.customer_id] = '-'
if ticket.customer_id
customer_user = User.lookup(id: ticket.customer_id)
if customer_user
customers[ticket.customer_id] = customer_user.fullname
end
end
end
if !organizations[ticket.organization_id]
organizations[ticket.organization_id] = '-'
if ticket.organization_id
organization = Organization.lookup(id: ticket.organization_id)
if organization
organizations[ticket.organization_id] = organization.name
end
end
end
if !agents[local_time_unit[:agent_id]]
agent_user = User.lookup(id: local_time_unit[:agent_id])
if agent_user
agents[local_time_unit[:agent_id]] = agent_user.fullname
end
end
result = {
ticket: ticket.attributes,
time_unit: local_time_unit[:time_unit],
customer: customers[ticket.customer_id],
organization: organizations[ticket.organization_id],
agent: agents[local_time_unit[:agent_id]],
}
results.push result
end
if !params[:download]
customers = {}
organizations = {}
agents = {}
results = []
time_unit.each do |ticket_id, local_time_unit|
ticket = Ticket.lookup(id: ticket_id)
next if !ticket
if params[:download]
header = [
{
name: 'Ticket#',
width: 15,
},
{
name: 'Title',
width: 30,
},
{
name: 'Customer',
width: 20,
},
{
name: 'Organization',
width: 20,
},
{
name: 'Agent',
width: 20,
},
{
name: 'Time Units',
width: 10,
},
{
name: 'Time Units Total',
width: 10,
},
{
name: 'Created at',
width: 18,
},
{
name: 'Closed at',
width: 18,
},
{
name: 'Close Escalation At',
width: 18,
},
{
name: 'Close In Min',
width: 10,
},
{
name: 'Close Diff In Min',
width: 10,
},
{
name: 'First Response At',
width: 18,
},
{
name: 'First Response Escalation At',
width: 18,
},
{
name: 'First Response In Min',
width: 10,
},
{
name: 'First Response Diff In Min',
width: 10,
},
{
name: 'Update Escalation At',
width: 18,
},
{
name: 'Update In Min',
width: 10,
},
{
name: 'Update Diff In Min',
width: 10,
},
{
name: 'Last Contact At',
width: 18,
},
{
name: 'Last Contact Agent At',
width: 18,
},
{
name: 'Last Contact Customer At',
width: 18,
},
{
name: 'Article Count',
width: 10,
},
{
name: 'Escalation At',
width: 18,
},
]
objects = ObjectManager::Attribute.where(editable: true,
active: true,
to_create: false,
object_lookup_id: ObjectLookup.lookup(name: 'Ticket').id)
.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 } }
objects.each do |object|
header.push({ name: object[:display], width: 18 })
end
result = []
results.each do |row|
result_row = [
row[:ticket]['number'],
row[:ticket]['title'],
row[:customer],
row[:organization],
row[:agent],
row[:time_unit],
row[:ticket]['time_unit'],
row[:ticket]['created_at'],
row[:ticket]['close_at'],
row[:ticket]['close_escalation_at'],
row[:ticket]['close_in_min'],
row[:ticket]['close_diff_in_min'],
row[:ticket]['first_response_at'],
row[:ticket]['first_response_escalation_at'],
row[:ticket]['first_response_in_min'],
row[:ticket]['first_response_diff_in_min'],
row[:ticket]['update_escalation_at'],
row[:ticket]['update_in_min'],
row[:ticket]['update_diff_in_min'],
row[:ticket]['last_contact_at'],
row[:ticket]['last_contact_agent_at'],
row[:ticket]['last_contact_customer_at'],
row[:ticket]['article_count'],
row[:ticket]['escalation_at'],
]
# Object Manager attributes
# We already queried ObjectManager::Attributes, so we just use objects
objects.each do |object|
key = object[:name]
case object[:data_type]
when 'boolean', 'select'
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]]
if !customers[ticket.customer_id]
customers[ticket.customer_id] = '-'
if ticket.customer_id
customer_user = User.lookup(id: ticket.customer_id)
if customer_user
customers[ticket.customer_id] = customer_user.fullname
end
value.present? ? result_row.push(value) : result_row.push('')
else
# for text, integer and tree select
row[:ticket][key].present? ? result_row.push(row[:ticket][key]) : result_row.push('')
end
end
result.push result_row
if !organizations[ticket.organization_id]
organizations[ticket.organization_id] = '-'
if ticket.organization_id
organization = Organization.lookup(id: ticket.organization_id)
if organization
organizations[ticket.organization_id] = organization.name
end
end
end
if !agents[local_time_unit[:agent_id]]
agent_user = User.lookup(id: local_time_unit[:agent_id])
if agent_user
agents[local_time_unit[:agent_id]] = agent_user.fullname
end
end
result = {
ticket: ticket.attributes,
time_unit: local_time_unit[:time_unit],
customer: customers[ticket.customer_id],
organization: organizations[ticket.organization_id],
agent: agents[local_time_unit[:agent_id]],
}
results.push result
end
content = sheet("By Ticket #{year}-#{month}", header, result)
send_data(
content,
filename: "by_ticket-#{year}-#{month}.xls",
type: 'application/vnd.ms-excel',
disposition: 'attachment'
)
render json: results
return
end
render json: results
ticket_ids = []
additional_attributes = []
additional_attributes_header = [{ display: 'Time Units', name: 'time_unit_for_range', width: 10, data_type: 'float' }]
time_unit.each do |ticket_id, local_time_unit|
ticket_ids.push ticket_id
additional_attribute = {
time_unit_for_range: local_time_unit[:time_unit],
}
additional_attributes.push additional_attribute
end
excel = ExcelSheet::Ticket.new(
title: "Tickets: #{year}-#{month}",
ticket_ids: ticket_ids,
additional_attributes: additional_attributes,
additional_attributes_header: additional_attributes_header,
timezone: params[:timezone],
locale: current_user.locale,
)
send_data(
excel.content,
filename: "by_ticket-#{year}-#{month}.xls",
type: 'application/vnd.ms-excel',
disposition: 'attachment'
)
end
def by_customer
@ -287,11 +150,12 @@ class TimeAccountingsController < ApplicationController
width: 30,
},
{
name: 'Time Units',
width: 10,
name: 'Time Units',
width: 10,
data_type: 'float'
}
]
result = []
records = []
results.each do |row|
customer_name = User.find(row[:customer]['id']).fullname
organization_name = ''
@ -299,11 +163,18 @@ class TimeAccountingsController < ApplicationController
organization_name = row[:organization]['name']
end
result_row = [customer_name, organization_name, row[:time_unit]]
result.push result_row
records.push result_row
end
content = sheet("By Customer #{year}-#{month}", header, result)
excel = ExcelSheet.new(
title: "By Customer #{year}-#{month}",
header: header,
records: records,
timezone: params[:timezone],
locale: current_user.locale,
)
send_data(
content,
excel.content,
filename: "by_customer-#{year}-#{month}.xls",
type: 'application/vnd.ms-excel',
disposition: 'attachment'
@ -360,22 +231,30 @@ class TimeAccountingsController < ApplicationController
width: 40,
},
{
name: 'Time Units',
width: 20,
name: 'Time Units',
width: 20,
data_type: 'float',
}
]
result = []
records = []
results.each do |row|
organization_name = ''
if row[:organization].present?
organization_name = row[:organization]['name']
end
result_row = [organization_name, row[:time_unit]]
result.push result_row
records.push result_row
end
content = sheet("By Organization #{year}-#{month}", header, result)
excel = ExcelSheet.new(
title: "By Organization #{year}-#{month}",
header: header,
records: records,
timezone: params[:timezone],
locale: current_user.locale,
)
send_data(
content,
excel.content,
filename: "by_organization-#{year}-#{month}.xls",
type: 'application/vnd.ms-excel',
disposition: 'attachment'
@ -385,90 +264,4 @@ class TimeAccountingsController < ApplicationController
render json: results
end
private
def sheet(title, header, result)
params[:timezone] ||= Setting.get('timezone_default')
# Create a new Excel workbook
temp_file = Tempfile.new('time_tracking.xls')
workbook = WriteExcel.new(temp_file)
# Add a worksheet
worksheet = workbook.add_worksheet
# Add and define a format
format = workbook.add_format # Add a format
format.set_bold
format.set_size(14)
format.set_color('black')
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.
worksheet.write_string(0, 0, title, format)
format_header = workbook.add_format # Add a format
format_header.set_italic
format_header.set_bg_color('gray')
format_header.set_color('white')
count = 0
header.each do |item|
if item[:width]
worksheet.set_column(count, count, item[:width])
end
worksheet.write_string(2, count, item[:name], format_header)
count += 1
end
row_count = 2
result.each do |row|
row_count += 1
row_item_count = 0
row.each do |item|
if item.acts_like?(:time)
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
worksheet.write_string(row_count, row_item_count, item.to_s)
end
row_item_count += 1
end
end
row_count += 2
worksheet.write_string(row_count, 0, "#{Translation.translate(current_user.locale, 'Timezone')}: #{params[:timezone]}", format_footer)
workbook.close
# read file again
file = File.new(temp_file, 'r')
contents = file.read
file.close
contents
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
local_time = time.utc.iso8601.to_s.sub(/Z$/, '')
local_time.sub(/T/, ' ')
end
end

173
lib/excel_sheet.rb Normal file
View file

@ -0,0 +1,173 @@
class ExcelSheet
def initialize(title:, header:, records:, timezone: nil, locale:)
@title = title
@header = header
@records = records
@timezone = timezone.presence || Setting.get('timezone_default')
@timezone_offset = @timezone.present? ? Time.now.in_time_zone(@timezone).utc_offset : 0
@locale = locale || 'en-en'
@tempfile = Tempfile.new('excel-export.xls')
@workbook = WriteExcel.new(@tempfile)
@worksheet = @workbook.add_worksheet
@contents = nil
@current_row = 0
@current_column = 0
@lookup_cache = {}
@format_time = @workbook.add_format(num_format: 'yyyy-mm-dd hh:mm:ss')
@format_date = @workbook.add_format(num_format: 'yyyy-mm-dd')
@format_headline = @workbook.add_format
@format_headline.set_bold
@format_headline.set_size(14)
@format_headline.set_color('black')
@format_header = @workbook.add_format
@format_header.set_italic
@format_header.set_bg_color('gray')
@format_header.set_color('white')
@format_footer = @workbook.add_format
@format_footer.set_italic
@format_footer.set_color('gray')
@format_footer.set_size(8)
end
def contents
file = File.new(@tempfile, 'r')
contents = file.read
file.close
contents
end
def content
gen_header
gen_rows
gen_footer
contents
end
def gen_header
@worksheet.write_string(@current_row, @current_column, @title, @format_headline)
@worksheet.set_row(0, 18)
@current_row += 2
@current_column = 0
@header.each do |header|
if header[:width]
@worksheet.set_column(@current_column, @current_column, header[:width])
end
@worksheet.write_string(@current_row, @current_column, header[:display] || header[:name], @format_header)
@current_column += 1
end
end
def gen_rows
@records.each do |record|
gen_row_by_array(record)
end
end
def gen_row_by_array(record)
@current_row += 1
@current_column = 0
record.each do |item|
begin
if item.acts_like?(:time)
value_convert(item, nil, { data_type: 'datetime' })
elsif item.acts_like?(:date)
value_convert(item, nil, { data_type: 'datetime' })
elsif item.is_a?(Integer) || item.is_a?(Float)
value_convert(item, nil, { data_type: 'integer' })
else
value_convert(item, nil, { data_type: 'string' })
end
rescue => e
Rails.logger.error e
end
@current_column += 1
end
end
def gen_row_by_header(record, additional = {})
@current_row += 1
@current_column = 0
@header.each do |header|
begin
value_convert(record, header[:name], header, additional)
rescue => e
Rails.logger.error e
end
@current_column += 1
end
end
def gen_footer
@current_row += 2
@worksheet.write_string(@current_row, 0, "#{Translation.translate(@locale, 'Timezone')}: #{@timezone}", @format_footer)
@workbook.close
end
def timestamp_in_localtime(time)
return if time.blank?
(time + @timezone_offset).utc.strftime('%F %T') # "2019-08-19 16:21:52"
end
def value_lookup(record, attribute, additional)
value = record[attribute.to_sym]
if attribute[-3, 3] == '_id'
ref = attribute[0, attribute.length - 3]
if record.respond_to?(ref.to_sym)
@lookup_cache[attribute] ||= {}
return @lookup_cache[attribute][value] if @lookup_cache[attribute][value]
ref_object = record.send(ref.to_sym)
ref_name = value
if ref_object.respond_to?(:fullname)
ref_name = ref_object.fullname
elsif ref_object.respond_to?(:name)
ref_name = ref_object.name
end
@lookup_cache[attribute][value] = ref_name
return ref_name
end
end
value = record.try(attribute)
# if no value exists, check additional values
if !value && additional && additional[attribute.to_sym]
value = additional[attribute.to_sym]
end
if value.is_a?(Array)
value = value.join(',')
end
value
end
def value_convert(record, attribute, object, additional = {})
value = if attribute
value_lookup(record, attribute, additional)
else
record
end
case object[:data_type]
when 'boolean', 'select'
if object[:data_option] && object[:data_option]['options'] && object[:data_option]['options'][value]
value = object[:data_option]['options'][value]
end
@worksheet.write_string(@current_row, @current_column, value) if value.present?
when 'datetime'
@worksheet.write_date_time(@current_row, @current_column, timestamp_in_localtime(value), @format_time) if value.present?
when 'date'
@worksheet.write_date_time(@current_row, @current_column, value.to_s, @format_date) if value.present?
when 'integer'
@worksheet.write_number(@current_row, @current_column, value) if value.present?
else
@worksheet.write_string(@current_row, @current_column, value.to_s) if value.present?
end
end
end

103
lib/excel_sheet/ticket.rb Normal file
View file

@ -0,0 +1,103 @@
class ExcelSheet::Ticket < ExcelSheet
=begin
excel = ExcelSheet::Ticket.new(
title: "#{year}-#{month}",
ticket_ids: ticket_ids,
additional_attributes: additional_attributes,
additional_attributes_header: additional_attributes_header,
timezone: params[:timezone],
locale: current_user.locale,
)
excel.content
=end
def initialize(params)
@ticket_ids = params[:ticket_ids] || []
@additional_attributes = params[:additional_attributes] || []
@additional_attributes_header = params[:additional_attributes_header] || []
super(
title: params[:title],
header: ticket_header,
records: [],
timezone: params[:timezone],
locale: params[:locale]
)
end
def ticket_header
header = [
{ display: '#', name: 'number', width: 18, data_type: 'string' },
{ display: 'Title', name: 'title', width: 34, data_type: 'string' },
{ display: 'State', name: 'state_id', width: 14, data_type: 'string' },
{ display: 'Priority', name: 'priority_id', width: 14, data_type: 'string' },
{ display: 'Group', name: 'group_id', width: 20, data_type: 'string' },
{ display: 'Owner', name: 'owner_id', width: 20, data_type: 'string' },
{ display: 'Customer', name: 'customer_id', width: 20, data_type: 'string' },
{ display: 'Organization', name: 'organization_id', width: 20, data_type: 'string' },
{ display: 'Create Channel', name: 'create_article_type_id', width: 10, data_type: 'string' },
{ display: 'Sender', name: 'create_article_sender_id', width: 14, data_type: 'string' },
{ display: 'Tags', name: 'tag_list', width: 20, data_type: 'string' },
{ display: 'Time Units Total', name: 'time_unit', width: 10, data_type: 'float' },
]
header = header.concat(@additional_attributes_header) if @additional_attributes_header
# ObjectManager attributes
objects = ObjectManager::Attribute.where(active: true,
to_create: false,
object_lookup_id: ObjectLookup.lookup(name: 'Ticket').id)
.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, width: 20 } }
objects.each do |object|
already_exists = false
header.each do |local_header|
next if local_header[:name] != object[:name]
already_exists = true
break
end
next if already_exists
header.push object
end
header = header.concat([
{ display: 'Created At', name: 'created_at', width: 18, data_type: 'datetime' },
{ display: 'Updated At', name: 'updated_at', width: 18, data_type: 'datetime' },
{ display: 'Closed At', name: 'close_at', width: 18, data_type: 'datetime' },
{ display: 'Close Escalation At', name: 'close_escalation_at', width: 18, data_type: 'datetime' },
{ display: 'Close In Min', name: 'close_in_min', width: 10, data_type: 'integer' },
{ display: 'Close Diff In Min', name: 'close_diff_in_min', width: 10, data_type: 'integer' },
{ display: 'First Response At', name: 'first_response_at', width: 18, data_type: 'datetime' },
{ display: 'First Response Escalation At', name: 'first_response_escalation_at', width: 18, data_type: 'datetime' },
{ display: 'First Response In Min', name: 'first_response_in_min', width: 10, data_type: 'integer' },
{ display: 'First Response Diff In Min', name: 'first_response_diff_in_min', width: 10, data_type: 'integer' },
{ display: 'Update Escalation At', name: 'update_escalation_at', width: 18, data_type: 'datetime' },
{ display: 'Update In Min', name: 'update_in_min', width: 10, data_type: 'integer' },
{ display: 'Update Diff In Min', name: 'update_diff_in_min', width: 10, data_type: 'integer' },
{ display: 'Last Contact At', name: 'last_contact_at', width: 18, data_type: 'datetime' },
{ display: 'Last Contact Agent At', name: 'last_contact_agent_at', width: 18, data_type: 'datetime' },
{ display: 'Last Contact Customer At', name: 'last_contact_customer_at', width: 18, data_type: 'datetime' },
{ display: 'Article Count', name: 'article_count', width: 10, data_type: 'integer' },
{ display: 'Escalation At', name: 'escalation_at', width: 18, data_type: 'datetime' },
])
header
end
def gen_rows
@ticket_ids.each_with_index do |ticket_id, index|
ticket = ::Ticket.lookup(id: ticket_id)
raise "Can't find Ticket with ID #{ticket_id} for '#{@title}' #{self.class.name} generation" if !ticket
gen_row_by_header(ticket, @additional_attributes[index])
rescue => e
Rails.logger.error e
end
end
end

View file

@ -0,0 +1,14 @@
require 'rails_helper'
RSpec.describe ExcelSheet do
describe '.timestamp_in_localtime' do
let(:document) { described_class.new(title: 'some title', header: [], records: [], timezone: 'Europe/Berlin', locale: 'de-de') }
it 'does convert UTC timestamp to local system based timestamp' do
expect(document.timestamp_in_localtime(Time.parse('2019-08-08T01:00:05Z').in_time_zone)).to eq('2019-08-08 03:00:05')
end
end
end

View file

@ -81,10 +81,6 @@ RSpec.describe 'Report', type: :request, searchindex: true do
expect(@response['Content-Type']).to eq('application/vnd.ms-excel')
end
it 'does convert UTC timestamp to local system based timestamp' do
expect(ReportsController.new.time_in_localtime_for_excel(Time.parse('2019-08-08T01:00:05Z').in_time_zone, 'Europe/Berlin')).to eq('2019-08-08 03:00:05')
end
it 'does report example - deliver result' do
skip('No ES configured') if !SearchIndexBackend.enabled?

View file

@ -62,8 +62,5 @@ RSpec.describe 'Time Accounting API endpoints', type: :request do
end
end
it 'does convert UTC timestamp to local system based timestamp' do
expect(TimeAccountingsController.new.instance_eval { time_in_localtime_for_excel(Time.parse('2019-08-08T01:00:05Z').in_time_zone, 'Europe/Berlin') }).to eq('2019-08-08 03:00:05')
end
end
end