ObjectiveTargets = function( options ) { let instance = this; instance.objectiveId = options.objectiveId; instance.staffLinkId = null; instance.staffFullName = null; instance.currentView = null; instance.objectiveUnpublishDate = options.unpublishDate; //console.log( "OPTIONS.TERRITORY", options.territory ); let currentUserId = parseInt( Fse.Portal.getConfiguration( "STP.userId" )); if( currentUserId === options.objManagerId || currentUserId === options.objManager2Id || currentUserId === options.objManager3Id ) { console.log( "Objective Manager using Summary View" ); instance.currentView = "summary"; } if ( ! instance.currentView && options.territory && options.territory.teamMembers ) { options.territory.teamMembers.forEach( function( tm ) { if( instance.currentView ) return; if( tm.teamMemberUserId === currentUserId && ( tm.teamMemberRole === "PrimaryManager" || tm.teamMemberRole === "SecondaryManager" || tm.teamMemberRole === "TeamManager" )) { console.log( "Territory Manager using Summary View" ); instance.currentView = "summary"; } }) } if( ! instance.currentView && Fse.Portal.checkPermission( "BCRMObjectiveManagementAdmin" )) { console.log( "Objective Admin Permission using Summary View" ); instance.currentView = "summary"; } if( ! instance.currentView && Array.isArray( options.staff )) { // see if the current user has a staff link options.staff.forEach( function( staff ) { if( staff.fspro_userId == currentUserId ) { instance.staffLinkId = staff.linkId; instance.staffFullName = staff.fullName; instance.currentView = "staff"; console.log( "Staff using Staff View" ); } }) } if( ! instance.currentView ) { console.log( "Defaulting to Summary View" ); instance.currentView = "summary"; } instance.dataReady = $.Deferred(); instance.summaryDataGrid = null; instance.targetDataGrid = null; instance.staffDataGrid = null; instance.multiView = null; } ObjectiveTargets.prototype.constructor = ObjectiveTargets; ObjectiveTargets.prototype.element = function() { let instance = this; if( instance.rootElement ) return instance.rootElement; let objectiveTargetsDataSourceOptions = { object : "BOM.objectiveTargets", key : "staffLinkId", objectParams : { objectiveId : instance.objectiveId } } if( instance.staffLinkId ) { objectiveTargetsDataSourceOptions.filter = [ "staffLinkId", "=", instance.staffLinkId ]; } let objectiveTargetsDataSource = Fse.Data.newDataSource( objectiveTargetsDataSourceOptions ); let loadPanel = $("
").dxLoadPanel( { message : "Loading...", onHidden : function( e ) { e.component.element().remove(); } }).appendTo( $("body")).dxLoadPanel( "instance" ) loadPanel.show(); objectiveTargetsDataSource.load().done( function( targetData ) { loadPanel.hide(); instance.targetData = targetData; instance.targetStore = new DevExpress.data.ArrayStore( { key : "staffLinkId", data : targetData } ); instance.dataReady.resolve(); }) instance.rootElement = $("
").addClass( "ObjectiveTargets" ); let multiViewItems = []; if( ! instance.staffLinkId ) { instance.summaryDataGrid = instance._createSummaryDataGrid(); instance.targetDataGrid = instance._createTargetDataGrid(); // NEW 09/16/2025 multiViewItems.push( { name : "summary", template : function( item ) { return instance.summaryDataGrid.element(); } }, { name : "detail", template : function( item ) { // return instance._createTargetDataGrid().element(); return instance.targetDataGrid.element(); // NEW 09/16/2025 } } ) } instance.staffDataGrid = instance._createStaffDataGrid(); multiViewItems.push( { name : "staff", template : function( item ){ return instance.staffDataGrid.element(); } } ) instance.staffTargetsElement = $("
").css( { "width" : "100%" } ); instance.multiView = $("
").dxMultiView( { height : "100%", width : "100%", swipeEnabled : false, selectedIndex : 0, items : multiViewItems }).dxMultiView( "instance" ) instance.toolbar = $("
").dxToolbar( { items : instance._toolbarItems( instance.currentView ) }).dxToolbar( "instance" ); instance.rootElement.dxBox( { height : "100%", width : "100%", direction : "col", items : [ { baseSize : 30, template : function() { return instance.toolbar.element() }}, { ratio : 1, template : function() { return instance.multiView.element() }} ] }) instance.dataReady.done( function() { if( ! instance.staffLinkId ) { instance.summaryDataGrid.option( { "dataSource" : { store : instance.targetStore } } ); instance.targetDataGrid = instance._createTargetDataGrid(); } else { instance.targetStore.byKey( instance.staffLinkId ).done( function( data ) { let targets = data.targets ? data.targets : []; instance.staffDataGrid.option( { "dataSource" : {store : { type : "array", key : "targetLinkId", data : targets } } }); }); } instance._selectView( instance.currentView ); }) return instance.rootElement; } ObjectiveTargets.prototype._selectView = function( viewName ) { let instance = this; if( ! instance.multiView ) return; let viewIndex = -1; instance.multiView.option( "items" ).forEach( function( view, idx ) { if( view.name == viewName ) viewIndex = idx; }) if( viewIndex >= 0 ) { instance.currentView = viewName; instance.multiView.option( "selectedIndex", viewIndex ); instance.toolbar.option( "items", instance._toolbarItems( viewName ) ); } } ObjectiveTargets.prototype._toolbarItems = function( viewName ) { let instance = this; let toolbarItems = []; switch( viewName ) { case "summary" : case "detail" : toolbarItems.push( { location : "before", widget : "dxButtonGroup", options : { items : [ { text : 'S', hint : "Target Summary", onClick : function( e ) { instance._selectView( "summary" ) }}, { text : "D", hint : "Target Detail", onClick : function( e ) { instance._selectView( "detail" ) }} ] } }); break; case "staff" : toolbarItems.push( { location : "before", template : function() { return $("
").text( instance.staffFullName ); } } ); if( ! instance.staffLinkId ) { toolbarItems.push( { location : "after", widget : "dxButton", options : { text : "Back to List", onClick : function(e) { instance._selectView( "summary" ) } } } ) } break; } const dataGrid = viewName == "summary" ? instance.summaryDataGrid : viewName == "detail" ? instance.targetDataGrid : viewName == "staff" ? instance.staffDataGrid : null; if( dataGrid ) { toolbarItems.push( { location : "after", widget : "dxButton", options : { hint : "Choose Columns", icon : "columnchooser", onClick : function( ) { let columnChooser = new CustomDataGridColumnChooser( dataGrid, function() { dataGrid.refresh() } ); columnChooser.show(); } } } ) } return toolbarItems; } ObjectiveTargets.prototype._createSummaryDataGrid = function() { let instance = this; let summaryDataGrid = $("
").dxDataGrid( { height : "100%", scrolling : { mode : "virtual" }, showBorders : true, loadPanel : { enabled : false }, filterRow : { visible : true }, columns : [ { dataField : "fullName", caption : "Sales Rep" }, { dataField : "quota", caption : "Quota", dataType : "number" }, { dataField : "quotaAchieved", caption : "Achieved", dataType : "number" }, { dataField : "quotaAchievement", caption :"Achievement %", dataType : "number", format : { type : "percent", precision : 0 }, xcalculateCellValue : function( rowData ) { if( rowData.quota > 0 ) { let quotaAchieved = rowData.quotaAchieved ? rowData.quotaAchieved : 0; return ( (quotaAchieved * 1.0) / ( rowData.quota * 1.0 )); } else { return null; } } }, { dataField : "callsToAchievement", caption : "Total Calls (Achievement)", dataType : "number", visible : false, width : "auto" }, { name : "quotaRemaining", caption : "Quota Remaining", dataType : "number", calculateCellValue : function( rowData ) { return rowData.quota - ( rowData.quotaAchieved ? rowData.quotaAchieved : 0 ); } }, { dataField : "remainingTargets", caption : "Targets Remaining", dataType : "number" }, { dataField : "completedCalls", caption : "Total Calls (All)", dataType : "number", visible : false }, { dataField : "noAchievementPlannedCalls", caption : "Planned", dataType : "number" }, { dataField : "remainingTargetsPlannedPct", caption : "Planned %", dataType : "number", format : { type : "percent", precision : 0 }, visible : false }, { dataField : "noAchievementUnplannedCalls", caption : "Unplanned", dataType : "number" }, { dataField : "remainingTargetsUnplannedPct", caption : "Unplanned %", dataType : "number", format : { type : "percent", precision : 0 }, visible : false}, { dataField : "faultCount", caption : "Total Warnings", width : "auto", dataType : "number", format : "fixedPoint" // ,cellTemplate : function( container, options ) { // container.append( $("
").text( options.text ) ); // if( options.value ) { // container.css( { "background-color": "#ff6b00" }) // } // } }, { dataField : "cases", caption : "Annual Cases", dataType : "number", format : "fixedPoint", visible : false }, { dataField : "impactCases", caption : "Impact Cases", dataType : "number", format : "fixedPoint", visible : false }, { dataField : "lbs", caption : "Annual Lbs", dataType : "number", format : "fixedPoint", visible : false }, { dataField : "impactLbs", caption : "Impact Lbs", dataType : "number", format : "fixedPoint", visible : false }, { dataField : "dollars", caption : "Annual Dollars", dataType : "number", format : "fixedPoint", visible : false }, { dataField : "impactDollars", caption : "Impact Dollars", dataType : "number", format : "fixedPoint", visible : false } ], onRowDblClick : function( e ) { if( e.rowType != "data" ) return; instance.staffFullName = e.data.fullName ? e.data.fullName : "Unknown"; instance.targetStore.byKey( e.data.staffLinkId ).done( function( data ) { let targets = data.targets ? data.targets : []; instance.staffDataGrid.option( { "dataSource" : {store : { type : "array", key : "targetLinkId", data : targets } } }); instance._selectView( "staff" ); }) } }).dxDataGrid("instance"); return summaryDataGrid; } ObjectiveTargets.prototype._createTargetDataGrid = function() { let instance = this; let targetDataGrid = $("
").dxDataGrid( { loadPanel : { enabled : false }, filterRow : { visible : true }, columns : [ { dataField : "fullName", caption : "Sales Rep" }, { dataField : "partnerName", caption : "Account" }, { dataField : "targetStatus", caption : "Status" }, { dataField : "targetAchievement", caption : "Achievement", dataType : "number" }, { dataField : "completedCalls", caption : "Completed Calls", dataType : "number" }, { dataField : "nextCall", caption : "Next Call", dataType : "date", cellTemplate : function( container, options ) { if( options.data.nextCall ) { let a = $("").text( DevExpress.localization.formatDate( new Date( options.data.nextCall ), "shortDate" ) ).css( "cursor" , "pointer" ) container.append( a ); } } }, { dataField : "targetComment", caption : "Target Comment", visible : false }, { caption : "Warnings", name : "warnings", width : "auto", allowHeaderFiltering : false, cellTemplate : function( container, options ) { return instance._warningIconsCellTemplate( container, options ); } } ], onContextMenuPreparing : function( e ) { if( e.target != "content" ) return; if( e.row.rowType == "data" ) { if( ! e.row.data.interactions || e.row.data.interactions.length == 0 ) return; if (!e.items) e.items = []; e.row.data.interactions.forEach( function( i ) { const interactionId = i.interactionId; let interactionDateText = "TBD" if( i.interactionDate ) { interactionDateText = DevExpress.localization.formatDate( new Date( i.interactionDate ), 'shortDate' ); } let dispositionText = i.disposition == '?' ? 'Planned' : 'Complete' e.items.push( { text : `${interactionDateText}: ${dispositionText}`, onItemClick : function( ee ) { Fse.CLOS.openInteractionDialog( interactionId,function() { }) } }) }) } }, onCellClick : function( e ) { if( e.rowType != "data" ) return; if( e.column.dataField == "nextCall" ) { if( ! e.data.nextCall ) return; let interactions = Array.isArray( e.data.interactions ) ? e.data.interactions : []; for( let ix = 0; ix < interactions.length; ix++ ) { if( interactions[ix].interactionDate == e.data.nextCall ) { Fse.CLOS.openInteractionDialog( interactions[ix].interactionId, function() { }) break; } } } }, onRowDblClick : function( e ) { let interactions = Array.isArray( e.data.interactions ) ? e.data.interactions : []; if( interactions.length ) { let interactionId = interactions[interactions.length-1].interactionId; Fse.CLOS.openInteractionDialog( interactionId, function() { }) } }, scrolling : { mode : "virtual" }, showBorders : true, rowAlternationEnabled : true, height : "100%", width : "100%" }).dxDataGrid( "instance" ); instance.dataReady.done( function(){ let targets = []; instance.targetData.forEach( function( staff ) { if( staff.targets ) { staff.targets.forEach( function( target ) { let newTarget = $.extend( true, { staffLinkId : staff.staffLinkId, fullName : staff.fullName }, target ); targets.push( newTarget ); }) } }) targetDataGrid.option( { "dataSource" : {store : { type : "array", key : "targetLinkId", data : targets } } }); }) return targetDataGrid; } ObjectiveTargets.prototype._warningIconsCellTemplate = function( container, options ) { let instance = this; let startDateTxt = DevExpress.localization.formatDate( new Date(), "shortDate" ); let endDateTxt = DevExpress.localization.formatDate( new Date( instance.objectiveUnpublishDate ), "shortDate" ); const faultCodeDefinitions = { "date" : { description : "Planned call outside of objective timeframe", code : "date", type : "warning", color : "#ff6b00", icon : "dx-icon-warning", correctiveAction : `Adjust call date to be within ${startDateTxt} - ${endDateTxt}` }, "product" : { code : "product", description : "Product(s) on sales calls do not qualify for objective", type : "warning", color : "#ff6b00", icon : "dx-icon-warning", correctiveAction : "Visit objective details or use sales call product filters to review eligible products" }, "typeCode" : { code : "typeCode", description : "Product(s) on sales calls are existing business, which does not qualify for objective", type : "warning", color : "#ff6b00", icon : "dx-icon-warning", correctiveAction : "Product(s) must be new business or incremental volume" }, "disposition" : { code : "disposition", description : "Product(s) on completed calls are in a follow up status, which does not qualify for objective", type : "information", color : "#81878c", icon : "dx-icon-info", correctiveAction : "For these product(s), close the sales cycle within the objective timeframe" } }; let content = $("
").css( { "padding-right" : "3px" } ); if( options.data.faultCodes ) { let codes = options.data.faultCodes.split( "," ); codes.forEach( function( code ) { for( let faultCode in faultCodeDefinitions ) { const fault = faultCodeDefinitions[faultCode]; if( fault ) { if( fault.code == code || fault.description == code ) { let icon = $("").addClass( fault.icon ).css( { color : fault.color, "font-size" : "18px" }); content.append( icon ); icon.on( "mouseenter", function( jqe ) { $("
").dxTooltip( { target : jqe.target, contentTemplate : function() { let table = $("").addClass( "fx-objective-target-warning" ).append( $("").append( $("").append( $("").append( $("
").text( fault.type == 'warning' ? 'WARNING' : 'INFORMATION' ) ).append( $("").text( fault.description ) ) ).append( $("
").text( fault.type == 'warning' ? 'CORRECTIVE ACTION' : 'GUIDANCE' ) ).append( $("").text( fault.correctiveAction ) ) ) ); return $("
").append( table ); }, onHidden : function( e ) { e.component.element().remove; }, xshowEvent : { name : "mouseenter", }, hideEvent : { name : "mouseout" } }).appendTo( $("body") ).dxTooltip("show"); } ) break; } } } }) } else { if( options.data.targetStatus == "Completed" ) { let icon = $("").addClass( "dx-icon-check" ).css( { "font-size" : "18px" }) if( options.data.targetAchievement ) { icon.css( { color : "#2b8000" }); // green } else { icon.css( { color : "#81878c" }); // grey } content.append( icon ); } } container.append( content ); } ObjectiveTargets.prototype._createStaffDataGrid = function() { let instance = this; let staffDataGrid = $("
").dxDataGrid( { loadPanel : { enabled : false }, filterRow : { visible : true }, headerFilter : { visible : true }, columns : [ { dataField : "partnerName", caption : "Account", allowHeaderFiltering : false }, { dataField : "targetStatus", caption : "Status", allowFiltering : false, allowHeaderFiltering : true, headerFilter : { dataSource : { store : { type : "array", key : "text", data : [ { text : "Not Planned", value : [ "targetStatus", "=", "Not Planned" ] }, { text : "In Progress", value : [ "targetStatus", "=", "In Progress" ] }, { text : "Completed", value : [[ "targetStatus", "=", "Completed" ], "or", [ "targetStatus", "=", "COMPLETED" ]] }, { text : "Not Completed", value : [ "targetStatus", "=", "Not Completed" ] } ]}} } }, { dataField : "targetAchievement", caption : "Achievement", dataType : "number", allowHeaderFiltering : false }, { caption : "", name : "warnings", width : "auto", allowHeaderFiltering : false, cellTemplate : function( container, options ) { return instance._warningIconsCellTemplate( container, options ); } }, { dataField : "completedCalls", caption : "Completed Calls", dataType : "number", allowHeaderFiltering : false }, { dataField : "callsToAchievement", caption : "Total Calls (Achievement)", dataType : "number", visible : false, width : "auto", allowHeaderFiltering : false }, { dataField : "nextCall", caption : "Next Call", dataType : "date", allowHeaderFiltering : false, cellTemplate : function( container, options ) { if( options.data.nextCall ) { let a = $("").text( DevExpress.localization.formatDate( new Date( options.data.nextCall ), "shortDate" ) ).css( "cursor" , "pointer" ) container.append( a ); } } } ], onCellClick : function( e ) { if( e.rowType != "data" ) return; if( e.column.dataField == "nextCall" ) { if( ! e.data.nextCall ) return; let interactions = Array.isArray( e.data.interactions ) ? e.data.interactions : []; for( let ix = 0; ix < interactions.length; ix++ ) { if( interactions[ix].interactionDate == e.data.nextCall ) { Fse.CLOS.openInteractionDialog( interactions[ix].interactionId, function() { }) break; } } } }, onContextMenuPreparing : function( e ) { if( e.target != "content" ) return; if( e.row.rowType == "data" ) { if( ! e.row.data.interactions || e.row.data.interactions.length == 0 ) return; if (!e.items) e.items = []; if( e.row.data.partnerType == "OPR" ) { const operatorId = e.row.data.partnerId; e.items.push( { text : "Operator Profile", onItemClick : function( ee ) { OperatorProfile.openPopupEditor( operatorId ); } }) } else if ( e.row.data.partnerType == "CDR" ) { const cdr_recordId = e.row.data.partnerId; e.items.push( { text : "Distributor Profile", onItemClick : function( ee ) { DistributorProfile.openPopupEditor( cdr_recordId ); } }) } e.row.data.interactions.forEach( function( i ) { const interactionId = i.interactionId; let interactionDateText = "TBD" if( i.interactionDate ) { interactionDateText = DevExpress.localization.formatDate( new Date( i.interactionDate ), 'shortDate' ); } let dispositionText = i.disposition == '?' ? 'Planned' : 'Complete' e.items.push( { text : `Open Call: ${interactionDateText}: ${dispositionText}`, onItemClick : function( ee ) { Fse.CLOS.openInteractionDialog( interactionId,function() { }) } }) }) } }, onRowDblClick : function( e ) { let interactions = Array.isArray( e.data.interactions ) ? e.data.interactions : []; if( interactions.length ) { let interactionId = interactions[interactions.length-1].interactionId; Fse.CLOS.openInteractionDialog( interactionId, function() { }) } }, scrolling : { mode : "virtual" }, showBorders : true, rowAlternationEnabled : true, height : "100%", width : "100%" }).dxDataGrid( "instance" ); return staffDataGrid; }