diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 2e8ede57f..08ff8fe45 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -91,6 +91,8 @@ class ReportsController < ApplicationController sheet: params[:sheet], ) + result = { count: 0, ticket_ids: [] } if result.nil? + # generate sheet next if !params[:sheet] content = sheet(get_params[:profile], backend[:display], result) @@ -205,6 +207,18 @@ 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 + objects = ObjectManager::Attribute.where(editable: true, + active: true, + 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.write_string(2, header_column, object[:display].capitalize, format_header) + header_column += 1 + end row = 2 result[:ticket_ids].each do |ticket_id| @@ -224,7 +238,24 @@ class ReportsController < ApplicationController 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) + worksheet.write_date_time(row, 13, ticket.close_at.to_time.iso8601) 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 = object[:data_option]['options'][ticket.send(key.to_sym)] + 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? + else + # for text, integer and tree select + worksheet.write_string(row, column, ticket.send(key.to_sym)) + end + column += 1 + end rescue => e Rails.logger.error "SKIP: #{e.message}" end diff --git a/app/controllers/time_accountings_controller.rb b/app/controllers/time_accountings_controller.rb index 338b9d54d..0c581a854 100644 --- a/app/controllers/time_accountings_controller.rb +++ b/app/controllers/time_accountings_controller.rb @@ -162,6 +162,15 @@ class TimeAccountingsController < ApplicationController width: 10, }, ] + objects = ObjectManager::Attribute.where(editable: true, + active: true, + 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: 10 }) + end + result = [] results.each do |row| row[:ticket].each_key do |field| @@ -197,6 +206,26 @@ class TimeAccountingsController < ApplicationController row[:ticket]['article_count'], 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.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('') + end + end + result.push result_row end content = sheet("By Ticket #{year}-#{month}", header, result) diff --git a/test/controllers/reports_controller_test.rb b/test/controllers/reports_controller_test.rb new file mode 100644 index 000000000..06a54096b --- /dev/null +++ b/test/controllers/reports_controller_test.rb @@ -0,0 +1,121 @@ +require 'test_helper' +require 'rake' + +class ReportsControllerTest < ActionDispatch::IntegrationTest + setup do + + # set accept header + @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } + + @year = DateTime.now.utc.year + @month = DateTime.now.utc.month + @week = DateTime.now.utc.strftime('%U').to_i + @day = DateTime.now.utc.day + + roles = Role.where(name: 'Admin') + groups = Group.all + + UserInfo.current_user_id = 1 + + @admin = User.create_or_update( + login: 'rest-admin', + firstname: 'Rest', + lastname: 'Agent', + email: 'rest-admin@example.com', + password: 'adminpw', + active: true, + roles: roles, + groups: groups, + updated_by_id: 1, + created_by_id: 1 + ) + + roles = Role.where(name: 'Customer') + @customer_without_org = User.create_or_update( + login: 'rest-customer1@example.com', + firstname: 'Rest', + lastname: 'Customer1', + email: 'rest-customer1@example.com', + password: 'customer1pw', + active: true, + roles: roles, + updated_by_id: 1, + created_by_id: 1 + ) + + @group1 = Group.create_or_update( + name: "GroupWithoutPermission-#{rand(9_999_999_999)}", + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + @ticket1 = Ticket.create!( + title: 'ticket for report', + group_id: @group1.id, + customer_id: @customer_without_org.id, + state: Ticket::State.lookup(name: 'open'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + + Ticket::Article.create!( + type: Ticket::Article::Type.lookup(name: 'note'), + sender: Ticket::Article::Sender.lookup(name: 'Customer'), + from: 'sender', + subject: 'subject', + body: 'some body', + ticket_id: @ticket1.id, + updated_by_id: 1, + created_by_id: 1, + ) + if ENV['ES_URL'].present? + #fail "ERROR: Need ES_URL - hint ES_URL='http://127.0.0.1:9200'" + Setting.set('es_url', ENV['ES_URL']) + + # Setting.set('es_url', 'http://127.0.0.1:9200') + # Setting.set('es_index', 'estest.local_zammad') + # Setting.set('es_user', 'elasticsearch') + # Setting.set('es_password', 'zammad') + + if ENV['ES_INDEX_RAND'].present? + ENV['ES_INDEX'] = "es_index_#{rand(999_999_999)}" + end + if ENV['ES_INDEX'].blank? + raise "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'" + end + Setting.set('es_index', ENV['ES_INDEX']) + + travel 1.minute + + # drop/create indexes + Rake::Task.clear + Zammad::Application.load_tasks + #Rake::Task["searchindex:drop"].execute + #Rake::Task["searchindex:create"].execute + Rake::Task['searchindex:rebuild'].execute + + # execute background jobs + Scheduler.worker(true) + + sleep 6 + end + end + teardown do + if ENV['ES_URL'].present? + Rake::Task['searchindex:drop'].execute + end + end + + test '01.01 report example - admin access' do + + credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw') + + get "/api/v1/reports/sets?sheet=true;metric=count;year=#{@year};month=#{@month};week=#{@week};day=#{@day};timeRange=year;profile_id=1;downloadBackendSelected=count::created", params: {}, headers: @headers.merge('Authorization' => credentials) + + assert_response(200) + assert(@response['Content-Disposition']) + assert_equal('attachment; filename="tickets--all--Created.xls"', @response['Content-Disposition']) + assert_equal('application/vnd.ms-excel', @response['Content-Type']) + end +end diff --git a/test/controllers/time_accounting_controller_test.rb b/test/controllers/time_accounting_controller_test.rb new file mode 100644 index 000000000..bb1add059 --- /dev/null +++ b/test/controllers/time_accounting_controller_test.rb @@ -0,0 +1,88 @@ +require 'test_helper' +require 'rake' + +class TimeAccountingControllerTest < ActionDispatch::IntegrationTest + setup do + + # set accept header + @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } + + roles = Role.where(name: 'Admin') + groups = Group.all + + UserInfo.current_user_id = 1 + + @year = DateTime.now.utc.year + @month = DateTime.now.utc.month + + @admin = User.create_or_update( + login: 'rest-admin', + firstname: 'Rest', + lastname: 'Agent', + email: 'rest-admin@example.com', + password: 'adminpw', + active: true, + roles: roles, + groups: groups, + updated_by_id: 1, + created_by_id: 1 + ) + + roles = Role.where(name: 'Customer') + @customer_without_org = User.create_or_update( + login: 'rest-customer1@example.com', + firstname: 'Rest', + lastname: 'Customer1', + email: 'rest-customer1@example.com', + password: 'customer1pw', + active: true, + roles: roles, + updated_by_id: 1, + created_by_id: 1 + ) + end + + test '01.01 time account report' do + group = Group.create_or_update( + name: "GroupWithoutPermission-#{rand(9_999_999_999)}", + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + ticket = Ticket.create!( + title: 'ticket for report', + group_id: group.id, + customer_id: @customer_without_org.id, + state: Ticket::State.lookup(name: 'open'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + + article = Ticket::Article.create!( + type: Ticket::Article::Type.lookup(name: 'note'), + sender: Ticket::Article::Sender.lookup(name: 'Customer'), + from: 'sender', + subject: 'subject', + body: 'some body', + ticket_id: ticket.id, + updated_by_id: 1, + created_by_id: 1, + ) + + Ticket::TimeAccounting.create!( + ticket_id: ticket.id, + ticket_article_id: article.id, + time_unit: 200, + ) + + credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw') + + get "/api/v1/time_accounting/log/by_ticket/#{@year}/#{@month}?download=true", params: {}, headers: @headers.merge('Authorization' => credentials) + + assert_response(200) + assert(@response['Content-Disposition']) + assert_equal("attachment; filename=\"by_ticket-#{@year}-#{@month}.xls\"", @response['Content-Disposition']) + assert_equal('application/vnd.ms-excel', @response['Content-Type']) + end +end