mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	feat: Consider business hours while generating the reports (#4330)
* feat: Consider business hours while generating the reports
This commit is contained in:
		
							
								
								
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -125,6 +125,9 @@ gem 'procore-sift' | ||||
| gem 'email_reply_trimmer' | ||||
| gem 'html2text' | ||||
|  | ||||
| # to calculate working hours | ||||
| gem 'working_hours' | ||||
|  | ||||
| group :production, :staging do | ||||
|   # we dont want request timing out in development while using byebug | ||||
|   gem 'rack-timeout' | ||||
|   | ||||
| @@ -636,6 +636,9 @@ GEM | ||||
|       websocket-extensions (>= 0.1.0) | ||||
|     websocket-extensions (0.1.5) | ||||
|     wisper (2.0.0) | ||||
|     working_hours (1.4.1) | ||||
|       activesupport (>= 3.2) | ||||
|       tzinfo | ||||
|     zeitwerk (2.5.4) | ||||
|  | ||||
| PLATFORMS | ||||
| @@ -746,6 +749,7 @@ DEPENDENCIES | ||||
|   webpacker (~> 5.x) | ||||
|   webpush | ||||
|   wisper (= 2.0.0) | ||||
|   working_hours | ||||
|  | ||||
| RUBY VERSION | ||||
|    ruby 3.0.2p107 | ||||
|   | ||||
| @@ -47,36 +47,36 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController | ||||
|     raise Pundit::NotAuthorizedError unless Current.account_user.administrator? | ||||
|   end | ||||
|  | ||||
|   def current_summary_params | ||||
|   def common_params | ||||
|     { | ||||
|       type: params[:type].to_sym, | ||||
|       id: params[:id], | ||||
|       since: range[:current][:since], | ||||
|       until: range[:current][:until], | ||||
|       group_by: params[:group_by] | ||||
|       group_by: params[:group_by], | ||||
|       business_hours: ActiveModel::Type::Boolean.new.cast(params[:business_hours]) | ||||
|     } | ||||
|   end | ||||
|  | ||||
|   def current_summary_params | ||||
|     common_params.merge({ | ||||
|                           since: range[:current][:since], | ||||
|                           until: range[:current][:until] | ||||
|                         }) | ||||
|   end | ||||
|  | ||||
|   def previous_summary_params | ||||
|     { | ||||
|       type: params[:type].to_sym, | ||||
|       id: params[:id], | ||||
|       since: range[:previous][:since], | ||||
|       until: range[:previous][:until], | ||||
|       group_by: params[:group_by] | ||||
|     } | ||||
|     common_params.merge({ | ||||
|                           since: range[:previous][:since], | ||||
|                           until: range[:previous][:until] | ||||
|                         }) | ||||
|   end | ||||
|  | ||||
|   def report_params | ||||
|     { | ||||
|       metric: params[:metric], | ||||
|       type: params[:type].to_sym, | ||||
|       since: params[:since], | ||||
|       until: params[:until], | ||||
|       id: params[:id], | ||||
|       group_by: params[:group_by], | ||||
|       timezone_offset: params[:timezone_offset] | ||||
|     } | ||||
|     common_params.merge({ | ||||
|                           metric: params[:metric], | ||||
|                           since: params[:since], | ||||
|                           until: params[:until], | ||||
|                           timezone_offset: params[:timezone_offset] | ||||
|                         }) | ||||
|   end | ||||
|  | ||||
|   def conversation_params | ||||
|   | ||||
| @@ -33,17 +33,23 @@ module ReportHelper | ||||
|   end | ||||
|  | ||||
|   def avg_first_response_time | ||||
|     (get_grouped_values scope.reporting_events.where(name: 'first_response')).average(:value) | ||||
|     grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'first_response')) | ||||
|     return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours] | ||||
|  | ||||
|     grouped_reporting_events.average(:value) | ||||
|   end | ||||
|  | ||||
|   def avg_resolution_time | ||||
|     (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved')).average(:value) | ||||
|     grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved')) | ||||
|     return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours] | ||||
|  | ||||
|     grouped_reporting_events.average(:value) | ||||
|   end | ||||
|  | ||||
|   def avg_resolution_time_summary | ||||
|     avg_rt = scope.reporting_events | ||||
|                   .where(name: 'conversation_resolved', created_at: range) | ||||
|                   .average(:value) | ||||
|     reporting_events = scope.reporting_events | ||||
|                             .where(name: 'conversation_resolved', created_at: range) | ||||
|     avg_rt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value) | ||||
|  | ||||
|     return 0 if avg_rt.blank? | ||||
|  | ||||
| @@ -51,9 +57,9 @@ module ReportHelper | ||||
|   end | ||||
|  | ||||
|   def avg_first_response_time_summary | ||||
|     avg_frt = scope.reporting_events | ||||
|                    .where(name: 'first_response', created_at: range) | ||||
|                    .average(:value) | ||||
|     reporting_events = scope.reporting_events | ||||
|                             .where(name: 'first_response', created_at: range) | ||||
|     avg_frt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value) | ||||
|  | ||||
|     return 0 if avg_frt.blank? | ||||
|  | ||||
|   | ||||
							
								
								
									
										50
									
								
								app/helpers/reporting_event_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								app/helpers/reporting_event_helper.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| module ReportingEventHelper | ||||
|   def business_hours(inbox, from, to) | ||||
|     return 0 unless inbox.working_hours_enabled? | ||||
|  | ||||
|     inbox_working_hours = configure_working_hours(inbox.working_hours) | ||||
|     return 0 if inbox_working_hours.blank? | ||||
|  | ||||
|     # Configure working hours | ||||
|     WorkingHours::Config.working_hours = inbox_working_hours | ||||
|  | ||||
|     # Configure timezone | ||||
|     WorkingHours::Config.time_zone = inbox.timezone | ||||
|  | ||||
|     # Use inbox timezone to change from & to values. | ||||
|     from_in_inbox_timezone = from.in_time_zone(inbox.timezone).to_time | ||||
|     to_in_inbox_timezone = to.in_time_zone(inbox.timezone).to_time | ||||
|     from_in_inbox_timezone.working_time_until(to_in_inbox_timezone) | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def configure_working_hours(working_hours) | ||||
|     working_hours.each_with_object({}) do |working_hour, object| | ||||
|       object[day(working_hour.day_of_week)] = working_hour_range(working_hour) unless working_hour.closed_all_day? | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def day(day_of_week) | ||||
|     week_days = { | ||||
|       0 => :sun, | ||||
|       1 => :mon, | ||||
|       2 => :tue, | ||||
|       3 => :wed, | ||||
|       4 => :thu, | ||||
|       5 => :fri, | ||||
|       6 => :sat | ||||
|     } | ||||
|     week_days[day_of_week] | ||||
|   end | ||||
|  | ||||
|   def working_hour_range(working_hour) | ||||
|     { format_time(working_hour.open_hour, working_hour.open_minutes) => format_time(working_hour.close_hour, working_hour.close_minutes) } | ||||
|   end | ||||
|  | ||||
|   def format_time(hour, minute) | ||||
|     hour = hour < 10 ? "0#{hour}" : hour | ||||
|     minute = minute < 10 ? "0#{minute}" : minute | ||||
|     "#{hour}:#{minute}" | ||||
|   end | ||||
| end | ||||
| @@ -8,7 +8,15 @@ class ReportsAPI extends ApiClient { | ||||
|     super('reports', { accountScoped: true, apiVersion: 'v2' }); | ||||
|   } | ||||
|  | ||||
|   getReports(metric, since, until, type = 'account', id, group_by) { | ||||
|   getReports( | ||||
|     metric, | ||||
|     since, | ||||
|     until, | ||||
|     type = 'account', | ||||
|     id, | ||||
|     group_by, | ||||
|     business_hours | ||||
|   ) { | ||||
|     return axios.get(`${this.url}`, { | ||||
|       params: { | ||||
|         metric, | ||||
| @@ -17,12 +25,13 @@ class ReportsAPI extends ApiClient { | ||||
|         type, | ||||
|         id, | ||||
|         group_by, | ||||
|         business_hours, | ||||
|         timezone_offset: getTimeOffset(), | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   getSummary(since, until, type = 'account', id, group_by) { | ||||
|   getSummary(since, until, type = 'account', id, group_by, business_hours) { | ||||
|     return axios.get(`${this.url}/summary`, { | ||||
|       params: { | ||||
|         since, | ||||
| @@ -30,6 +39,7 @@ class ReportsAPI extends ApiClient { | ||||
|         type, | ||||
|         id, | ||||
|         group_by, | ||||
|         business_hours, | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
|   | ||||
| @@ -78,5 +78,10 @@ | ||||
|       font-size: $font-size-default; | ||||
|       color: $color-gray; | ||||
|     } | ||||
|  | ||||
|     .business-hours { | ||||
|       margin: $space-normal; | ||||
|       text-align: center; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -25,3 +25,21 @@ | ||||
|   align-items: center; | ||||
|   display: flex; | ||||
| } | ||||
|  | ||||
| .business-hours { | ||||
|   align-items: center; | ||||
|   display: flex; | ||||
|   justify-content: end; | ||||
|   margin-bottom: var(--space-normal); | ||||
|   margin-left: auto; | ||||
|   padding-right: var(--space-normal); | ||||
| } | ||||
|  | ||||
| .business-hours-text { | ||||
|   font-size: var(--font-size-small); | ||||
| } | ||||
|  | ||||
| .switch { | ||||
|   margin-bottom: var(--space-zero); | ||||
|   margin-left: var(--space-small); | ||||
| } | ||||
|   | ||||
| @@ -78,7 +78,8 @@ | ||||
|       { "id": 2, "groupBy": "Week" }, | ||||
|       { "id": 3, "groupBy": "Month" }, | ||||
|       { "id": 4, "groupBy": "Year" } | ||||
|     ] | ||||
|     ], | ||||
|     "BUSINESS_HOURS": "Business Hours" | ||||
|   }, | ||||
|   "AGENT_REPORTS": { | ||||
|     "HEADER": "Agents Overview", | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
|       :filter-items-list="filterItemsList" | ||||
|       @date-range-change="onDateRangeChange" | ||||
|       @filter-change="onFilterChange" | ||||
|       @business-hours-toggle="onBusinessHoursToggle" | ||||
|     /> | ||||
|     <div class="row"> | ||||
|       <woot-report-stats-card | ||||
| @@ -79,6 +80,7 @@ export default { | ||||
|       groupBy: GROUP_BY_FILTER[1], | ||||
|       filterItemsList: this.$t('REPORT.GROUP_BY_DAY_OPTIONS'), | ||||
|       selectedGroupByFilter: {}, | ||||
|       businessHours: false, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -166,21 +168,23 @@ export default { | ||||
|   }, | ||||
|   methods: { | ||||
|     fetchAllData() { | ||||
|       const { from, to, groupBy } = this; | ||||
|       const { from, to, groupBy, businessHours } = this; | ||||
|       this.$store.dispatch('fetchAccountSummary', { | ||||
|         from, | ||||
|         to, | ||||
|         groupBy: groupBy.period, | ||||
|         businessHours, | ||||
|       }); | ||||
|       this.fetchChartData(); | ||||
|     }, | ||||
|     fetchChartData() { | ||||
|       const { from, to, groupBy } = this; | ||||
|       const { from, to, groupBy, businessHours } = this; | ||||
|       this.$store.dispatch('fetchAccountReport', { | ||||
|         metric: this.metrics[this.currentSelection].KEY, | ||||
|         from, | ||||
|         to, | ||||
|         groupBy: groupBy.period, | ||||
|         businessHours, | ||||
|       }); | ||||
|     }, | ||||
|     downloadAgentReports() { | ||||
| @@ -226,6 +230,10 @@ export default { | ||||
|           return this.$t('REPORT.GROUP_BY_DAY_OPTIONS'); | ||||
|       } | ||||
|     }, | ||||
|     onBusinessHoursToggle(value) { | ||||
|       this.businessHours = value; | ||||
|       this.fetchAllData(); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -61,6 +61,12 @@ | ||||
|         @input="handleAgentsFilterSelection" | ||||
|       /> | ||||
|     </div> | ||||
|     <div class="small-12 medium-3 business-hours"> | ||||
|       <span class="business-hours-text">{{ $t('REPORT.BUSINESS_HOURS') }}</span> | ||||
|       <span> | ||||
|         <woot-switch v-model="businessHoursSelected" /> | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| @@ -105,6 +111,7 @@ export default { | ||||
|       customDateRange: [new Date(), new Date()], | ||||
|       currentSelectedFilter: null, | ||||
|       selectedAgents: [], | ||||
|       businessHoursSelected: false, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -153,6 +160,9 @@ export default { | ||||
|     filterItemsList() { | ||||
|       this.currentSelectedFilter = this.selectedGroupByFilter; | ||||
|     }, | ||||
|     businessHoursSelected() { | ||||
|       this.$emit('business-hours-toggle', this.businessHoursSelected); | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.onDateRangeChange(); | ||||
|   | ||||
| @@ -145,6 +145,12 @@ | ||||
|         @input="changeGroupByFilterSelection" | ||||
|       /> | ||||
|     </div> | ||||
|     <div class="small-12 medium-3 business-hours"> | ||||
|       <span class="business-hours-text">{{ $t('REPORT.BUSINESS_HOURS') }}</span> | ||||
|       <span> | ||||
|         <woot-switch v-model="businessHoursSelected" /> | ||||
|       </span> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
| @@ -188,6 +194,7 @@ export default { | ||||
|       dateRange: this.$t('REPORT.DATE_RANGE'), | ||||
|       customDateRange: [new Date(), new Date()], | ||||
|       currentSelectedGroupByFilter: null, | ||||
|       businessHoursSelected: false, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -249,6 +256,9 @@ export default { | ||||
|     groupByFilterItemsList() { | ||||
|       this.currentSelectedGroupByFilter = this.selectedGroupByFilter; | ||||
|     }, | ||||
|     businessHoursSelected() { | ||||
|       this.$emit('business-hours-toggle', this.businessHoursSelected); | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.onDateRangeChange(); | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
|       @date-range-change="onDateRangeChange" | ||||
|       @filter-change="onFilterChange" | ||||
|       @group-by-filter-change="onGroupByFilterChange" | ||||
|       @business-hours-toggle="onBusinessHoursToggle" | ||||
|     /> | ||||
|     <div> | ||||
|       <div v-if="filterItemsList.length" class="row"> | ||||
| @@ -100,6 +101,7 @@ export default { | ||||
|       groupBy: GROUP_BY_FILTER[1], | ||||
|       groupByfilterItemsList: this.$t('REPORT.GROUP_BY_DAY_OPTIONS'), | ||||
|       selectedGroupByFilter: null, | ||||
|       businessHours: false, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
| @@ -202,19 +204,20 @@ export default { | ||||
|   methods: { | ||||
|     fetchAllData() { | ||||
|       if (this.selectedFilter) { | ||||
|         const { from, to, groupBy } = this; | ||||
|         const { from, to, groupBy, businessHours } = this; | ||||
|         this.$store.dispatch('fetchAccountSummary', { | ||||
|           from, | ||||
|           to, | ||||
|           type: this.type, | ||||
|           id: this.selectedFilter.id, | ||||
|           groupBy: groupBy.period, | ||||
|           businessHours, | ||||
|         }); | ||||
|         this.fetchChartData(); | ||||
|       } | ||||
|     }, | ||||
|     fetchChartData() { | ||||
|       const { from, to, groupBy } = this; | ||||
|       const { from, to, groupBy, businessHours } = this; | ||||
|       this.$store.dispatch('fetchAccountReport', { | ||||
|         metric: this.metrics[this.currentSelection].KEY, | ||||
|         from, | ||||
| @@ -222,6 +225,7 @@ export default { | ||||
|         type: this.type, | ||||
|         id: this.selectedFilter.id, | ||||
|         groupBy: groupBy.period, | ||||
|         businessHours, | ||||
|       }); | ||||
|     }, | ||||
|     downloadReports() { | ||||
| @@ -288,6 +292,10 @@ export default { | ||||
|           return this.$t('REPORT.GROUP_BY_DAY_OPTIONS'); | ||||
|       } | ||||
|     }, | ||||
|     onBusinessHoursToggle(value) { | ||||
|       this.businessHours = value; | ||||
|       this.fetchAllData(); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -42,7 +42,8 @@ export const actions = { | ||||
|       reportObj.to, | ||||
|       reportObj.type, | ||||
|       reportObj.id, | ||||
|       reportObj.groupBy | ||||
|       reportObj.groupBy, | ||||
|       reportObj.businessHours | ||||
|     ).then(accountReport => { | ||||
|       let { data } = accountReport; | ||||
|       data = data.filter( | ||||
| @@ -69,7 +70,8 @@ export const actions = { | ||||
|       reportObj.to, | ||||
|       reportObj.type, | ||||
|       reportObj.id, | ||||
|       reportObj.groupBy | ||||
|       reportObj.groupBy, | ||||
|       reportObj.businessHours | ||||
|     ) | ||||
|       .then(accountSummary => { | ||||
|         commit(types.default.SET_ACCOUNT_SUMMARY, accountSummary.data); | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| class ReportingEventListener < BaseListener | ||||
|   include ReportingEventHelper | ||||
|   def conversation_resolved(event) | ||||
|     conversation = extract_conversation_and_account(event)[0] | ||||
|     time_to_resolve = conversation.updated_at.to_i - conversation.created_at.to_i | ||||
| @@ -6,10 +7,14 @@ class ReportingEventListener < BaseListener | ||||
|     reporting_event = ReportingEvent.new( | ||||
|       name: 'conversation_resolved', | ||||
|       value: time_to_resolve, | ||||
|       value_in_business_hours: business_hours(conversation.inbox, conversation.created_at, | ||||
|                                               conversation.updated_at), | ||||
|       account_id: conversation.account_id, | ||||
|       inbox_id: conversation.inbox_id, | ||||
|       user_id: conversation.assignee_id, | ||||
|       conversation_id: conversation.id | ||||
|       conversation_id: conversation.id, | ||||
|       event_start_time: conversation.created_at, | ||||
|       event_end_time: conversation.updated_at | ||||
|     ) | ||||
|     reporting_event.save | ||||
|   end | ||||
| @@ -22,10 +27,14 @@ class ReportingEventListener < BaseListener | ||||
|     reporting_event = ReportingEvent.new( | ||||
|       name: 'first_response', | ||||
|       value: first_response_time, | ||||
|       value_in_business_hours: business_hours(conversation.inbox, conversation.created_at, | ||||
|                                               message.created_at), | ||||
|       account_id: conversation.account_id, | ||||
|       inbox_id: conversation.inbox_id, | ||||
|       user_id: conversation.assignee_id, | ||||
|       conversation_id: conversation.id | ||||
|       conversation_id: conversation.id, | ||||
|       event_start_time: conversation.created_at, | ||||
|       event_end_time: message.created_at | ||||
|     ) | ||||
|     reporting_event.save | ||||
|   end | ||||
|   | ||||
| @@ -2,15 +2,18 @@ | ||||
| # | ||||
| # Table name: reporting_events | ||||
| # | ||||
| #  id              :bigint           not null, primary key | ||||
| #  name            :string | ||||
| #  value           :float | ||||
| #  created_at      :datetime         not null | ||||
| #  updated_at      :datetime         not null | ||||
| #  account_id      :integer | ||||
| #  conversation_id :integer | ||||
| #  inbox_id        :integer | ||||
| #  user_id         :integer | ||||
| #  id                      :bigint           not null, primary key | ||||
| #  event_end_time          :datetime | ||||
| #  event_start_time        :datetime | ||||
| #  name                    :string | ||||
| #  value                   :float | ||||
| #  value_in_business_hours :float | ||||
| #  created_at              :datetime         not null | ||||
| #  updated_at              :datetime         not null | ||||
| #  account_id              :integer | ||||
| #  conversation_id         :integer | ||||
| #  inbox_id                :integer | ||||
| #  user_id                 :integer | ||||
| # | ||||
| # Indexes | ||||
| # | ||||
|   | ||||
| @@ -0,0 +1,9 @@ | ||||
| class AddValueInBusinessHoursToReportingEvent < ActiveRecord::Migration[6.1] | ||||
|   def change | ||||
|     change_table :reporting_events, bulk: true do |t| | ||||
|       t.float :value_in_business_hours, default: nil | ||||
|       t.datetime :event_start_time, default: nil | ||||
|       t.datetime :event_end_time, default: nil | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -657,6 +657,9 @@ ActiveRecord::Schema.define(version: 2022_04_05_092033) do | ||||
|     t.integer "conversation_id" | ||||
|     t.datetime "created_at", precision: 6, null: false | ||||
|     t.datetime "updated_at", precision: 6, null: false | ||||
|     t.float "value_in_business_hours" | ||||
|     t.datetime "event_start_time" | ||||
|     t.datetime "event_end_time" | ||||
|     t.index ["account_id"], name: "index_reporting_events_on_account_id" | ||||
|     t.index ["created_at"], name: "index_reporting_events_on_created_at" | ||||
|     t.index ["inbox_id"], name: "index_reporting_events_on_inbox_id" | ||||
|   | ||||
| @@ -17,6 +17,21 @@ describe ReportingEventListener do | ||||
|       listener.conversation_resolved(event) | ||||
|       expect(account.reporting_events.where(name: 'conversation_resolved').count).to be 1 | ||||
|     end | ||||
|  | ||||
|     context 'when business hours enabled for inbox' do | ||||
|       let(:created_at) { Time.zone.parse('March 20, 2022 00:00') } | ||||
|       let(:updated_at) { Time.zone.parse('March 26, 2022 23:59') } | ||||
|       let!(:new_inbox) { create(:inbox, working_hours_enabled: true, account: account) } | ||||
|       let!(:new_conversation) do | ||||
|         create(:conversation, created_at: created_at, updated_at: updated_at, account: account, inbox: new_inbox, assignee: user) | ||||
|       end | ||||
|  | ||||
|       it 'creates conversation_resolved event with business hour value' do | ||||
|         event = Events::Base.new('conversation.resolved', Time.zone.now, conversation: new_conversation) | ||||
|         listener.conversation_resolved(event) | ||||
|         expect(account.reporting_events.where(name: 'conversation_resolved')[0]['value_in_business_hours']).to be 144_000.0 | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#first_reply_created' do | ||||
| @@ -26,5 +41,24 @@ describe ReportingEventListener do | ||||
|       listener.first_reply_created(event) | ||||
|       expect(account.reporting_events.where(name: 'first_response').count).to eql previous_count + 1 | ||||
|     end | ||||
|  | ||||
|     context 'when business hours enabled for inbox' do | ||||
|       let(:conversation_created_at) { Time.zone.parse('March 20, 2022 00:00') } | ||||
|       let(:message_created_at) { Time.zone.parse('March 26, 2022 23:59') } | ||||
|       let!(:new_inbox) { create(:inbox, working_hours_enabled: true, account: account) } | ||||
|       let!(:new_conversation) do | ||||
|         create(:conversation, created_at: conversation_created_at, account: account, inbox: new_inbox, assignee: user) | ||||
|       end | ||||
|       let!(:new_message) do | ||||
|         create(:message, message_type: 'outgoing', created_at: message_created_at, | ||||
|                          account: account, inbox: new_inbox, conversation: new_conversation) | ||||
|       end | ||||
|  | ||||
|       it 'creates first_response event with business hour value' do | ||||
|         event = Events::Base.new('first.reply.created', Time.zone.now, message: new_message) | ||||
|         listener.first_reply_created(event) | ||||
|         expect(account.reporting_events.where(name: 'first_response')[0]['value_in_business_hours']).to be 144_000.0 | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Aswin Dev P.S
					Aswin Dev P.S