"use strict"; /** * Created by andey on 19-08-2017. */ (function () { 'use strict'; angular.module('layoutConfigModule') .controller('StatusBarController', ['$scope', 'events', 'objectValueMapperService', 'fieldValidationModel', 'ticketModel', '$rootScope', '$modal', 'screenConfigurationModel', function ($scope, events, objectValueMapperService, fieldValidationModel, ticketModel, $rootScope, $modal, screenConfigurationModel) { var originalStatus, originalStatusReason; var selected = { status: null, statusReason: null, resolutionNote: null }, statusField = new FieldVO().build({ name: $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status', type: 'characterField', dataType: 'text', ootb: true, editable: true, readOnly: false }), validStatuses, originalTicket; if ($scope.data) { statusField = angular.copy($scope.data); } $scope.statusField = statusField; $scope.defaultResolutionNoteLength = 250; $scope.displayTruncatedText = false; $scope.isStatusDisabled = function () { return $scope.ticket.accessMappings.allEditAllowed === false || ($scope.ticket.type === EntityVO.TYPE_TASK ? $scope.ticket.accessMappings.fieldMappings.taskStatus === 'read' : $scope.ticket.accessMappings.fieldMappings.status === 'read'); }; $scope.isStatusReasonDisabled = function () { return $scope.ticket.accessMappings.allEditAllowed === false || ($scope.ticket.type === EntityVO.TYPE_TASK ? $scope.ticket.accessMappings.fieldMappings.taskStatusReason === 'read' : $scope.ticket.accessMappings.fieldMappings.statusReason === 'read'); }; $scope.isResolutionDisabled = function () { return $scope.ticket.accessMappings.fieldMappings.statusReason === 'read'; }; var statusReasonField = new FieldVO().build({ name: $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason', type: 'characterField', dataType: 'text', ootb: true }), resolutionNoteField = new FieldVO().build({ name: 'resolution', type: 'characterField', dataType: 'text', ootb: true }); $scope.statusReasonField = statusReasonField; function init() { selected.status = _.cloneDeep(_.find($scope.metadata.statuses, { name: $scope.ticket.status.value })); originalStatus = _.cloneDeep(selected.status); if (!_.isEmpty(selected.status)) { selected.statusReason = _.find(selected.status.statusReasons, { name: $scope.ticket.status.reason }); if ($scope.ticket.status.reason && !selected.statusReason) { var screenName = screenConfigurationModel.getScreenNameByTicketType($scope.ticket.type), screenPanels = screenConfigurationModel.screensCacheByName[screenName] ? screenConfigurationModel.screensCacheByName[screenName].panels : [], statusFieldFull, statusReasonFieldFull; _.forEach(screenPanels, function (panel) { statusFieldFull = _.findLast(panel.fields, { name: 'status' }); if (statusFieldFull) { return false; } }); statusReasonFieldFull = _.find(statusFieldFull.members, { name: statusReasonField.name }); selected.statusReason = _.find(statusReasonFieldFull.options, { name: $scope.ticket.status.reason }); } } else { selected.statusReason = null; } originalStatusReason = _.cloneDeep(selected.statusReason); selected.resolutionNote = $scope.ticket.resolution ? $scope.ticket.resolution : ''; selected.resolutionNoteLength = selected.resolutionNote ? selected.resolutionNote.length : 0; if (selected.resolutionNoteLength > $scope.defaultResolutionNoteLength) { $scope.displayTruncatedText = true; } if (selected.status && selected.status.invalidStatusTransitions && selected.status.invalidStatusTransitions.length) { $scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) { return ~_.indexOf(selected.status.invalidStatusTransitions, status.name) ? false : true; }); } else if (selected.status && selected.status.validKnowledgeTransitions) { if (selected.status.validKnowledgeTransitions.length) { $scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) { return _.find(selected.status.validKnowledgeTransitions, { validStatus: status.name }); }); } else { $scope.availableStatuses = []; } } else if ($scope.ticket.type === EntityVO.TYPE_CHANGE || (($scope.ticket.type === EntityVO.TYPE_PROBLEM || $scope.ticket.type === EntityVO.TYPE_KNOWNERROR) && !$scope.isDraft)) { ticketModel.getAvailableStatuses($scope.ticket.id, $scope.ticket.type).then(function (validStatuses) { $scope.availableStatuses = _.filter($scope.metadata.statuses, function (status) { return validStatuses.indexOf(status.name) !== -1; }); }); } else if ($scope.ticket.type === EntityVO.TYPE_RELEASE && !$scope.isDraft) { $scope.availableMilestoneStatuses = _.filter($scope.metadata.milestones, function (milestone) { return _.findIndex(validStatuses, { milestone: milestone.name }) !== -1; }); $scope.changeMileStone(selected.milestone, 'release'); } else { $scope.availableStatuses = $scope.metadata.statuses; } statusField.value = selected.status && selected.status.name; statusReasonField.value = selected.statusReason && selected.statusReason.name; resolutionNoteField.value = selected.resolutionNote; objectValueMapperService.addFields([statusField, statusReasonField, resolutionNoteField]); $scope.selected = selected; statusField.value = selected.status && selected.status.name; statusReasonField.value = selected.statusReason ? selected.statusReason.name : ''; resolutionNoteField.value = selected.resolutionNote || ''; if (selected.status && selected.status.name === 'Pending' && selected.status.statusReasons) { _.remove(selected.status.statusReasons, function (reason) { return reason.name === 'Pending Original Incident'; }); } } init(); $scope.loadMore = function () { $scope.selected.expanded = (_.isUndefined($scope.selected.expanded)) ? true : !$scope.selected.expanded; }; $scope.$watch('statusField.setValueFlag', function (value) { var status; if (value !== '#$#') { if (value) { status = _.find($scope.metadata.statuses, { name: value }); if (status) { $scope.changeStatus(status); } } $scope.statusField.setValueFlag = '#$#'; } }); $scope.$watch('statusReasonField.setValueFlag', function (value) { var statusReason; if (value !== '#$#') { if (value) { statusReason = _.find(selected.status.statusReasons, { name: value }); if (statusReason) { $scope.changeStatusReason(statusReason); } } $scope.statusReasonField.setValueFlag = '#$#'; } }); $scope.changeStatus = function (status) { selected.status = status; selected.statusReason = null; if ($scope.ticket.type && $scope.ticket.type === 'incident' && $scope.ticket.resolution === null && (selected.status.name !== 'Closed' && selected.status.name !== 'Resolved')) { selected.resolutionNote = ''; $scope.changeResolutionNote(); } var statusField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status'); statusField.value = selected.status.name; //set the status reason field value on status change, otherwise the expressions are not evaluated correctly var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason'); statusReasonField.value = selected.statusReason && selected.statusReason.name; var memberName = $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatus' : 'status'; $scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: statusField.name, memberName: memberName }); $scope.fixScheduledDates = $scope.ticket.type === 'change' && selected.status.name === 'Scheduled For Review' && (($scope.ticket.scheduledStartDate && $scope.ticket.scheduledStartDate.valueOf() <= $scope.ticket.earliestStartDate) || ($scope.ticket.scheduledEndDate && $scope.ticket.scheduledEndDate.valueOf() <= $scope.ticket.earliestStartDate)); if ($scope.ticket.type && $scope.ticket.type === 'change' && selected.status.name === 'Completed') { selected.statusReason = _.find(status.statusReasons, { name: 'Final Review Required' }); } if (selected.status && selected.status.name === 'Pending' && selected.status.statusReasons) { _.remove(selected.status.statusReasons, function (reason) { return reason.name === 'Pending Original Incident'; }); } }; $scope.changeStatusReason = function (statusReason) { selected.statusReason = statusReason; var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason'); statusReasonField.value = selected.statusReason.name; var memberName = $scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason'; $scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: statusReasonField.name, memberName: memberName }); }; $scope.changeResolutionNote = function () { var resolutionNoteField = objectValueMapperService.getFieldByName('resolution'); resolutionNoteField.value = selected.resolutionNote; $scope.$emit(events.WIDGET_VALUE_CHANGE, { fieldName: resolutionNoteField.name, memberName: 'resolution' }); }; $scope.needResolutionNote = function () { return ($scope.ticket.type === EntityVO.TYPE_INCIDENT) && (~[EntityVO.STATUS_CLOSED, EntityVO.STATUS_RESOLVED].indexOf(selected.status.name.toLowerCase()) || !_.isEmpty($scope.ticket.resolution)); }; $scope.isFieldRequired = function (fieldName) { if (fieldName === 'statusReason') { if ($scope.ticket.type === EntityVO.TYPE_INCIDENT || $scope.ticket.type === EntityVO.TYPE_CHANGE || $scope.ticket.type === EntityVO.TYPE_RELEASE || $scope.ticket.type === EntityVO.TYPE_PROBLEM || $scope.ticket.type === EntityVO.TYPE_TASK || $scope.ticket.type === EntityVO.TYPE_KNOWNERROR) { return fieldValidationModel.isFieldRequired($scope.ticket.type, $scope.selected.status.name, $scope.ticket.timing, fieldName); } else if ($scope.ticket.type === EntityVO.TYPE_WORKORDER || $scope.ticket.type === EntityVO.TYPE_ACTIVITY) { return false; } else { return true; } } //only show when moving from a status where it's not required to a status where it's required return fieldValidationModel.isFieldRequired($scope.ticket.type, $scope.ticket.status.value, $scope.ticket.timing, fieldName) && !fieldValidationModel.isFieldRequired($scope.ticket.type, originalTicket.status.value, $scope.ticket.timing, fieldName); }; $scope.switchState = function (direction, ticketType) { var currentStatusIndex, switchToState = {}, prevStatusIndex, nextStatusIndex; if (ticketType !== 'release') { currentStatusIndex = _.findIndex($scope.availableStatuses, function (status) { return status.index === $scope.selected.status.index; }); } else { currentStatusIndex = _.findIndex($scope.availableMilestoneStatuses, function (status) { return status.index === $scope.selected.milestone.index; }); } if (currentStatusIndex !== -1) { if (direction === 'prev') { if ((ticketType === 'change' || ticketType === 'problem') && $scope.availableStatuses[currentStatusIndex].name === 'Completed') { prevStatusIndex = currentStatusIndex !== 0 ? parseInt(currentStatusIndex - 2) : 0; } else { prevStatusIndex = currentStatusIndex !== 0 ? parseInt(currentStatusIndex - 1) : 0; } if (ticketType === 'release') { switchToState = $scope.availableMilestoneStatuses[prevStatusIndex] || {}; } else { switchToState = $scope.availableStatuses[prevStatusIndex] || {}; } } else if (direction === 'next') { if (((ticketType === 'change' && ($scope.availableStatuses[currentStatusIndex].name === 'Implementation In Progress' || $scope.availableStatuses[currentStatusIndex].name === 'Planning In Progress')) || ticketType === 'problem') && $scope.availableStatuses[currentStatusIndex + 1] && $scope.availableStatuses[currentStatusIndex + 1].name === 'Pending') { nextStatusIndex = currentStatusIndex !== $scope.availableStatuses.length - 1 ? parseInt(currentStatusIndex + 2) : $scope.availableStatuses.length - 1; } else { nextStatusIndex = currentStatusIndex !== $scope.availableStatuses.length - 1 ? parseInt(currentStatusIndex + 1) : $scope.availableStatuses.length - 1; } if (ticketType === 'release') { switchToState = $scope.availableMilestoneStatuses[nextStatusIndex] || {}; } else { switchToState = $scope.availableStatuses[nextStatusIndex] || {}; } } } if (ticketType !== 'release') { $scope.changeStatus(switchToState, ticketType); } else { selected.status = {}; $scope.changeMileStone(switchToState, ticketType); } }; $scope.clearStatusReason = function (item) { var statusReasonField = objectValueMapperService.getFieldByName($scope.ticket.type === EntityVO.TYPE_TASK ? 'taskStatusReason' : 'statusReason'); statusReasonField.value = ""; }; $scope.checkStatusSwitcherIsDisabled = function (type, ticketType) { var noSwitchStatuses = ['Pending', 'Cancelled', 'Closed', 'Rejected'], currentStatusIndex, nextStatusIndex, nextStatus; if (ticketType !== 'release') { currentStatusIndex = _.findIndex($scope.availableStatuses, function (status) { return status.index === $scope.selected.status.index; }); } else { currentStatusIndex = _.findIndex($scope.availableMilestoneStatuses, function (status) { return status.index === $scope.selected.milestone.index; }); } if (currentStatusIndex !== -1 && ticketType !== 'release') { if (type === 'prev') { return ((currentStatusIndex === 0) || noSwitchStatuses.indexOf($scope.selected.status.name) >= 0); } else if (type === 'next') { if (((ticketType === 'change' && ($scope.availableStatuses[currentStatusIndex].name === 'Implementation In Progress' || $scope.availableStatuses[currentStatusIndex].name === 'Planning In Progress')) || (ticketType === 'problem' || ticketType === 'knownerror')) && $scope.availableStatuses[currentStatusIndex + 1] && ($scope.availableStatuses[currentStatusIndex + 1].name === 'Pending' || $scope.availableStatuses[currentStatusIndex + 1].name === 'Cancelled')) { nextStatusIndex = parseInt(currentStatusIndex + 2); nextStatus = $scope.availableStatuses[nextStatusIndex] || {}; } else { nextStatusIndex = parseInt(currentStatusIndex + 1); nextStatus = $scope.availableStatuses[nextStatusIndex] || {}; } if ($scope.selected.status.name === 'Completed' && nextStatus.name === 'Closed') { return (noSwitchStatuses.indexOf($scope.selected.status.name) >= 0); } else { return (noSwitchStatuses.indexOf(nextStatus.name) >= 0 || noSwitchStatuses.indexOf($scope.selected.status.name) >= 0); } } } if (currentStatusIndex !== -1 && ticketType === 'release') { if (type === 'prev') { return (currentStatusIndex === 0); } else if (type === 'next') { nextStatusIndex = parseInt(currentStatusIndex + 1); if ($scope.availableMilestoneStatuses[nextStatusIndex] === undefined) { return true; } } } }; $scope.$on(events.TOGGLE_EDIT_MODE, handleToggleEditMode); $scope.$on(events.AFTER_SAVED_CHANGES, afterSaveChangesHandler); $scope.$on(events.DISCARD_CHANGES, handleDiscardChanges); var unbindRootScopeListener = $rootScope.$on(events.TICKET_TEMPLATE_UPDATED, function (e, value) { selected.status = value.selectedStatus; selected.statusReason = value.selectedStatusReason; statusField.value = value.selectedStatus.name; selected.resolutionNote = value.resolution; }); function handleToggleEditMode() { $scope.editMode = true; } function afterSaveChangesHandler() { $scope.editMode = false; originalStatus = _.cloneDeep(selected.status); originalStatusReason = _.cloneDeep(selected.statusReason); } function handleDiscardChanges() { $scope.editMode = false; selected.status = _.cloneDeep(originalStatus); selected.statusReason = _.cloneDeep(originalStatusReason); init(); } function checkIfValidDates() { var scheduledStartTime = $scope.ticket.scheduledStartDate.valueOf(), scheduledEndTime = $scope.ticket.scheduledEndDate.valueOf(); $scope.fixScheduledDates = $scope.ticket && $scope.ticket.type === 'change' && selected.status.name === 'Scheduled For Review' && (scheduledStartTime <= $scope.ticket.earliestStartDate || scheduledEndTime <= $scope.ticket.earliestStartDate); } $scope.$watch('ticket.scheduledStartDate', function () { if ($scope.ticket && $scope.ticket.type === 'change' && selected.status.name === 'Scheduled For Review' && $scope.ticket.scheduledStartDate) { checkIfValidDates(); } }); $scope.$watch('ticket.scheduledEndDate', function () { if ($scope.ticket && $scope.ticket.type === 'change' && selected.status.name === 'Scheduled For Review' && $scope.ticket.scheduledEndDate) { checkIfValidDates(); } }); $scope.editTicketStatus = function () { $scope.$emit(events.EDIT_STATUS_CLICK); }; $scope.$on('$destroy', function () { unbindRootScopeListener(); }); }]); })();