Browse Source

Fixes #2594 - Wrong date format in Excel Exports of reporting download.

Martin Edenhofer 5 years ago
parent
commit
04d829c7e9
2 changed files with 101 additions and 41 deletions
  1. 55 13
      app/controllers/reports_controller.rb
  2. 46 28
      app/controllers/time_accountings_controller.rb

+ 55 - 13
app/controllers/reports_controller.rb

@@ -61,6 +61,8 @@ class ReportsController < ApplicationController
 
     # get data
     result = {}
+    content = nil
+    filename = nil
     get_params[:metric][:backend].each do |backend|
       next if params[:downloadBackendSelected] != backend[:name]
 
@@ -86,17 +88,21 @@ class ReportsController < ApplicationController
       result = { count: 0, ticket_ids: [] } if result.nil?
 
       # generate sheet
-      next if !params[:sheet]
-
-      content = sheet(get_params[:profile], backend[:display], result)
+      if params[:sheet]
+        content = sheet(get_params[:profile], backend[:display], result)
+        filename = "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls"
+      end
+      break
+    end
+    if content
       send_data(
         content,
-        filename:    "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls",
+        filename:    filename,
         type:        'application/vnd.ms-excel',
         disposition: 'attachment'
       )
+      return
     end
-    return if params[:sheet]
 
     render json: result
   end
@@ -172,24 +178,29 @@ class ReportsController < ApplicationController
 
   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')
-    worksheet.set_row(0, 0, 6)
 
     # Write a formatted and unformatted string, row and column notation.
     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_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)
@@ -213,6 +232,7 @@ class ReportsController < ApplicationController
     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
@@ -223,6 +243,7 @@ class ReportsController < ApplicationController
                                       .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
@@ -243,9 +264,11 @@ class ReportsController < ApplicationController
         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, ticket.created_at.to_time.iso8601)
-        worksheet.write_date_time(row, 12, ticket.updated_at.to_time.iso8601)
-        worksheet.write_date_time(row, 13, ticket.close_at.to_time.iso8601) if ticket.close_at.present?
+
+        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
@@ -253,13 +276,20 @@ class ReportsController < ApplicationController
           key = object[:name]
           case object[:data_type]
           when 'boolean', 'select'
-            value = object[:data_option]['options'][ticket.send(key.to_sym)]
+            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', 'date'
-            worksheet.write_date_time(row, column, ticket.send(key.to_sym).to_time.iso8601) if ticket.send(key.to_sym).present?
+          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))
+            worksheet.write_string(row, column, ticket.send(key.to_sym).to_s)
           end
           column += 1
         end
@@ -268,6 +298,9 @@ class ReportsController < ApplicationController
       end
     end
 
+    row += 2
+    worksheet.write_string(row, 0, "#{Translation.translate(current_user.locale, 'Timezone')}: #{params[:timezone]}", format_footer)
+
     workbook.close
 
     # read file again
@@ -277,4 +310,13 @@ class ReportsController < ApplicationController
     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
+    time.utc.iso8601.to_s.sub(/Z$/, '')
+  end
 end

+ 46 - 28
app/controllers/time_accountings_controller.rb

@@ -96,15 +96,15 @@ class TimeAccountingsController < ApplicationController
         },
         {
           name:  'Created at',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Closed at',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Close Escalation At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Close In Min',
@@ -116,11 +116,11 @@ class TimeAccountingsController < ApplicationController
         },
         {
           name:  'First Response At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'First Response Escalation At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'First Response In Min',
@@ -132,7 +132,7 @@ class TimeAccountingsController < ApplicationController
         },
         {
           name:  'Update Escalation At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Update In Min',
@@ -144,15 +144,15 @@ class TimeAccountingsController < ApplicationController
         },
         {
           name:  'Last Contact At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Last Contact Agent At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Last Contact Customer At',
-          width: 10,
+          width: 18,
         },
         {
           name:  'Article Count',
@@ -160,7 +160,7 @@ class TimeAccountingsController < ApplicationController
         },
         {
           name:  'Escalation At',
-          width: 10,
+          width: 18,
         },
       ]
       objects = ObjectManager::Attribute.where(editable:         true,
@@ -170,18 +170,11 @@ class TimeAccountingsController < ApplicationController
                                         .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: 10 })
+        header.push({ name: object[:display], width: 18 })
       end
 
       result = []
       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 = [
           row[:ticket]['number'],
           row[:ticket]['title'],
@@ -209,19 +202,17 @@ class TimeAccountingsController < ApplicationController
           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
         # 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 = 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('')
-          when 'datetime', 'date'
-            row[:ticket][key].present? ? result_row.push(row[:ticket][key].to_time.iso8601) : result_row.push('')
           else
             # for text, integer and tree select
             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)
 
+    params[:timezone] ||= Setting.get('timezone_default')
+
     # Create a new Excel workbook
     temp_file = Tempfile.new('time_tracking.xls')
     workbook = WriteExcel.new(temp_file)
@@ -412,7 +405,16 @@ class TimeAccountingsController < ApplicationController
     format.set_bold
     format.set_size(14)
     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.
     worksheet.write_string(0, 0, title, format)
@@ -435,15 +437,22 @@ class TimeAccountingsController < ApplicationController
       row_count += 1
       row_item_count = 0
       row.each do |item|
-        if item.acts_like?(:date)
-          worksheet.write_date_time(row_count, row_item_count, item.to_time.iso8601)
+        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)
+          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
@@ -453,4 +462,13 @@ class TimeAccountingsController < ApplicationController
     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
+    time.utc.iso8601.to_s.sub(/Z$/, '')
+  end
 end