diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.coffee index f702b06b0..e196d002e 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.coffee @@ -663,7 +663,10 @@ class App.TicketZoom extends App.Controller ticketParams = @formParam(@$('.edit')) # validate ticket - ticket = App.Ticket.find(@ticket_id) + # we need to use the full ticket because + # the time accouting needs all attributes + # for condition check + ticket = App.Ticket.fullLocal(@ticket_id) # reset article - should not be resubmited on next ticket update ticket.article = undefined @@ -740,9 +743,9 @@ class App.TicketZoom extends App.Controller @submitPost(e, ticket) return - # verify if time accounting is active for ticket - if false + time_accounting_selector = @Config.get('time_accounting_selector') + if !App.Ticket.selector(ticket, time_accounting_selector['condition']) @submitPost(e, ticket) return diff --git a/app/assets/javascripts/app/controllers/time_accounting.coffee b/app/assets/javascripts/app/controllers/time_accounting.coffee index e81fa2c48..c7b34172c 100644 --- a/app/assets/javascripts/app/controllers/time_accounting.coffee +++ b/app/assets/javascripts/app/controllers/time_accounting.coffee @@ -5,6 +5,8 @@ class Index extends App.ControllerSubContent 'change .js-timeAccountingSetting input': 'setTimeAccounting' 'click .js-timePickerYear': 'setYear' 'click .js-timePickerMonth': 'setMonth' + 'click .js-timeAccountingFilter': 'setFilter' + 'click .js-timeAccountingFilterReset': 'resetFilter' elements: '.js-timeAccountingSetting input': 'timeAccountingSetting' @@ -103,10 +105,12 @@ class Index extends App.ControllerSubContent { name: 'condition', display: 'Conditions for effected objects', tag: 'ticket_selector', null: false, preview: false, action: false, hasChanged: false }, ] - new App.ControllerForm( + filter_params = App.Setting.get('time_accounting_selector') + @filter = new App.ControllerForm( el: @$('.js-selector') model: configure_attributes: configure_attributes, + params: filter_params autofocus: true ) @@ -128,6 +132,21 @@ class Index extends App.ControllerSubContent month: @month ) + setFilter: (e) => + e.preventDefault() + + # get form data + params = @formParam(@filter.form) + + # save filter settings + App.Setting.set('time_accounting_selector', params, notify: true) + + resetFilter: (e) -> + e.preventDefault() + + # save filter settings + App.Setting.set('time_accounting_selector', {}, notify: true) + setTimeAccounting: (e) => value = @timeAccountingSetting.prop('checked') App.Setting.set('time_accounting', value) diff --git a/app/assets/javascripts/app/lib/app_post/utils.coffee b/app/assets/javascripts/app/lib/app_post/utils.coffee index 5b3c1ace8..2539ff434 100644 --- a/app/assets/javascripts/app/lib/app_post/utils.coffee +++ b/app/assets/javascripts/app/lib/app_post/utils.coffee @@ -99,6 +99,9 @@ class App.Utils else '>' + @escapeRegExp: (str) -> + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&") + # htmlEscaped = App.Utils.htmlEscape(rawText) @htmlEscape: (ascii) -> return ascii if !ascii diff --git a/app/assets/javascripts/app/models/ticket.coffee b/app/assets/javascripts/app/models/ticket.coffee index af478516f..ac9d93df1 100644 --- a/app/assets/javascripts/app/models/ticket.coffee +++ b/app/assets/javascripts/app/models/ticket.coffee @@ -124,3 +124,103 @@ class App.Ticket extends App.Model # apply direct value changes else params.ticket[attributes[1]] = content.value + + # check if selector is matching + @selector: (ticket, selector) -> + return true if _.isEmpty(selector) + + for objectAttribute, condition of selector + [objectName, attributeName] = objectAttribute.split('.') + + # there is no article.subject so we take the title instead + if objectAttribute == 'article.subject' && !ticket['article']['subject'] + objectName = 'ticket' + attributeName = 'title' + + # for new articles there is no created_by_id so we set the current user + # if no id is given + if objectAttribute == 'article.created_by_id' && !ticket['article']['created_by_id'] + ticket['article']['created_by_id'] = App.Session.get('id') + + if objectName == 'ticket' + object = ticket + else + object = ticket[objectName] || {} + + return false if !@_selectorMatch(object, objectName, attributeName, condition) + + return true + + @_selectorConditionDate: (condition, operator) -> + return if operator != '+' && operator != '-' + + conditionValue = new Date() + if condition['range'] == 'minute' + conditionValue.setTime( eval( conditionValue.getTime() + operator + 60 * 1000 ) ) + else if condition['range'] == 'hour' + conditionValue.setTime( eval( conditionValue.getTime() + operator + 60 * 60 * 1000 ) ) + else if condition['range'] == 'day' + conditionValue.setTime( eval( conditionValue.getTime() + operator + 60 * 60 * 24 * 1000 ) ) + else if condition['range'] == 'month' + conditionValue.setTime( eval( conditionValue.getTime() + operator + 60 * 60 * 30 * 1000 ) ) + else if condition['range'] == 'year' + conditionValue.setTime( eval( conditionValue.getTime() + operator + 60 * 60 * 365 * 1000 ) ) + + conditionValue + + @_selectorMatch: (object, objectName, attributeName, condition) -> + conditionValue = condition.value + conditionValue = '' if conditionValue == undefined + objectValue = object[attributeName] + objectValue = '' if objectValue == undefined + + # take care about pre conditions + if condition['pre_condition'] + [conditionType, conditionKey] = condition['pre_condition'].split('.') + + if conditionType == 'current_user' + conditionValue = App.Session.get(conditionKey) + else if condition['pre_condition'] == 'not_set' + conditionValue = '' + + # prepare regex for contains conditions + contains_regex = new RegExp(App.Utils.escapeRegExp(conditionValue.toString()), 'i') + + # move value to array if it is not already + if !_.isArray(objectValue) + objectValue = [objectValue] + # move value to array if it is not already + if !_.isArray(conditionValue) + conditionValue = [conditionValue] + + result = false + for loopObjectKey, loopObjectValue of objectValue + for loopConditionKey, loopConditionValue of conditionValue + if condition.operator == 'contains' + result = true if objectValue.toString().match(contains_regex) + else if condition.operator == 'contains not' + result = true if !objectValue.toString().match(contains_regex) + else if condition.operator == 'is' + result = true if objectValue.toString().trim().toLowerCase() is loopConditionValue.toString().trim().toLowerCase() + else if condition.operator == 'is not' + result = true if objectValue.toString().trim().toLowerCase() isnt loopConditionValue.toString().trim().toLowerCase() + else if condition.operator == 'after (absolute)' + result = true if new Date(objectValue.toString()) > new Date(loopConditionValue.toString()) + else if condition.operator == 'before (absolute)' + result = true if new Date(objectValue.toString()) < new Date(loopConditionValue.toString()) + else if condition.operator == 'before (relative)' + loopConditionValue = @_selectorConditionDate(condition, '-') + result = true if new Date(objectValue.toString()) < new Date(loopConditionValue.toString()) + else if condition.operator == 'within last (relative)' + loopConditionValue = @_selectorConditionDate(condition, '-') + result = true if new Date(objectValue.toString()) < new Date() && new Date(objectValue.toString()) > new Date(loopConditionValue.toString()) + else if condition.operator == 'after (relative)' + loopConditionValue = @_selectorConditionDate(condition, '+') + result = true if new Date(objectValue.toString()) > new Date(loopConditionValue.toString()) + else if condition.operator == 'within next (relative)' + loopConditionValue = @_selectorConditionDate(condition, '+') + result = true if new Date(objectValue.toString()) > new Date() && new Date(objectValue.toString()) < new Date(loopConditionValue.toString()) + else + throw "Unknown operator: #{condition.operator}" + + result diff --git a/app/assets/javascripts/app/views/time_accounting/index.jst.eco b/app/assets/javascripts/app/views/time_accounting/index.jst.eco index fb25f4d8c..c4f988651 100644 --- a/app/assets/javascripts/app/views/time_accounting/index.jst.eco +++ b/app/assets/javascripts/app/views/time_accounting/index.jst.eco @@ -15,6 +15,8 @@

<%- @T('Enable time accounting for following matching tickets.') %>

+ +
diff --git a/app/views/tests/ticket_selector.html.erb b/app/views/tests/ticket_selector.html.erb new file mode 100644 index 000000000..36f67335f --- /dev/null +++ b/app/views/tests/ticket_selector.html.erb @@ -0,0 +1,15 @@ + + + + + + + + + +
diff --git a/config/routes/test.rb b/config/routes/test.rb index 56730879f..4298d13da 100644 --- a/config/routes/test.rb +++ b/config/routes/test.rb @@ -14,6 +14,7 @@ Zammad::Application.routes.draw do match '/tests_form_searchable_select', to: 'tests#form_searchable_select', via: :get match '/tests_table', to: 'tests#table', via: :get match '/tests_html_utils', to: 'tests#html_utils', via: :get + match '/tests_ticket_selector', to: 'tests#ticket_selector', via: :get match '/tests_taskbar', to: 'tests#taskbar', via: :get match '/tests/wait/:sec', to: 'tests#wait', via: :get match '/tests/unprocessable_entity', to: 'tests#error_unprocessable_entity', via: :get diff --git a/public/assets/tests/ticket_selector.js b/public/assets/tests/ticket_selector.js new file mode 100644 index 000000000..e9783afba --- /dev/null +++ b/public/assets/tests/ticket_selector.js @@ -0,0 +1,962 @@ +window.onload = function() { + + var ticketData = { + "number": "72008", + "title": "asdfasdf", + "group_id": 1, + "owner_id": 6, + "updated_by_id": 6, + "created_by_id": 6, + "customer_id": 6, + "state_id": 4, + "priority_id": 2, + "created_at": "2017-02-09T09:16:56.192Z", + "updated_at": "2017-02-09T09:16:56.192Z", + "pending_time": "2017-02-09T09:16:56.192Z", + "aaaaa": "1234568791", + "anrede": "Herr", + "asdf": "", + "organization_id": 6, + "organization": { + "name": "harald test gmbh", + "domain": "www.harald-ist-cool.de", + "shared": true, + "note": "
harald test gmbh
", + "member_ids": [ + 6, + 2 + ], + "active": true, + "created_at": "2017-02-09T09:16:56.192Z", + "updated_at": "2017-02-09T09:16:56.192Z", + "domain_assignment": false, + "updated_by_id": 6, + "created_by_id": 6, + "id": 6 + }, + "group": { + "name": "Users", + "assignment_timeout": null, + "follow_up_possible": "reject", + "follow_up_assignment": true, + "email_address_id": 1, + "signature_id": 1, + "note": "Standard Group/Pool for Tickets.", + "active": true, + "updated_at": "2017-01-18T13:45:30.528Z", + "id": 1 + }, + "owner": { + "login": "-", + "firstname": "-", + "lastname": "", + "email": "", + "web": "", + "password": "", + "phone": "", + "fax": "", + "mobile": "", + "street": "", + "zip": "", + "city": "", + "country": "", + "organization_id": null, + "department": "", + "note": "", + "role_ids": [], + "group_ids": [], + "active": false, + "updated_at": "2016-08-02T14:25:24.053Z", + "address": "", + "vip": false, + "anrede": null, + "asdf": null, + "id": 1 + }, + "state": { + "name": "closed", + "note": null, + "active": true, + "id": 4 + }, + "priority": { + "name": "2 normal", + "note": null, + "active": true, + "updated_at": "2016-08-02T14:25:24.677Z", + "id": 2 + }, + "article": { + "from": "Test Master Agent", + "to": "agent1@example.com", + "cc": "agent1+cc@example.com", + "body": "asdfasdfasdf

Test Master Agent

--
Super Support - Waterford Business Park
5201 Blue Lagoon Drive - 8th Floor & 9th Floor - Miami, 33126 USA
Email: hot@example.com - Web: http://www.example.com/
--
", + "content_type": "text/html", + "ticket_id": "2", + "type_id": 1, + "sender_id": 1, + "internal": false, + "in_reply_to": "<20170217100622.2.152971@zammad.example.com>", + "form_id": "326044216" + }, + "customer": { + "login": "hc@zammad.com", + "firstname": "Harald", + "lastname": "Customer", + "email": "hc@zammad.com", + "web": "zammad.com", + "password": "", + "phone": "1234567894", + "fax": "", + "mobile": "", + "street": "", + "zip": "", + "city": "", + "country": "", + "organization_id": 6, + "created_by_id": 6, + "updated_by_id": 6, + "department": "", + "note": "", + "role_ids": [ + 3 + ], + "group_ids": [], + "active": true, + "created_at": "2017-02-09T09:16:56.192Z", + "updated_at": "2017-02-09T09:16:56.192Z", + "address": "Walter-Gropius-Straße 17, 80807 München, Germany", + "web": "www.harald-ist-cool.de", + "vip": false, + "id": 434 + }, + "escalation_at": "2017-02-09T09:16:56.192Z", + "last_contact_agent_at": "2017-02-09T09:16:56.192Z", + "last_contact_agent_at": "2017-02-09T09:16:56.192Z", + "last_contact_at": "2017-02-09T09:16:56.192Z", + "last_contact_customer_at": "2017-02-09T09:16:56.192Z", + "first_response_at": "2017-02-09T09:16:56.192Z", + "close_at": "2017-02-09T09:16:56.192Z", + "id": 8 + }; + + var sessionData = { + "login": "hh@zammad.com", + "firstname": "Harald", + "lastname": "Habebe", + "email": "hh@zammad.com", + "web": "", + "password": "", + "phone": "", + "fax": "", + "mobile": "", + "street": "", + "zip": "", + "city": "", + "country": "", + "organization_id": 6, + "department": "", + "note": "", + "role_ids": [ + 1, + 2, + 5, + 6, + 4 + ], + "group_ids": [ + 1 + ], + "active": true, + "updated_at": "2017-02-09T09:17:04.770Z", + "address": "", + "vip": false, + "anrede": "", + "asdf": "", + "id": 6 + }; + + /* + * ------------------------------------------------------------------------ + * Test functions + * ------------------------------------------------------------------------ + */ + + var testContains = function (key, value, ticket) { + setting = { + "condition": { + [key]: { + "operator": "contains", + "value": value + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "contains not", + "value": value + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + }; + + var testIs = function (key, value, ticket) { + setting = { + "condition": { + [key]: { + "operator": "is", + "value": value + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "value": value + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + }; + + var testPreConditionUser = function (key, specificValue, ticket, session) { + App.Session.set(sessionData); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "current_user.id", + "value": "", + "value_completion": "" + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "current_user.id", + "value": "", + "value_completion": "" + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "not_set", + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "not_set", + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + }; + + var testPreConditionOrganization = function (key, specificValue, ticket, session) { + App.Session.set(sessionData); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "current_user.organization_id", + "value": "", + "value_completion": "" + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "current_user.organization_id", + "value": "", + "value_completion": "" + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "specific", + "value": specificValue, + "value_completion": "Nicole Braun " + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is", + "pre_condition": "not_set", + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + setting = { + "condition": { + [key]: { + "operator": "is not", + "pre_condition": "not_set", + } + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + }; + + var testTime = function (key, value, ticket) { + valueDate = new Date(value); + compareDate = new Date( valueDate.setHours( valueDate.getHours() - 1 ) ).toISOString(); + setting = { + "condition": { + [key]: { + "operator": "after (absolute)", + "value": compareDate + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + valueDate = new Date(value); + compareDate = new Date( valueDate.setHours( valueDate.getHours() + 1 ) ).toISOString(); + setting = { + "condition": { + [key]: { + "operator": "after (absolute)", + "value": compareDate + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + valueDate = new Date(value); + compareDate = new Date( valueDate.setHours( valueDate.getHours() - 1 ) ).toISOString(); + setting = { + "condition": { + [key]: { + "operator": "before (absolute)", + "value": compareDate + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, false, result); + + valueDate = new Date(value); + compareDate = new Date( valueDate.setHours( valueDate.getHours() + 1 ) ).toISOString(); + setting = { + "condition": { + [key]: { + "operator": "before (absolute)", + "value": compareDate + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + + valueDate = new Date(value); + compareDate = new Date( valueDate.setHours( valueDate.getHours() + 2 ) ).toISOString(); + setting = { + "condition": { + [key]: { + "operator": "before (relative)", + "value": 1, + "range": "hour" + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, true, result); + }; + + var testTimeBeforeRelative = function (key, value, range, expectedResult, ticket) { + setting = { + "condition": { + [key]: { + "operator": "before (relative)", + "value": value, + "range": range + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, expectedResult, result); + }; + + var testTimeAfterRelative = function (key, value, range, expectedResult, ticket) { + setting = { + "condition": { + [key]: { + "operator": "after (relative)", + "value": value, + "range": range + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, expectedResult, result); + }; + + var testTimeWithinNextRelative = function (key, value, range, expectedResult, ticket) { + setting = { + "condition": { + [key]: { + "operator": "within next (relative)", + "value": value, + "range": range + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, expectedResult, result); + }; + + var testTimeWithinLastRelative = function (key, value, range, expectedResult, ticket) { + setting = { + "condition": { + [key]: { + "operator": "within last (relative)", + "value": value, + "range": range + }, + } + }; + result = App.Ticket.selector(ticket, setting['condition'] ); + equal(result, expectedResult, result); + }; + + /* + * ------------------------------------------------------------------------ + * Field tests + * ------------------------------------------------------------------------ + */ + + test("ticket number", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('ticket.number', '72', ticket); + }); + + test("ticket title", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('ticket.title', 'asd', ticket); + }); + + test("ticket customer_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + App.Session.set(sessionData); + + testPreConditionUser('ticket.customer_id', '6', ticket, sessionData); + }); + + test("ticket organization_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('ticket.organization_id', '6', ticket, sessionData); + }); + + test("ticket group_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('ticket.group_id', ['1'], ticket, sessionData); + }); + + test("ticket owner_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + App.Session.set(sessionData); + + testPreConditionUser('ticket.owner_id', '6', ticket, sessionData); + }); + + test("ticket state_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('ticket.state_id', ['4'], ticket, sessionData); + }); + + test("ticket pending_time", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.pending_time', ticket.pending_time, ticket); + + // ------------------------- + // BEFORE TIME + // ------------------------- + + // hour + ticket.pending_time = new Date().toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'hour', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'hour', true, ticket); + + // day + ticket.pending_time = new Date().toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'day', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() - 60 * 60 * 48 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'day', true, ticket); + + // year + ticket.pending_time = new Date().toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'year', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() - 60 * 60 * 365 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeBeforeRelative('ticket.pending_time', 1, 'year', true, ticket); + + // ------------------------- + // AFTER TIME + // ------------------------- + + // hour + ticket.pending_time = new Date().toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'hour', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'hour', true, ticket); + + // day + ticket.pending_time = new Date().toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'day', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() + 60 * 60 * 48 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'day', true, ticket); + + // year + ticket.pending_time = new Date().toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'year', false, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() + 60 * 60 * 365 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeAfterRelative('ticket.pending_time', 1, 'year', true, ticket); + + + // ------------------------- + // WITHIN LAST TIME + // ------------------------- + + // hour + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() - 60 * 60 * 0.5 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeWithinLastRelative('ticket.pending_time', 1, 'hour', true, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeWithinLastRelative('ticket.pending_time', 1, 'hour', false, ticket); + + // ------------------------- + // WITHIN NEXT TIME + // ------------------------- + + // hour + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() + 60 * 60 * 0.5 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeWithinNextRelative('ticket.pending_time', 1, 'hour', true, ticket); + + compareDate = new Date(); + compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000 ); + ticket.pending_time = compareDate.toISOString(); + testTimeWithinNextRelative('ticket.pending_time', 1, 'hour', false, ticket); + }); + + test("ticket priority_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('ticket.priority_id', ['2'], ticket, sessionData); + }); + + test("ticket escalation_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.escalation_at', ticket.escalation_at, ticket); + }); + + test("ticket last_contact_agent_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.last_contact_agent_at', ticket.last_contact_agent_at, ticket); + }); + + test("ticket last_contact_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.last_contact_at', ticket.last_contact_at, ticket); + }); + + test("ticket last_contact_customer_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.last_contact_customer_at', ticket.last_contact_customer_at, ticket); + }); + + test("ticket first_response_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.first_response_at', ticket.first_response_at, ticket); + }); + + test("ticket close_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.close_at', ticket.close_at, ticket); + }); + + test("ticket created_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + App.Session.set(sessionData); + + testPreConditionUser('ticket.created_by_id', '6', ticket, sessionData); + }); + + test("ticket created_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.created_at', ticket.created_at, ticket); + }); + + test("ticket updated_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('ticket.updated_at', ticket.updated_at, ticket); + }); + + test("ticket updated_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + App.Session.set(sessionData); + + testPreConditionUser('ticket.updated_by_id', '6', ticket, sessionData); + }); + + test("article from", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('article.from', 'Master', ticket); + }); + + test("article to", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('article.to', 'agent1', ticket); + }); + + test("article cc", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('article.cc', 'agent1+cc', ticket); + }); + + test("article subject", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('article.subject', 'asdf', ticket); + }); + + test("article type_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('article.type_id', ['1'], ticket); + }); + + test("article sender_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('article.sender_id', ['1'], ticket); + }); + + test("article internal", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('article.internal', ['false'], ticket); + }); + + test("article created_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('article.created_by_id', '6', ticket, sessionData); + }); + + test("customer login", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.login', 'hc', ticket); + }); + + test("customer firstname", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.firstname', 'Harald', ticket); + }); + + test("customer lastname", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.lastname', 'Customer', ticket); + }); + + test("customer email", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.email', 'hc', ticket); + }); + + test("customer organization_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionOrganization('customer.organization_id', '6', ticket, sessionData); + }); + + test("customer created_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('customer.created_by_id', '6', ticket, sessionData); + }); + + test("customer created_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('customer.created_at', ticket.customer.created_at, ticket); + }); + + test("customer updated_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('customer.updated_by_id', '6', ticket, sessionData); + }); + + test("customer missing_field", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.missing_field', '', ticket); + }); + + test("customer web", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('customer.web', 'cool', ticket); + }); + + test("organization name", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('organization.name', 'gmbh', ticket); + }); + + test("organization shared", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('organization.shared', true, ticket); + }); + + test("organization created_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('organization.created_by_id', 6, ticket); + }); + + test("organization updated_by_id", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testPreConditionUser('organization.updated_by_id', 6, ticket); + }); + + test("organization created_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('organization.created_at', ticket.organization.created_at, ticket); + }); + + test("organization updated_at", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testTime('organization.updated_at', ticket.organization.updated_at, ticket); + }); + + test("organization domain_assignment", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testIs('organization.domain_assignment', false, ticket); + }); + + test("organization domain", function() { + ticket = new App.Ticket(); + ticket.load(ticketData); + + testContains('organization.domain', 'cool', ticket); + }); +} \ No newline at end of file diff --git a/test/browser/aab_unit_test.rb b/test/browser/aab_unit_test.rb index f8130f8e5..c0bd30301 100644 --- a/test/browser/aab_unit_test.rb +++ b/test/browser/aab_unit_test.rb @@ -34,6 +34,13 @@ class AAbUnitTest < TestCase css: '.result .failed', value: '0', ) + + location(url: browser_url + '/tests_ticket_selector') + sleep 8 + match( + css: '.result .failed', + value: '0', + ) end def test_form