state.rb 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. # Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. class Ticket::State < ApplicationModel
  3. include HasDefaultModelUserRelations
  4. include CanBeImported
  5. include ChecksHtmlSanitized
  6. include HasCollectionUpdate
  7. include HasSearchIndexBackend
  8. belongs_to :state_type, class_name: 'Ticket::StateType', inverse_of: :states, optional: true
  9. belongs_to :next_state, class_name: 'Ticket::State', optional: true
  10. after_create :ensure_defaults
  11. before_update :prevent_merged_state_editing
  12. after_update :ensure_defaults
  13. before_destroy :prevent_merged_state_destruction
  14. after_destroy :ensure_defaults
  15. after_destroy :update_object_manager_attribute
  16. after_save :update_object_manager_attribute
  17. validates :name, presence: true, uniqueness: { case_sensitive: false }
  18. validates :note, length: { maximum: 250 }
  19. sanitized_html :note
  20. validates :state_type_id, uniqueness: { if: :state_type_solo? }
  21. attr_accessor :callback_loop
  22. default_scope { order(id: :asc) }
  23. =begin
  24. looks up states for a given category
  25. states = Ticket::State.by_category(:open) # :open|:closed|:work_on|:work_on_all|:viewable|:viewable_agent_new|:viewable_agent_edit|:viewable_customer_new|:viewable_customer_edit|:pending_reminder|:pending_action|:pending|:merged
  26. returns:
  27. state object list
  28. =end
  29. scope :by_category, lambda { |category|
  30. joins(:state_type)
  31. .where(ticket_state_types: { name: Ticket::StateType.names_in_category(category) })
  32. }
  33. scope :active, -> { where(active: true) }
  34. def self.by_category_ids(category)
  35. by_category(category).pluck(:id)
  36. end
  37. def ensure_defaults
  38. return if callback_loop
  39. %w[default_create default_follow_up].each do |default_field|
  40. states_with_default = Ticket::State.where(default_field => true)
  41. next if states_with_default.count == 1
  42. if states_with_default.count.zero?
  43. state = Ticket::State.where(active: true).reorder(id: :asc).first
  44. state[default_field] = true
  45. state.callback_loop = true
  46. state.save!
  47. next
  48. end
  49. Ticket::State.all.each do |local_state|
  50. next if local_state.id == id
  51. next if local_state[default_field] == false
  52. local_state[default_field] = false
  53. local_state.callback_loop = true
  54. local_state.save!
  55. next
  56. end
  57. end
  58. end
  59. def self.update_state_field_configuration
  60. attr = ObjectManager::Attribute.get(
  61. object: 'Ticket',
  62. name: 'state_id',
  63. )
  64. active_states = Ticket::State.where(active: true)
  65. attr.data_option[:filter] = active_states.by_category_ids(:viewable)
  66. attr.screens[:create_middle]['ticket.agent'][:filter] = active_states.by_category_ids(:viewable_agent_new)
  67. attr.screens[:create_middle]['ticket.customer'][:filter] = active_states.by_category_ids(:viewable_customer_new)
  68. attr.screens[:edit]['ticket.agent'][:filter] = active_states.by_category_ids(:viewable_agent_edit)
  69. attr.screens[:edit]['ticket.customer'][:filter] = active_states.by_category_ids(:viewable_customer_edit)
  70. attr.screens[:overview_bulk]['ticket.agent'][:filter] = active_states.by_category_ids(:viewable_agent_edit)
  71. attr.save!
  72. end
  73. # Allow to lookup state by state type ID
  74. def self.lookup_keys
  75. @lookup_keys ||= super + [:state_type_id]
  76. end
  77. private
  78. def update_object_manager_attribute
  79. return if !Setting.get('system_init_done')
  80. return if callback_loop
  81. self.class.update_state_field_configuration
  82. end
  83. def state_type_solo?
  84. # OTRS import creates a copy of all states, including merged, and that's OK
  85. return false if Setting.get('import_mode')
  86. state_type&.solo?
  87. end
  88. def prevent_merged_state_editing
  89. # OTRS import creates a copy of all states, including merged, and that's OK
  90. return if Setting.get('import_mode')
  91. return if state_type.name != 'merged'
  92. throw :abort
  93. end
  94. def prevent_merged_state_destruction
  95. # OTRS import creates a copy of all states, including merged, and that's OK
  96. return if Setting.get('import_mode')
  97. return if state_type.name != 'merged'
  98. throw :abort
  99. end
  100. end