item.rb 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Checklist::Item < ApplicationModel
  3. include ChecksClientNotification
  4. include HasHistory
  5. include HasDefaultModelUserRelations
  6. include Checklist::Item::Assets
  7. include Checklist::Item::TriggersSubscriptions
  8. attr_accessor :initial_clone
  9. belongs_to :checklist
  10. belongs_to :ticket, optional: true, inverse_of: :referencing_checklist_items
  11. scope :incomplete, -> { where(checked: false) }
  12. before_validation :detect_ticket_reference, unless: :initial_clone
  13. before_validation :detect_ticket_reference_state
  14. validate :detect_ticket_loop_reference, unless: -> { ticket.blank? }
  15. validate :validate_item_count, on: :create, unless: :initial_clone
  16. # MySQL does not support default value on non-null text columns
  17. # Can be removed after dropping MySQL
  18. before_validation :ensure_text_not_nil, if: -> { ActiveRecord::Base.connection_db_config.configuration_hash[:adapter] == 'mysql2' }
  19. after_update :history_update_checked, if: -> { saved_change_to_checked? }
  20. after_destroy :update_checklist_on_destroy
  21. after_destroy :update_referenced_ticket
  22. after_save :update_checklist_on_save, unless: :initial_clone
  23. after_save :update_referenced_ticket
  24. history_attributes_ignored :checked
  25. def history_log_attributes
  26. {
  27. related_o_id: checklist.ticket.id,
  28. related_history_object: 'Ticket',
  29. }
  30. end
  31. def history_create
  32. history_log('created', created_by_id, { value_to: text })
  33. end
  34. def history_update_checked
  35. history_log('checklist_item_checked', updated_by_id, {
  36. value_from: text,
  37. value_to: checked.to_s,
  38. })
  39. end
  40. def history_destroy
  41. history_log('removed', updated_by_id, { value_to: text })
  42. end
  43. def notify_clients_data_attributes
  44. {
  45. id: id,
  46. updated_at: updated_at,
  47. updated_by_id: updated_by_id,
  48. }
  49. end
  50. private
  51. def update_checklist_on_save
  52. checklist.sorted_item_ids |= [id.to_s]
  53. # It is necessary to make checklist dirty if checklist item was edited, but sorting was not changed
  54. # Otherwise legacy UI will not update properly
  55. checklist.updated_at = Time.current
  56. checklist.save!
  57. end
  58. def update_checklist_on_destroy
  59. # do not touch checklist if this item is destroyed by checklist's dependent: destroy
  60. return if destroyed_by_association
  61. checklist.sorted_item_ids -= [id.to_s]
  62. checklist.save!
  63. end
  64. def detect_ticket_reference
  65. return if ticket_id_changed?
  66. ticket = Ticket::Number.check(text)
  67. return if ticket.blank?
  68. self.ticket = ticket
  69. end
  70. def detect_ticket_reference_state
  71. return if !ticket
  72. return if !ticket_id_changed?
  73. self.checked = Checklist.ticket_closed?(ticket)
  74. end
  75. def detect_ticket_loop_reference
  76. return if checklist_id != ticket.checklist_id
  77. errors.add(:ticket, __('reference must not be the checklist ticket.'))
  78. end
  79. def validate_item_count
  80. return if checklist.items.count < 100
  81. errors.add(:base, __('Checklist items are limited to 100 items per checklist.'))
  82. end
  83. def update_referenced_ticket
  84. return if !saved_change_to_ticket_id? && !destroyed?
  85. [ticket_id, ticket_id_before_last_save]
  86. .compact
  87. .map { |elem| Ticket.find_by(id: elem) }
  88. .each do |elem|
  89. elem.updated_at = Time.current
  90. elem.save!
  91. end
  92. end
  93. # MySQL does not support default value on non-null text columns
  94. # Can be removed after dropping MySQL
  95. def ensure_text_not_nil
  96. self.text ||= ''
  97. end
  98. end