base.rb 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Report::Base
  3. # :object
  4. # :type created|updated
  5. # :attribute
  6. # :value_from
  7. # :value_to
  8. # :start
  9. # :end
  10. # :selector
  11. def self.history_count(params)
  12. history_object = History::Object.lookup(name: params[:object])
  13. query, bind_params, tables = Ticket.selector2sql(params[:selector])
  14. # created
  15. if params[:type] == 'created'
  16. history_type = History::Type.lookup(name: 'created')
  17. return History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  18. .where(
  19. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ?', params[:start], params[:end], history_object.id, history_type.id
  20. )
  21. .where(query, *bind_params).joins(tables).count
  22. end
  23. # updated
  24. if params[:type] == 'updated'
  25. history_type = History::Type.lookup(name: 'updated')
  26. history_attribute = History::Attribute.lookup(name: params[:attribute])
  27. result = nil
  28. if !history_attribute || !history_type
  29. result = 0
  30. elsif params[:id_not_from] && params[:id_to]
  31. result = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  32. .where(query, *bind_params).joins(tables)
  33. .where(
  34. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_from NOT IN (?) AND histories.id_to IN (?)',
  35. params[:start],
  36. params[:end],
  37. history_object.id,
  38. history_type.id,
  39. history_attribute.id,
  40. params[:id_not_from],
  41. params[:id_to],
  42. ).count
  43. elsif params[:id_from] && params[:id_not_to]
  44. result = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  45. .where(query, *bind_params).joins(tables)
  46. .where(
  47. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_from IN (?) AND histories.id_to NOT IN (?)',
  48. params[:start],
  49. params[:end],
  50. history_object.id,
  51. history_type.id,
  52. history_attribute.id,
  53. params[:id_from],
  54. params[:id_not_to],
  55. ).count
  56. elsif params[:value_from] && params[:value_not_to]
  57. result = History.joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  58. .where(query, *bind_params).joins(tables)
  59. .where(
  60. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.value_from IN (?) AND histories.value_to NOT IN (?)',
  61. params[:start],
  62. params[:end],
  63. history_object.id,
  64. history_type.id,
  65. history_attribute.id,
  66. params[:value_from],
  67. params[:value_not_to],
  68. ).count
  69. elsif params[:value_to]
  70. result = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  71. .where(query, *bind_params).joins(tables)
  72. .where(
  73. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.value_to IN (?)',
  74. params[:start],
  75. params[:end],
  76. history_object.id,
  77. history_type.id,
  78. history_attribute.id,
  79. params[:value_to],
  80. ).count
  81. elsif params[:id_to]
  82. result = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  83. .where(query, *bind_params).joins(tables)
  84. .where(
  85. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_to IN (?)',
  86. params[:start],
  87. params[:end],
  88. history_object.id,
  89. history_type.id,
  90. history_attribute.id,
  91. params[:id_to],
  92. ).count
  93. end
  94. return result if !result.nil?
  95. raise "UNKOWN params (#{params.inspect})!"
  96. end
  97. raise "UNKOWN :type (#{params[:type]})!"
  98. end
  99. # :object
  100. # :type created|updated
  101. # :attribute
  102. # :value_from
  103. # :value_to
  104. # :start
  105. # :end
  106. # :condition
  107. def self.history(data)
  108. history_object = History::Object.lookup(name: data[:object])
  109. query, bind_params, tables = Ticket.selector2sql(data[:selector])
  110. count = 0
  111. ticket_ids = []
  112. # created
  113. if data[:type] == 'created'
  114. history_type = History::Type.lookup(name: 'created')
  115. histories = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  116. .where(
  117. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ?', data[:start], data[:end], history_object.id, history_type.id
  118. )
  119. .where(query, *bind_params).joins(tables)
  120. histories.each do |history|
  121. count += 1
  122. ticket_ids.push history.o_id
  123. end
  124. return {
  125. count: count,
  126. ticket_ids: ticket_ids,
  127. }
  128. end
  129. # updated
  130. if data[:type] == 'updated'
  131. history_type = History::Type.lookup(name: 'updated')
  132. history_attribute = History::Attribute.lookup(name: data[:attribute])
  133. if !history_attribute || !history_type
  134. count = 0
  135. else
  136. if data[:id_not_from] && data[:id_to]
  137. histories = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  138. .where(query, *bind_params).joins(tables)
  139. .where(
  140. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_from NOT IN (?) AND histories.id_to IN (?)',
  141. data[:start],
  142. data[:end],
  143. history_object.id,
  144. history_type.id,
  145. history_attribute.id,
  146. data[:id_not_from],
  147. data[:id_to],
  148. )
  149. elsif data[:id_from] && data[:id_not_to]
  150. histories = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  151. .where(query, *bind_params).joins(tables)
  152. .where(
  153. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_from IN (?) AND histories.id_to NOT IN (?)',
  154. data[:start],
  155. data[:end],
  156. history_object.id,
  157. history_type.id,
  158. history_attribute.id,
  159. data[:id_from],
  160. data[:id_not_to],
  161. )
  162. elsif data[:value_from] && data[:value_not_to]
  163. histories = History.joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  164. .where(query, *bind_params).joins(tables)
  165. .where(
  166. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.value_from IN (?) AND histories.value_to NOT IN (?)',
  167. data[:start],
  168. data[:end],
  169. history_object.id,
  170. history_type.id,
  171. history_attribute.id,
  172. data[:value_from],
  173. data[:value_not_to],
  174. )
  175. elsif data[:value_to]
  176. histories = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  177. .where(query, *bind_params).joins(tables)
  178. .where(
  179. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.value_to IN (?)',
  180. data[:start],
  181. data[:end],
  182. history_object.id,
  183. history_type.id,
  184. history_attribute.id,
  185. data[:value_to],
  186. )
  187. elsif data[:id_to]
  188. histories = History.select('histories.o_id').joins('INNER JOIN tickets ON tickets.id = histories.o_id')
  189. .where(query, *bind_params).joins(tables)
  190. .where(
  191. 'histories.created_at >= ? AND histories.created_at <= ? AND histories.history_object_id = ? AND histories.history_type_id = ? AND histories.history_attribute_id IN (?) AND histories.id_to IN (?)',
  192. data[:start],
  193. data[:end],
  194. history_object.id,
  195. history_type.id,
  196. history_attribute.id,
  197. data[:id_to],
  198. )
  199. end
  200. histories.each do |history|
  201. count += 1
  202. ticket_ids.push history.o_id
  203. end
  204. end
  205. return {
  206. count: count,
  207. ticket_ids: ticket_ids,
  208. }
  209. end
  210. raise "UNKOWN :type (#{data[:type]})!"
  211. end
  212. # :type
  213. # :start
  214. # :end
  215. # :condition
  216. def self.time_average(data)
  217. query, bind_params, tables = Ticket.selector2sql(data[:condition])
  218. ticket_list = Ticket.where('tickets.created_at >= ? AND tickets.created_at <= ?', data[:start], data[:end])
  219. .where(query, *bind_params).joins(tables)
  220. tickets = 0
  221. time_total = 0
  222. ticket_list.each do |ticket|
  223. timestamp = ticket[ data[:type].to_sym ]
  224. next if !timestamp
  225. # puts 'FR:' + first_response.to_s
  226. # puts 'CT:' + ticket.created_at.to_s
  227. diff = timestamp - ticket.created_at
  228. # puts 'DIFF:' + diff.to_s
  229. time_total += diff
  230. tickets += 1
  231. end
  232. if time_total.zero? || tickets.zero?
  233. tickets = -0.001
  234. else
  235. tickets = time_total / tickets / 60
  236. tickets = tickets.to_i
  237. end
  238. {
  239. count: tickets,
  240. }
  241. end
  242. # :type
  243. # :start
  244. # :end
  245. # :condition
  246. def self.time_min(data)
  247. query, bind_params, tables = Ticket.selector2sql(data[:condition])
  248. ticket_list = Ticket.where('tickets.created_at >= ? AND tickets.created_at <= ?', data[:start], data[:end])
  249. .where(query, *bind_params).joins(tables)
  250. time_min = 0
  251. ticket_ids = []
  252. ticket_list.each do |ticket|
  253. timestamp = ticket[ data[:type].to_sym ]
  254. next if !timestamp
  255. ticket_ids.push ticket.id
  256. # puts 'FR:' + first_response.to_s
  257. # puts 'CT:' + ticket.created_at.to_s
  258. diff = timestamp - ticket.created_at
  259. # puts 'DIFF:' + diff.to_s
  260. if !time_min
  261. time_min = diff
  262. end
  263. if diff < time_min
  264. time_min = diff
  265. end
  266. end
  267. tickets = if time_min.zero?
  268. -0.001
  269. else
  270. (time_min / 60).to_i
  271. end
  272. {
  273. count: tickets,
  274. ticket_ids: ticket_ids,
  275. }
  276. end
  277. # :type
  278. # :start
  279. # :end
  280. # :condition
  281. def self.time_max(data)
  282. query, bind_params, tables = Ticket.selector2sql(data[:condition])
  283. ticket_list = Ticket.where('tickets.created_at >= ? AND tickets.created_at <= ?', data[:start], data[:end])
  284. .where(query, *bind_params).joins(tables)
  285. time_max = 0
  286. ticket_ids = []
  287. ticket_list.each do |ticket|
  288. timestamp = ticket[ data[:type].to_sym ]
  289. next if !timestamp
  290. ticket_ids.push ticket.id
  291. # puts "#{data[:type].to_s} - #{timestamp} - #{ticket.inspect}"
  292. # puts 'FR:' + ticket.first_response.to_s
  293. # puts 'CT:' + ticket.created_at.to_s
  294. diff = timestamp - ticket.created_at
  295. # puts 'DIFF:' + diff.to_s
  296. if !time_max
  297. time_max = diff
  298. end
  299. if diff > time_max
  300. time_max = diff
  301. end
  302. end
  303. tickets = if time_max.zero?
  304. -0.001
  305. else
  306. (time_max / 60).to_i
  307. end
  308. {
  309. count: tickets,
  310. ticket_ids: ticket_ids,
  311. }
  312. end
  313. def self.ticket_condition(ticket_id, condition)
  314. ticket = Ticket.lookup(id: ticket_id)
  315. condition.each do |key, value|
  316. if ticket[key.to_sym] != value
  317. return false
  318. end
  319. end
  320. true
  321. end
  322. INTERVAL_LENGTH = {
  323. month: 12,
  324. week: 7,
  325. # day: 31, Day is counted bellow by given month/year
  326. hour: 24,
  327. minute: 60,
  328. }.with_indifferent_access
  329. def self.interval_length(params)
  330. interval = params[:interval]
  331. if interval == 'day'
  332. return Time.days_in_month params[:range_start].month, params[:range_start].year
  333. end
  334. INTERVAL_LENGTH[interval]
  335. end
  336. end