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 @@
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