DistributionAnalyzer = function( options ) { this.rootElement = null; this.filterPreferences = null; this.dataVisible = false; this.config = $.extend( true, { }, options ? options : {} ) this.allocationType = "agreementOwnerName"; this.allocationTypesDataSource = new DevExpress.data.DataSource( { store : { type : "array", data : [ { value : "agreementOwnerName", text : "Agreement Owner" }, { value : "operatorSegment", text : "Segment" }, { value : "classification", text : "Operator Classification" } ], key : "value" } }); this.data = []; let date = new Date(); date.setMonth( date.getMonth() - 1 ); let defaultLastPurchasingMonth = DevExpress.localization.formatDate( date, "MM/01/yyyy" ); this.initialSearchParams = { lastPurchasingMonth : defaultLastPurchasingMonth, windowMonths : 12 } if( this.config.windowMonths ) { this.initialSearchParams.windowMonths = this.config.windowMonths; } if( this.config.lastPurchasingMonth ) { this.initialSearchParams.lastPurchasingMonth = this.config.lastPurchasingMonth; } if( this.config.cdr_dstPath ) { this.initialSearchParams.cdr_dstPath = this.config.cdr_dstPath; } this.searchParams = $.extend( true, {}, this.initialSearchParams ); console.log( "searchParams", this.searchParams ); this.dashboard = null; this.pieChartMonthThreshold = 100; } DistributionAnalyzer.prototype.setDashboard = function( dashboard ) { this.dashboard = dashboard; } DistributionAnalyzer.prototype.isDataVisible = function() { return this.dataVisible; } DistributionAnalyzer.prototype.constructor = DistributionAnalyzer; DistributionAnalyzer.prototype.element = function() { if( this.rootElement ) { return this.rootElement; } let instance = this; instance.rootElement = $("
").addClass( "DistributionAnalyzer" ).css( { "width" : "100%" }); instance.createBreadcrumbs(); instance.createToolbar(); instance.multiView = $("
").dxMultiView( { swipeEnabled : false, height : "100%", width : "100%", items : [ { perspective : "dataGrid", template : function(itemData, itemIndex, itemContainer ) { itemData.dataGrid = instance.createDataGrid(); instance.dataGrid = itemData.dataGrid; itemContainer.append( itemData.dataGrid.element() ); } }, { perspective : "chart", template : function(itemData, itemIndex, itemContainer ) { itemData.pieChart = instance.createPieChart(); instance.pieChart = itemData.pieChart; itemContainer.css( { "width" : "100%" } ).append( itemData.pieChart.element().css( { "padding" : "10px", "width" : "99%", "height" : "99%" }) ); } } ], selectedIndex : 0, onOptionChanged : function( e ) { if( e.name == "selectedIndex" ) { if( e.value == 1 ) { instance.chartTopNSelect.option( "disabled", false ); } else { instance.chartTopNSelect.option( "disabled", true ); } } }, onSelectionChanged : function( e ) { console.log( "MultiView onSelectionChanged" ); console.log( e ) /* let selectedItem = e.component.option( "selectedItem" ); if( selectedItem.dataGrid ) { instance.perspective = selectedItem.perspective; instance.dataGrid = selectedItem.dataGrid; if( instance.searchTimestamp != selectedItem.searchTimestamp ) { instance.applyFilters(); } } */ } }).dxMultiView( "instance" ) // instance.rootElement.append( instance.multiView.element() ); instance.loadPanel = $("
").dxLoadPanel({ hideOnOutsideClick: false, message : "Loading..." }).dxLoadPanel( "instance" ); $("body").append( instance.loadPanel.element()); let boxItems = []; boxItems.push( { baseSize : 30, template : function() { return $("
") .append( instance.breadcrumbs.element() ) }} ) boxItems.push( { baseSize : 30, template : function() { return instance.toolbar.element() } }, { ratio : 1, template : function() { return instance.multiView.element() } } ); instance.rootElement.dxBox( { direction : "col", height : "100%", width : "100%", items : boxItems }) return instance.rootElement; } DistributionAnalyzer.prototype.createBreadcrumbs = function() { let instance = this; instance.breadcrumbs = new Breadcrumbs( { onRemove : function( p ) { let copySearchParams = $.extend( true, {}, instance.searchParams ); copySearchParams[p] = null; instance.search( copySearchParams ); }, onOpen : function( p ) { instance.showFilters(); }, items : [ { searchParam : "lastPurchasingMonth", removable : false, displayExpr : function( lastPurchasingMonth, options ) { let windowMonthsOffset = ( options.searchParams.windowMonths - 1 ) ; let d2 = new Date( lastPurchasingMonth ); let m2 = d2.getMonth() + 1; let y2 = d2.getYear() + 1900; let sMonth2 = Fse.Date.getMonthAbbreviation( m2 - 1 ) + " " + y2; let d1 = new Date(d2.setMonth(d2.getMonth()-windowMonthsOffset)); let m1 = d1.getMonth() + 1; let y1 = d1.getYear() + 1900; let sMonth1 = Fse.Date.getMonthAbbreviation( m1 - 1 ) + " " + y1; return sMonth1 + " - " + sMonth2; } }, { searchParam : "territoryPath", hint : "Territory", multipleDisplay : "Multiple Territories", dataObject : { name : "TER.salesTerritories", key : "territoryPath" }, displayExpr : "territoryPath" }, { searchParam : "accountOwner_fspro_userId", hint : "Account Owner", multipleDisplay : "Multiple Account Owners", dataObject : { name : "CRM.salesRepList", key : "fspro_userId" }, displayExpr : "fullName" }, { searchParam : "cdr_dstPath", visible : instance.config.cdr_dstPath ? false : true, hint : "Distributor", multipleDisplay : "Multiple Distributors", dataObject : { name : "CDR.distributors", key : "cdr_dstPath" }, displayExpr : "cdr_dstPath" }, { searchParam : "buyingGroupId", hint : "Buying Group", multipleDisplay : "Multiple Buying Groups", dataObject : { name : "CDR.buyingGroups", key : "uniqueId" }, displayExpr : "bgName" }, { searchParam : "classificationId", hint : "Classification", multipleDisplay : "Multiple Classifications", dataObject : { name : "CDR.classifications", key : "classificationId" }, displayExpr : "classificationName" }, { searchParam : "mfr_id", hint : "Manufacturer", multipleDisplay : "Multiple Manufacturers", dataObject : { name : "PRD.manufacturers", key : "mfr_id" }, displayExpr : "mfr_name" }, { searchParam : "budgetCategoryId", hint : "Budget Category", multipleDisplay : "Multiple Budget Categories", dataObject : { name : "PRD.budgetCategories", key : "budgetCategoryId" }, displayExpr : "budgetCategory" }, { searchParam : "brandId", hint : "Brand", multipleDisplay : "Multiple Brands", dataObject : { name : "PRD.brandsList", key : "brandId" }, displayExpr : "brand" }, { searchParam : "productHierarchyPath", hint : "Product", multipleDisplay : "Multiple Products", dataObject : { name : "PRD.productHierarchyPaths", key : "productHierarchyPath" }, displayExpr : "productHierarchyPath" }, { searchParam : "accountOwner_ownerType", hint : "Staff Type", multipleDisplay : "Multiple Staff Types", dataStore : new DevExpress.data.ArrayStore( { data : [ { "value":"MFR","text":"Manufacturer Staff Only"}, {"value":"BRO","text":"Broker Staff Only"} ], key : "value" } ), displayExpr : "text" }, { searchParam : "productSetTags", hint : "Product Set", multipleDisplay : "Multiple Product Sets", dataObject : { name : "PRD.productSets", key : "productSetTag" }, displayExpr : "productSetName" } ] }) // instance.rootElement.append( instance.breadcrumbs.element() ); } DistributionAnalyzer.prototype.updateBreadcrumbs = function() { if( this.breadcrumbs ) { this.breadcrumbs.update( this.searchParams ); } } DistributionAnalyzer.prototype.createToolbar = function() { let instance = this; let toolbarItems = []; toolbarItems.push( { location : "before", template : function() { return $("
").text( "View by:" ) } }) toolbarItems.push( { location : "before", template : function() { instance.allocationTypeSelectBox = $("
").dxSelectBox( { value : instance.allocationType, width : 300, valueExpr : "value", displayExpr : "text", dataSource : instance.allocationTypesDataSource, onValueChanged : function( e ) { instance.allocationType = e.value; instance.applyFilters(); } }).dxSelectBox( "instance" ); return instance.allocationTypeSelectBox.element(); } }) toolbarItems.push( { widget : "dxButtonGroup", options : { items : [ { multiViewIndex : 0, "icon" : "detailslayout" }, { multiViewIndex : 1, icon : "chart" } ], onItemClick : function( e ) { if( e.itemData ) { instance.multiView.option( "selectedIndex", e.itemData.multiViewIndex ) } } } }); toolbarItems.push( { template : function() { instance.chartTopNSelect = $("
").dxSelectBox( { placeholder : "chart all", width : 150, disabled : true, showClearButton : true, items : [ { topN : 2, displayValue : 'Chart Top 2' }, { topN : 3, displayValue : 'Chart Top 3' }, { topN : 5, displayValue : 'Chart Top 5' }, { topN : 10, displayValue : 'Chart Top 10' }, { topN : 15, displayValue : 'Chart Top 15' }, { topN : 20, displayValue : 'Chart Top 20' } ], displayExpr : "displayValue", valueExpr : "topN", onSelectionChanged : function( e ) { let smallValuesGrouping = null; let chartSeriesOption = instance.pieChart.option( "series" ); console.log( chartSeriesOption ); if( e.selectedItem ) { smallValuesGrouping = { mode : "topN", topCount : e.selectedItem.topN, groupName : "Other" } } chartSeriesOption[0].smallValuesGrouping = smallValuesGrouping; instance.pieChart.option( "series", chartSeriesOption ); } }).dxSelectBox( "instance" ) return instance.chartTopNSelect.element(); } }) toolbarItems.push( { location : "after", widget : "dxButton", options : { hint : "Search", icon : "filter", onClick : function ( e ) { instance.showFilters() } } }); toolbarItems.push( { location : "after", widget : "dxButton", options : { text : "Reset All", onClick : function ( e ) { instance.dataGrid.beginUpdate(); // instance.dataGrid.option( "dataSource", [] ); instance.dataGrid.clearFilter(); instance.dataGrid.state( null ); instance.dataGrid.endUpdate(); instance.search( instance.initialSearchParams ); // instance.updateColumns(); }} }); toolbarItems.push( { location: "after", widget : "dxButton", options : { hint : "Excel Export", icon : "export", onClick : function( e ) { Fse.UI.DataGridHelper.exportDataGrid( { dataGrid : instance.dataGrid, fileName : "DistributionAnalysis.xlsx" }); }}}); toolbarItems.push( { location : "after", widget : "dxButton", options : { hint : "Choose Columns", icon : "columnchooser", onClick : function( e ) { instance.showColumnChooser(); } } }); toolbarItems.push( { widget: "dxButton", location: "after", options : { type : "normal", icon :"help", hint : "View Help", onClick : function( e ) { Fse.Portal.showQuickHelp( "DistributionAnalyzer" ); } }} ); instance.toolbar = $("
").dxToolbar( { items : toolbarItems }).dxToolbar( "instance" ); instance.toolbar.element().css( { "margin-bottom" : "5px" } ); // instance.rootElement.append( instance.toolbar.element() ); } DistributionAnalyzer.prototype.search = function( searchParams ) { let instance = this; instance.searchParams = $.extend( true, {}, searchParams ); if( ! this.rootElement ) { // this will create the UI. instance.element() } instance.applyFilters(); } DistributionAnalyzer.prototype.setFilterPreferences = function( filterPreferences ) { this.filterPreferences = filterPreferences; if( this.isDataVisible() ) { this.applyFilters(); } } DistributionAnalyzer.prototype.mergeFilterPreferences = function( searchParamsIn ) { let instance = this; let searchParams = $.extend( true, {}, searchParamsIn ); // when the global filters are expressed with different variable names, they need to translated to this widgets variable names const preferencableFilters = { // widgetVariableName : "globalFilterVariableName" territoryPath : "territoryPath", budgetCategoryId : "budgetCategoryId", accountOwner_fspro_userId : "salesRepId", productHierarchyPath : "productHierarchyPath", mfr_id : "mfr_id", accountOwner_ownerType : "staffType", productSetTags : "productSetTags" } for( let p in preferencableFilters ) { let gp = p; // global filter param is the same name as widget param // apply translation - global filter param is not the same name as widget param if( preferencableFilters[p] ) { gp = preferencableFilters[p]; } // if the global filter preferences have the propery and it has a value, update the objectparams if( instance.filterPreferences && instance.filterPreferences.hasOwnProperty( gp ) && instance.filterPreferences[gp]) { if( searchParams[p] == null ) { searchParams[p] = instance.filterPreferences[gp]; } } } return searchParams; } DistributionAnalyzer.prototype.applyFilters = function() { let instance = this; // if( instance.config.cdr_dstPath ) { // instance.searchParams.cdr_dstPath = instance.config.cdr_dstPath; // } let objectParams = instance.buildObjectParams( instance.searchParams ); instance.loadPanel.show(); let dataSource = Fse.Data.newDataSource( { object : "TPM.distributionAnalyzerData", paginate : false , objectParams : objectParams }) dataSource.sort( [ { selector: "allocationRank", desc: false }, { selector: "R1", desc : true }, { selector: instance.allocationType, desc: false } ]) instance.dataGrid.beginUpdate(); dataSource.load() .done( function( data ) { instance.data = data; instance.dataGrid.option( "dataSource", instance.data ); if( instance.pieChart ) { instance.pieChart.option( "dataSource", instance.createPieChartData() ); } }) .then( function() { instance.loadPanel.hide(); instance.dataGrid.endUpdate(); instance.dataVisible = true; }) instance.updateBreadcrumbs(); instance.updateColumns(); } DistributionAnalyzer.prototype.createPieChartData = function() { let instance = this; let chartData = []; if( ! instance.data ) { return chartData; } let q = DevExpress.data.query( instance.data ).select( instance.allocationType, "R1" ).groupBy( instance.allocationType ); q.toArray().forEach( function( group ) { let item = { allocationName : group.key, R1 : 0 } if( ! item.allocationName ) { item.allocationName = 'Unknown'; } group.items.forEach( function( gi ) { item.R1 += gi.R1; }) chartData.push( item ); }) return chartData; } DistributionAnalyzer.prototype.updateColumns = function() { let instance = this; let columns = instance.dataGrid.option( "columns" ); columns.forEach( function( c ) { let co = instance.dataGrid.columnOption( c.dataField ); if( co.allocationType ) { if( co.allocationType == instance.allocationType ) { instance.dataGrid.columnOption( c.dataField, { visible : true } ); } else { instance.dataGrid.columnOption( c.dataField, { visible : false } ); } } if( co.dataField == "R1" || co.dataField == "R0" ) { let endDate = new Date(); endDate.setTime( Date.parse( instance.searchParams.lastPurchasingMonth ) ); if( co.dataField == "R0" ) { endDate.setMonth( endDate.getMonth() - 12 ); } let startDate = new Date(); startDate.setTime( endDate.getTime() ); startDate.setMonth( startDate.getMonth() - ( instance.searchParams.windowMonths - 1)); let startFormatted = DevExpress.localization.formatDate( startDate, "MMM yyyy" ); let endFormatted = DevExpress.localization.formatDate( endDate, "MMM yyyy" ); let caption = `${startFormatted} - ${endFormatted}`; instance.dataGrid.columnOption( co.dataField, { "caption" : caption } ); } }) } DistributionAnalyzer.prototype.buildObjectParams = function( searchParamsIn ) { console.log( "searchParamsIn", searchParamsIn ); let instance = this; let objectParams = { distributorFilter : [], productFilter : [], windowMonths : null, lastPurchasingMonth : null, allocationType : instance.allocationType } let distributorFilter = objectParams.distributorFilter; let productFilter = objectParams.productFilter; let searchParams = this.mergeFilterPreferences( searchParamsIn ); objectParams.windowMonths = searchParams.windowMonths; objectParams.lastPurchasingMonth = searchParams.lastPurchasingMonth; for( p in searchParams ) { if( searchParams[p] ) { switch ( p ) { // distributor filter parts case "territoryPath" : case "cdr_dstPath" : case "accountOwner_fspro_userId" : case "accountOwner_ownerType" : case "classificationId" : case "buyingGroupId" : { let filter = []; let op = "=" if( p == "territoryPath" || p == "cdr_dstPath" ) { op = "startswith"; } let v = searchParams[p]; if( ! Array.isArray( v )) { v = [v]; // an array of one } v.forEach( function( ve ) { if( filter.length ) { filter.push( "or" ); } if( p == "buyingGroupId" ) { filter.push( [ "buyingGroupId", "=", ve ], "or", [ "buyingGroupId2", "=", ve ], "or", [ "buyingGroupId3", "=", ve ] ); } else { filter.push( [ p, op, ve ] ); } }) if( distributorFilter.length ) { distributorFilter.push( "and" ) } distributorFilter.push( filter ); } break; // product filter parts case "mfr_id" : case "budgetCategoryId" : case "brandId" : case "productHierarchyPath" : case "productSetTags" : { let filter = []; let op = "=" if( p == "productHierarchyPath" ) { op = "startswith"; } if( p == "productSetTags" ) { op ="contains"; } let v = searchParams[p]; if( ! Array.isArray( v )) { v = [v]; // an array of one } v.forEach( function( ve ) { if( filter.length ) { filter.push( "or" ); } filter.push( [ p, op, ve ] ); }) if( productFilter.length ) { productFilter.push( "and" ) } productFilter.push( filter ); } break; } } } if( distributorFilter.length == 0 ) { distributorFilter.push( [ "dstId", "=", -1 ] ); // so that nothing is returned } let columns = instance.dataGrid.option( "columns" ); let productColumns = []; let operatorColumns = []; columns.forEach( function( c ) { let co = instance.dataGrid.columnOption( c.dataField ); if ( co.resultType == "product" && co.visible ) { productColumns.push( co.dataField ); } else if ( co.resultType == "operator" && co.visible ) { operatorColumns.push( co.dataField ); } }) if( productColumns.length ) { objectParams.productColumns = productColumns; } if( operatorColumns.length ) { objectParams.operatorColumns = operatorColumns; } return objectParams; } DistributionAnalyzer.prototype.createDataGrid = function(){ let instance = this; let columns = [ { dataField : "agreementOwnerName", caption : "Agreement Owner", allocationType : "agreementOwnerName", visible : instance.allocationType == "agreementOwnerName" ? true : false, calculateCellValue : function( data ) { return data.agreementOwnerName ? data.agreementOwnerName : "Unknown"; } }, { dataField : "classification", caption : "Operator Classification", allocationType : "classification", visible : instance.allocationType == "classification" ? true : false, calculateCellValue : function( data ) { return data.classification ? data.classification : "Unknown"; } }, { dataField : "operatorSegment", caption : "Segment", allocationType : "operatorSegment", visible : instance.allocationType == "operatorSegment" ? true : false, calculateCellValue : function( data ) { return data.operatorSegment ? data.operatorSegment : "Unknown"; } } ]; columns.push( { resultType : "operator", dataField : "dstName", caption : "Distributor", visible : false }, { resultType : "operator", dataField : "territoryName", caption : "Territory", visible : false } ) columns.push( { resultType : "product", dataField : "brand", visible : false }, { resultType : "product", dataField : "productLineCode", visible : false }, { resultType : "product", dataField : "productLine", visible : false }, { resultType : "product", dataField : "catnum", visible : false }, { resultType : "product", dataField : "category", visible : false }, { resultType : "product", dataField : "product", visible : false }, { resultType : "product", dataField : "shortDesc", visible : false }, { resultType : "product", dataField : "sku", visible : false }, { resultType : "product", dataField : "skuDesc", visible : false }, { resultType : "product", dataField : "budgetCategory", visible : false } ) for( let p = 13; p <= 24; p++ ) { columns.push( { dataField : `P${p-12}`, width : 60, dataType : "number", format : { type : "fixedPoint", precision : 0 }, visible : false } ) } columns.push( { dataField : "R1", width : 140, caption : "Current", dataType : "number", format : { type : "fixedPoint", precision : 0 }, visible : true, showInColumnChooser : false }, { resultType : "data", dataField : "R0", width : 140, caption : "Prior", dataType : "number", format : { type : "fixedPoint", precision : 0 }, visible : true }, { resultType : "data", dataField : "D1", width : 90, caption : "Change", dataType : "number", format : { type : "fixedPoint", precision : 0 }, visible : true }, { resultType : "data", dataField : "V1", width : 90, caption : "Var. Pct.", dataType : "number", format : { type : "percent", precision : 0 }, visible : true, allowFiltering : false } ) columns.forEach( function( c ) { if( c.resultType ) { c.showInColumnChooser = true; } if( ! c.showInColumnChooser ) { c.showInColumnChooser = false; } }) instance.dataGrid = $("
").dxDataGrid( { rowAlternationEnabled : true, columns : columns, showBorders : true, height : "100%", width : "100%", scrolling : { mode : "virtual" }, filterRow : { visible : true }, onContextMenuPreparing : function( e ) { if( e.target != "content") return; if( e.row.rowType != "data" ) return; if( ! ( e.column.dataField == "agreementOwnerName" || e.column.dataField == "classification" || e.column.dataField == "operatorSegment" )) return; if (!e.items) e.items = []; let items = e.items; if( e.row.data.allocationRank == 1 ) { items.push( { text : "View Distributor Sales", onItemClick : function( ee ) { instance.gotoSalesAnalyzer(); } }); } else { items.push( { text : "Operator Analyzer", onItemClick : function( ee ) { let params = {}; let fp = e.column.dataField; if( fp == "agreementOwnerName" ) { fp = "agreementOwnerChoId"; } else if ( fp == "classification" ) { fp = "classificationId"; } else if ( fp == "operatorSegment" ) { fp = "segmentId"; } params[fp] = e.row.data[fp]; instance.gotoOperatorAnalyzer( params ); } }); } }, onRowPrepared : function( e ) { if( e.rowType != "data" ) { return; } if( e.data.allocationRank != 1 ) { return; } e.rowElement.css( { "background-color" : "#e5f1f9" } ); }, summary : { totalItems : [ { column : "R1", summaryType : "sum", valueFormat : { type : "fixedPoint", precision : 0 }, displayFormat : "{0}" }, { column : "R0", summaryType : "sum", valueFormat : { type : "fixedPoint", precision : 0 }, displayFormat : "{0}" }, { column : "D1", summaryType : "sum", valueFormat : { type : "fixedPoint", precision : 0 }, displayFormat : "{0}" } ] } }).dxDataGrid( "instance" ) instance.updateColumns(); return instance.dataGrid; } DistributionAnalyzer.prototype.gotoSalesAnalyzer = function( ) { let instance = this; let analyzerParams = { territoryPath : instance.searchParams.territoryPath, cdr_dstPath : instance.searchParams.cdr_dstPath, buyingGroupId : instance.searchParams.buyingGroupId, accountOwner_fspro_userId : instance.searchParams.accountOwner_fspro_userId, mfr_id : instance.searchParams.mfr_id, budgetCategoryId : instance.searchParams.budgetCategoryId, brandId : instance.searchParams.brandId, productHierarchyPath : instance.searchParams.productHierarchyPath, customRange : true, salesPeriodStart : null, salesPeriodEnd : null } let endDate = new Date( instance.searchParams.lastPurchasingMonth ); let endDateMonth = endDate.getMonth(); let startDate = new Date( endDate ); startDate.setMonth( endDateMonth - ( instance.searchParams.windowMonths - 1 )); Fse.CRM.dateRanges.salesPeriods.forEach( function( sp ) { if( analyzerParams.salesPeriodStart && analyzerParams.salesPeriodEnd ) return; if( ! ( sp.periodType == "M" && sp.calendarType == "F" )) return; let salesPeriodDate = new Date( sp.fiscalStartMonth ); if( salesPeriodDate.getTime() == startDate.getTime() ) { analyzerParams.salesPeriodStart = sp.rangeKey; } if( salesPeriodDate.getTime() == endDate.getTime() ) { analyzerParams.salesPeriodEnd = sp.rangeKey; } }) // put the default value in the timeframe parameter let dateRangesDataSource = Fse.CRM.dateRanges.createDataSource(); dateRangesDataSource.filter( [["calendarType", "=", "F" ], "and", [ "rangeCode", "=", "TYLI" ]]); // year to last invoice dateRangesDataSource.load(); analyzerParams.timeframe = dateRangesDataSource.items()[0]; console.log( "gotoSalesAnalyzer" ); console.log( analyzerParams ) instance.dashboard.tabSearch( "SalesAnalyzer", analyzerParams ) } DistributionAnalyzer.prototype.gotoOperatorAnalyzer = function( params ) { let instance = this; let analyzerSearchParams = $.extend( true, {}, instance.searchParams ); let analyzerParams = { windowMonths : analyzerSearchParams.windowMonths, lastPurchasingMonth : analyzerSearchParams.lastPurchasingMonth } // distribution filters let distributorParams = {}; let needDistributors = false; if( analyzerSearchParams.territoryPath ) { distributorParams.territoryPath = analyzerSearchParams.territoryPath; needDistributors = true; } if( analyzerSearchParams.cdr_dstPath ) { needDistributors = true; distributorParams.cdr_dstPath = analyzerSearchParams.cdr_dstPath; } if( analyzerSearchParams.buyingGroupId ) { needDistributors = true; distributorParams.buyingGroupId = analyzerSearchParams.buyingGroupId; } // NOTE that classificationId is also used for the the operator allocationType classification - be careful if( analyzerSearchParams.classificationId ) { needDistributors = true; distributorParams.classificationId = analyzerSearchParams.classificationId; } // product filters if( analyzerSearchParams.accountOwner_fspro_userId ) { needDistributors = true; distributorParams.accountOwner_fspro_userId = analyzerSearchParams.accountOwner_fspro_userId; } if( analyzerSearchParams.mfr_id ) { analyzerParams.mfr_id = analyzerSearchParams.mfr_id } if( analyzerSearchParams.budgetCategoryId ) { analyzerParams.budgetCategoryId = analyzerSearchParams.budgetCategoryId; } if( analyzerSearchParams.brandId ) { analyzerParams.brandId = analyzerSearchParams.brandId; } let ready = $.Deferred(); let filtersToResolve = 0; // click filters to resolve if( params.segmentId ) { filtersToResolve++; let opaSegmentStore = Fse.Data.newDataSource( { object : "OPA.operatorAnalyzerSegments", keyField : "operatorSegmentId", paginate : false } ).store(); opaSegmentStore.byKey( params.segmentId ).done( function( data ) { let segment = data; // data[0]; console.log( segment ); params.segmentId = segment.segmentId; filtersToResolve--; if( filtersToResolve == 0 ) { ready.resolve(); } }) } // product fitlers to resolve if( analyzerSearchParams.productHierarchyPath ) { let paths = analyzerSearchParams.productHierarchyPath; if( ! Array.isArray( paths ) ) { paths = [ paths ]; } filtersToResolve += paths.length; let phpStore = Fse.Data.newDataSource( { object : "PRD.productHierarchyPaths", keyField: "productHierarchyPath" }).store(); paths.forEach( function( p ) { phpStore.byKey( p ).done( function( data ) { let php = data; // data[0]; filtersToResolve--; let catalogIds = null; if( php.catalogType == "LIN") { if( ! analyzerParams.prodline_Id ) analyzerParams.prodline_Id = []; catalogIds = analyzerParams.prodline_Id; } else if ( php.catalogType == "CAT" ) { if( ! analyzerParams.categoryId ) analyzerParams.categoryId = []; catalogIds = analyzerParams.categoryId; } else if ( php.catalogType == "PRD" ) { if( ! analyzerParams.prodId ) analyzerParams.prodId = []; catalogIds = analyzerParams.prodId; } else if ( php.catalogType == "SKU" ) { if( ! analyzerParams.skuId ) analyzerParams.skuId = []; catalogIds = analyzerParams.skuId; } if( catalogIds ) { catalogIds.push( php.catalogId ) } if( filtersToResolve == 0 ) { ready.resolve(); } }); }) } if( needDistributors ) { filtersToResolve++; // resolve distributor filter let distributorFilter = []; for( let fp in distributorParams ) { let fv = analyzerSearchParams[fp]; if( ! fv ) return; if( ! Array.isArray( fv )) fv = [fv]; let op = "="; if( fp == "territoryPath" || fp == "cdr_dstPath" ) op = "startswith"; let filter = []; if( fv.length == 1 ) { filter.push( fp, op, fv[0] ); } else { fv.forEach( function( fvi ) { if( filter.length ) filter.push( "or" ); filter.push( [ fv, op, fvi ] ); }) } if( distributorFilter.length ) distributorFilter.push( "and" ); distributorFilter.push( filter ); } let distributorDS = Fse.Data.newDataSource( { object : "CDR.distributors2", keyField : "cdr_recordId", paginate : false }); distributorDS.filter( distributorFilter ); distributorDS.load().done( function( distributors ) { let distributor1FSIds = []; distributors.forEach( function( d ) { if( d.fsl_dstId ) { if( d.cdr_dstCompanyType == "P" ) { distributor1FSIds.push( `parentDstId:${d.fsl_dstId}`); } else { distributor1FSIds.push( `dstId:${d.fsl_dstId}`); } } }) analyzerParams.distributorKeyId = distributor1FSIds; let opaDistributorsStore = Fse.Data.newDataSource( { paginate : false, object : "OPA.distributors", keyField : "keyId", objectParams : { operatorPurchasing : true } } ).store(); opaDistributorsStore.load().done( function( data ) { let resolvedDistributorKeyIds = []; let lookupStore = new DevExpress.data.ArrayStore( { data : data, key : "keyId" } ); distributor1FSIds.forEach( function( keyId ) { lookupStore.byKey( keyId ).done( function( opaDist ) { if( data ) { resolvedDistributorKeyIds.push( opaDist.keyId ); } }) }) analyzerParams.distributorKeyId = resolvedDistributorKeyIds; filtersToResolve--; if( filtersToResolve == 0 ) { ready.resolve(); } }) }) } if( filtersToResolve == 0 ) { // nothing to resolve, so we are done ready.resolve(); } ready.done( function() { // make sure classification id is not already in analyzer params (it shouldn't be but this makes sure it didnt get in there somehow ) delete analyzerParams.classificationId; analyzerParams = $.extend( true, analyzerParams, params ); /* console.log( "gotoOperatorAnalyzer" ); console.log( analyzerParams ); */ instance.dashboard.tabSearch( "OperatorAnalyzer", analyzerParams ); }) } DistributionAnalyzer.prototype.createPieChart = function() { let instance = this; instance.paletteColors = DevExpress.viz.generateColors( "Material", 25, { baseColorSet : "simpleSet", paletteExtensionMode : "extrapolate" }); let pieChart = null; let allocationPieChartConfig = { type : "pie", // height : 200, // xwidth : "100%", tooltip : { enabled : true, format : { type : "fixedPoint", precision : 2 }, customizeTooltip : function( o ) { let formattedPercent = DevExpress.localization.formatNumber(o.percent, { type : "percent", precision : 1 } ); //o.percentText; return { text : o.argumentText + ": " + o.valueText + " (" + formattedPercent + ")" }; }, zIndex : 500000 }, palette : instance.paletteColors, // elementAttr : { id : "distributionAllocationPieChart" }, dataSource: instance.createPieChartData(), legend : { visible : true, horizontalAlignment : "right", verticalAlignment : "top", customizeItems : function( legendItems ) { legendItems.forEach( function( legendItem ) { let point = legendItem.points[0]; let formattedPercent = DevExpress.localization.formatNumber( point.percent, { type : "percent", precision : 1 } ); legendItem.text = `${legendItem.text} (${formattedPercent})`; }) } }, series: [{ argumentField: 'allocationName', valueField: 'R1', name: 'allocationName', label: { visible : false, connector : { visible : false }} }] }; pieChart = $("
").dxPieChart( allocationPieChartConfig ).dxPieChart("instance"); return pieChart; } DistributionAnalyzer.prototype.showFilters = function() { let instance = this; if( ! instance.searchCenter ) { instance.searchCenter = new DistributionAnalyzerSearch( { applySearch : function( searchParams ) { // instance.dataGrid.option( "dataSource", null ); // instance.dataGrid.clearFilter( "row" ); // instance.dataGrid.clearFilter( "header" ); instance.search( searchParams ) }, getSearchParams : function() { return _instance.searchParams; }, partnerMode : instance.config.cdr_dstPath ? true : false }); } instance.searchCenter.show( instance.searchParams, instance.filterPreferences ); // scrum 46030 } DistributionAnalyzer.prototype.showColumnChooser = function() { let instance = this; if(! instance.columnChooser ) { instance.columnChooser = new CustomDataGridColumnChooser( instance.dataGrid, function() { instance.applyFilters() } ); } instance.columnChooser.show(); }