checklist.rb 3.1 KB

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