checklist.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Checklist < ApplicationModel
  3. include HasDefaultModelUserRelations
  4. include ChecksClientNotification
  5. include HasHistory
  6. include Checklist::SearchIndex
  7. include Checklist::TriggersSubscriptions
  8. include Checklist::Assets
  9. include CanChecklistSortedItems
  10. has_one :ticket, dependent: :nullify
  11. has_many :items, inverse_of: :checklist, dependent: :destroy
  12. validates :name, length: { maximum: 250 }
  13. history_attributes_ignored :sorted_item_ids
  14. # Those callbacks are necessary to trigger updates in legacy UI.
  15. # First checklist item is created right after the checklist itself
  16. # and it triggers update on the freshly created ticket.
  17. # Thus no need for after_create callback.
  18. after_update :update_ticket
  19. after_destroy :update_ticket
  20. def history_log_attributes
  21. {
  22. related_o_id: ticket.id,
  23. related_history_object: 'Ticket',
  24. }
  25. end
  26. def history_create
  27. history_log('created', created_by_id, { value_to: name })
  28. end
  29. def history_destroy
  30. history_log('removed', updated_by_id, { value_to: name })
  31. end
  32. def notify_clients_data_attributes
  33. {
  34. id: id,
  35. ticket_id: ticket.id,
  36. updated_at: updated_at,
  37. updated_by_id: updated_by_id,
  38. }
  39. end
  40. def completed?
  41. incomplete.zero?
  42. end
  43. def incomplete
  44. items.incomplete.count
  45. end
  46. def total
  47. items.count
  48. end
  49. def complete
  50. total - incomplete
  51. end
  52. # Returns scope to tickets tracking the given target ticket in their checklists.
  53. # If a user is given, it returns tickets acccessible to that user only.
  54. #
  55. # @param target_ticket [Ticket, Integer] target ticket or it's id
  56. # @param user [User] to optionally filter accessible tickets
  57. def self.tickets_referencing(target_ticket, user = nil)
  58. source_checklist_ids = joins(:items)
  59. .where(items: { ticket: target_ticket })
  60. .pluck(:id)
  61. scope = Ticket.where(checklist_id: source_checklist_ids)
  62. return scope if !user
  63. TicketPolicy::ReadScope
  64. .new(user, scope)
  65. .resolve
  66. end
  67. def self.ticket_closed?(ticket)
  68. state = Ticket::State.lookup id: ticket.state_id
  69. state_type = Ticket::StateType.lookup id: state.state_type_id
  70. %w[closed merged].include? state_type.name
  71. end
  72. def self.create_fresh!(ticket)
  73. ActiveRecord::Base.transaction do
  74. Checklist
  75. .create!(ticket:)
  76. .tap { |checklist| checklist.items.create! }
  77. end
  78. end
  79. def self.create_from_template!(ticket, template)
  80. if !template.active
  81. raise Exceptions::UnprocessableEntity, __('Checklist template must be active to use as a checklist starting point.')
  82. end
  83. ActiveRecord::Base.transaction do
  84. Checklist.create!(name: template.name, ticket:)
  85. .tap do |checklist|
  86. sorted_item_ids = template
  87. .items
  88. .map { |elem| checklist.items.create!(text: elem.text, initial_clone: true) }
  89. .pluck(:id)
  90. checklist.update! sorted_item_ids:
  91. end
  92. end
  93. end
  94. private
  95. def update_ticket
  96. return if ticket.destroyed?
  97. ticket.updated_at = Time.current
  98. ticket.save!
  99. end
  100. end