Initial commit: Add logistics and order_detail message types
Some checks failed
Lock Threads / action (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Run Linux nightly installer / nightly (push) Has been cancelled

- Add Logistics component with progress tracking
- Add OrderDetail component for order information
- Support data-driven steps and actions
- Add blue color scale to widget SCSS
- Fix node overflow and progress bar rendering issues
- Add English translations for dashboard components

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Liang XJ
2026-01-26 11:16:56 +08:00
commit 092fb2e083
7646 changed files with 975643 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
require 'rails_helper'
RSpec.describe Sla::EvaluateAppliedSlaService do
let!(:account) { create(:account) }
let!(:user_1) { create(:user, account: account) }
let!(:sla_policy) do
create(:sla_policy,
account: account,
first_response_time_threshold: nil,
next_response_time_threshold: nil,
resolution_time_threshold: nil)
end
let!(:conversation) do
create(:conversation,
created_at: 6.hours.ago, assignee: user_1,
account: sla_policy.account,
sla_policy: sla_policy)
end
let!(:applied_sla) { conversation.applied_sla }
describe '#perform - SLA misses' do
context 'when first response SLA is missed' do
before { applied_sla.sla_policy.update(first_response_time_threshold: 1.hour) }
it 'updates the SLA status to missed and logs a warning' do
allow(Rails.logger).to receive(:warn)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:warn).with("SLA frt missed for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
end
it 'creates SlaEvent only for frt miss' do
described_class.new(applied_sla: applied_sla).perform
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(1)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(0)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(0)
end
end
context 'when next response SLA is missed' do
before do
applied_sla.sla_policy.update(next_response_time_threshold: 1.hour)
conversation.update(first_reply_created_at: 5.hours.ago, waiting_since: 5.hours.ago)
end
it 'updates the SLA status to missed and logs a warning' do
allow(Rails.logger).to receive(:warn)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:warn).with("SLA nrt missed for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
end
it 'creates SlaEvent only for nrt miss' do
described_class.new(applied_sla: applied_sla).perform
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(1)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(0)
end
end
context 'when resolution time SLA is missed' do
before { applied_sla.sla_policy.update(resolution_time_threshold: 1.hour) }
it 'updates the SLA status to missed and logs a warning' do
allow(Rails.logger).to receive(:warn)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:warn).with("SLA rt missed for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
end
it 'creates SlaEvent only for rt miss' do
described_class.new(applied_sla: applied_sla).perform
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(0)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(1)
end
end
# We will mark resolved miss only if while processing the SLA
# if the conversation is resolved and the resolution time is missed by small margins then we will not mark it as missed
context 'when resolved conversation with resolution time SLA is missed' do
before do
conversation.resolved!
applied_sla.sla_policy.update(resolution_time_threshold: 1.hour)
end
it 'does not update the SLA status to missed' do
described_class.new(applied_sla: applied_sla).perform
expect(applied_sla.reload.sla_status).to eq('hit')
end
end
context 'when multiple SLAs are missed' do
before do
applied_sla.sla_policy.update(first_response_time_threshold: 1.hour, next_response_time_threshold: 1.hour, resolution_time_threshold: 1.hour)
conversation.update(first_reply_created_at: 5.hours.ago, waiting_since: 5.hours.ago)
end
it 'updates the SLA status to missed and logs multiple warnings' do
allow(Rails.logger).to receive(:warn)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:warn).with("SLA rt missed for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}").exactly(1).time
expect(Rails.logger).to have_received(:warn).with("SLA nrt missed for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}").exactly(1).time
expect(applied_sla.reload.sla_status).to eq('active_with_misses')
end
end
end
describe '#perform - SLA hits' do
context 'when first response SLA is hit' do
before do
applied_sla.sla_policy.update(first_response_time_threshold: 6.hours)
conversation.update(first_reply_created_at: 30.minutes.ago)
end
it 'sla remains active until conversation is resolved' do
described_class.new(applied_sla: applied_sla).perform
expect(applied_sla.reload.sla_status).to eq('active')
end
it 'updates the SLA status to hit and logs an info when conversations is resolved' do
conversation.resolved!
allow(Rails.logger).to receive(:info)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('hit')
expect(SlaEvent.count).to eq(0)
expect(Notification.count).to eq(0)
end
end
context 'when next response SLA is hit' do
before do
applied_sla.sla_policy.update(next_response_time_threshold: 6.hours)
conversation.update(first_reply_created_at: 30.minutes.ago, waiting_since: nil)
end
it 'sla remains active until conversation is resolved' do
described_class.new(applied_sla: applied_sla).perform
expect(applied_sla.reload.sla_status).to eq('active')
end
it 'updates the SLA status to hit and logs an info when conversations is resolved' do
conversation.resolved!
allow(Rails.logger).to receive(:info)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('hit')
expect(SlaEvent.count).to eq(0)
end
end
context 'when resolution time SLA is hit' do
before do
applied_sla.sla_policy.update(resolution_time_threshold: 8.hours)
conversation.resolved!
end
it 'updates the SLA status to hit and logs an info' do
allow(Rails.logger).to receive(:info)
described_class.new(applied_sla: applied_sla).perform
expect(Rails.logger).to have_received(:info).with("SLA hit for conversation #{conversation.id} in account " \
"#{applied_sla.account_id} for sla_policy #{sla_policy.id}")
expect(applied_sla.reload.sla_status).to eq('hit')
expect(SlaEvent.count).to eq(0)
end
end
end
describe 'SLA evaluation with frt hit, multiple nrt misses and rt miss' do
before do
# Setup SLA Policy thresholds
applied_sla.sla_policy.update(
first_response_time_threshold: 2.hours, # Hit frt
next_response_time_threshold: 1.hour, # Miss nrt multiple times
resolution_time_threshold: 4.hours # Miss rt
)
# Simulate conversation timeline
# Hit frt
# incoming message from customer
create(:message, conversation: conversation, created_at: 6.hours.ago, message_type: :incoming)
# outgoing message from agent within frt
create(:message, conversation: conversation, created_at: 5.hours.ago, message_type: :outgoing)
# Miss nrt first time
create(:message, conversation: conversation, created_at: 4.hours.ago, message_type: :incoming)
described_class.new(applied_sla: applied_sla).perform
# Miss nrt second time
create(:message, conversation: conversation, created_at: 3.hours.ago, message_type: :incoming)
described_class.new(applied_sla: applied_sla).perform
# Conversation is resolved missing rt
conversation.update(status: 'resolved')
# this will not create a new notification for rt miss as conversation is resolved
# but we would have already created an rt miss notification during previous evaluation
described_class.new(applied_sla: applied_sla).perform
end
it 'updates the SLA status to missed' do
# the status would be missed as the conversation is resolved
expect(applied_sla.reload.sla_status).to eq('missed')
end
it 'creates necessary sla events' do
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'frt').count).to eq(0)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'nrt').count).to eq(2)
expect(SlaEvent.where(applied_sla: applied_sla, event_type: 'rt').count).to eq(1)
end
end
end