'use strict'; app.controller('teamInfoController', ['$scope', '$http', 'hoursResourcesConverter', 'cellHighligting', 'teamInfoService', function ($scope, $http, hoursResourcesConverter, cellHighligting, teamInfoService) { var collapsedIcon = 'fa-plus-square', nonCollapsedIcon = 'fa-minus-square'; var RowType = { Vacations: 1, Trainings: 2, Team: 3, ExpenditureCategory: 4 }; $scope.InternalData = null; //DAL data model $scope.DisplayMode = { // Page Options IsUOMHours: true, // display data in Hours GroupCapacityByTeam: false, // do not group capacity by team TotalsAs: 1, // Allocated/Capacity CapacityView: false, // Planned IsAvgMode: false // Totals average mode. SA. ENV-1046 }; $scope.DisplayData = {}; // UI data model $scope.DisplayDataOrder = ["Vacations", "Trainings"]; $scope.$on('rebindTeamInfo', function (event, data) { if (!data) return; $scope.InternalData = { Vacations: data.Vacations || {}, Trainings: data.Trainings || {}, Header: data.Header || {} }; initOptions(data.DisplayMode); initRows(); }); $scope.$on('groupCapacityByTeamChanged', function (event, data) { $scope.DisplayMode.GroupCapacityByTeam = data; initRows(); }); $scope.$on('changeUOMMode', function (event, data) { $scope.DisplayMode.IsUOMHours = data; initRows(); }); $scope.$on('totalsAsChanged', function (event, data) { $scope.DisplayMode.TotalsAs = data; initRows(); }); $scope.$on('capacityViewChanged', function (event, data) { $scope.DisplayMode.CapacityView = data; initRows(); }); $scope.$on('expenditureCategoryValueChanged', function (event, data) { if (!data) return; expenditureCategoryValueChanged(data.TeamId, data.ExpenditureCategoryId, data.WeekIndex); }); $scope.$on('resourceValueChanged', function (event, data) { if (!data) return; resourceValueChanged(data.TeamId, data.ExpenditureCategoryId, data.ResourceId, data.WeekIndex); }); $scope.toggleExpCategoryRow = function (key, $event) { if (!!$event && angular.isFunction($event.preventDefault)) $event.preventDefault(); $scope.DisplayData[key].IsCollapsed = !$scope.DisplayData[key].IsCollapsed; }; $scope.isAvgMode = function () { return $scope.DisplayMode.IsAvgMode && !$scope.DisplayMode.IsUOMHours; } // set page options with values received from outer scope function initOptions(options) { if (!options) return; var modes = Object.keys(options); if (modes.indexOf('IsUOMHours') >= 0) $scope.DisplayMode.IsUOMHours = options.IsUOMHours; if (modes.indexOf('GroupCapacityByTeam') >= 0) $scope.DisplayMode.GroupCapacityByTeam = options.GroupCapacityByTeam; if (modes.indexOf('TotalsAs') >= 0) $scope.DisplayMode.TotalsAs = options.TotalsAs; if (modes.indexOf('CapacityView') >= 0) $scope.DisplayMode.CapacityView = options.CapacityView; if (modes.indexOf('IsAvgMode') >= 0) $scope.DisplayMode.IsAvgMode = options.IsAvgMode; } //==========Start Convert data model to UI data model methods=============// function initVacationsRow() { return { Name: "Vacations", Type: RowType.Vacations, Cells: new Array($scope.InternalData.Header.Weeks.length) }; } function initTrainingsRow() { return { Name: "Trainings", Type: RowType.Trainings, Cells: new Array($scope.InternalData.Header.Weeks.length) }; } function initTeamRow(id, name) { return { Id: id, Name: name, Type: RowType.Team, Cells: new Array($scope.InternalData.Header.Weeks.length), CSSClass: new Array($scope.InternalData.Header.Weeks.length) }; } function initExpCategoryRow(category, teamId) { return { Id: category.Id, TeamId: teamId, Name: category.Name, Type: RowType.ExpenditureCategory, IsCollapsed: true, Cells: new Array($scope.InternalData.Header.Weeks.length), Resources: [], CSSClass: new Array($scope.InternalData.Header.Weeks.length) }; } function initResourceRow(resource, catId, teamId) { return { Id: resource.Id, ExpCatId: catId, TeamId: teamId, Name: resource.Name, Cells: new Array($scope.InternalData.Header.Weeks.length), CSSClass: new Array($scope.InternalData.Header.Weeks.length) }; } function initRows() { if (!$scope.InternalData) return; $scope.DisplayData = { "Vacations": initVacationsRow(), "Trainings": initTrainingsRow() }; $scope.DisplayDataOrder = ["Vacations", "Trainings"]; var teams = teamInfoService.getAll(); if (!!teams) { for (var teamId in teams) { var team = teams[teamId]; if ($scope.DisplayMode.GroupCapacityByTeam === true) { $scope.DisplayData[team.Id] = initTeamRow(team.Id, team.Name); $scope.DisplayDataOrder.push(team.Id); } if (!team.ExpCategories) continue; for (var expCatId in team.ExpCategories) { var ec = team.ExpCategories[expCatId]; var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + ec.Id : ec.Id; var teamId = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id : null; if (!$scope.DisplayData[ecKey]) { $scope.DisplayData[ecKey] = initExpCategoryRow(ec, teamId); $scope.DisplayDataOrder.push(ecKey); } if (!ec.Resources) continue; for (var resourceId in ec.Resources) { var resource = initResourceRow(ec.Resources[resourceId], ec.Id, teamId); $scope.DisplayData[ecKey].Resources.push(resource); } } } } initRowsData(); } function initRowsData() { if (!$scope.InternalData.Header.Months || !$scope.InternalData.Header.Weeks) return; for (var i in $scope.DisplayData) { var fillCellFunction = undefined, originalRow = $scope.DisplayData[i], expCat = undefined, team = undefined, resource = undefined; switch (originalRow.Type) { case RowType.Vacations: fillCellFunction = fillVacationCell; break; case RowType.Trainings: fillCellFunction = fillTrainingCell; break; case RowType.Team: fillCellFunction = fillTeamCell; team = teamInfoService.getById(originalRow.Id); break; case RowType.ExpenditureCategory: fillCellFunction = fillECTotalCell; team = teamInfoService.getById(originalRow.TeamId); if (team != null) expCat = teamInfoService.getExpenditureCategoryInTeam(originalRow.TeamId, originalRow.Id); break; } for (var mIndex in $scope.InternalData.Header.Months) { var month = $scope.InternalData.Header.Months[mIndex]; if (!month.Childs) continue; for (var wIndex in month.Childs) { if (fillCellFunction == undefined || typeof fillCellFunction !== 'function') { updateTotalCell(originalRow, month.Childs[wIndex], month.SelfIndexInWeeks, [0, 0]); } else { fillCellFunction(month.Childs[wIndex], month.SelfIndexInWeeks, originalRow, team, expCat); } } } } } function fillVacationCell(wIndex, mIndex, originalRow) { var week = $scope.InternalData.Header.Weeks[wIndex]; var value = 0; for (var expCatId in $scope.InternalData.Vacations) { var v = $scope.InternalData.Vacations[expCatId][week.Milliseconds] || 0; if (!$scope.DisplayMode.IsUOMHours) { value += hoursResourcesConverter.convertToResources(expCatId, v); } else { value += v; } } updateSimpleCell(originalRow, wIndex, mIndex, value); } function fillTrainingCell(wIndex, mIndex, originalRow) { var week = $scope.InternalData.Header.Weeks[wIndex]; var value = 0; for (var expCatId in $scope.InternalData.Trainings) { var v = $scope.InternalData.Trainings[expCatId][week.Milliseconds] || 0; if (!$scope.DisplayMode.IsUOMHours) { value += hoursResourcesConverter.convertToResources(expCatId, v); } else { value += v; } } updateSimpleCell(originalRow, wIndex, mIndex, value); } function fillECTotalCell(wIndex, mIndex, originalRow, team, expCat) { var week = $scope.InternalData.Header.Weeks[wIndex]; var values = { Value1: 0, Value2: 0 }; var resources = []; if (!team) { var teams = teamInfoService.getAll(); if (!!teams) { for (var teamId in teams) { var teamItem = teams[teamId]; for (var catKey in teamItem.ExpCategories) { if (teamItem.ExpCategories[catKey].Id == originalRow.Id) { values = getEcCellValue(teamItem.ExpCategories[catKey], week.Milliseconds, values); for (var resourceId in teamItem.ExpCategories[catKey].Resources) { resources.push(teamItem.ExpCategories[catKey].Resources[resourceId]); } } } } } } else { if (!expCat) { throw 'expCat for the team ' + team.Name + ' (' + team.Id + ') is not set'; } else { values = getEcCellValue(expCat, week.Milliseconds); for (var resourceId in expCat.Resources) { resources.push(expCat.Resources[resourceId]); } } } if (!$scope.DisplayMode.IsUOMHours) { values.Value1 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value1); values.Value2 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value2); } updateTotalCell(originalRow, wIndex, mIndex, values); updateResourcesCell(originalRow, wIndex, mIndex, resources, week.Milliseconds); } function fillTeamCell(wIndex, mIndex, originalRow, team) { if (team == null) return; var week = $scope.InternalData.Header.Weeks[wIndex]; var values = { Value1: 0, Value2: 0 }; for (var catKey in team.ExpCategories) { values = getEcCellValue(team.ExpCategories[catKey], week.Milliseconds, values); } if (!$scope.DisplayMode.IsUOMHours) { values.Value1 = hoursResourcesConverter.convertToResources(catKey, values.Value1); values.Value2 = hoursResourcesConverter.convertToResources(catKey, values.Value2); } updateTotalCell(originalRow, wIndex, mIndex, values); } function updateSimpleCell(originalRow, weekIndex, monthIndex, newValue) { if (!originalRow || !originalRow.Cells) return; if (originalRow.Cells[monthIndex] == undefined) originalRow.Cells[monthIndex] = 0; if (originalRow.Cells[weekIndex] == undefined) originalRow.Cells[weekIndex] = 0; // we should increase/decrease month total value by delta between new and old values var totalsDelta = newValue; var showAverageTotals = $scope.isAvgMode(); if (showAverageTotals) { var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex; var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length; totalsDelta = totalsDelta / weekCountInThisMonth; } originalRow.Cells[monthIndex] += totalsDelta - originalRow.Cells[weekIndex]; originalRow.Cells[weekIndex] = newValue; } function updateResourceCell(expCatRow, originalRow, weekIndex, monthIndex, newValues) { if (!originalRow || !originalRow.Cells) return; if (originalRow.Cells[monthIndex] == undefined) originalRow.Cells[monthIndex] = { Value1: 0, Value2: 0 }; if (originalRow.Cells[weekIndex] == undefined) originalRow.Cells[weekIndex] = { Value1: 0, Value2: 0 }; // we should to increase/decrease month total value by delta between new and old values var totalsDelta = {}; // SA. ENV-1046 totalsDelta.Value1 = newValues.Value1 - originalRow.Cells[weekIndex].Value1; totalsDelta.Value2 = newValues.Value2 - originalRow.Cells[weekIndex].Value2; var showAverageTotals = $scope.isAvgMode(); if (showAverageTotals) { var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex; var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length; totalsDelta.Value1 = totalsDelta.Value1 / weekCountInThisMonth; totalsDelta.Value2 = totalsDelta.Value2 / weekCountInThisMonth; } originalRow.Cells[monthIndex].Value1 += totalsDelta.Value1; originalRow.Cells[monthIndex].Value2 += totalsDelta.Value2; originalRow.Cells[weekIndex] = newValues; cellHighligting.setCellCssClasses(expCatRow, originalRow, weekIndex); cellHighligting.setCellCssClasses(expCatRow, originalRow, monthIndex); } function updateResourcesCell(originalRow, weekIndex, monthIndex, resources, milliseconds) { if (!originalRow || !originalRow.Resources) return; for (var resIndex = 0; resIndex < originalRow.Resources.length; resIndex++) { var resRow = originalRow.Resources[resIndex]; for (var i = 0; i < resources.length; i++) { if (resRow.Id == resources[i].Id) { var values = getResourceCellValue(resources[i], milliseconds); if (!$scope.DisplayMode.IsUOMHours) { values.Value1 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value1); values.Value2 = hoursResourcesConverter.convertToResources(originalRow.Id, values.Value2); } updateResourceCell(originalRow, resRow, weekIndex, monthIndex, values); continue; } } } } function updateTotalCell(originalRow, weekIndex, monthIndex, newValues) { if (!originalRow || !originalRow.Cells) return; if (originalRow.Cells[monthIndex] == undefined) originalRow.Cells[monthIndex] = { Value1: 0, Value2: 0 }; if (originalRow.Cells[weekIndex] == undefined) originalRow.Cells[weekIndex] = { Value1: 0, Value2: 0 }; // we should increase/decrease month total value by delta between new and old values var totalsDelta = {}; // SA. ENV-1046 totalsDelta.Value1 = newValues.Value1 - originalRow.Cells[weekIndex].Value1; totalsDelta.Value2 = newValues.Value2 - originalRow.Cells[weekIndex].Value2; var showAverageTotals = $scope.isAvgMode(); if (showAverageTotals) { var monthIndexInMonthes = $scope.InternalData.Header.Weeks[weekIndex].ParentIndex; var weekCountInThisMonth = $scope.InternalData.Header.Months[monthIndexInMonthes].Childs.length; totalsDelta.Value1 = totalsDelta.Value1 / weekCountInThisMonth; totalsDelta.Value2 = totalsDelta.Value2 / weekCountInThisMonth; } originalRow.Cells[monthIndex].Value1 += totalsDelta.Value1; originalRow.Cells[monthIndex].Value2 += totalsDelta.Value2; originalRow.Cells[weekIndex] = newValues; cellHighligting.setCellCssClasses(originalRow, null, weekIndex); cellHighligting.setCellCssClasses(originalRow, null, monthIndex); } // returns an object with values to display in Expenditure Category row (bottom part) function getEcCellValue(expCat, index, values) { if (!values) { values = { Value1: 0, Value2: 0 }; } if ($scope.DisplayMode.CapacityView) { // capacity = Actual switch (parseInt($scope.DisplayMode.TotalsAs)) { case 1: //Allocated/Capacity values.Value1 += expCat.AllocatedCapacity[index] || 0; values.Value2 += expCat.ActualCapacityValues[index] || 0; break; case 2: //Need/Capacity values.Value1 += expCat.NeedCapacity[index] || 0; values.Value2 += expCat.ActualCapacityValues[index] || 0; break; case 3: //Allocated/Need values.Value1 += expCat.AllocatedCapacity[index] || 0; values.Value2 += expCat.NeedCapacity[index] || 0; break; } } else { // capacity = Planned switch (parseInt($scope.DisplayMode.TotalsAs)) { case 1: //Allocated/Capacity values.Value1 += expCat.AllocatedCapacity[index] || 0; values.Value2 += expCat.PlannedCapacityValues[index] || 0; break; case 2: //Need/Capacity values.Value1 += expCat.NeedCapacity[index] || 0; values.Value2 += expCat.PlannedCapacityValues[index] || 0; break; case 3: //Allocated/Need values.Value1 += expCat.AllocatedCapacity[index] || 0; values.Value2 += expCat.NeedCapacity[index] || 0; break; } } return values; } // returns an object with values to display in Resource row (bottom part) function getResourceCellValue(resource, index) { return { Value1: resource.AllocatedCapacity[index] || 0, Value2: resource.TotalCapacity[index] || 0 }; } //==========End Convert data model to UI data model methods=============// function expenditureCategoryValueChanged(teamId, expenditureCategoryId, weekIndex) { if (!teamId || !expenditureCategoryId) return; var team = teamInfoService.getById(teamId); if (!team) return; var expCategoryInTeam = teamInfoService.getExpenditureCategoryInTeam(teamId, expenditureCategoryId); if (!expCategoryInTeam) return; var week = $scope.InternalData.Header.Weeks[weekIndex]; if (!week) return; var month = $scope.InternalData.Header.Months[week.ParentIndex]; if (!month) return; var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + expenditureCategoryId : expenditureCategoryId; var originalRow = $scope.DisplayData[ecKey]; if (!originalRow) return; if ($scope.DisplayMode.GroupCapacityByTeam === true) { fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow, team, expCategoryInTeam); if (!!$scope.DisplayData[team.Id]) { fillTeamCell(weekIndex, month.SelfIndexInWeeks, $scope.DisplayData[team.Id], team); } } else { fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow); } } function resourceValueChanged(teamId, expenditureCategoryId, resourceId, weekIndex) { if (!teamId || !expenditureCategoryId || !resourceId) return; var team = teamInfoService.getById(teamId); if (!team) return; var expCategoryInTeam = team.ExpCategories[expenditureCategoryId]; if (!expCategoryInTeam) return; var week = $scope.InternalData.Header.Weeks[weekIndex]; if (!week) return; var month = $scope.InternalData.Header.Months[week.ParentIndex]; if (!month) return; var ecKey = $scope.DisplayMode.GroupCapacityByTeam === true ? team.Id + '-' + expenditureCategoryId : expenditureCategoryId; var originalRow = $scope.DisplayData[ecKey]; if (!originalRow) return; if ($scope.DisplayMode.GroupCapacityByTeam === true) { fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow, team, expCategoryInTeam); if (!!$scope.DisplayData[team.Id]) { fillTeamCell(weekIndex, month.SelfIndexInWeeks, $scope.DisplayData[team.Id], team); } } else { fillECTotalCell(weekIndex, month.SelfIndexInWeeks, originalRow); } } }]);