time_accountings_controller.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class TimeAccountingsController < ApplicationController
  3. prepend_before_action :authenticate_and_authorize!
  4. def index
  5. model_index_render(ticket_time_accounting_scope, params)
  6. end
  7. def show
  8. model_show_render(ticket_time_accounting_scope, params)
  9. end
  10. def create
  11. model_create_render(ticket_time_accounting_scope, params)
  12. end
  13. def update
  14. model_update_render(ticket_time_accounting_scope, params)
  15. end
  16. def destroy
  17. model_references_check(Ticket::TimeAccounting, params)
  18. model_destroy_render(ticket_time_accounting_scope, params)
  19. end
  20. def by_activity
  21. year = params[:year] || Time.zone.now.year
  22. month = params[:month] || Time.zone.now.month
  23. start_periode = Time.zone.parse("#{year}-#{month}-01")
  24. end_periode = start_periode.end_of_month
  25. records = []
  26. Ticket::TimeAccounting.where('created_at >= ? AND created_at <= ?', start_periode, end_periode).pluck(:ticket_id, :ticket_article_id, :time_unit, :type_id, :created_by_id, :created_at).each do |record|
  27. records.push record
  28. end
  29. customers = {}
  30. organizations = {}
  31. types = {}
  32. agents = {}
  33. results = []
  34. records.each do |record|
  35. ticket = Ticket.lookup(id: record[0])
  36. next if !ticket
  37. customers[ticket.customer_id] ||= User.lookup(id: ticket.customer_id).fullname
  38. organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
  39. types[record[3]] ||= Ticket::TimeAccounting::Type.lookup(id: record[3])&.name
  40. agents[record[4]] ||= User.lookup(id: record[4])
  41. result = if params[:download]
  42. [
  43. ticket.number,
  44. ticket.title,
  45. customers[ticket.customer_id] || '-',
  46. organizations[ticket.organization_id] || '-',
  47. agents[record[4]].fullname,
  48. agents[record[4]].login,
  49. record[2],
  50. *([types[record[3]] || '-'] if Setting.get('time_accounting_types')),
  51. record[5]
  52. ]
  53. else
  54. {
  55. ticket: ticket.attributes,
  56. time_unit: record[2],
  57. type: (types[record[3]] || '-' if Setting.get('time_accounting_types')),
  58. customer: customers[ticket.customer_id] || '-',
  59. organization: organizations[ticket.organization_id] || '-',
  60. agent: agents[record[4]].fullname,
  61. created_at: record[5],
  62. }.compact
  63. end
  64. results.push result
  65. end
  66. if !params[:download]
  67. results = results.last(params[:limit].to_i) if params[:limit]
  68. render json: results
  69. return
  70. end
  71. header = [
  72. {
  73. name: __('Ticket#'),
  74. width: 20,
  75. },
  76. {
  77. name: __('Title'),
  78. width: 20,
  79. },
  80. {
  81. name: "#{__('Customer')} - #{__('Name')}",
  82. width: 20,
  83. },
  84. {
  85. name: __('Organization'),
  86. width: 20,
  87. },
  88. {
  89. name: "#{__('Agent')} - #{__('Name')}",
  90. width: 20,
  91. },
  92. {
  93. name: "#{__('Agent')} - #{__('Login')}",
  94. width: 20,
  95. },
  96. {
  97. name: __('Time Units'),
  98. width: 10,
  99. data_type: 'float'
  100. },
  101. *(if Setting.get('time_accounting_types')
  102. [{
  103. name: __('Activity Type'),
  104. width: 20,
  105. }]
  106. end),
  107. {
  108. name: __('Created at'),
  109. width: 20,
  110. },
  111. ]
  112. excel = ExcelSheet.new(
  113. title: "By Activity #{year}-#{month}",
  114. header: header,
  115. records: results,
  116. timezone: params[:timezone],
  117. locale: current_user.locale,
  118. )
  119. send_data(
  120. excel.content,
  121. filename: "by_activity-#{year}-#{month}.xlsx",
  122. type: ExcelSheet::CONTENT_TYPE,
  123. disposition: 'attachment'
  124. )
  125. end
  126. def by_ticket
  127. year = params[:year] || Time.zone.now.year
  128. month = params[:month] || Time.zone.now.month
  129. start_periode = Time.zone.parse("#{year}-#{month}-01")
  130. end_periode = start_periode.end_of_month
  131. time_unit = {}
  132. Ticket::TimeAccounting.where('created_at >= ? AND created_at <= ?', start_periode, end_periode).pluck(:ticket_id, :time_unit, :created_by_id).each do |record|
  133. if !time_unit[record[0]]
  134. time_unit[record[0]] = {
  135. time_unit: 0,
  136. agent_id: record[2],
  137. }
  138. end
  139. time_unit[record[0]][:time_unit] += record[1]
  140. end
  141. if !params[:download]
  142. customers = {}
  143. organizations = {}
  144. agents = {}
  145. results = []
  146. time_unit.each do |ticket_id, local_time_unit|
  147. ticket = Ticket.lookup(id: ticket_id)
  148. next if !ticket
  149. customers[ticket.customer_id] ||= User.lookup(id: ticket.customer_id).fullname
  150. organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
  151. agents[local_time_unit[:agent_id]] ||= User.lookup(id: local_time_unit[:agent_id]).fullname
  152. result = {
  153. ticket: ticket.attributes,
  154. time_unit: local_time_unit[:time_unit],
  155. customer: customers[ticket.customer_id] || '-',
  156. organization: organizations[ticket.organization_id] || '-',
  157. agent: agents[local_time_unit[:agent_id]],
  158. }
  159. results.push result
  160. end
  161. results = results.last(params[:limit].to_i) if params[:limit]
  162. render json: results
  163. return
  164. end
  165. ticket_ids = []
  166. additional_attributes = []
  167. additional_attributes_header = [{ display: __('Time Units'), name: 'time_unit_for_range', width: 10, data_type: 'float' }]
  168. time_unit.each do |ticket_id, local_time_unit|
  169. ticket_ids.push ticket_id
  170. additional_attribute = {
  171. time_unit_for_range: local_time_unit[:time_unit],
  172. }
  173. additional_attributes.push additional_attribute
  174. end
  175. excel = ExcelSheet::Ticket.new(
  176. title: "Tickets: #{year}-#{month}",
  177. ticket_ids: ticket_ids,
  178. additional_attributes: additional_attributes,
  179. additional_attributes_header: additional_attributes_header,
  180. timezone: params[:timezone],
  181. locale: current_user.locale,
  182. )
  183. send_data(
  184. excel.content,
  185. filename: "by_ticket-#{year}-#{month}.xlsx",
  186. type: ExcelSheet::CONTENT_TYPE,
  187. disposition: 'attachment'
  188. )
  189. end
  190. def by_customer
  191. year = params[:year] || Time.zone.now.year
  192. month = params[:month] || Time.zone.now.month
  193. start_periode = Time.zone.parse("#{year}-#{month}-01")
  194. end_periode = start_periode.end_of_month
  195. time_unit = {}
  196. Ticket::TimeAccounting.where('created_at >= ? AND created_at <= ?', start_periode, end_periode).pluck(:ticket_id, :time_unit, :created_by_id).each do |record|
  197. time_unit[record[0]] ||= {
  198. time_unit: 0,
  199. agent_id: record[2],
  200. }
  201. time_unit[record[0]][:time_unit] += record[1]
  202. end
  203. customers = {}
  204. time_unit.each do |ticket_id, local_time_unit|
  205. ticket = Ticket.lookup(id: ticket_id)
  206. next if !ticket
  207. customers[ticket.customer_id] ||= {}
  208. customers[ticket.customer_id][ticket.organization_id] ||= {
  209. customer: User.lookup(id: ticket.customer_id).attributes,
  210. organization: Organization.lookup(id: ticket.organization_id)&.attributes,
  211. time_unit: 0,
  212. }
  213. customers[ticket.customer_id][ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
  214. end
  215. results = []
  216. customers.each_value do |organizations|
  217. organizations.each_value do |content|
  218. results.push content
  219. end
  220. end
  221. if params[:download]
  222. header = [
  223. {
  224. name: __('Customer'),
  225. width: 30,
  226. },
  227. {
  228. name: __('Organization'),
  229. width: 30,
  230. },
  231. {
  232. name: __('Time Units'),
  233. width: 10,
  234. data_type: 'float'
  235. }
  236. ]
  237. records = []
  238. results.each do |row|
  239. customer_name = User.find(row[:customer]['id']).fullname
  240. organization_name = ''
  241. if row[:organization].present?
  242. organization_name = row[:organization]['name']
  243. end
  244. result_row = [customer_name, organization_name, row[:time_unit]]
  245. records.push result_row
  246. end
  247. excel = ExcelSheet.new(
  248. title: "By Customer #{year}-#{month}",
  249. header: header,
  250. records: records,
  251. timezone: params[:timezone],
  252. locale: current_user.locale,
  253. )
  254. send_data(
  255. excel.content,
  256. filename: "by_customer-#{year}-#{month}.xlsx",
  257. type: ExcelSheet::CONTENT_TYPE,
  258. disposition: 'attachment'
  259. )
  260. return
  261. end
  262. results = results.last(params[:limit].to_i) if params[:limit]
  263. render json: results
  264. end
  265. def by_organization
  266. year = params[:year] || Time.zone.now.year
  267. month = params[:month] || Time.zone.now.month
  268. start_periode = Time.zone.parse("#{year}-#{month}-01")
  269. end_periode = start_periode.end_of_month
  270. time_unit = {}
  271. Ticket::TimeAccounting.where('created_at >= ? AND created_at <= ?', start_periode, end_periode).pluck(:ticket_id, :time_unit, :created_by_id).each do |record|
  272. time_unit[record[0]] ||= {
  273. time_unit: 0,
  274. agent_id: record[2],
  275. }
  276. time_unit[record[0]][:time_unit] += record[1]
  277. end
  278. organizations = {}
  279. time_unit.each do |ticket_id, local_time_unit|
  280. ticket = Ticket.lookup(id: ticket_id)
  281. next if !ticket
  282. next if !ticket.organization_id
  283. organizations[ticket.organization_id] ||= {
  284. organization: Organization.lookup(id: ticket.organization_id).attributes,
  285. time_unit: 0,
  286. }
  287. organizations[ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
  288. end
  289. results = []
  290. organizations.each_value do |content|
  291. results.push content
  292. end
  293. if params[:download]
  294. header = [
  295. {
  296. name: __('Organization'),
  297. width: 40,
  298. },
  299. {
  300. name: __('Time Units'),
  301. width: 20,
  302. data_type: 'float',
  303. }
  304. ]
  305. records = []
  306. results.each do |row|
  307. organization_name = ''
  308. if row[:organization].present?
  309. organization_name = row[:organization]['name']
  310. end
  311. result_row = [organization_name, row[:time_unit]]
  312. records.push result_row
  313. end
  314. excel = ExcelSheet.new(
  315. title: "By Organization #{year}-#{month}",
  316. header: header,
  317. records: records,
  318. timezone: params[:timezone],
  319. locale: current_user.locale,
  320. )
  321. send_data(
  322. excel.content,
  323. filename: "by_organization-#{year}-#{month}.xlsx",
  324. type: ExcelSheet::CONTENT_TYPE,
  325. disposition: 'attachment'
  326. )
  327. return
  328. end
  329. results = results.last(params[:limit].to_i) if params[:limit]
  330. render json: results
  331. end
  332. private
  333. def ticket_time_accounting_scope
  334. @ticket_time_accounting_scope ||= begin
  335. if params[:ticket_id]
  336. Ticket::TimeAccounting.where(ticket_id: params[:ticket_id])
  337. else
  338. Ticket::TimeAccounting
  339. end
  340. end
  341. end
  342. end