diff --git a/app/builders/v2/new_report_builder.rb b/app/builders/v2/new_report_builder.rb new file mode 100644 index 000000000..fc04010f3 --- /dev/null +++ b/app/builders/v2/new_report_builder.rb @@ -0,0 +1,32 @@ +class V2::NewReportBuilder + include DateRangeHelper + + pattr_initialize :account, :params + + AVG_METRICS = %w[avg_first_response_time avg_resolution_time reply_time].freeze + COUNT_METRICS = %w[conversations_count incoming_messages_count outgoing_messages_count resolutions_count bot_resolutions_count + bot_handoffs_count].freeze + + DEFAULT_GROUP_BY = 'day'.freeze + AGENT_RESULTS_PER_PAGE = 25 + + def build + builder_class = case params[:metric] + when *AVG_METRICS + V2::Reports::Timeseries::AverageReportBuilder + when *COUNT_METRICS + V2::Reports::Timeseries::MetricCountReportBuilder + else + log_invalid_metric + return {} + end + + builder_class.new(account, params).build + end + + private + + def log_invalid_metric + Rails.logger.error "ReportBuilder: Invalid metric - #{params[:metric]}" + end +end diff --git a/app/builders/v2/reports/timeseries/average_report_builder.rb b/app/builders/v2/reports/timeseries/average_report_builder.rb new file mode 100644 index 000000000..01891f3bf --- /dev/null +++ b/app/builders/v2/reports/timeseries/average_report_builder.rb @@ -0,0 +1,40 @@ +class V2::Reports::Timeseries::AverageReportBuilder < V2::Reports::Timeseries::BaseTimeseriesBuilder + def build + grouped_average_time = reporting_events.average(average_value_key) + grouped_event_count = reporting_events.count + grouped_average_time.each_with_object([]) do |element, arr| + event_date, average_time = element + arr << { + value: average_time, + timestamp: event_date.to_time.to_i, + count: grouped_event_count[event_date] + } + end + end + + private + + def event_name + metric_to_event_name = { + avg_first_response_time: :first_response, + avg_resolution_time: :conversation_resolved, + reply_time: :reply_time + } + metric_to_event_name[params[:metric].to_sym] + end + + def reporting_events + object_scope = scope.reporting_events.where(name: event_name) + @grouped_values = object_scope.group_by_period( + group_by, + :created_at, + default_value: 0, + permit: %w[day week month year hour], + time_zone: timezone + ) + end + + def average_value_key + @average_value_key ||= params[:business_hours].present? ? :value_in_business_hours : :value + end +end diff --git a/app/builders/v2/reports/timeseries/base_timeseries_builder.rb b/app/builders/v2/reports/timeseries/base_timeseries_builder.rb new file mode 100644 index 000000000..c2ee5676d --- /dev/null +++ b/app/builders/v2/reports/timeseries/base_timeseries_builder.rb @@ -0,0 +1,49 @@ +class V2::Reports::Timeseries::BaseTimeseriesBuilder + include DateRangeHelper + DEFAULT_GROUP_BY = 'day'.freeze + + pattr_initialize :account, :params + + def scope + case params[:type] + when :account + account + when :inbox + inbox + when :agent + user + when :label + label + when :team + team + end + end + + def inbox + @inbox ||= account.inboxes.find(params[:id]) + end + + def user + @user ||= account.users.find(params[:id]) + end + + def label + @label ||= account.labels.find(params[:id]) + end + + def team + @team ||= account.teams.find(params[:id]) + end + + def group_by + @group_by ||= params[:group_by] || DEFAULT_GROUP_BY + end + + def timezone + @timezone ||= ActiveSupport::TimeZone[timezone_offset]&.name + end + + def timezone_offset + @timezone_offset ||= params.fetch(:timezone_offset, 0).to_f + end +end diff --git a/app/builders/v2/reports/timeseries/metric_count_report_builder.rb b/app/builders/v2/reports/timeseries/metric_count_report_builder.rb new file mode 100644 index 000000000..fbd807312 --- /dev/null +++ b/app/builders/v2/reports/timeseries/metric_count_report_builder.rb @@ -0,0 +1,61 @@ +class V2::Reports::Timeseries::MetricCountReportBuilder < V2::Reports::Timeseries::BaseTimeseriesBuilder + def build + grouped_count.each_with_object([]) do |element, arr| + event_date, event_count = element + arr << { value: event_count, timestamp: event_date.to_time.to_i } + end + end + + private + + def metric + @metric ||= params[:metric] + end + + def object_scope + send("scope_for_#{metric}") + end + + def scope_for_conversations_count + scope.conversations.where(account_id: account.id, created_at: range) + end + + def scope_for_incoming_messages_count + scope.messages.where(account_id: account.id, created_at: range).incoming.unscope(:order) + end + + def scope_for_outgoing_messages_count + scope.messages.where(account_id: account.id, created_at: range).outgoing.unscope(:order) + end + + def scope_for_resolutions_count + scope.reporting_events.joins(:conversation).select(:conversation_id).where( + name: :conversation_resolved, + conversations: { status: :resolved }, created_at: range + ).distinct + end + + def scope_for_bot_resolutions_count + scope.reporting_events.joins(:conversation).select(:conversation_id).where( + name: :conversation_bot_resolved, + conversations: { status: :resolved }, created_at: range + ).distinct + end + + def scope_for_bot_handoffs_count + scope.reporting_events.joins(:conversation).select(:conversation_id).where( + name: :conversation_bot_handoff, + created_at: range + ).distinct + end + + def grouped_count + @grouped_values = object_scope.group_by_period( + group_by, + :created_at, + default_value: 0, + permit: %w[day week month year hour], + time_zone: timezone + ).count + end +end diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb index 38be4cdbf..ff85e8616 100644 --- a/app/controllers/api/v2/accounts/reports_controller.rb +++ b/app/controllers/api/v2/accounts/reports_controller.rb @@ -5,7 +5,7 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController before_action :check_authorization def index - builder = V2::ReportBuilder.new(Current.account, report_params) + builder = V2::NewReportBuilder.new(Current.account, report_params) data = builder.build render json: data end