ObjectiveManagement = function() { let instance = this; instance.objectiveEditor = null; } ObjectiveManagement.prototype.constructor = ObjectiveManagement ObjectiveManagement.prototype.element = function() { let instance = this; if( instance.rootElement ) return instance.rootElement; instance.rootElement = $("
").addClass( "ObjectiveManagement" ).css( { "height" : "100%" } ); instance.multiView = $("
").css( { "height" : "100%" } ).dxMultiView({ swipeEnabled : false, deferRendering : false, items : [ { template : function() { instance.objectiveList = new ObjectiveList( { stateKey : "ObjectManagement.ObjectiveList", openObjective : function( objective, options ) { instance.openObjective( objective, options ); }, createObjective : function( createData ) { instance.createObjective( createData ); } }); return instance.objectiveList.element(); } }, { template : function() { let container = $("
").dxBox( { height : "100%", direction : "col", items : [ { baseSize : 30, template : function() { instance.toolbarSocket = $("
" ); return instance.toolbarSocket; } }, { ratio : 1, template : function() { instance.detailSocket = $("
").css( "height", "100%" ).text( "Details" ); return instance.detailSocket; } } ] }); // $("
").dxToolbar( { // items : [ // { // location : "after", // widget : "dxButton", // options : { // text : "Back to List", // onClick : function( e ) { // instance.multiView.option( "selectedIndex", 0 ); // } // } // } // ] // }).appendTo( container ); // instance.detailSocket = $("
").css( "height", "100%" ).text( "Details" ); // container.append( instance.detailSocket ); return container; } }, { template : function() { let container = $("
").dxBox( { height : "100%", direction : "col", items : [ { baseSize : 30, template : function() { instance.subObjectiveToolbarSocket = $("
" ); return instance.subObjectiveToolbarSocket; } }, { ratio : 1, template : function() { instance.subObjectiveSocket = $("
").css( "height", "100%" ).text( "Sub-Objective" ); return instance.subObjectiveSocket; } } ] }); return container; } } ], onSelectionChanged : function( e ) { let selectedIndex = e.component.option( "selectedIndex" ); if( selectedIndex == 0 ) { if( instance.refreshList ) { instance.refreshList = false; instance.objectiveList.refresh(); } } } }).dxMultiView( "instance" ); instance.rootElement.append( instance.multiView.element() ); return instance.rootElement; } ObjectiveManagement.prototype.updateToolbar = function( objective ) { let instance = this; let toolbarItems = []; if( objective && objective.objectiveId ) { if( ! objective.parentObjectiveId ) { // top level objective toolbar items toolbarItems.push( { location : "before", widget : "dxButton", options : { icon : "copy", hint : "Copy this objective", onClick : function( e ) { instance.copyObjective( objective ).done( function( copyResult ) { instance.openObjective( { objectiveId : copyResult.objectiveId } ) }); } } }, { location : "before", widget : "dxButton", options : { icon : "trash", hint : "Delete this objective", onClick : function( e ) { instance.deleteObjective( objective ).done( function() { instance.showList( true ); }); } } }, { location : "before", widget : "dxButton", options : { icon : "email", hint : "Email Notifications", onClick : function( e ) { instance.notifyObjective( objective ); } } } ) // // for testing only // if( objective.objLevel == "P" ) { // toolbarItems.push( { // location : "before", // widget : "dxButton", // options : { // icon : "plus", // text : "New Sub-Objective", // onClick : function( e ) { // instance.createSubObjective( objective ); // } // } // }) // } } else { // sub-objective toolbar items toolbarItems.push( { location : "before", widget : "dxButton", options : { icon : "trash", hint : "Delete this objective", onClick : function( e ) { instance.deleteObjective( objective ).done( function() { instance.showList( true ); }); } } }, { location : "before", widget : "dxButton", options : { icon : "email", hint : "Email Notifications", onClick : function( e ) { instance.notifyObjective( objective ); } } } ) } } else { // new objective toolbar items } toolbarItems.push( { location : "after", widget : "dxButton", options : { text : "Back to List", onClick : function( e ) { instance.showList(); } } } ) $("
").dxToolbar( { items : toolbarItems }).appendTo( instance.toolbarSocket.empty() ); } ObjectiveManagement.prototype.updateSubObjectiveToolbar = function( objective ) { let instance = this; let toolbarItems = []; // sub-objective toolbar items toolbarItems.push( { location : "before", widget : "dxButton", options : { icon : "trash", hint : "Delete this objective", onClick : function( e ) { instance.deleteObjective( objective ).done( function() { instance.multiView.option( "selectedIndex", 1 ); }); } } }, { location : "before", widget : "dxButton", options : { icon : "email", hint : "Email Notifications", onClick : function( e ) { instance.notifyObjective( objective ); } } } ) toolbarItems.push( { location : "after", widget : "dxButton", options : { text : "Back to Enterprise", onClick : function( e ) { instance.multiView.option( "selectedIndex", 1 ); } } } ) $("
").dxToolbar( { items : toolbarItems }).appendTo( instance.subObjectiveToolbarSocket.empty() ); } ObjectiveManagement.prototype.showList = function( refresh ) { let instance = this; if( refresh ) { instance.refreshList = true; } instance.multiView.option( "selectedIndex", 0 ); } ObjectiveManagement.prototype.deleteObjective = function( objective ) { let instance = this; let deletePromise = $.Deferred(); let confirmationMessage = `Delete '${objective.objName}'`; if( objective.objLevel == "P" ) { confirmationMessage = `${confirmationMessage} and all of it's sub-objectives` } confirmationMessage = confirmationMessage + '?'; if( confirm( confirmationMessage )) { let loadPanel = $("
").dxLoadPanel( { message : "Deleting...", onHidden : function( e ) { e.component.element().remove(); } }).appendTo( $("body") ).dxLoadPanel( "instance" ); loadPanel.show(); Fse.Ajax.performAction( { object : "BOM.deleteObjective", data : { objectiveId : objective.objectiveId } } ).done( function( deleteResult ) { loadPanel.hide(); $("
").dxToast( { onHidden : function( e ) { e.component.element().remove(); }, message : "Objective deleted.", displayTime : 2000, type : "success" }).appendTo( $("body") ).dxToast( "show" ); deletePromise.resolve(); }) } else { deletePromise.reject(); } return deletePromise; } ObjectiveManagement.prototype.copyObjective = function( objective ) { let copyPromise = $.Deferred(); let copyForm; let copyFormItems = []; copyFormItems.push( { dataField : "objName", label : { text : "New Name" }, isRequired : true, colSpan : 2 }, { dataField : "bundleId", label : { text : "New Group" }, colSpan : 2, editorType : "dxSelectBox", editorOptions : { dataSource : Fse.Data.newDataSource( { object : "BOM.objectiveBundles", key : "bundleId", paginate : false } ), searchExpr : "bundleName", searchEnabled : true, searchMode : "contains", displayExpr : "bundleName", valueExpr : "bundleId", placeholder : "Select Group...", showClearButton : true, buttons : [ "dropDown", { name : "editBundles", options : { icon : "edit", visible : Fse.Portal.checkPermission( "BCRMObjectiveManagementAdmin" ), onClick : function( e ) { let editor = copyForm.getEditor( "bundleId" ) ObjectiveManagement.editBundles( editor.option( "value" ) ).done( function( changesMade ) { if( changesMade ) { editor.getDataSource().load(); } }); } } } ] } } ); if( objective.objOwnerType == "MFR" ) { copyFormItems.push( { dataField : "objOwnerId", label : { text : "New Owner" }, colSpan : 2, editorType : "dxSelectBox", isRequired : true, editorOptions : { dataSource : Fse.Data.newDataSource( { object : "PRD.manufacturers", keyField : "mfr_id" } ), searchExpr : "mfr_name", searchMode : "contains", searchEnabled : true, displayExpr : "mfr_name", valueExpr : "mfr_id", placehoder : "Select Manufacturer" } } ); } if( objective.objLevel == "P" ) { copyFormItems.push( { dataField : "copySubObjectives", label : { text : "Copy Sub-Objectives" }, colSpan : 2, editorType : "dxSwitch"} ); } copyFormItems.push( { dataField : "copyStaff", label : { text : "Copy Staff" }, colSpan : 2, editorType : "dxSwitch"}, { dataField : "copyTargets", label : { text : "Copy Targets" }, colSpan : 1, editorType : "dxSwitch"}, { dataField : "uncompletedTargetsOnly", label : { text : "Uncompleted Targets Only" }, colSpan : 1, editorType : "dxCheckBox" }, { dataField : "copyProducts", label : { text : "Copy Products" }, colSpan : 2, editorType : "dxSwitch"}, { dataField : "copyFiles", label : { text : "Copy Files" }, colSpan : 2, editorType : "dxSwitch"} ) let copyPopup = $("
").dxPopup( { title : `Copy Objective - ${objective.objName}`, width : 600, height : "auto", toolbarItems : [ { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "Cancel", onClick : function( e ) { copyPopup.hide(); } } }, { toolbar : "bottom", location : "after", widget : "dxButton", options : { type : "default", text : "Copy", onClick : function( e ) { let vr = copyForm.validate(); if( ! vr.isValid ) return; let dataToSend = copyForm.option( "formData" ); let loadPanel = $("
").dxLoadPanel( { message : "Copying...", onHidden : function( e ) { e.component.element().remove(); } }).appendTo( $("body") ).dxLoadPanel( "instance" ); loadPanel.show(); Fse.Ajax.performAction( { object : "BOM.copyObjective", data : dataToSend } ).done( function( copyResult ) { if( copyResult.status ) { loadPanel.hide(); copyPopup.hide(); copyPromise.resolve( copyResult ); } }) } } } ], contentTemplate : function() { copyForm = $("
").dxForm( { colCount : 2, formData : { sourceObjectiveId : objective.objectiveId, objName : null, bundleId : objective.bundleId ? objective.bundleId : null, objOwnerId : objective.objOwnerId, copySubObjectives : true, copyProducts : true, copyStaff : true, copyFiles : true, copyTargets : true, uncompletedTargetsOnly : false, }, items : copyFormItems, onFieldDataChanged : function( e ) { let copyStaffField = e.component.getEditor( "copyStaff" ); let copyTargetsField = e.component.getEditor( "copyTargets" ); let uncompletedTargetsOnlyField = e.component.getEditor( "uncompletedTargetsOnly" ); if( e.dataField == "copySubObjectives" ) { if( e.value ) { copyStaffField.option( "disabled", false ); copyTargetsField.option( "disabled", false ); if( e.component.option( "formData").copyTargets ) { uncompletedTargetsOnlyField.option( "disabled", false ); } } else { copyStaffField.option( "disabled", true ); copyTargetsField.option( "disabled", true ); uncompletedTargetsOnlyField.option( "disabled", true ); e.component.updateData( { "copyStaff" : false, "copyTargets" : false, "uncompletedTargetsOnly" : false } ) } } if( e.dataField == "copyStaff" ) { if( e.value ) { copyTargetsField.option( "disabled", false ); if( e.component.option( "formData").copyTargets ) { uncompletedTargetsOnlyField.option( "disabled", false ); } } else { copyTargetsField.option( "disabled", true ); uncompletedTargetsOnlyField.option( "disabled", true ); e.component.updateData( { "copyTargets" : false, "uncompletedTargetsOnly" : false } ) } } if( e.dataField == "copyTargets" ) { if( e.value ) { uncompletedTargetsOnlyField.option( "disabled", false ); } else { uncompletedTargetsOnlyField.option( "disabled", true ); e.component.updateData( { "uncompletedTargetsOnly" : false } ) } } } }).dxForm( "instance" ); return copyForm.element(); }, onHidden : function( e ) { e.component.element().remove(); }, hideOnOutsideClick : true, onShown : function( e ) { copyForm.getEditor("objName").focus() } }).appendTo( $("body") ).dxPopup( "instance" ); copyPopup.show(); return copyPromise; } ObjectiveManagement.prototype.notifyObjective = function( objective ) { let customOptions = [{ dataField : "sendConfirmation" , text : "Send Confirmation", value : true }];; let toItems; if( objective.objLevel == "P" ) { toItems = [ { value : "staff", text : "Each Staff Member assigned to all Sub Objectives", title : "Each email will show Objective Name, Start Date, End Date, Sales Rep Name and Sales Rep Quota" }, { value : "manager", text : "Each Objective Manager assigned to all Sub Objectives", title : "Each email will show Objective Name, Start Date and End Date" }, { value : "specificstaff", text : "Selected Staff from the Sub Objectives", title : "Each email will show Objective Name, Start Date, End Date, Sales Rep Name and Sales Rep Quota", dataSourceLabel : "Sub-Objective Staff", dataSource : Fse.Data.newDataSource( { object : "BOM.objectiveStaff", key : "email", objectParams : { objectiveId : objective.objectiveId, includeSubObjectiveStaff : true }, map : function( item ) { item.type = "company"; return item; } }) } ]; } else { toItems = [ { value : "staff", text : "Each Staff Member assigned to this Objective", title : "Each email will show Objective Name, Start Date, End Date, Sales Rep Name and Sales Rep Quota" }, { value : "manager", text : "Each Objective Manager assigned to this Objectives", title : "Each email will show Objective Name, Start Date and End Date" }, { value : "specificstaff", text : "Selected Staff from this Objective", title : "Each email will show Objective Name, Start Date, End Date, Sales Rep Name and Sales Rep Quota", dataSourceLabel : "Sub-Objective Staff", dataSource : Fse.Data.newDataSource( { object : "BOM.objectiveStaff", key : "email", objectParams : { objectiveId : objective.objectiveId }, map : function( item ) { item.type = "company"; return item; } }) } ]; } let emailSender = new EmailSender( { title : "Send Objective Email Notification", subject : `New Objective Alert: ${objective.objName}`, customOptions : customOptions, toItems : toItems, prepareAjax : function( formData ) { let ajaxOptions = { method : "POST", url : Fse.Util.updateURL( $("link#PortalDocRootURL").attr( "href" ) + "/apps/BOM/index.cfm", { "mode" : "direct", "do" : "notifyObjective" } ), data : { objid : objective.objectiveId, notifyTo : formData.toOption, selectedStaff : formData.to ? formData.to : "", notifyFrom : formData.from, notifySubject : formData.subject, notifyMessage : formData.message, sendConfirmation : formData.customOption_sendConfirmation ? true : false } } return ajaxOptions } }) let notifyPromise = emailSender.show(); return notifyPromise; } ObjectiveManagement.prototype.createSubObjective = function( parentObjective ) { let instance = this; let form; let quotaLabel = `${parentObjective.quotaTypeName} Quota`; let popup = $("
").dxPopup( { title : "Create Sub-Objective", width : 600, height : "auto", onHidden : function( e ) { e.component.element().remove(); }, hideOnOutsideClick : true, contentTemplate : function() { form = $("
").dxForm( { formData : { objName : parentObjective.objName, objDescription : parentObjective.objDescription, parentObjectiveId : parentObjective.objectiveId, }, items : [ { dataField : "territoryId", label : { text : "Territory" }, isRequired : true, editorType : "dxSelectBox", editorOptions : { // dataSource : Fse.Data.newDataSource( { object : "TER.salesTerritories", keyField : "TerritoryID", filter : [ "localMarket", "=", 1 ] }), disabled : true, displayExpr : "territoryName", valueExpr : "TerritoryID", searchEnabled : true, showClearButton : false, placeholder : "Select Territory" } }, { dataField : "objName", label : { text : "Name" }, isRequired : true, editorOptions : { maxLength : 50 } }, { dataField : "objManagerId", label : { text : "Manager" }, editorType : "dxSelectBox", isRequired : true, editorOptions : { placeholder : "Select Manager...", searchEnabled : true, searchMode : "contains", searchExpr : "fullName", dataSource : Fse.Data.newDataSource( { object : "FSPRO.members", key : "fspro_userId" } ), displayExpr : "fullName", valueExpr : "fspro_userId" }}, { dataField : "objManager2Id", label : { text : "Manager #2" }, editorType : "dxSelectBox", isRequired : false, editorOptions : { showClearButton : true, placeholder : "Select Manager #2...", searchEnabled : true, searchMode : "contains", searchExpr : "fullName", dataSource : Fse.Data.newDataSource( { object : "FSPRO.members", key : "fspro_userId" } ), displayExpr : "fullName", valueExpr : "fspro_userId" }}, { dataField : "objManager3Id", label : { text : "Manager #3" }, editorType : "dxSelectBox", isRequired : false, editorOptions : { showClearButton : true, placeholder : "Select Manager #3...", searchEnabled : true, searchMode : "contains", searchExpr : "fullName", dataSource : Fse.Data.newDataSource( { object : "FSPRO.members", key : "fspro_userId" } ), displayExpr : "fullName", valueExpr : "fspro_userId" }}, { dataField : "totalQuota", label : { text : quotaLabel }, editorType : "dxNumberBox", isRequired : true, editorOptions : { minValue : 0, showSpinButtons : false } }, { dataField : "objDescription", label : { text : "Directions" }, isRequired : true, editorType : "dxTextArea", editorOptions : { maxLength : 500, height : "4.5em" } } ], onFieldDataChanged : function( e ) { if( e.dataField == "territoryId" ) { if( e.value ) { let territory = e.component.getEditor( "territoryId" ).option( "selectedItem" ); if( territory.primaryManager ) { let useInternalSalesId = Fse.Portal.getConfiguration( "BOM.defaultSubObjectiveNameSuffix") == "internalSalesId"; let suffix = territory.internalSalesId; if( ! useInternalSalesId ) { suffix = territory.shortTerritoryName; if( ! suffix ) { suffix = territory.territoryName; } } e.component.updateData( { "objName" : `${parentObjective.objName} - ${suffix}`, "objManagerId" : territory.primaryManager, }); } } } } }).dxForm( "instance" ); let existingChildObjectives = {}; let childObjectivesDataSource = Fse.Data.newDataSource( { object : "BOM.objectives", filter : [ "parentObjectiveId", "=", parentObjective.objectiveId ], paginate : false, key : "objectiveId" }); childObjectivesDataSource.load().done( function( childObjectives ) { childObjectives.forEach( function( co ) { existingChildObjectives[co.territoryId] = co; }) console.log( "Child Objectives", existingChildObjectives ); territoryFilter = [ "localMarket", "=", 1 ]; if( parentObjective.territoryPath ) { territoryFilter = [ [ "territoryPath", "startswith", parentObjective.territoryPath ], "and", territoryFilter ]; } let territoryDataSource = Fse.Data.newDataSource( { object : "TER.salesTerritories", key : "TerritoryID", filter : territoryFilter, paginate : false, map : function( data ) { data.disabled = existingChildObjectives[data.TerritoryID] ? true : false return data; } }); form.getEditor( "territoryId" ).option( { disabled : false, dataSource : territoryDataSource } ); }) return form.element(); }, toolbarItems : [ { toolbar : "bottom", location : "after", widget : "dxButton", options : { text : "Create", type : "default", onClick : function( e ) { let vr = form.validate(); if( ! vr.isValid ) return; Fse.Ajax.performAction( { object : "BOM.createSubObjective", data : form.option( "formData" ) } ).done( function( createResult ) { console.log( "BOM.createSubObjective", createResult ); instance.objectiveEditor.showSubObjectives( true ); }) popup.hide(); } } } ], onShown : function( e ) { form.getEditor( "territoryId" ).focus(); } }).appendTo( $("body") ).dxPopup("instance"); popup.show(); } ObjectiveManagement.prototype.createObjective = function ( createData ) { let instance = this; instance.updateToolbar(); instance.detailSocket.empty(); let oe = new ObjectiveEditor( createData, { onCancel : function( e ) { if( e.instance.data.objectiveId > 0 ) { e.instance.refresh(); } else { let backToList = true; if( e.instance.isDirty()) { backToList = confirm( "Discard changes?" ); } if( backToList ) instance.showList(); } } } ); instance.detailSocket.append( oe.element() ); instance.multiView.option( "selectedIndex", 1 ); } ObjectiveManagement.prototype.openObjective = function( objective, options ) { let instance = this; instance.updateToolbar( objective ); let editorOptions = $.extend( true, {}, options ); editorOptions.openSubObjective = function( objective, options ) { console.log( "openSubObjective", objective ); instance.updateSubObjectiveToolbar( objective ); instance.subObjectiveEditor = new ObjectiveEditor( objective, options ); instance.subObjectiveSocket.empty().append( instance.subObjectiveEditor.element() ); instance.multiView.option( "selectedIndex", 2 ); }; instance.objectiveEditor = new ObjectiveEditor( objective, editorOptions ); instance.detailSocket.empty().append( instance.objectiveEditor.element() ); instance.multiView.option( "selectedIndex", 1 ); } ObjectiveManagement.editBundles = function( currentBundleId ) { let editPromise = $.Deferred(); let changesMade = 0; let popup = $("
").dxPopup( { title : "Manage Objective Groups", width : 600, height : "auto", contentTemplate : function() { let dataGrid = $("
").dxDataGrid( { dataSource : null, disabled : true, keyExpr : "bundleId", editing : { allowAdding : true, allowUpdating : true, allowDeleting: function( options) { if( options.row.data.bundleId == currentBundleId ) return false; return options.row.data.objectiveCount ? false : true; }, mode : "row", startEditAction : "click", useIcons : true, }, selection : { mode : "single", showCheckBoxesMode : "always" }, onInitNewRow : function( e ) { e.data.active = 'Y'; console.log( "onInitNewRow", e ); }, onRowInserted : function( e ) { console.log( "onRowInserted", e ); }, onSaving : function( e ) { console.log( "onSaving", e ); const change = e.changes[0]; if (change) { e.cancel = true; // loadPanel.show(); let dataToSave = null; if( change.type == "update" || change.type == "remove" ) { e.component.byKey( change.key ).done( function( rowData ) { dataToSave = $.extend( true, {}, rowData, change.data ); if( change.type == "remove" ) dataToSave.delete = true; }) } else { dataToSave = change.data; } // console.log( "dataToSave", dataToSave ); Fse.Ajax.performAction( { object : "BOM.saveObjectiveBundle", data : dataToSave } ) .then( function( result ) { let bundleDataSource = e.component.option( "dataSource" ); if( change.type == "insert" ) { change.key = result.bundleId; change.data.bundleId = result.bundleId; } bundleDataSource = DevExpress.data.applyChanges( bundleDataSource, [ change ], { keyExpr : "bundleId" } ); e.component.option( { dataSource : bundleDataSource, editing : { editingRowKey : null, changes : []} } ); changesMade++; }) } }, columns : [ { dataField : "bundleName", caption : "Name" }, { dataField : "active", caption : "Active", width : 60, lookup : { dataSource : { store : { type : "array", data : [ { "text" : "Y" }, { "text" : "N" } ], key : "text" }}, displayExpr : "text", valueExpr : "text" } }, { dataField : "objectiveCount", caption : "Objectives", dataType : "number", width : 80, format : "fixedPoint", allowEditing : false } ], showBorders : true, scrolling : { mode : "virtual" }, height : 400 }).dxDataGrid( "instance" ); // dataSource option is set to a simple array in order to facilitate in place editing let bundleDataSource = Fse.Data.newDataSource( { object : "BOM.objectiveBundles", key : "bundleId", paginate : false, objectParams : { includeStats : true } } ); bundleDataSource.load().done( function( bundles ) { dataGrid.option( { "dataSource" : bundles, "disabled" : false } ) }) return dataGrid.element(); }, onHidden : function( e ) { e.component.element().remove(); editPromise.resolve( changesMade ) } }).dxPopup("instance"); popup.element().appendTo( $("body") ) popup.show(); return editPromise; }