diff --git a/db/migrate/20240319062553_create_sla_events.rb b/db/migrate/20240319062553_create_sla_events.rb new file mode 100644 index 000000000..a6f1a5de2 --- /dev/null +++ b/db/migrate/20240319062553_create_sla_events.rb @@ -0,0 +1,16 @@ +class CreateSlaEvents < ActiveRecord::Migration[7.0] + def change + create_table :sla_events do |t| + t.references :applied_sla, null: false + t.references :conversation, null: false + t.references :account, null: false + t.references :sla_policy, null: false + t.references :inbox, null: false + + t.integer :event_type + t.jsonb :meta, default: {} + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index d0499cb7b..498ad13d3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_03_06_201954) do +ActiveRecord::Schema[7.0].define(version: 2024_03_19_062553) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" enable_extension "pg_trgm" @@ -842,6 +842,23 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_06_201954) do t.index ["user_id"], name: "index_reporting_events_on_user_id" end + create_table "sla_events", force: :cascade do |t| + t.bigint "applied_sla_id", null: false + t.bigint "conversation_id", null: false + t.bigint "account_id", null: false + t.bigint "sla_policy_id", null: false + t.bigint "inbox_id", null: false + t.integer "event_type" + t.jsonb "meta", default: {} + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id"], name: "index_sla_events_on_account_id" + t.index ["applied_sla_id"], name: "index_sla_events_on_applied_sla_id" + t.index ["conversation_id"], name: "index_sla_events_on_conversation_id" + t.index ["inbox_id"], name: "index_sla_events_on_inbox_id" + t.index ["sla_policy_id"], name: "index_sla_events_on_sla_policy_id" + end + create_table "sla_policies", force: :cascade do |t| t.string "name", null: false t.float "first_response_time_threshold" diff --git a/enterprise/app/models/applied_sla.rb b/enterprise/app/models/applied_sla.rb index 48fd852e4..c2dde8377 100644 --- a/enterprise/app/models/applied_sla.rb +++ b/enterprise/app/models/applied_sla.rb @@ -22,6 +22,8 @@ class AppliedSla < ApplicationRecord belongs_to :sla_policy belongs_to :conversation + has_many :sla_events, dependent: :destroy + validates :account_id, uniqueness: { scope: %i[sla_policy_id conversation_id] } before_validation :ensure_account_id diff --git a/enterprise/app/models/sla_event.rb b/enterprise/app/models/sla_event.rb new file mode 100644 index 000000000..28f709346 --- /dev/null +++ b/enterprise/app/models/sla_event.rb @@ -0,0 +1,52 @@ +# == Schema Information +# +# Table name: sla_events +# +# id :bigint not null, primary key +# event_type :integer +# meta :jsonb +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint not null +# applied_sla_id :bigint not null +# conversation_id :bigint not null +# inbox_id :bigint not null +# sla_policy_id :bigint not null +# +# Indexes +# +# index_sla_events_on_account_id (account_id) +# index_sla_events_on_applied_sla_id (applied_sla_id) +# index_sla_events_on_conversation_id (conversation_id) +# index_sla_events_on_inbox_id (inbox_id) +# index_sla_events_on_sla_policy_id (sla_policy_id) +# +class SlaEvent < ApplicationRecord + belongs_to :account + belongs_to :inbox + belongs_to :conversation + belongs_to :sla_policy + belongs_to :applied_sla + + enum event_type: { frt: 0, nrt: 1, rt: 2 } + + before_validation :ensure_applied_sla_id, :ensure_account_id, :ensure_inbox_id, :ensure_sla_policy_id + + private + + def ensure_applied_sla_id + self.applied_sla_id ||= AppliedSla.find_by(conversation_id: conversation_id)&.last&.id + end + + def ensure_account_id + self.account_id ||= conversation&.account_id + end + + def ensure_inbox_id + self.inbox_id ||= conversation&.inbox_id + end + + def ensure_sla_policy_id + self.sla_policy_id ||= applied_sla&.sla_policy_id + end +end diff --git a/spec/enterprise/models/sla_event_spec.rb b/spec/enterprise/models/sla_event_spec.rb new file mode 100644 index 000000000..862b22e6c --- /dev/null +++ b/spec/enterprise/models/sla_event_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe SlaEvent, type: :model do + describe 'associations' do + it { is_expected.to belong_to(:applied_sla) } + it { is_expected.to belong_to(:conversation) } + it { is_expected.to belong_to(:account) } + it { is_expected.to belong_to(:sla_policy) } + it { is_expected.to belong_to(:inbox) } + end + + describe 'validates_factory' do + it 'creates valid sla event object' do + sla_event = create(:sla_event) + expect(sla_event.event_type).to eq 'frt' + end + end + + describe 'backfilling ids' do + it 'automatically backfills account_id, inbox_id, and sla_id upon creation' do + sla_event = create(:sla_event) + + expect(sla_event.account_id).to eq sla_event.conversation.account_id + expect(sla_event.inbox_id).to eq sla_event.conversation.inbox_id + expect(sla_event.sla_policy_id).to eq sla_event.applied_sla.sla_policy_id + end + end +end diff --git a/spec/factories/sla_events.rb b/spec/factories/sla_events.rb new file mode 100644 index 000000000..12be18ede --- /dev/null +++ b/spec/factories/sla_events.rb @@ -0,0 +1,10 @@ +FactoryBot.define do + factory :sla_event do + applied_sla + conversation + event_type { 'frt' } + account { conversation.account } + inbox { conversation.inbox } + sla_policy { applied_sla.sla_policy } + end +end