SubObjectives = function( options ) { let instance = this; instance.parentObjective = $.extend( {}, options.parentObjective ); instance.onModified = options.onModified; instance.subObjectives = null; instance.validationGroupBase = `SubObjectivesValidationGroup_${instance.parentObjective.objectiveId ? instance.parentObjective.objectiveId : 0 }`; instance.subObjectiveChanges = new DevExpress.data.ArrayStore( { data : [], key : "key" } ); instance.existingSubObjectives = {}; instance.lastKey = 0; instance.subObjectiveForms = {}; instance.contentReadyPromises = []; } SubObjectives.prototype.constructor = SubObjectives SubObjectives.prototype.element = function() { let instance = this; if( instance.rootElement ) return instance.rootElement; instance.rootElement = $( "
" ).text( "Sub-Objectives" ).css( { "height": "100%" } ) instance.reload();// instance.load().done( function() { instance._createUI() } ); return instance.rootElement; } SubObjectives.prototype.reload = function() { let instance = this; let loadingPanel = $("
").dxLoadPanel( { message : "Loading Sub-Objectives...", onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body") ).dxLoadPanel("instance"); let p = $.Deferred(); p.done( function() { loadingPanel.hide(); }) instance.contentReadyPromises.push( p ); loadingPanel.show(); return instance.load().done( function() { instance._createUI() } ); } SubObjectives.prototype._createUI = function() { let instance = this; console.log( "Creating UI", instance.subObjectives ); instance.rootElement.empty(); for( fk in instance.subObjectiveForms ) { instance.subObjectiveForms[fk].dispose(); } instance.subObjectiveForms = {}; instance.loadPanel = $("
").dxLoadPanel( { message : "Updating..." }).appendTo( $("body") ).dxLoadPanel( "instance" ) let box = $("
").dxBox( { height : "100%", direction : "col", items : [ { baseSize : 32, template : function( e ) { return $( "
").css( { "padding" : "5px" } ).dxToolbar( { items : [ { location : "before", widget : "dxButton", options : { text : "Spread Quota", onClick : function( e ) { instance.spreadQuota(); } } }, { location : "before", template : function() { let territoryFilter = []; if( instance.parentObjective.territoryPath ) { territoryFilter = [ "territoryPath", "startswith", instance.parentObjective.territoryPath ]; } let territoryDataSource = Fse.Data.newDataSource( { object : "TER.salesTerritories", key : "TerritoryID", filter : territoryFilter.length ? territoryFilter : null, paginate : false }); instance.addSubObjectiveTerritorySelect = $("
").dxSelectBox( { dataSource : territoryDataSource, displayExpr : "territoryName", width : 300, valueExpr : "TerritoryID", searchEnabled : true, showClearButton : true, placeholder : "Select Territory to Add", onSelectionChanged : function( e ) { let selectedItem = e.component.option( "selectedItem" ); let addOneDisabled = true; let addMultipleDisabled = true; let nameSuffixDisabled = true; if( selectedItem ) { if( selectedItem.localMarket ) { addOneDisabled = false; } else { addMultipleDisabled = false; } nameSuffixDisabled = false; } instance.addOneSubObjectiveButton.option( "disabled", addOneDisabled ); instance.addOnePerLocalMarketButton.option( "disabled", addMultipleDisabled ); instance.nameSuffixRadioGroup.option( "disabled", nameSuffixDisabled ); } } ).dxSelectBox( "instance" ); return instance.addSubObjectiveTerritorySelect.element(); } }, { location : "before", template : function() { instance.addOneSubObjectiveButton = $("
").dxButton( { text : "Add One Sub-Objective", //icon : "plus", disabled : true, onClick : function( e ) { instance.addSubObjectives(); } }).dxButton( "instance" ); return instance.addOneSubObjectiveButton.element(); } }, { location : "before", template : function () { instance.addOnePerLocalMarketButton = $("
").dxButton( { text : "Add One Per Market", //icon : "plus", onClick : function( e ) { instance.addSubObjectives(); }, disabled : true }).dxButton( "instance" ); return instance.addOnePerLocalMarketButton.element(); } }, { location : "before", template : function() { instance.nameSuffixRadioGroup = $("
").dxRadioGroup( { layout : "horizontal", items : [ { text : "Terr. Code", value : "internalSalesId" }, { text : "Terr. Name", value : "territoryName"} ], value : Fse.Portal.getConfiguration( "BOM.defaultSubObjectiveNameSuffix") == "internalSalesId" ? "internalSalesId" : "territoryName", valueExpr : "value", disabled : true }).dxRadioGroup( "instance" ) return instance.nameSuffixRadioGroup.element(); } } ] }) } }, { ratio : 1, template : function() { instance.subObjectiveList = $("
").dxList( { onContentReady : function( e ) { let p = instance.contentReadyPromises.shift(); while( p ) { p.resolve(); p = instance.contentReadyPromises.shift(); } }, height : "100%", dataSource : { store : instance.subObjectiveArrayStore, paginate : false, onLoadingChanged : function( isLoading ) { console.log( `isLoading = ${isLoading}` ); } }, itemTemplate : function( subObjective ) { let content = $("
").css( { "padding-bottom" : "10px", "border-bottom" : "2px solid silver" }) return content.append( instance._createSubObjectiveForm( subObjective )); } }).css( { "margin" : "5px", "border-style" : "solid", "border-width" : "1px" } ).addClass( "dx-theme-border-color" ).dxList( "instance" ); return instance.subObjectiveList.element(); } } ] }) instance.rootElement.append( box ); } SubObjectives.prototype._createSubObjectiveForm = function( subObjective ) { let instance = this; let quotaLabel = `${instance.parentObjective.quotaTypeName} Quota`; let territoryFilter = [ "localMarket", "=", 1 ]; if( instance.parentObjective.territoryPath ) { territoryFilter = [ [ "territoryPath", "startswith", instance.parentObjective.territoryPath ], "and", territoryFilter ]; } let territoryDataSource = Fse.Data.newDataSource( { object : "TER.salesTerritories", key : "TerritoryID", filter : territoryFilter, paginate : false }); let form = $("
").css( { "xpadding" : "5px 0px 10px 0px", "xborder-top-width" : "2px", "border-top-style" : "solid" }).addClass( "dx-theme-border-color" ).dxForm( { formData : subObjective, readOnly : false, validationGroup : `${instance.validationGroupBase}_${subObjective.key}`, items : [ { itemType : "group", colCount : 2, items : [ { itemType : "group", colCount : 2, items : [ { dataField : "objName", label : { text : "Name" }, isRequired : true, editorOptions : { maxLength : 50 }, colSpan : 2 }, { dataField : "totalQuota", label : { text : quotaLabel }, editorType : "dxNumberBox", isRequired : true, editorOptions : { minValue : 0, showSpinButtons : false } }, { itemType : "empty" } ] }, { itemType : "group", items : [ { dataField : "territoryId", label : { text : "Territory" }, isRequired : true, editorType : "dxSelectBox", editorOptions : { disabled : true, // subObjective.objectiveId ? true : false, dataSource : territoryDataSource, displayExpr : "territoryName", valueExpr : "TerritoryID", searchEnabled : true, showClearButton : false, placeholder : "Select Territory" } }, { 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 : "objDescription", label : { text : "Directions" }, isRequired : true, editorType : "dxTextArea", editorOptions : { maxLength : 500, height : "3.5em" } } ] }).dxForm( "instance" ); instance.subObjectiveForms[subObjective.key] = form; form.on( "fieldDataChanged", function( e ) { let data = e.component.option( "formData" ); instance.subObjectiveArrayStore.update( data.key, data ); }) return form.element(); } SubObjectives.prototype.save = function() { let instance = this; let changes = []; instance.subObjectiveChanges.load().done( function( data ) { changes = data; }); if( changes.length == 0 ) return; let isValid = true let validationResults = []; let subObjectiveCount = 0; instance.subObjectiveList.getDataSource().store().load().done( function( subObjectives ) { subObjectives.forEach( function( subObjective ) { subObjectiveCount++; let validationGroup = `${instance.validationGroupBase}_${subObjective.key}`; console.log( "Validating", validationGroup ); let vr = DevExpress.validationEngine.validateGroup( validationGroup ); validationResults.push( vr ); if( ! vr.isValid ) { isValid = false; } }) }) if( isValid ) { let savingPanel = $("
").dxLoadPanel( { message : "Saving...", onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body" ) ).dxLoadPanel("instance"); savingPanel.show(); Fse.Ajax.performAction( { object : "BOM.saveSubObjectives", data : changes }).done( function() { instance.reload().done( function() { savingPanel.hide(); }); }) } else { // issues for( let idx = 0; idx < validationResults.length; idx++ ) { let vr = validationResults[idx]; if( ! vr.isValid ) { vr.brokenRules[0].validator.focus(); instance.subObjectiveList.scrollToItem( idx ); break; } } } } SubObjectives.prototype.load = function() { let instance = this; let filter = [ [ "parentObjectiveId", "=", instance.parentObjective.objectiveId ], "and", [ "objLevel", "=", "C" ] ]; instance.existingSubObjectives = {}; instance.subObjectiveChanges = new DevExpress.data.ArrayStore( { data : [], key : "key" } ); if( instance.onModified ) { instance.subObjectiveChanges.on( "modified", function( e ) { instance.subObjectiveChanges.load().done( function( changes ) { instance.onModified( { component : instance, changes : changes }) }) }) } instance.lastKey = 1; let dataSource = Fse.Data.newDataSource( { object : "BOM.subObjectives", key : "objectiveId", filter : filter, paginate : false, objectParams : { parentObjectiveId : instance.parentObjective.objectiveId }, map: function (dataItem) { let data = { key : instance.lastKey++, parentObjectiveId : dataItem.parentObjectiveId, // instance.parentObjective.objectiveId, objectiveId : dataItem.objectiveId, objName : dataItem.objName, objDescription : dataItem.objDescription, totalQuota : dataItem.totalQuota, objManagerId : dataItem.objManagerId, objManager2Id : dataItem.objManager2Id, objManager3Id : dataItem.objManager3Id, territoryId : dataItem.territoryId } instance.existingSubObjectives[data.territoryId] = data; return data; } } ); return dataSource.load().done( function( data ) { instance.subObjectiveArrayStore = new DevExpress.data.ArrayStore( { data : data, key : "key", onUpdated : function( key, data ) { console.log( "onUpdated", key, data ); instance.subObjectiveChanges.update( key, data ).fail( function() { data.key = key instance.subObjectiveChanges.insert( data ); }) }, onInserted : function( data, key ) { console.log( "onInserted", data ); instance.subObjectiveChanges.update( key, data ).fail( function() { instance.subObjectiveChanges.insert( data ); }) } } ); }) } SubObjectives.prototype.spreadQuota = function() { let instance = this; instance.subObjectiveArrayStore.load().done( function( data ) { //console.log( "TotalQuota", instance.parentObjective.totalQuota ); let remainingQuota = instance.parentObjective.totalQuota let portion = parseInt( remainingQuota / data.length ); //console.log( "portion", portion ); data.forEach( function( objectiveItem ) { let objectiveData = $.extend( { }, objectiveItem ); let form = instance.subObjectiveForms[objectiveItem.key]; if( objectiveData.totalQuota != portion ) { form.updateData( { totalQuota : portion }); } remainingQuota -= portion; }) if( remainingQuota > 0 ) { let form = instance.subObjectiveForms[data[0].key]; form.updateData( { totalQuota : portion + remainingQuota }); } // let allocatedQuota = 0; // data.forEach( function( objectiveItem ) { // let form = instance.subObjectiveForms[objectiveItem.key]; // allocatedQuota += form.option( "formData").totalQuota; // }) // console.log( "Allocated", allocatedQuota ); }) } SubObjectives.prototype.addSubObjectives = function() { let instance = this; let targetTerritory = instance.addSubObjectiveTerritorySelect.option( "selectedItem" ); if( ! targetTerritory ) return; instance.addSubObjectiveTerritorySelect.option( "value", null ); let territoryDataSource = Fse.Data.newDataSource( { object : "TER.salesTerritories", key : "TerritoryID", filter : [[ "localMarket", "=", 1 ], "and", [ "territoryPath", "startswith", targetTerritory.territoryPath ]], paginate : false }); territoryDataSource.load().done( function( territories ) { let addCount = 0; territories.forEach( function( territory ) { // skip if already here if( instance.existingSubObjectives[territory.TerritoryID] ) return; let objDescription = instance.parentObjective.objDescription; let useInternalSalesId = instance.nameSuffixRadioGroup.option( "value" ) == "internalSalesId"; let suffix = territory.internalSalesId; if( ! useInternalSalesId ) { suffix = territory.shortTerritoryName; if( ! suffix ) { suffix = territory.territoryName; } } let objName = `${instance.parentObjective.objName} - ${suffix}`; let subObjective = { key : instance.lastKey++, parentObjectiveId : instance.parentObjective.objectiveId, objectiveId : 0, objName : objName, objDescription : objDescription, totalQuota : null, objManagerId : territory.primaryManager, objManager2Id : null, objManager3Id : null, territoryId : territory.TerritoryID } instance.existingSubObjectives[subObjective.territoryId] = subObjective; instance.subObjectiveArrayStore.insert( subObjective ); addCount++; }) if( addCount ) { instance.loadPanel.show(); let promise = $.Deferred(); promise.done( function() { instance.loadPanel.hide(); let loadToast = $("
").dxToast( { message : `${addCount} Sub-Objective(s) added`, type : "success", onHidden : function( e ) { e.component.element().remove(); e.component.dispose(); } }).appendTo( $("body")).dxToast("instance"); loadToast.show(); instance.subObjectiveList.getDataSource().store().load().done( function( data ) { instance.subObjectiveList.scrollToItem( data.length - 1 ); }) }); instance.contentReadyPromises.push( promise ); setTimeout( function() { instance.subObjectiveList.reload(); }, 10 ) } }) }