ticket_generic_time.rb 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. # Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. class Report::TicketGenericTime < Report::BaseElasticSearch
  3. =begin
  4. result = Report::TicketGenericTime.aggs(
  5. range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
  6. range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
  7. interval: 'month', # year, quarter, month, week, day, hour, minute, second
  8. selector: selector, # ticket selector to get only a collection of tickets
  9. params: { field: 'created_at', selector: selector_sub },
  10. timezone: 'Europe/Berlin',
  11. )
  12. returns
  13. [4,5,1,5,0,51,5,56,7,4]
  14. =end
  15. def self.aggs(params_origin)
  16. params = params_origin.deep_dup
  17. interval_es = params[:interval]
  18. if params[:interval] == 'week'
  19. interval_es = 'day'
  20. end
  21. aggs_interval = {
  22. from: params[:range_start].iso8601,
  23. to: params[:range_end].iso8601,
  24. interval: interval_es, # year, quarter, month, week, day, hour, minute, second
  25. field: params[:params][:field],
  26. timezone: params[:timezone],
  27. }
  28. selector = params[:selector].clone
  29. if params[:params].present? && params[:params][:selector].present?
  30. selector = selector.merge(params[:params][:selector])
  31. end
  32. selector.merge!(without_merged_tickets_selector) # do not show merged tickets in reports
  33. result_es = SearchIndexBackend.selectors('Ticket', selector, { current_user: params_origin[:current_user] }, aggs_interval) # use params_origin because deep_dup removes current_user.id
  34. case params[:interval]
  35. when 'month'
  36. stop_interval = 12
  37. when 'week'
  38. stop_interval = 7
  39. when 'day'
  40. stop_interval = ((params[:range_end] - params[:range_start]) / 86_400).to_i + 1
  41. when 'hour'
  42. stop_interval = 24
  43. when 'minute'
  44. stop_interval = 60
  45. end
  46. result = []
  47. (1..stop_interval).each do |_counter|
  48. match = false
  49. if !result_es
  50. raise "Invalid es result #{result_es.inspect}"
  51. end
  52. if !result_es['aggregations']
  53. raise "Invalid es result, no aggregations #{result_es.inspect}"
  54. end
  55. if !result_es['aggregations']['time_buckets']
  56. raise "Invalid es result, no time_buckets #{result_es.inspect}"
  57. end
  58. if !result_es['aggregations']['time_buckets']['buckets']
  59. raise "Invalid es result, no buckets #{result_es.inspect}"
  60. end
  61. result_es['aggregations']['time_buckets']['buckets'].each do |item|
  62. key_as_string = Time.zone.parse(item['key_as_string'])
  63. next if !item['doc_count']
  64. next if item['doc_count'].zero?
  65. # only compare date - in certain cases elasticsearch timezone offset will not match
  66. replace = ':\d\dZ$'
  67. case params[:interval]
  68. when 'month'
  69. replace = '\d\dT\d\d:\d\d:\d\dZ$'
  70. when 'day', 'week'
  71. replace = '\d\d:\d\d:\d\dZ$'
  72. end
  73. next if key_as_string.iso8601.sub(%r{#{replace}}, '') != params[:range_start].iso8601.sub(%r{#{replace}}, '')
  74. next if match
  75. match = true
  76. result.push item['doc_count']
  77. case params[:interval]
  78. when 'month'
  79. params[:range_start] = params[:range_start].next_month
  80. when 'week', 'day'
  81. params[:range_start] = params[:range_start].next_day
  82. when 'hour'
  83. params[:range_start] = params[:range_start] + 1.hour
  84. when 'minute'
  85. params[:range_start] = params[:range_start] + 1.minute
  86. end
  87. end
  88. next if match
  89. result.push 0
  90. case params[:interval]
  91. when 'month'
  92. params[:range_start] = params[:range_start].next_month
  93. when 'week'
  94. params[:range_start] = params[:range_start].next_day
  95. when 'day'
  96. params[:range_start] = params[:range_start] + 1.day
  97. when 'hour'
  98. params[:range_start] = params[:range_start] + 1.hour
  99. when 'minute'
  100. params[:range_start] = params[:range_start] + 1.minute
  101. end
  102. end
  103. result
  104. end
  105. =begin
  106. result = Report::TicketGenericTime.items(
  107. range_start: Time.zone.parse('2015-01-01T00:00:00Z'),
  108. range_end: Time.zone.parse('2015-12-31T23:59:59Z'),
  109. selector: selector, # ticket selector to get only a collection of tickets
  110. params: { field: 'created_at' },
  111. )
  112. returns
  113. {
  114. count: 123,
  115. ticket_ids: [4,5,1,5,0,51,5,56,7,4],
  116. assets: assets,
  117. }
  118. =end
  119. def self.items(params)
  120. aggs_interval = {
  121. from: params[:range_start].iso8601,
  122. to: params[:range_end].iso8601,
  123. field: params[:params][:field],
  124. }
  125. limit = 6000
  126. if params[:sheet].blank?
  127. limit = 100
  128. end
  129. selector = params[:selector].clone
  130. if params[:params] && params[:params][:selector]
  131. selector = selector.merge(params[:params][:selector])
  132. end
  133. selector.merge!(without_merged_tickets_selector) # do not show merged tickets in reports
  134. result = SearchIndexBackend.selectors('Ticket', selector, { current_user: params[:current_user], limit: limit }, aggs_interval)
  135. result[:ticket_ids] = result.delete(:object_ids)
  136. return result if params[:sheet].present?
  137. assets = {}
  138. result[:ticket_ids].each do |ticket_id|
  139. suppress(ActiveRecord::RecordNotFound) do
  140. ticket_full = Ticket.find(ticket_id)
  141. assets = ticket_full.assets(assets)
  142. end
  143. end
  144. result[:assets] = assets
  145. result
  146. end
  147. end