123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class Checklist < ApplicationModel
- include HasDefaultModelUserRelations
- include ChecksClientNotification
- include HasHistory
- include Checklist::SearchIndex
- include Checklist::TriggersSubscriptions
- include Checklist::Assets
- include CanChecklistSortedItems
- has_one :ticket, dependent: :nullify
- has_many :items, inverse_of: :checklist, dependent: :destroy
- validates :name, length: { maximum: 250 }
- history_attributes_ignored :sorted_item_ids
- # Those callbacks are necessary to trigger updates in legacy UI.
- # First checklist item is created right after the checklist itself
- # and it triggers update on the freshly created ticket.
- # Thus no need for after_create callback.
- after_update :update_ticket
- after_destroy :update_ticket
- def history_log_attributes
- {
- related_o_id: ticket.id,
- related_history_object: 'Ticket',
- }
- end
- def history_create
- history_log('created', created_by_id, { value_to: name })
- end
- def history_destroy
- history_log('removed', updated_by_id, { value_to: name })
- end
- def notify_clients_data_attributes
- {
- id: id,
- ticket_id: ticket.id,
- updated_at: updated_at,
- updated_by_id: updated_by_id,
- }
- end
- def completed?
- incomplete.zero?
- end
- def incomplete
- items.incomplete.count
- end
- def total
- items.count
- end
- def complete
- total - incomplete
- end
- # Returns scope to tickets tracking the given target ticket in their checklists.
- # If a user is given, it returns tickets acccessible to that user only.
- #
- # @param target_ticket [Ticket, Integer] target ticket or it's id
- # @param user [User] to optionally filter accessible tickets
- def self.tickets_referencing(target_ticket, user = nil)
- source_checklist_ids = joins(:items)
- .where(items: { ticket: target_ticket })
- .pluck(:id)
- scope = Ticket.where(checklist_id: source_checklist_ids)
- return scope if !user
- TicketPolicy::ReadScope
- .new(user, scope)
- .resolve
- end
- def self.ticket_closed?(ticket)
- state = Ticket::State.lookup id: ticket.state_id
- state_type = Ticket::StateType.lookup id: state.state_type_id
- %w[closed merged].include? state_type.name
- end
- def self.create_fresh!(ticket)
- ActiveRecord::Base.transaction do
- Checklist
- .create!(ticket:)
- .tap { |checklist| checklist.items.create! }
- end
- end
- def self.create_from_template!(ticket, template)
- if !template.active
- raise Exceptions::UnprocessableEntity, __('Checklist template must be active to use as a checklist starting point.')
- end
- ActiveRecord::Base.transaction do
- Checklist.create!(name: template.name, ticket:)
- .tap do |checklist|
- sorted_item_ids = template
- .items
- .map { |elem| checklist.items.create!(text: elem.text, initial_clone: true) }
- .pluck(:id)
- checklist.update! sorted_item_ids:
- end
- end
- end
- private
- def update_ticket
- return if ticket.destroyed?
- ticket.updated_at = Time.current
- ticket.save!
- end
- end
|