Follow up fa4577d463
- Fixes #3710 - Unable to close tickets in certran cases if core workflow is used.
This commit is contained in:
parent
8da05162ee
commit
041c0d61ef
10 changed files with 90 additions and 25 deletions
|
@ -4,7 +4,8 @@ module ChecksCoreWorkflow
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_validation :validate_workflows
|
before_create :validate_workflows
|
||||||
|
before_update :validate_workflows
|
||||||
|
|
||||||
attr_accessor :screen
|
attr_accessor :screen
|
||||||
end
|
end
|
||||||
|
@ -32,14 +33,16 @@ module ChecksCoreWorkflow
|
||||||
changes.each_key do |key|
|
changes.each_key do |key|
|
||||||
next if perform_result[:restrict_values][key].blank?
|
next if perform_result[:restrict_values][key].blank?
|
||||||
next if self[key].blank?
|
next if self[key].blank?
|
||||||
|
next if restricted_value?(perform_result, key)
|
||||||
value_found = perform_result[:restrict_values][key].any? { |value| value.to_s == self[key].to_s }
|
|
||||||
next if value_found
|
|
||||||
|
|
||||||
raise Exceptions::UnprocessableEntity, "Invalid value '#{self[key]}' for field '#{key}'!"
|
raise Exceptions::UnprocessableEntity, "Invalid value '#{self[key]}' for field '#{key}'!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def restricted_value?(perform_result, key)
|
||||||
|
perform_result[:restrict_values][key].any? { |value| value.to_s == self[key].to_s }
|
||||||
|
end
|
||||||
|
|
||||||
def check_visibility(perform_result)
|
def check_visibility(perform_result)
|
||||||
perform_result[:visibility].each_key do |key|
|
perform_result[:visibility].each_key do |key|
|
||||||
next if perform_result[:visibility][key] != 'remove'
|
next if perform_result[:visibility][key] != 'remove'
|
||||||
|
@ -50,11 +53,28 @@ module ChecksCoreWorkflow
|
||||||
|
|
||||||
def check_mandatory(perform_result)
|
def check_mandatory(perform_result)
|
||||||
perform_result[:mandatory].each_key do |key|
|
perform_result[:mandatory].each_key do |key|
|
||||||
next if %w[hide remove].include?(perform_result[:visibility][key])
|
next if field_visible?(perform_result, key)
|
||||||
next if !perform_result[:mandatory][key]
|
next if !field_mandatory?(perform_result, key)
|
||||||
next if self[key].present?
|
next if !column_value?(key)
|
||||||
|
next if !colum_default?(key)
|
||||||
|
|
||||||
raise Exceptions::UnprocessableEntity, "Missing required value for field '#{key}'!"
|
raise Exceptions::UnprocessableEntity, "Missing required value for field '#{key}'!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def field_visible?(perform_result, key)
|
||||||
|
%w[hide remove].include?(perform_result[:visibility][key])
|
||||||
|
end
|
||||||
|
|
||||||
|
def field_mandatory?(perform_result, key)
|
||||||
|
perform_result[:mandatory][key]
|
||||||
|
end
|
||||||
|
|
||||||
|
def column_value?(key)
|
||||||
|
self[key].nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def colum_default?(key)
|
||||||
|
self.class.column_defaults[key].nil?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -78,16 +78,11 @@ class CoreWorkflow::Attributes
|
||||||
# dont cache this else the result object will work with references and cache bugs occur
|
# dont cache this else the result object will work with references and cache bugs occur
|
||||||
def visibility_default
|
def visibility_default
|
||||||
object_elements.each_with_object({}) do |attribute, result|
|
object_elements.each_with_object({}) do |attribute, result|
|
||||||
result[ attribute[:name] ] = if @payload['request_id'] == 'ChecksCoreWorkflow.validate_workflows'
|
result[ attribute[:name] ] = screen_value(attribute, 'shown') == false ? 'hide' : 'show'
|
||||||
'show'
|
|
||||||
else
|
|
||||||
screen_value(attribute, 'shown') == false ? 'hide' : 'show'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attribute_mandatory?(attribute)
|
def attribute_mandatory?(attribute)
|
||||||
return false if @payload['request_id'] == 'ChecksCoreWorkflow.validate_workflows'
|
|
||||||
return screen_value(attribute, 'required').present? if !screen_value(attribute, 'required').nil?
|
return screen_value(attribute, 'required').present? if !screen_value(attribute, 'required').nil?
|
||||||
return screen_value(attribute, 'null').blank? if !screen_value(attribute, 'null').nil?
|
return screen_value(attribute, 'null').blank? if !screen_value(attribute, 'null').nil?
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ class Group < ApplicationModel
|
||||||
include CanBeImported
|
include CanBeImported
|
||||||
include HasActivityStreamLog
|
include HasActivityStreamLog
|
||||||
include ChecksClientNotification
|
include ChecksClientNotification
|
||||||
include ChecksCoreWorkflow
|
|
||||||
include ChecksHtmlSanitized
|
include ChecksHtmlSanitized
|
||||||
include ChecksLatestChangeObserved
|
include ChecksLatestChangeObserved
|
||||||
include HasHistory
|
include HasHistory
|
||||||
|
@ -16,6 +15,9 @@ class Group < ApplicationModel
|
||||||
belongs_to :email_address, optional: true
|
belongs_to :email_address, optional: true
|
||||||
belongs_to :signature, optional: true
|
belongs_to :signature, optional: true
|
||||||
|
|
||||||
|
# workflow checks should run after before_create and before_update callbacks
|
||||||
|
include ChecksCoreWorkflow
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
|
|
||||||
sanitized_html :note
|
sanitized_html :note
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class ObjectManager::Attribute::Validation::Required < ObjectManager::Attribute::Validation::Backend
|
class ObjectManager::Attribute::Validation::Required < ObjectManager::Attribute::Validation::Backend
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
|
return if record.class.include?(ChecksCoreWorkflow)
|
||||||
return if !value.nil?
|
return if !value.nil?
|
||||||
return if optional_for_user?
|
return if optional_for_user?
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
class Organization < ApplicationModel
|
class Organization < ApplicationModel
|
||||||
include HasActivityStreamLog
|
include HasActivityStreamLog
|
||||||
include ChecksClientNotification
|
include ChecksClientNotification
|
||||||
include ChecksCoreWorkflow
|
|
||||||
include ChecksLatestChangeObserved
|
include ChecksLatestChangeObserved
|
||||||
include HasHistory
|
include HasHistory
|
||||||
include HasSearchIndexBackend
|
include HasSearchIndexBackend
|
||||||
|
@ -26,6 +25,9 @@ class Organization < ApplicationModel
|
||||||
before_create :domain_cleanup
|
before_create :domain_cleanup
|
||||||
before_update :domain_cleanup
|
before_update :domain_cleanup
|
||||||
|
|
||||||
|
# workflow checks should run after before_create and before_update callbacks
|
||||||
|
include ChecksCoreWorkflow
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :domain, presence: { message: 'required when Domain Based Assignment is enabled' }, if: :domain_assignment
|
validates :domain, presence: { message: 'required when Domain Based Assignment is enabled' }, if: :domain_assignment
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,18 @@
|
||||||
class Sla < ApplicationModel
|
class Sla < ApplicationModel
|
||||||
include ChecksClientNotification
|
include ChecksClientNotification
|
||||||
include ChecksConditionValidation
|
include ChecksConditionValidation
|
||||||
include ChecksCoreWorkflow
|
|
||||||
include HasEscalationCalculationImpact
|
include HasEscalationCalculationImpact
|
||||||
|
|
||||||
include Sla::Assets
|
include Sla::Assets
|
||||||
|
|
||||||
|
belongs_to :calendar, optional: true
|
||||||
|
|
||||||
|
# workflow checks should run after before_create and before_update callbacks
|
||||||
|
include ChecksCoreWorkflow
|
||||||
|
|
||||||
|
validates :name, presence: true
|
||||||
|
|
||||||
store :condition
|
store :condition
|
||||||
store :data
|
store :data
|
||||||
validates :name, presence: true
|
|
||||||
belongs_to :calendar, optional: true
|
|
||||||
|
|
||||||
def condition_matches?(ticket)
|
def condition_matches?(ticket)
|
||||||
query_condition, bind_condition, tables = Ticket.selector2sql(condition)
|
query_condition, bind_condition, tables = Ticket.selector2sql(condition)
|
||||||
|
|
|
@ -4,7 +4,6 @@ class Ticket < ApplicationModel
|
||||||
include CanBeImported
|
include CanBeImported
|
||||||
include HasActivityStreamLog
|
include HasActivityStreamLog
|
||||||
include ChecksClientNotification
|
include ChecksClientNotification
|
||||||
include ChecksCoreWorkflow
|
|
||||||
include ChecksLatestChangeObserved
|
include ChecksLatestChangeObserved
|
||||||
include CanCsvImport
|
include CanCsvImport
|
||||||
include ChecksHtmlSanitized
|
include ChecksHtmlSanitized
|
||||||
|
@ -39,6 +38,9 @@ class Ticket < ApplicationModel
|
||||||
|
|
||||||
include HasTransactionDispatcher
|
include HasTransactionDispatcher
|
||||||
|
|
||||||
|
# workflow checks should run after before_create and before_update callbacks
|
||||||
|
include ChecksCoreWorkflow
|
||||||
|
|
||||||
validates :group_id, presence: true
|
validates :group_id, presence: true
|
||||||
|
|
||||||
activity_stream_permission 'ticket.agent'
|
activity_stream_permission 'ticket.agent'
|
||||||
|
|
|
@ -5,7 +5,6 @@ class User < ApplicationModel
|
||||||
include CanBeImported
|
include CanBeImported
|
||||||
include HasActivityStreamLog
|
include HasActivityStreamLog
|
||||||
include ChecksClientNotification
|
include ChecksClientNotification
|
||||||
include ChecksCoreWorkflow
|
|
||||||
include HasHistory
|
include HasHistory
|
||||||
include HasSearchIndexBackend
|
include HasSearchIndexBackend
|
||||||
include CanCsvImport
|
include CanCsvImport
|
||||||
|
@ -54,6 +53,9 @@ class User < ApplicationModel
|
||||||
before_destroy :destroy_longer_required_objects, :destroy_move_dependency_ownership
|
before_destroy :destroy_longer_required_objects, :destroy_move_dependency_ownership
|
||||||
after_commit :update_caller_id
|
after_commit :update_caller_id
|
||||||
|
|
||||||
|
# workflow checks should run after before_create and before_update callbacks
|
||||||
|
include ChecksCoreWorkflow
|
||||||
|
|
||||||
store :preferences
|
store :preferences
|
||||||
|
|
||||||
association_attributes_ignored :online_notifications, :templates, :taskbars, :user_devices, :chat_sessions, :karma_activity_logs, :cti_caller_ids, :text_modules, :customer_tickets, :owner_tickets, :created_recent_views, :chat_agents, :data_privacy_tasks, :overviews, :mentions
|
association_attributes_ignored :online_notifications, :templates, :taskbars, :user_devices, :chat_sessions, :karma_activity_logs, :cti_caller_ids, :text_modules, :customer_tickets, :owner_tickets, :created_recent_views, :chat_agents, :data_privacy_tasks, :overviews, :mentions
|
||||||
|
|
|
@ -12,7 +12,7 @@ RSpec.describe ::ObjectManager::Attribute::Validation::Required do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:record) { build(:user) }
|
let(:record) { build(:ticket_article) }
|
||||||
let(:attribute) { build(:object_manager_attribute_date) }
|
let(:attribute) { build(:object_manager_attribute_date) }
|
||||||
|
|
||||||
it_behaves_like 'validate backend'
|
it_behaves_like 'validate backend'
|
||||||
|
@ -52,7 +52,7 @@ RSpec.describe ::ObjectManager::Attribute::Validation::Required do
|
||||||
context 'when action is edit' do
|
context 'when action is edit' do
|
||||||
|
|
||||||
let(:action) { 'edit' }
|
let(:action) { 'edit' }
|
||||||
let(:record) { create(:user) }
|
let(:record) { create(:ticket_article) }
|
||||||
|
|
||||||
it_behaves_like 'a validation with errors'
|
it_behaves_like 'a validation with errors'
|
||||||
end
|
end
|
||||||
|
@ -116,7 +116,7 @@ RSpec.describe ::ObjectManager::Attribute::Validation::Required do
|
||||||
context 'when action is edit' do
|
context 'when action is edit' do
|
||||||
|
|
||||||
let(:action) { 'edit' }
|
let(:action) { 'edit' }
|
||||||
let(:record) { create(:user) }
|
let(:record) { create(:ticket_article) }
|
||||||
|
|
||||||
it_behaves_like 'a validation without errors'
|
it_behaves_like 'a validation without errors'
|
||||||
end
|
end
|
||||||
|
@ -147,7 +147,7 @@ RSpec.describe ::ObjectManager::Attribute::Validation::Required do
|
||||||
context 'when action is edit' do
|
context 'when action is edit' do
|
||||||
|
|
||||||
let(:action) { 'edit' }
|
let(:action) { 'edit' }
|
||||||
let(:record) { create(:user) }
|
let(:record) { create(:ticket_article) }
|
||||||
|
|
||||||
it_behaves_like 'a validation without errors'
|
it_behaves_like 'a validation without errors'
|
||||||
end
|
end
|
||||||
|
|
|
@ -2045,4 +2045,42 @@ RSpec.describe 'Ticket zoom', type: :system do
|
||||||
expect_no_upload_and_text
|
expect_no_upload_and_text
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Unable to close tickets in certran cases if core workflow is used #3710', authenticated_as: :authenticate, db_strategy: :reset do
|
||||||
|
let!(:ticket) { create(:ticket, group: Group.find_by(name: 'Users')) }
|
||||||
|
let(:field_name) { SecureRandom.uuid }
|
||||||
|
let(:field) do
|
||||||
|
create :object_manager_attribute_text, name: field_name, display: field_name, screens: {
|
||||||
|
'edit' => {
|
||||||
|
'ticket.agent' => {
|
||||||
|
'shown' => false,
|
||||||
|
'required' => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ObjectManager::Attribute.migration_execute
|
||||||
|
end
|
||||||
|
let(:workflow) do
|
||||||
|
create(:core_workflow,
|
||||||
|
object: 'Ticket',
|
||||||
|
perform: { "ticket.#{field_name}" => { 'operator' => 'set_mandatory', 'set_mandatory' => 'true' } })
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate
|
||||||
|
field
|
||||||
|
workflow
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
visit "#ticket/zoom/#{ticket.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does save the ticket because the field is mandatory but hidden' do
|
||||||
|
admin = User.find_by(email: 'admin@example.com')
|
||||||
|
select admin.fullname, from: 'Owner'
|
||||||
|
find('.js-submit').click
|
||||||
|
expect(ticket.reload.owner_id).to eq(admin.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue