time_accountings_controller.rb 11 KB

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