mirror of
https://github.com/zammad/zammad
synced 2026-05-24 09:48:36 +00:00
376 lines
11 KiB
Ruby
376 lines
11 KiB
Ruby
# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
|
|
|
|
class TimeAccountingsController < ApplicationController
|
|
prepend_before_action :authenticate_and_authorize!
|
|
|
|
def index
|
|
model_index_render(ticket_time_accounting_scope, params)
|
|
end
|
|
|
|
def show
|
|
model_show_render(ticket_time_accounting_scope, params)
|
|
end
|
|
|
|
def create
|
|
model_create_render(ticket_time_accounting_scope, params)
|
|
end
|
|
|
|
def update
|
|
model_update_render(ticket_time_accounting_scope, params)
|
|
end
|
|
|
|
def destroy
|
|
model_references_check(Ticket::TimeAccounting, params)
|
|
model_destroy_render(ticket_time_accounting_scope, params)
|
|
end
|
|
|
|
def by_activity
|
|
records = Ticket::TimeAccounting
|
|
.where(created_at: reporting_period)
|
|
.pluck(:ticket_id, :ticket_article_id, :time_unit, :type_id, :created_by_id, :created_at)
|
|
|
|
customers = {}
|
|
organizations = {}
|
|
types = {}
|
|
agents = {}
|
|
results = []
|
|
records.each do |record|
|
|
ticket = Ticket.lookup(id: record[0])
|
|
next if !ticket
|
|
|
|
customers[ticket.customer_id] ||= User.lookup(id: ticket.customer_id).fullname
|
|
organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
|
|
types[record[3]] ||= Ticket::TimeAccounting::Type.lookup(id: record[3])&.name
|
|
agents[record[4]] ||= User.lookup(id: record[4])
|
|
|
|
result = if params[:download]
|
|
[
|
|
ticket.number,
|
|
ticket.title,
|
|
customers[ticket.customer_id] || '-',
|
|
organizations[ticket.organization_id] || '-',
|
|
agents[record[4]].fullname,
|
|
agents[record[4]].login,
|
|
record[2],
|
|
*([types[record[3]] || '-'] if Setting.get('time_accounting_types')),
|
|
record[5]
|
|
]
|
|
else
|
|
{
|
|
ticket: ticket.attributes,
|
|
time_unit: record[2],
|
|
type: (types[record[3]] || '-' if Setting.get('time_accounting_types')),
|
|
customer: customers[ticket.customer_id] || '-',
|
|
organization: organizations[ticket.organization_id] || '-',
|
|
agent: agents[record[4]].fullname,
|
|
created_at: record[5],
|
|
}.compact
|
|
end
|
|
|
|
results.push result
|
|
end
|
|
|
|
if !params[:download]
|
|
results = results.last(params[:limit].to_i) if params[:limit]
|
|
render json: results
|
|
return
|
|
end
|
|
|
|
header = [
|
|
{
|
|
name: __('Ticket#'),
|
|
width: 20,
|
|
},
|
|
{
|
|
name: __('Title'),
|
|
width: 20,
|
|
},
|
|
{
|
|
name: "#{__('Customer')} - #{__('Name')}",
|
|
width: 20,
|
|
},
|
|
{
|
|
name: __('Organization'),
|
|
width: 20,
|
|
},
|
|
{
|
|
name: "#{__('Agent')} - #{__('Name')}",
|
|
width: 20,
|
|
},
|
|
{
|
|
name: "#{__('Agent')} - #{__('Login')}",
|
|
width: 20,
|
|
},
|
|
{
|
|
name: __('Time Units'),
|
|
width: 10,
|
|
data_type: 'float'
|
|
},
|
|
*(if Setting.get('time_accounting_types')
|
|
[{
|
|
name: __('Activity Type'),
|
|
width: 20,
|
|
}]
|
|
end),
|
|
{
|
|
name: __('Created at'),
|
|
width: 20,
|
|
data_type: 'datetime',
|
|
},
|
|
]
|
|
|
|
excel = ExcelSheet.new(
|
|
title: "By Activity #{year}-#{month}",
|
|
header: header,
|
|
records: results,
|
|
timezone: params[:timezone],
|
|
locale: current_user.locale,
|
|
)
|
|
send_data(
|
|
excel.content,
|
|
filename: "by_activity-#{year}-#{month}.xlsx",
|
|
type: ExcelSheet::CONTENT_TYPE,
|
|
disposition: 'attachment'
|
|
)
|
|
end
|
|
|
|
def by_ticket
|
|
time_unit = Ticket::TimeAccounting
|
|
.where(created_at: reporting_period)
|
|
.pluck(:ticket_id, :time_unit, :created_by_id)
|
|
.each_with_object({}) do |record, memo|
|
|
if !memo[record[0]]
|
|
memo[record[0]] = {
|
|
time_unit: 0,
|
|
agent_id: record[2],
|
|
}
|
|
end
|
|
memo[record[0]][:time_unit] += record[1]
|
|
end
|
|
|
|
if !params[:download]
|
|
customers = {}
|
|
organizations = {}
|
|
agents = {}
|
|
results = []
|
|
time_unit.each do |ticket_id, local_time_unit|
|
|
ticket = Ticket.lookup(id: ticket_id)
|
|
next if !ticket
|
|
|
|
customers[ticket.customer_id] ||= User.lookup(id: ticket.customer_id).fullname
|
|
organizations[ticket.organization_id] ||= Organization.lookup(id: ticket.organization_id)&.name
|
|
agents[local_time_unit[:agent_id]] ||= User.lookup(id: local_time_unit[:agent_id]).fullname
|
|
|
|
result = {
|
|
ticket: ticket.attributes,
|
|
time_unit: local_time_unit[:time_unit],
|
|
customer: customers[ticket.customer_id] || '-',
|
|
organization: organizations[ticket.organization_id] || '-',
|
|
agent: agents[local_time_unit[:agent_id]],
|
|
}
|
|
results.push result
|
|
end
|
|
|
|
results = results.last(params[:limit].to_i) if params[:limit]
|
|
render json: results
|
|
return
|
|
end
|
|
|
|
ticket_ids = []
|
|
additional_attributes = []
|
|
additional_attributes_header = [{ display: __('Time Units'), name: 'time_unit_for_range', width: 10, data_type: 'float' }]
|
|
time_unit.each do |ticket_id, local_time_unit|
|
|
ticket_ids.push ticket_id
|
|
additional_attribute = {
|
|
time_unit_for_range: local_time_unit[:time_unit],
|
|
}
|
|
additional_attributes.push additional_attribute
|
|
end
|
|
|
|
excel = ExcelSheet::Ticket.new(
|
|
title: "Tickets: #{year}-#{month}",
|
|
ticket_ids: ticket_ids,
|
|
additional_attributes: additional_attributes,
|
|
additional_attributes_header: additional_attributes_header,
|
|
timezone: params[:timezone],
|
|
locale: current_user.locale,
|
|
)
|
|
|
|
send_data(
|
|
excel.content,
|
|
filename: "by_ticket-#{year}-#{month}.xlsx",
|
|
type: ExcelSheet::CONTENT_TYPE,
|
|
disposition: 'attachment'
|
|
)
|
|
end
|
|
|
|
def by_customer
|
|
results = Ticket::TimeAccounting
|
|
.where(created_at: reporting_period)
|
|
.pluck(:ticket_id, :time_unit, :created_by_id)
|
|
.each_with_object({}) do |record, memo|
|
|
memo[record[0]] ||= {
|
|
time_unit: 0,
|
|
agent_id: record[2],
|
|
}
|
|
memo[record[0]][:time_unit] += record[1]
|
|
end
|
|
.each_with_object({}) do |(ticket_id, local_time_unit), memo|
|
|
ticket = Ticket.lookup(id: ticket_id)
|
|
next if !ticket
|
|
|
|
memo[ticket.customer_id] ||= {}
|
|
memo[ticket.customer_id][ticket.organization_id] ||= {
|
|
customer: User.lookup(id: ticket.customer_id).attributes,
|
|
organization: Organization.lookup(id: ticket.organization_id)&.attributes,
|
|
time_unit: 0,
|
|
}
|
|
memo[ticket.customer_id][ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
|
|
end
|
|
.values
|
|
.map(&:values)
|
|
.flatten
|
|
|
|
if params[:download]
|
|
header = [
|
|
{
|
|
name: __('Customer'),
|
|
width: 30,
|
|
},
|
|
{
|
|
name: __('Organization'),
|
|
width: 30,
|
|
},
|
|
{
|
|
name: __('Time Units'),
|
|
width: 10,
|
|
data_type: 'float'
|
|
}
|
|
]
|
|
records = results.map do |row|
|
|
customer_name = User.find(row[:customer]['id']).fullname
|
|
organization_name = ''
|
|
if row[:organization].present?
|
|
organization_name = row[:organization]['name']
|
|
end
|
|
[customer_name, organization_name, row[:time_unit]]
|
|
end
|
|
|
|
excel = ExcelSheet.new(
|
|
title: "By Customer #{year}-#{month}",
|
|
header: header,
|
|
records: records,
|
|
timezone: params[:timezone],
|
|
locale: current_user.locale,
|
|
)
|
|
send_data(
|
|
excel.content,
|
|
filename: "by_customer-#{year}-#{month}.xlsx",
|
|
type: ExcelSheet::CONTENT_TYPE,
|
|
disposition: 'attachment'
|
|
)
|
|
return
|
|
end
|
|
|
|
results = results.last(params[:limit].to_i) if params[:limit]
|
|
render json: results
|
|
end
|
|
|
|
def by_organization
|
|
results = Ticket::TimeAccounting
|
|
.where(created_at: reporting_period)
|
|
.pluck(:ticket_id, :time_unit, :created_by_id)
|
|
.each_with_object({}) do |record, memo|
|
|
memo[record[0]] ||= {
|
|
time_unit: 0,
|
|
agent_id: record[2],
|
|
}
|
|
memo[record[0]][:time_unit] += record[1]
|
|
end
|
|
.each_with_object({}) do |(ticket_id, local_time_unit), memo|
|
|
ticket = Ticket.lookup(id: ticket_id)
|
|
next if !ticket
|
|
next if !ticket.organization_id
|
|
|
|
memo[ticket.organization_id] ||= {
|
|
organization: Organization.lookup(id: ticket.organization_id).attributes,
|
|
time_unit: 0,
|
|
}
|
|
memo[ticket.organization_id][:time_unit] += local_time_unit[:time_unit]
|
|
end
|
|
.values
|
|
|
|
if params[:download]
|
|
header = [
|
|
{
|
|
name: __('Organization'),
|
|
width: 40,
|
|
},
|
|
{
|
|
name: __('Time Units'),
|
|
width: 20,
|
|
data_type: 'float',
|
|
}
|
|
]
|
|
|
|
records = results.map do |row|
|
|
organization_name = ''
|
|
if row[:organization].present?
|
|
organization_name = row[:organization]['name']
|
|
end
|
|
[organization_name, row[:time_unit]]
|
|
end
|
|
|
|
excel = ExcelSheet.new(
|
|
title: "By Organization #{year}-#{month}",
|
|
header: header,
|
|
records: records,
|
|
timezone: params[:timezone],
|
|
locale: current_user.locale,
|
|
)
|
|
send_data(
|
|
excel.content,
|
|
filename: "by_organization-#{year}-#{month}.xlsx",
|
|
type: ExcelSheet::CONTENT_TYPE,
|
|
disposition: 'attachment'
|
|
)
|
|
return
|
|
end
|
|
|
|
results = results.last(params[:limit].to_i) if params[:limit]
|
|
render json: results
|
|
end
|
|
|
|
private
|
|
|
|
def ticket_time_accounting_scope
|
|
@ticket_time_accounting_scope ||= begin
|
|
if params[:ticket_id]
|
|
Ticket::TimeAccounting.where(ticket_id: params[:ticket_id])
|
|
else
|
|
Ticket::TimeAccounting
|
|
end
|
|
end
|
|
end
|
|
|
|
def year
|
|
@year ||= Time.use_zone(Setting.get('timezone_default')) do
|
|
params[:year] || Time.zone.now.year
|
|
end
|
|
end
|
|
|
|
def month
|
|
@month ||= Time.use_zone(Setting.get('timezone_default')) do
|
|
params[:month] || Time.zone.now.month
|
|
end
|
|
end
|
|
|
|
def reporting_period
|
|
@reporting_period ||= Time.use_zone(Setting.get('timezone_default')) do
|
|
start_period = Time.zone.parse("#{year}-#{month}-01")
|
|
end_period = start_period.end_of_month
|
|
|
|
(start_period..end_period)
|
|
end
|
|
end
|
|
end
|