Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e59df461f8 | ||
|
|
077dcdd659 | ||
|
|
49acab85f5 |
@@ -0,0 +1,81 @@
|
|||||||
|
class V2::Reports::OutgoingMessagesCountBuilder
|
||||||
|
include DateRangeHelper
|
||||||
|
attr_reader :account, :params
|
||||||
|
|
||||||
|
def initialize(account, params)
|
||||||
|
@account = account
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def build
|
||||||
|
send("build_by_#{params[:group_by]}")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def base_messages
|
||||||
|
scope = account.messages.outgoing.unscope(:order).where(created_at: range)
|
||||||
|
scope = scope.where.not(sender_type: ['AgentBot', 'Captain::Assistant']) if params[:group_by].to_s == 'agent'
|
||||||
|
scope
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_by_agent
|
||||||
|
counts = base_messages
|
||||||
|
.joins('INNER JOIN conversations ON messages.conversation_id = conversations.id')
|
||||||
|
.where.not(conversations: { assignee_id: nil })
|
||||||
|
.group('conversations.assignee_id')
|
||||||
|
.count
|
||||||
|
|
||||||
|
user_names = account.users.where(id: counts.keys).index_by(&:id)
|
||||||
|
|
||||||
|
counts.map do |user_id, count|
|
||||||
|
user = user_names[user_id]
|
||||||
|
{ id: user_id, name: user&.name, outgoing_messages_count: count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_by_team
|
||||||
|
counts = base_messages
|
||||||
|
.joins('INNER JOIN conversations ON messages.conversation_id = conversations.id')
|
||||||
|
.where.not(conversations: { team_id: nil })
|
||||||
|
.group('conversations.team_id')
|
||||||
|
.count
|
||||||
|
|
||||||
|
team_names = account.teams.where(id: counts.keys).index_by(&:id)
|
||||||
|
|
||||||
|
counts.map do |team_id, count|
|
||||||
|
team = team_names[team_id]
|
||||||
|
{ id: team_id, name: team&.name, outgoing_messages_count: count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_by_inbox
|
||||||
|
counts = base_messages
|
||||||
|
.group(:inbox_id)
|
||||||
|
.count
|
||||||
|
|
||||||
|
inbox_names = account.inboxes.where(id: counts.keys).index_by(&:id)
|
||||||
|
|
||||||
|
counts.map do |inbox_id, count|
|
||||||
|
inbox = inbox_names[inbox_id]
|
||||||
|
{ id: inbox_id, name: inbox&.name, outgoing_messages_count: count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def build_by_label
|
||||||
|
counts = base_messages
|
||||||
|
.joins('INNER JOIN conversations ON messages.conversation_id = conversations.id')
|
||||||
|
.joins("INNER JOIN taggings ON taggings.taggable_id = conversations.id
|
||||||
|
AND taggings.taggable_type = 'Conversation' AND taggings.context = 'labels'")
|
||||||
|
.joins('INNER JOIN tags ON tags.id = taggings.tag_id')
|
||||||
|
.group('tags.name')
|
||||||
|
.count
|
||||||
|
|
||||||
|
label_ids = account.labels.where(title: counts.keys).index_by(&:title)
|
||||||
|
|
||||||
|
counts.map do |label_name, count|
|
||||||
|
label = label_ids[label_name]
|
||||||
|
{ id: label&.id, name: label_name, outgoing_messages_count: count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -62,6 +62,11 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
|||||||
render json: bot_metrics
|
render json: bot_metrics
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def outgoing_messages_count
|
||||||
|
builder = V2::Reports::OutgoingMessagesCountBuilder.new(Current.account, outgoing_messages_count_params)
|
||||||
|
render json: builder.build
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def generate_csv(filename, template)
|
def generate_csv(filename, template)
|
||||||
@@ -139,4 +144,12 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController
|
|||||||
def conversation_metrics
|
def conversation_metrics
|
||||||
V2::ReportBuilder.new(Current.account, conversation_params).conversation_metrics
|
V2::ReportBuilder.new(Current.account, conversation_params).conversation_metrics
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def outgoing_messages_count_params
|
||||||
|
{
|
||||||
|
group_by: params[:group_by],
|
||||||
|
since: params[:since],
|
||||||
|
until: params[:until]
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ Rails.application.routes.draw do
|
|||||||
get :conversations_summary
|
get :conversations_summary
|
||||||
get :conversation_traffic
|
get :conversation_traffic
|
||||||
get :bot_metrics
|
get :bot_metrics
|
||||||
|
get :outgoing_messages_count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
resource :year_in_review, only: [:show]
|
resource :year_in_review, only: [:show]
|
||||||
|
|||||||
@@ -196,4 +196,123 @@ RSpec.describe Api::V2::Accounts::ReportsController, type: :request do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'GET /api/v2/accounts/{account.id}/reports/outgoing_messages_count' do
|
||||||
|
let(:since_epoch) { 1.week.ago.to_i.to_s }
|
||||||
|
let(:until_epoch) { 1.day.from_now.to_i.to_s }
|
||||||
|
|
||||||
|
context 'when unauthenticated' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'agent', since: since_epoch, until: until_epoch }
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when authenticated as agent' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'agent', since: since_epoch, until: until_epoch },
|
||||||
|
headers: agent.create_new_auth_token, as: :json
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when authenticated as admin' do
|
||||||
|
let(:agent2) { create(:user, account: account, role: :agent) }
|
||||||
|
let(:team) { create(:team, account: account) }
|
||||||
|
let(:inbox2) { create(:inbox, account: account) }
|
||||||
|
|
||||||
|
# Separate conversations for agent and team grouping because
|
||||||
|
# model callbacks clear assignee_id when team is set.
|
||||||
|
before do
|
||||||
|
conv_agent = create(:conversation, account: account, inbox: inbox, assignee: agent)
|
||||||
|
conv_agent2 = create(:conversation, account: account, inbox: inbox2, assignee: agent2)
|
||||||
|
conv_team = create(:conversation, account: account, inbox: inbox, team: team)
|
||||||
|
|
||||||
|
create_list(:message, 3, account: account, conversation: conv_agent, inbox: inbox, message_type: :outgoing)
|
||||||
|
create_list(:message, 2, account: account, conversation: conv_agent2, inbox: inbox2, message_type: :outgoing)
|
||||||
|
create_list(:message, 4, account: account, conversation: conv_team, inbox: inbox, message_type: :outgoing)
|
||||||
|
# incoming message should not be counted
|
||||||
|
create(:message, account: account, conversation: conv_agent, inbox: inbox, message_type: :incoming)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns outgoing message counts grouped by agent' do
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'agent', since: since_epoch, until: until_epoch },
|
||||||
|
headers: admin.create_new_auth_token, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = response.parsed_body
|
||||||
|
expect(data).to be_an(Array)
|
||||||
|
|
||||||
|
agent_entry = data.find { |e| e['id'] == agent.id }
|
||||||
|
agent2_entry = data.find { |e| e['id'] == agent2.id }
|
||||||
|
expect(agent_entry['outgoing_messages_count']).to eq(3)
|
||||||
|
expect(agent2_entry['outgoing_messages_count']).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns outgoing message counts grouped by team' do
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'team', since: since_epoch, until: until_epoch },
|
||||||
|
headers: admin.create_new_auth_token, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = response.parsed_body
|
||||||
|
expect(data).to be_an(Array)
|
||||||
|
expect(data.length).to eq(1)
|
||||||
|
expect(data.first['id']).to eq(team.id)
|
||||||
|
expect(data.first['outgoing_messages_count']).to eq(4)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns outgoing message counts grouped by inbox' do
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'inbox', since: since_epoch, until: until_epoch },
|
||||||
|
headers: admin.create_new_auth_token, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = response.parsed_body
|
||||||
|
expect(data).to be_an(Array)
|
||||||
|
|
||||||
|
inbox_entry = data.find { |e| e['id'] == inbox.id }
|
||||||
|
inbox2_entry = data.find { |e| e['id'] == inbox2.id }
|
||||||
|
expect(inbox_entry['outgoing_messages_count']).to eq(7)
|
||||||
|
expect(inbox2_entry['outgoing_messages_count']).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns outgoing message counts grouped by label' do
|
||||||
|
label = create(:label, account: account, title: 'support')
|
||||||
|
conversation = account.conversations.first
|
||||||
|
conversation.label_list.add('support')
|
||||||
|
conversation.save!
|
||||||
|
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'label', since: since_epoch, until: until_epoch },
|
||||||
|
headers: admin.create_new_auth_token, as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
data = response.parsed_body
|
||||||
|
expect(data).to be_an(Array)
|
||||||
|
expect(data.length).to eq(1)
|
||||||
|
expect(data.first['id']).to eq(label.id)
|
||||||
|
expect(data.first['name']).to eq('support')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'excludes bot messages when grouped by agent' do
|
||||||
|
bot = create(:agent_bot)
|
||||||
|
bot_conversation = create(:conversation, account: account, inbox: inbox, assignee: agent)
|
||||||
|
create(:message, account: account, conversation: bot_conversation, inbox: inbox,
|
||||||
|
message_type: :outgoing, sender: bot)
|
||||||
|
|
||||||
|
get "/api/v2/accounts/#{account.id}/reports/outgoing_messages_count",
|
||||||
|
params: { group_by: 'agent', since: since_epoch, until: until_epoch },
|
||||||
|
headers: admin.create_new_auth_token, as: :json
|
||||||
|
|
||||||
|
data = response.parsed_body
|
||||||
|
agent_entry = data.find { |e| e['id'] == agent.id }
|
||||||
|
# 3 from before block; bot message excluded
|
||||||
|
expect(agent_entry['outgoing_messages_count']).to eq(3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user