diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee index 08c447960..8e40c64f5 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee @@ -7,9 +7,9 @@ class App.UiElement.ticket_selector ticket: name: 'Ticket' model: 'Ticket' - #article: - # name: 'Article' - # model: 'TicketArticle' + article: + name: 'Article' + model: 'TicketArticle' customer: name: 'Customer' model: 'User' diff --git a/app/assets/javascripts/app/controllers/job.coffee b/app/assets/javascripts/app/controllers/job.coffee index 3d29dc0ee..a7fff60bf 100644 --- a/app/assets/javascripts/app/controllers/job.coffee +++ b/app/assets/javascripts/app/controllers/job.coffee @@ -23,7 +23,7 @@ class Index extends App.ControllerContent { name: 'New Scheduler', 'data-type': 'new', class: 'btn--success' } ] container: @el.closest('.content') - #large: true + large: true ) App.Config.set('Job', { prio: 3400, name: 'Scheduler', parent: '#manage', target: '#manage/job', controller: Index, role: ['Admin'] }, 'NavBarAdmin') diff --git a/app/assets/javascripts/app/controllers/trigger.coffee b/app/assets/javascripts/app/controllers/trigger.coffee index 251143ccf..b58841385 100644 --- a/app/assets/javascripts/app/controllers/trigger.coffee +++ b/app/assets/javascripts/app/controllers/trigger.coffee @@ -23,7 +23,7 @@ class Index extends App.ControllerContent { name: 'New Trigger', 'data-type': 'new', class: 'btn--success' } ] container: @el.closest('.content') - #large: true + large: true ) App.Config.set('Trigger', { prio: 3300, name: 'Trigger', parent: '#manage', target: '#manage/trigger', controller: Index, role: ['Admin'] }, 'NavBarAdmin') diff --git a/app/assets/javascripts/app/models/ticket_article.coffee b/app/assets/javascripts/app/models/ticket_article.coffee index 736a2b785..1eb27461f 100644 --- a/app/assets/javascripts/app/models/ticket_article.coffee +++ b/app/assets/javascripts/app/models/ticket_article.coffee @@ -3,19 +3,19 @@ class App.TicketArticle extends App.Model @extend Spine.Model.Ajax @url: @apiPath + '/ticket_articles' @configure_attributes = [ - { name: 'ticket_id', display: 'TicketID', null: false, readonly: 1, }, + { name: 'ticket_id', display: 'TicketID', null: false, readonly: 1, searchable: false }, { name: 'from', display: 'From', tag: 'input', type: 'text', limit: 100, null: false }, { name: 'to', display: 'To', tag: 'input', type: 'text', limit: 100, null: true }, { name: 'cc', display: 'Cc', tag: 'input', type: 'text', limit: 100, null: true }, { name: 'subject', display: 'Subject', tag: 'input', type: 'text', limit: 100, null: true }, - { name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: false }, + { name: 'body', display: 'Text', tag: 'textarea', rows: 5, limit: 100, null: false, searchable: false }, { name: 'type_id', display: 'Type', tag: 'select', multiple: false, null: false, relation: 'TicketArticleType', default: '' }, { name: 'sender_id', display: 'Sender', tag: 'select', multiple: false, null: false, relation: 'TicketArticleSender', default: '' }, { name: 'internal', display: 'Visibility', tag: 'radio', default: false, null: true, options: { true: 'internal', false: 'public' } }, { name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 }, - { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 }, - { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 }, - { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, + { name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1, searchable: false }, + { name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1, searchable: false }, + { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1, searchable: false }, ] uiUrl: -> diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 1caf3e1c6..67e297ef9 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -726,6 +726,7 @@ perform changes on ticket } # get subject + value['subject'].gsub!(/\#\{config\.(.+?)\}/, '<%= c "\\1", false %>') value['subject'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", false %>') subject = NotificationFactory::Mailer.template( templateInline: value['subject'], @@ -734,6 +735,7 @@ perform changes on ticket ) subject = subject_build(subject) + value['body'].gsub!(/\#\{config\.(.+?)\}/, '<%= c "\\1", true %>') value['body'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", true %>') body = NotificationFactory::Mailer.template( templateInline: value['body'], diff --git a/app/models/transaction/trigger.rb b/app/models/transaction/trigger.rb index d2dfb9f6d..d79f4389a 100644 --- a/app/models/transaction/trigger.rb +++ b/app/models/transaction/trigger.rb @@ -49,16 +49,33 @@ class Transaction::Trigger condition.delete('ticket.action') end + # check if selector is matching condition['ticket.id'] = { operator: 'is', value: ticket.id, } + if article + condition['article.id'] = { + operator: 'is', + value: article.id, + } + end + ticket_count, tickets = Ticket.selectors(condition, 1) next if ticket_count == 0 next if tickets.first.id != ticket.id + # check if min one article attribute is used + article_selector = false + trigger.condition.each do |key, _value| + (object_name, attribute) = key.split('.', 2) + next if object_name != 'article' + next if attribute == 'id' + article_selector = true + end + # check in min one attribute has changed - if @item[:type] == 'update' + if @item[:type] == 'update' && !article_selector match = false trigger.condition.each do |key, _value| (object_name, attribute) = key.split('.', 2) diff --git a/db/seeds.rb b/db/seeds.rb index b4a90f59b..f86b4592a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -3856,6 +3856,81 @@ Scheduler.create_or_update( created_by_id: 1, ) +Trigger.create_or_update( + name: 'auto reply (on new tickets)', + condition: { + 'ticket.action' => { + 'operator' => 'is', + 'value' => 'create', + }, + 'ticket.state_id' => { + 'operator' => 'is not', + 'value' => '4', + }, + 'article.type_id' => { + 'operator' => 'is', + 'value' => [ + Ticket::Article::Type.lookup(name: 'email').id, + Ticket::Article::Type.lookup(name: 'phone').id, + Ticket::Article::Type.lookup(name: 'web').id, + ], + }, + }, + perform: { + 'notification.email' => { + 'body' => '
Your request (#{config.ticket_hook}##{ticket.number}) has been received and will be reviewed by our support staff.
+
+
To provide additional information, please reply to this email or click on the following link: +#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id} +
+Zammad, your customer support system
', + 'recipient' => 'ticket_customer', + 'subject' => 'Thanks for your inquiry (#{ticket.title})', + }, + }, + active: true, + created_by_id: 1, + updated_by_id: 1, +) +Trigger.create_or_update( + name: 'auto reply (on follow up of tickets)', + condition: { + 'ticket.action' => { + 'operator' => 'is', + 'value' => 'update', + }, + 'article.sender_id' => { + 'operator' => 'is', + 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id, + }, + 'article.type_id' => { + 'operator' => 'is', + 'value' => [ + Ticket::Article::Type.lookup(name: 'email').id, + Ticket::Article::Type.lookup(name: 'phone').id, + Ticket::Article::Type.lookup(name: 'web').id, + ], + }, + }, + perform: { + 'notification.email' => { + 'body' => 'Your follow up for (#{config.ticket_hook}##{ticket.number}) has been received and will be reviewed by our support staff.
+
+
To provide additional information, please reply to this email or click on the following link: +#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id} +
+Zammad, your customer support system
', + 'recipient' => 'ticket_customer', + 'subject' => 'Thanks for your follow up (#{ticket.title})', + }, + }, + active: true, + created_by_id: 1, + updated_by_id: 1, +) + # reset primary key sequences if ActiveRecord::Base.connection_config[:adapter] == 'postgresql' ActiveRecord::Base.connection.tables.each do |t| diff --git a/test/unit/ticket_trigger_test.rb b/test/unit/ticket_trigger_test.rb index 3047073a6..f669ee791 100644 --- a/test/unit/ticket_trigger_test.rb +++ b/test/unit/ticket_trigger_test.rb @@ -369,12 +369,30 @@ class TicketTriggerTest < ActiveSupport::TestCase 'operator' => 'is', 'value' => 'create', }, + 'ticket.state_id' => { + 'operator' => 'is not', + 'value' => '4', + }, + 'article.type_id' => { + 'operator' => 'is', + 'value' => [ + Ticket::Article::Type.lookup(name: 'email').id, + Ticket::Article::Type.lookup(name: 'phone').id, + Ticket::Article::Type.lookup(name: 'web').id, + ], + }, }, perform: { 'notification.email' => { - 'body' => 'some textYour request (Ticket##{ticket.number}) has been received and will be reviewed by our support staff.
+
+
To provide additional information, please reply to this email or click on the following link: +#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id} +
+Zammad, your customer support system
', 'recipient' => 'ticket_customer', - 'subject' => 'Thanks for your inquiry (#{ticket.title})!', + 'subject' => 'Thanks for your inquiry (#{ticket.title})', }, }, disable_notification: true, @@ -384,6 +402,44 @@ class TicketTriggerTest < ActiveSupport::TestCase ) trigger2 = Trigger.create_or_update( + name: 'auto reply (on follow up of tickets)', + condition: { + 'ticket.action' => { + 'operator' => 'is', + 'value' => 'update', + }, + 'article.sender_id' => { + 'operator' => 'is', + 'value' => Ticket::Article::Sender.lookup(name: 'Customer').id, + }, + 'article.type_id' => { + 'operator' => 'is', + 'value' => [ + Ticket::Article::Type.lookup(name: 'email').id, + Ticket::Article::Type.lookup(name: 'phone').id, + Ticket::Article::Type.lookup(name: 'web').id, + ], + }, + }, + perform: { + 'notification.email' => { + 'body' => 'Your follow up for (#{config.ticket_hook}##{ticket.number}) has been received and will be reviewed by our support staff.
+
+
To provide additional information, please reply to this email or click on the following link: +#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id} +
+Zammad, your customer support system
', + 'recipient' => 'ticket_customer', + 'subject' => 'Thanks for your follow up (#{ticket.title})', + }, + }, + active: true, + created_by_id: 1, + updated_by_id: 1, + ) + + trigger3 = Trigger.create_or_update( name: 'not matching', condition: { 'ticket.action' => { @@ -408,80 +464,131 @@ class TicketTriggerTest < ActiveSupport::TestCase updated_by_id: 1, ) - # ticket #1 - ticket1 = Ticket.create( - title: 'test auto reply 1', - group: Group.lookup(name: 'Users'), - customer_id: customer1.id, - state: Ticket::State.lookup(name: 'new'), - priority: Ticket::Priority.lookup(name: '2 normal'), + # process mail without Precedence header + content = IO.binread('test/fixtures/ticket_trigger/mail1.box') + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, content) + + assert_equal('aaäöüßad asd', ticket_p.title) + assert_equal('Users', ticket_p.group.name) + assert_equal('new', ticket_p.state.name) + assert_equal(2, ticket_p.articles.count) + article_p = ticket_p.articles.last + assert_match('Thanks for your inquiry (aaäöüßad asd)', article_p.subject) + assert_match('Zammad