Browse Source

Fixes #3694 - Inheritance of out of office settings.

Rolf Schmidt 3 years ago
parent
commit
87f77338be
3 changed files with 117 additions and 4 deletions
  1. 25 3
      app/models/user.rb
  2. 91 0
      spec/models/user_spec.rb
  3. 1 1
      test/unit/ticket_notification_test.rb

+ 25 - 3
app/models/user.rb

@@ -217,11 +217,21 @@ returns
 
 =end
 
-  def out_of_office_agent
+  def out_of_office_agent(loop_user_ids: [])
     return if !out_of_office?
     return if out_of_office_replacement_id.blank?
 
-    User.find_by(id: out_of_office_replacement_id)
+    user = User.find_by(id: out_of_office_replacement_id)
+
+    # stop if users are occuring multiple times to prevent endless loops
+    return user if loop_user_ids.include?(out_of_office_replacement_id)
+
+    loop_user_ids |= [out_of_office_replacement_id]
+
+    ooo_agent = user.out_of_office_agent(loop_user_ids: loop_user_ids)
+    return ooo_agent if ooo_agent.present?
+
+    user
   end
 
 =begin
@@ -238,7 +248,19 @@ returns
 =end
 
   def out_of_office_agent_of
-    User.where(active: true, out_of_office: true, out_of_office_replacement_id: id).where('out_of_office_start_at <= ? AND out_of_office_end_at >= ?', Time.zone.today, Time.zone.today)
+    User.where(id: out_of_office_agent_of_recursive(user_id: id))
+  end
+
+  def out_of_office_agent_of_recursive(user_id:, result: [])
+    User.where(active: true, out_of_office: true, out_of_office_replacement_id: user_id).where('out_of_office_start_at <= ? AND out_of_office_end_at >= ?', Time.zone.today, Time.zone.today).each do |user|
+
+      # stop if users are occuring multiple times to prevent endless loops
+      break if result.include?(user.id)
+
+      result |= [user.id]
+      result |= out_of_office_agent_of_recursive(user_id: user.id, result: result)
+    end
+    result
   end
 
 =begin

+ 91 - 0
spec/models/user_spec.rb

@@ -208,6 +208,48 @@ RSpec.describe User, type: :model do
             expect(user.out_of_office_agent).to eq(substitute)
           end
         end
+
+        context 'with recursive out of office structure' do
+          let(:out_of_office) { true }
+          let(:substitute) do
+            create(:user,
+                   out_of_office:                out_of_office,
+                   out_of_office_start_at:       Time.zone.yesterday,
+                   out_of_office_end_at:         Time.zone.tomorrow,
+                   out_of_office_replacement_id: user_active.id,)
+          end
+          let!(:user_active) { create(:user) }
+
+          it 'returns the designated substitute recursive' do
+            expect(user.out_of_office_agent).to eq(user_active)
+          end
+        end
+
+        context 'with recursive out of office structure with a endless loop' do
+          let(:out_of_office) { true }
+          let(:substitute) do
+            create(:user,
+                   out_of_office:                out_of_office,
+                   out_of_office_start_at:       Time.zone.yesterday,
+                   out_of_office_end_at:         Time.zone.tomorrow,
+                   out_of_office_replacement_id: user_active.id,)
+          end
+          let!(:user_active) do
+            create(:user,
+                   out_of_office:                out_of_office,
+                   out_of_office_start_at:       Time.zone.yesterday,
+                   out_of_office_end_at:         Time.zone.tomorrow,
+                   out_of_office_replacement_id: agent.id,)
+          end
+
+          before do
+            user_active.update(out_of_office_replacement_id: substitute.id)
+          end
+
+          it 'returns the designated substitute recursive with a endless loop' do
+            expect(user.out_of_office_agent).to eq(substitute)
+          end
+        end
       end
     end
 
@@ -249,6 +291,55 @@ RSpec.describe User, type: :model do
               .to match_array([agent_on_holiday])
           end
         end
+
+        context 'when inherited' do
+          let(:out_of_office) { true }
+          let!(:agent_on_holiday_sub) do
+            create(
+              :agent,
+              out_of_office_start_at:       Time.current.yesterday,
+              out_of_office_end_at:         Time.current.tomorrow,
+              out_of_office_replacement_id: agent_on_holiday.id,
+              out_of_office:                out_of_office
+            )
+          end
+
+          it 'returns an ActiveRecord::Relation including both agents' do
+            expect(agent.out_of_office_agent_of)
+              .to match_array([agent_on_holiday, agent_on_holiday_sub])
+          end
+        end
+
+        context 'when inherited endless loop' do
+          let(:out_of_office) { true }
+          let!(:agent_on_holiday_sub) do
+            create(
+              :agent,
+              out_of_office_start_at:       Time.current.yesterday,
+              out_of_office_end_at:         Time.current.tomorrow,
+              out_of_office_replacement_id: agent_on_holiday.id,
+              out_of_office:                out_of_office
+            )
+          end
+          let!(:agent_on_holiday_sub2) do
+            create(
+              :agent,
+              out_of_office_start_at:       Time.current.yesterday,
+              out_of_office_end_at:         Time.current.tomorrow,
+              out_of_office_replacement_id: agent_on_holiday_sub.id,
+              out_of_office:                out_of_office
+            )
+          end
+
+          before do
+            agent_on_holiday_sub.update(out_of_office_replacement_id: agent_on_holiday_sub2.id)
+          end
+
+          it 'returns an ActiveRecord::Relation including both agents referencing each other' do
+            expect(agent_on_holiday_sub.out_of_office_agent_of)
+              .to match_array([agent_on_holiday_sub, agent_on_holiday_sub2])
+          end
+        end
       end
     end
 

+ 1 - 1
test/unit/ticket_notification_test.rb

@@ -1122,7 +1122,7 @@ class TicketNotificationTest < ActiveSupport::TestCase
     # verify notifications to @agent1 + @agent2
     assert_equal(0, NotificationFactory::Mailer.already_sent?(ticket2, @agent1, 'email'), ticket2.id)
     assert_equal(3, NotificationFactory::Mailer.already_sent?(ticket2, @agent2, 'email'), ticket2.id)
-    assert_equal(3, NotificationFactory::Mailer.already_sent?(ticket2, @agent3, 'email'), ticket2.id)
+    assert_equal(2, NotificationFactory::Mailer.already_sent?(ticket2, @agent3, 'email'), ticket2.id)
     assert_equal(1, NotificationFactory::Mailer.already_sent?(ticket2, @agent4, 'email'), ticket2.id)
 
   end