time_accountings_controller.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. data_type: 'datetime',
  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_period = Time.zone.parse("#{year}-#{month}-01")
  130. end_period = start_period.end_of_month
  131. time_unit = Ticket::TimeAccounting
  132. .where(created_at: (start_period..end_period))
  133. .pluck(:ticket_id, :time_unit, :created_by_id)
  134. .each_with_object({}) do |record, memo|
  135. if !memo[record[0]]
  136. memo[record[0]] = {
  137. time_unit: 0,
  138. agent_id: record[2],
  139. }
  140. end
  141. memo[record[0]][:time_unit] += record[1]
  142. end
  143. if !params[:download]
  144. customers = {}
  145. organizations = {}
  146. agents = {}
  147. results = []
  148. time_unit.each do |ticket_id, local_time_unit|
  149. ticket = Ticket.lookup(id: ticket_id)
  150. next if !ticket
  151. customers[ticket.customer_id] ||= User.lookup(id: ticket.customer_id).fullname
  152. organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
  153. agents[local_time_unit[:agent_id]] ||= User.lookup(id: local_time_unit[:agent_id]).fullname
  154. result = {
  155. ticket: ticket.attributes,
  156. time_unit: local_time_unit[:time_unit],
  157. customer: customers[ticket.customer_id] || '-',
  158. organization: organizations[ticket.organization_id] || '-',
  159. agent: agents[local_time_unit[:agent_id]],
  160. }
  161. results.push result
  162. end
  163. results = results.last(params[:limit].to_i) if params[:limit]
  164. render json: results
  165. return
  166. end
  167. ticket_ids = []
  168. additional_attributes = []
  169. additional_attributes_header = [{ display: __('Time Units'), name: 'time_unit_for_range', width: 10, data_type: 'float' }]
  170. time_unit.each do |ticket_id, local_time_unit|
  171. ticket_ids.push ticket_id
  172. additional_attribute = {
  173. time_unit_for_range: local_time_unit[:time_unit],
  174. }
  175. additional_attributes.push additional_attribute
  176. end
  177. excel = ExcelSheet::Ticket.new(
  178. title: "Tickets: #{year}-#{month}",
  179. ticket_ids: ticket_ids,
  180. additional_attributes: additional_attributes,
  181. additional_attributes_header: additional_attributes_header,
  182. timezone: params[:timezone],
  183. locale: current_user.locale,
  184. )
  185. send_data(
  186. excel.content,
  187. filename: "by_ticket-#{year}-#{month}.xlsx",
  188. type: ExcelSheet::CONTENT_TYPE,
  189. disposition: 'attachment'
  190. )
  191. end
  192. def by_customer
  193. year = params[:year] || Time.zone.now.year
  194. month = params[:month] || Time.zone.now.month
  195. start_period = Time.zone.parse("#{year}-#{month}-01")
  196. end_period = start_period.end_of_month
  197. results = Ticket::TimeAccounting
  198. .where(created_at: (start_period..end_period))
  199. .pluck(:ticket_id, :time_unit, :created_by_id)
  200. .each_with_object({}) do |record, memo|
  201. memo[record[0]] ||= {
  202. time_unit: 0,
  203. agent_id: record[2],
  204. }
  205. memo[record[0]][:time_unit] += record[1]
  206. end
  207. .each_with_object({}) do |(ticket_id, local_time_unit), memo|
  208. ticket = Ticket.lookup(id: ticket_id)
  209. next if !ticket
  210. memo[ticket.customer_id] ||= {}
  211. memo[ticket.customer_id][ticket.organization_id] ||= {
  212. customer: User.lookup(id: ticket.customer_id).attributes,
  213. organization: Organization.lookup(id: ticket.organization_id)&.attributes,
  214. time_unit: 0,
  215. }
  216. memo[ticket.customer_id][ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
  217. end
  218. .values
  219. .map(&:values)
  220. .flatten
  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 = results.map do |row|
  238. customer_name = User.find(row[:customer]['id']).fullname
  239. organization_name = ''
  240. if row[:organization].present?
  241. organization_name = row[:organization]['name']
  242. end
  243. [customer_name, organization_name, row[:time_unit]]
  244. end
  245. excel = ExcelSheet.new(
  246. title: "By Customer #{year}-#{month}",
  247. header: header,
  248. records: records,
  249. timezone: params[:timezone],
  250. locale: current_user.locale,
  251. )
  252. send_data(
  253. excel.content,
  254. filename: "by_customer-#{year}-#{month}.xlsx",
  255. type: ExcelSheet::CONTENT_TYPE,
  256. disposition: 'attachment'
  257. )
  258. return
  259. end
  260. results = results.last(params[:limit].to_i) if params[:limit]
  261. render json: results
  262. end
  263. def by_organization
  264. year = params[:year] || Time.zone.now.year
  265. month = params[:month] || Time.zone.now.month
  266. start_period = Time.zone.parse("#{year}-#{month}-01")
  267. end_period = start_period.end_of_month
  268. results = Ticket::TimeAccounting
  269. .where(created_at: (start_period..end_period))
  270. .pluck(:ticket_id, :time_unit, :created_by_id)
  271. .each_with_object({}) do |record, memo|
  272. memo[record[0]] ||= {
  273. time_unit: 0,
  274. agent_id: record[2],
  275. }
  276. memo[record[0]][:time_unit] += record[1]
  277. end
  278. .each_with_object({}) do |(ticket_id, local_time_unit), memo|
  279. ticket = Ticket.lookup(id: ticket_id)
  280. next if !ticket
  281. next if !ticket.organization_id
  282. memo[ticket.organization_id] ||= {
  283. organization: Organization.lookup(id: ticket.organization_id).attributes,
  284. time_unit: 0,
  285. }
  286. memo[ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
  287. end
  288. .values
  289. if params[:download]
  290. header = [
  291. {
  292. name: __('Organization'),
  293. width: 40,
  294. },
  295. {
  296. name: __('Time Units'),
  297. width: 20,
  298. data_type: 'float',
  299. }
  300. ]
  301. records = results.map do |row|
  302. organization_name = ''
  303. if row[:organization].present?
  304. organization_name = row[:organization]['name']
  305. end
  306. [organization_name, row[:time_unit]]
  307. end
  308. excel = ExcelSheet.new(
  309. title: "By Organization #{year}-#{month}",
  310. header: header,
  311. records: records,
  312. timezone: params[:timezone],
  313. locale: current_user.locale,
  314. )
  315. send_data(
  316. excel.content,
  317. filename: "by_organization-#{year}-#{month}.xlsx",
  318. type: ExcelSheet::CONTENT_TYPE,
  319. disposition: 'attachment'
  320. )
  321. return
  322. end
  323. results = results.last(params[:limit].to_i) if params[:limit]
  324. render json: results
  325. end
  326. private
  327. def ticket_time_accounting_scope
  328. @ticket_time_accounting_scope ||= begin
  329. if params[:ticket_id]
  330. Ticket::TimeAccounting.where(ticket_id: params[:ticket_id])
  331. else
  332. Ticket::TimeAccounting
  333. end
  334. end
  335. end
  336. end