3054 lines
150 KiB
JavaScript
3054 lines
150 KiB
JavaScript
'use strict';
|
|
|
|
app
|
|
.directive('optionClassExpr', function ($compile, $parse) {
|
|
var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
|
|
|
|
return {
|
|
restrict: 'A',
|
|
link: function optionClassExprPostLink(scope, elem, attrs) {
|
|
var optionsExp = attrs.ngOptions;
|
|
if (!optionsExp) return;
|
|
|
|
var match = optionsExp.match(NG_OPTIONS_REGEXP);
|
|
if (!match) return;
|
|
|
|
var values = match[7];
|
|
|
|
scope.$watchCollection(function () {
|
|
return elem.children();
|
|
}, function (newValue) {
|
|
angular.forEach(newValue, function (child, index) {
|
|
var child = angular.element(child);
|
|
var val = child.val();
|
|
if (val) {
|
|
child.attr('ng-class', values + '[' + (index - 1) + '].' + attrs.optionClassExpr);
|
|
$compile(child)(scope);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
})
|
|
.directive('selectedSourceChanged', ['$timeout', function ($timeout) {
|
|
return {
|
|
link: function ($scope, element, attrs) {
|
|
$scope.$on('selectedSourceChanged', function () {
|
|
$timeout(function () { // You might need this timeout to be sure its run after DOM render.
|
|
element.trigger("change");
|
|
}, 0, false);
|
|
})
|
|
}
|
|
};
|
|
}])
|
|
.controller('capacityManagementController', ['$scope', '$http', '$location', '$timeout', '$window', 'cellHighlightingService', 'scenarioDetailsService', 'dataSources', '$document', function ($scope, $http, $location, $timeout, $window, cellHighlightingService, scenarioDetailsService, dataSources, $document) {
|
|
$scope.RowType = {
|
|
Project: 0,
|
|
ProjectExpenditureCategory: 1,
|
|
Total: 2,
|
|
Capacity: 3,
|
|
BottomCategory: 4,
|
|
Team: 5,
|
|
CurrentlyAssigned: 6,
|
|
NonProjectTimeTotal: 7,
|
|
Actual: 8,
|
|
NonProjectTimeCategory: 9,
|
|
NonProjectTime: 10
|
|
}
|
|
$scope.CollapsedIcon = 'fa-plus-square';
|
|
$scope.NonCollapsedIcon = 'fa-minus-square';
|
|
|
|
$scope.ScenarioCollapsedIcon = 'fa-plus-square-1';
|
|
$scope.ScenarioNonCollapsedIcon = 'fa-minus-square-1';
|
|
|
|
$scope.ExpCatCollapsedIcon = 'fa-plus-square-2';
|
|
$scope.ExpCatNonCollapsedIcon = 'fa-minus-square-2';
|
|
|
|
$scope.id = $location.absUrl().substr($location.absUrl().lastIndexOf('ls/') + 3, 36);
|
|
//$scope.data = {
|
|
// VisibleCellCount: 1
|
|
//};
|
|
$scope.dataSection = "";
|
|
$scope.pageTitle = ""; // SA. ENV-905
|
|
$scope.preferences = [];
|
|
$scope.isOverAllocated = false;
|
|
$scope.isMatchChecked = false;
|
|
$scope.saveType = "0"; // save scenarios with preserving their current types (BU or TD)
|
|
$scope.SaveAs = 0;
|
|
$scope.isActiveScenario = true;
|
|
$scope.ScenarioName = "";
|
|
$scope.dateError = false;
|
|
$scope.isReadOnly = false;
|
|
var scrollWidthHeight = $.getScrollBarWidthHeight();
|
|
$scope.calendarViewSettings = {
|
|
headerWidth: 70,
|
|
tableHeightMin: 450,
|
|
scrollWidth: scrollWidthHeight[0],
|
|
scrollHeight: scrollWidthHeight[1]
|
|
};
|
|
$scope.calendarFilters = {
|
|
CompanyId: null,
|
|
StartDate: null,
|
|
EndDate: null,
|
|
ViewId: null,
|
|
TeamId: null,
|
|
ResourceId: null,
|
|
IsUOMHours: null,
|
|
PreferredTotalsDisplaying: null,
|
|
ShowUpper: true,
|
|
ShowLower: true,
|
|
IsBarMode: true,
|
|
ShowCapacity: 1, //"Total Allocated/Total Capacity"
|
|
GroupByTeam: true,
|
|
IsViewModeMonth: true,
|
|
ShowAvgTotals: true,
|
|
IsCapacityModeActuals: true,
|
|
sortOrder: false,
|
|
sortBy: 'Name'
|
|
};
|
|
|
|
// SA. ENV-799
|
|
$scope.CalendarFilterMode = {
|
|
IsCompany: true,
|
|
IsView: false,
|
|
IsTeam: false,
|
|
IsResource: false,
|
|
|
|
FilteredEntityTitle: "Company",
|
|
SelectedItemId: null,
|
|
}
|
|
|
|
$scope.SpreadType = {
|
|
Notspecified: -1,
|
|
Equal: 0,
|
|
Less: 1,
|
|
Over: 2
|
|
};
|
|
|
|
$scope.availableFilterOptions = {};
|
|
$scope.data = null;
|
|
$scope.data2Update = {
|
|
IsOverAllocated: false,
|
|
IsMatchChecked: false,
|
|
SaveType: "0",
|
|
SaveAs: 0,
|
|
IsActiveScenario: false,
|
|
ScenarioName: "",
|
|
ChangedExpCats: [],
|
|
NonProjectTimeCats: [],
|
|
ChangedSupperExpCatProjects: []
|
|
};
|
|
|
|
$scope.grandtotalrow = null;
|
|
|
|
$scope.$watch("saveType", function (newValue, oldValue) {
|
|
if (newValue != oldValue) {
|
|
if (newValue == "1") {
|
|
$scope.isMatchChecked = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
function getExpCatById(scenarioId, ExpCatId, teamId) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ExpCatId != null
|
|
&& $scope.data.Calendar[i].ScenarioId == scenarioId && $scope.data.Calendar[i].ExpCatId == ExpCatId &&
|
|
(!$scope.calendarFilters.GroupByTeam || $scope.CalendarFilterMode.IsTeam || $scope.data.Calendar[i].TeamId == teamId)) {
|
|
return $scope.data.Calendar[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getNonProjectTimeCatById(nonProjectTimeCategoryId) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == $scope.RowType.NonProjectTimeTotal) {
|
|
if (nonProjectTimeCategoryId == null) {
|
|
return $scope.data.Calendar[i];
|
|
} else {
|
|
for (var j in $scope.data.Calendar[i].Categories) {
|
|
var category = $scope.data.Calendar[i].Categories[j];
|
|
if (category.Id == nonProjectTimeCategoryId) {
|
|
return category;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getNonProjectTimeById(Id) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == $scope.RowType.NonProjectTimeTotal) {
|
|
for (var j in $scope.data.Calendar[i].Categories) {
|
|
var category = $scope.data.Calendar[i].Categories[j];
|
|
if (category.Id == Id) {
|
|
return category;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getResourceByNonProjectTime(category, resId) {
|
|
for (var i = 0; i < category.Resources.length; i++) {
|
|
if (category.Resources[i].Id == resId) {
|
|
return category.Resources[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// this method returns first project row, but not related for any team
|
|
// just for now it is using only for getting start/end date
|
|
function getProjectById(projectId) {
|
|
return getProjectById(projectId, null);
|
|
}
|
|
|
|
function getProjectById(projectId, teamId) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ExpCatId == null && $scope.data.Calendar[i].ProjectId == projectId && (teamId == null || teamId == $scope.data.Calendar[i].TeamId)) {
|
|
return $scope.data.Calendar[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function isProjectHaveSupperExpCat(projectId) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ExpCatId != null && $scope.data.Calendar[i].ProjectId == projectId && $scope.data.Calendar[i].AllowResourceAssignment == false) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function getResourceById(resId) {
|
|
for (var i = 0; i < $scope.data.AllResources.length; i++) {
|
|
if ($scope.data.AllResources[i].Id == resId) {
|
|
return $scope.data.AllResources[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getResourceByExpCat(expCat, resId) {
|
|
if (expCat != null) {
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
|
|
if (expCat.Resources[i].Id == resId) {
|
|
return expCat.Resources[i];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getECsThatContainResource(resourceId) {
|
|
if (!resourceId)
|
|
return;
|
|
|
|
var result = [];
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
var expCatTotal = $scope.data.Calendar[i];
|
|
if (expCatTotal.RowType != $scope.RowType.BottomCategory)
|
|
continue;
|
|
|
|
var resource = getResourceByExpCat(expCatTotal, resourceId);
|
|
if (resource) {
|
|
result.push(expCatTotal);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
function getResourceActualByExpCat(expCat, resId) {
|
|
if (expCat != null) {
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
|
|
if (expCat.Resources[i].Id == resId) {
|
|
return expCat.Resources[i];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function setChildrenCollapsed(row, internal, parentCollapsed) {
|
|
|
|
var isProject = row.ProjectId != null && row.ExpCatId == null;
|
|
var isExpCat = row.ExpCatId != null;
|
|
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
var currRow = $scope.data.Calendar[i];
|
|
if (isProject && currRow.ExpCatId != null && currRow.ProjectId == row.ProjectId &&
|
|
(!$scope.calendarFilters.GroupByTeam || currRow.TeamId == row.TeamId)) {
|
|
var expCat = currRow;
|
|
if (internal) {
|
|
expCat.IsParentCollapsed = parentCollapsed;
|
|
setChildrenCollapsed(expCat, true, parentCollapsed);
|
|
} else {
|
|
expCat.IsParentCollapsed = row.ProjectCollapsed;
|
|
setChildrenCollapsed(expCat, true, row.ProjectCollapsed);
|
|
}
|
|
} else if (isExpCat && currRow.ExpCatId == row.ExpCatId && currRow.ScenarioId == row.ScenarioId &&
|
|
(!$scope.calendarFilters.GroupByTeam || currRow.TeamId == row.TeamId)) {
|
|
var resource = currRow;
|
|
if (internal) {
|
|
resource.IsParentCollapsed = parentCollapsed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearResource(scenarioId, expCatId, resource, teamId) {
|
|
if (resource != null) {
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
changeResourceValue(0, scenarioId, expCatId, resource.Id, teamId, i, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateTotals(expCat, expCatTotal, resourceTotal, resource, colIndex, newQuantity, oldQuantity, newCost, oldCost) {
|
|
var monthStartIndex = colIndex;
|
|
var monthEndIndex = colIndex;
|
|
var weeks = 1;
|
|
var project = getProjectById(expCat.ProjectId);
|
|
var resourceEndDateWeekending = getNearestWeekending(resource.EndDate);
|
|
var projectEndDateWeekending = getNearestWeekending(project.EndDate);
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
|
|
//Get current month start/end weeks index and weeks count
|
|
var montIndex = 0;
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth) {
|
|
monthEndIndex = i;
|
|
montIndex = $scope.data.Headers[i].MonthIndex;
|
|
weeks = $scope.data.Headers[i].Weeks.length;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < monthEndIndex; i++) {
|
|
var currWeekending = $scope.data.Headers[i].Milliseconds;
|
|
|
|
if (montIndex == $scope.data.Headers[i].MonthIndex && currWeekending >= resource.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending &&
|
|
currWeekending >= project.StartDate && currWeekending <= projectEndDateWeekending) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
monthStartIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Get grand total for all months and months count
|
|
var firstWeekIndex = -1;
|
|
var lastWeekIndex = -1;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
|
|
var currWeekending = $scope.data.Headers[i].Milliseconds;
|
|
if ((currWeekending >= resource.StartDate && currWeekending <= resourceEndDateWeekending &&
|
|
currWeekending >= project.StartDate && currWeekending <= projectEndDateWeekending)) {
|
|
if (!$scope.data.Headers[i].IsMonth && firstWeekIndex < 0) {
|
|
firstWeekIndex = i;
|
|
}
|
|
lastWeekIndex = i;
|
|
}
|
|
}
|
|
|
|
var totalWeeksQuantity = 0;
|
|
var totalWeeks = 0;
|
|
//In case when resource hire dates are later then project dates
|
|
if (firstWeekIndex > -1 && lastWeekIndex > -1) {
|
|
for (var i = firstWeekIndex; i <= lastWeekIndex; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
totalWeeksQuantity += (i == colIndex) ? newQuantity : resource.QuantityValues[i];
|
|
totalWeeks++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Calculate grand total
|
|
if (avg) {
|
|
resource.GrandTotalQuantity = Math.round(totalWeeksQuantity / totalWeeks * 1000) / 1000;
|
|
} else {
|
|
resource.GrandTotalQuantity = totalWeeksQuantity;
|
|
}
|
|
|
|
oldQuantity = resource.QuantityValues[monthEndIndex];
|
|
|
|
//Get current month total
|
|
var monthTotal = 0;
|
|
for (var i = monthStartIndex; i < monthEndIndex; i++) {
|
|
monthTotal += (colIndex == i) ? newQuantity : resource.QuantityValues[i];
|
|
}
|
|
|
|
//Calculate current month total
|
|
if (avg) {
|
|
newQuantity = Math.round(monthTotal / weeks * 1000) / 1000;
|
|
} else {
|
|
newQuantity = monthTotal;
|
|
}
|
|
|
|
//Change quantity for month
|
|
//resource.QuantityValues[monthEndIndex] = newQuantity;
|
|
if (resourceTotal != null) {
|
|
if (avg) {
|
|
recalcButtomPartRows(resourceTotal, expCatTotal, monthEndIndex);
|
|
} else {
|
|
if (expCat.ExpCatId === expCatTotal.ExpCatId) {
|
|
resourceTotal.QuantityValues[monthEndIndex] += (newQuantity - oldQuantity);
|
|
resourceTotal.GrandTotalQuantity += (newQuantity - oldQuantity);
|
|
expCatTotal.QuantityTotalAllocatedValue[monthEndIndex] += (newQuantity - oldQuantity);
|
|
}
|
|
resourceTotal.AllocatedQuantityValues[monthEndIndex] += (newQuantity - oldQuantity);
|
|
}
|
|
}
|
|
|
|
return {
|
|
MonthEndIndex: monthEndIndex,
|
|
NewQuantity: newQuantity
|
|
};
|
|
}
|
|
|
|
function updateNonProjectTimeTotals(nonProjectTimeCategory, nonProjectTimeTotal, nonProjectTime, resource, colIndex, newQuantity, oldQuantity) {
|
|
var monthStartIndex = -1;
|
|
var mounthWeeks = 1;
|
|
var monthColIndex = 0;
|
|
var categoryMonthTotal = 0;
|
|
var monthNonProjectTimeTotalTotal = 0;
|
|
var monthNonProjectTimeTotal = 0;
|
|
|
|
var categoryMonth = 0;
|
|
var month = 0;
|
|
var monthNonProjectTime = 0;
|
|
|
|
var firstWeekIndex = -1;
|
|
var lastWeekIndex = -1;
|
|
|
|
var totalWeeksQuantity = 0;
|
|
var totalWeeks = 0;
|
|
var monthTotal = 0;
|
|
|
|
var monthIndex = $scope.data.Headers[colIndex].MonthIndex;
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
var delta = 0;
|
|
if (nonProjectTime.IsTeamMode)
|
|
delta = newQuantity - oldQuantity;
|
|
else
|
|
delta = newQuantity - oldQuantity;
|
|
|
|
//Change NPT, NPT Total and NPT Category values
|
|
nonProjectTimeCategory.QuantityValues[colIndex] += delta;
|
|
nonProjectTimeTotal.QuantityValues[colIndex] += delta;
|
|
nonProjectTime.QuantityValues[colIndex] += delta;
|
|
|
|
//Get grand total for all months and months count
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
|
|
if ($scope.data.Headers[i].IsMonth && monthIndex == $scope.data.Headers[i].MonthIndex) {
|
|
//monthEndIndex = i;
|
|
//montIndex = $scope.data.Headers[i].MonthIndex;
|
|
mounthWeeks = $scope.data.Headers[i].Weeks.length;
|
|
monthColIndex = i;
|
|
//break;
|
|
}
|
|
|
|
if (!$scope.data.Headers[i].IsMonth && monthIndex == $scope.data.Headers[i].MonthIndex && monthStartIndex == -1) {
|
|
monthStartIndex = i;
|
|
//break;
|
|
}
|
|
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
if (firstWeekIndex == -1) {
|
|
firstWeekIndex = i;
|
|
}
|
|
lastWeekIndex = i;
|
|
}
|
|
}
|
|
|
|
monthStartIndex = monthStartIndex == -1 ? colIndex : monthStartIndex;
|
|
|
|
//In case when resource hire dates are later then project dates
|
|
if (firstWeekIndex > -1 && lastWeekIndex > -1) {
|
|
for (var i = firstWeekIndex; i <= lastWeekIndex; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
if (!nonProjectTime.IsTeamMode)
|
|
totalWeeksQuantity += (i == colIndex) ? newQuantity : resource.QuantityValues[i];
|
|
else
|
|
totalWeeksQuantity += (i == colIndex) ? newQuantity : nonProjectTime.QuantityValues[i];
|
|
totalWeeks++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Calculate resource grand total
|
|
if (!nonProjectTime.IsTeamMode)
|
|
resource.GrandTotalQuantity = avg ? Math.round(totalWeeksQuantity / totalWeeks * 1000) / 1000 : totalWeeksQuantity;
|
|
else
|
|
nonProjectTime.GrandTotalQuantity = avg ? Math.round(totalWeeksQuantity / totalWeeks * 1000) / 1000 : totalWeeksQuantity;
|
|
|
|
//Get current resource month total
|
|
for (var i = monthStartIndex; i < monthColIndex; i++) {
|
|
if (!nonProjectTime.IsTeamMode)
|
|
monthTotal += (colIndex == i) ? newQuantity : resource.QuantityValues[i];
|
|
else
|
|
monthTotal += (colIndex == i) ? newQuantity : nonProjectTime.QuantityValues[i];
|
|
}
|
|
|
|
//Calculate current month total
|
|
var newMonthQuantity = avg ? Math.round(monthTotal / mounthWeeks * 1000) / 1000 : monthTotal;
|
|
|
|
//Change quantity for month
|
|
if (!nonProjectTime.IsTeamMode)
|
|
resource.QuantityValues[monthColIndex] = newMonthQuantity;
|
|
else
|
|
nonProjectTime.QuantityValues[monthColIndex] = newMonthQuantity;
|
|
|
|
//Agregate NPT, NPT Total and NPT Category month and grandtotal values
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
if (monthIndex == $scope.data.Headers[i].MonthIndex) {
|
|
categoryMonth += nonProjectTimeCategory.QuantityValues[i];
|
|
month += nonProjectTimeTotal.QuantityValues[i];
|
|
monthNonProjectTime += nonProjectTime.QuantityValues[i];
|
|
}
|
|
categoryMonthTotal += nonProjectTimeCategory.QuantityValues[i];
|
|
monthNonProjectTimeTotalTotal += nonProjectTimeTotal.QuantityValues[i];
|
|
monthNonProjectTimeTotal += nonProjectTime.QuantityValues[i];
|
|
}
|
|
}
|
|
|
|
//Change NPT, NPT Total and NPT Category month values
|
|
nonProjectTimeCategory.QuantityValues[monthColIndex] = avg ? categoryMonth / mounthWeeks : categoryMonth;
|
|
nonProjectTimeTotal.QuantityValues[monthColIndex] = avg ? month / mounthWeeks : month;
|
|
nonProjectTime.QuantityValues[monthColIndex] = avg ? monthNonProjectTime / mounthWeeks : monthNonProjectTime;
|
|
|
|
//Change NPT, NPT Total and NPT Category grandtotal values
|
|
nonProjectTimeCategory.GrandTotalQuantity = avg ? categoryMonthTotal / totalWeeks : categoryMonthTotal;
|
|
nonProjectTimeTotal.GrandTotalQuantity = avg ? monthNonProjectTimeTotalTotal / totalWeeks : monthNonProjectTimeTotalTotal;
|
|
nonProjectTime.GrandTotalQuantity = avg ? monthNonProjectTimeTotal / totalWeeks : monthNonProjectTimeTotal;
|
|
}
|
|
|
|
function updateActualTotals(expCat, expCatTotal, actualTotal, resource, colIndex, newQuantity, oldQuantity) {
|
|
var monthStartIndex = colIndex;
|
|
var monthEndIndex = colIndex;
|
|
var weeks = 1;
|
|
var project = getProjectById(expCat.ProjectId);
|
|
var resourceEndDateWeekending = getNearestWeekending(resource.EndDate);
|
|
var projectEndDateWeekending = getNearestWeekending(project.EndDate);
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
|
|
//Get current month start/end weeks index and weeks count
|
|
var montIndex = 0;
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth) {
|
|
monthEndIndex = i;
|
|
montIndex = $scope.data.Headers[i].MonthIndex;
|
|
weeks = $scope.data.Headers[i].Weeks.length;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < monthEndIndex; i++) {
|
|
var currWeekending = $scope.data.Headers[i].Milliseconds;
|
|
|
|
if (montIndex == $scope.data.Headers[i].MonthIndex && currWeekending >= resource.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending &&
|
|
currWeekending >= project.StartDate && currWeekending <= projectEndDateWeekending) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
monthStartIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Get grand total for all months and months count
|
|
var firstWeekIndex = -1;
|
|
var lastWeekIndex = -1;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
|
|
var currWeekending = $scope.data.Headers[i].Milliseconds;
|
|
if ((currWeekending >= resource.StartDate && currWeekending <= resourceEndDateWeekending &&
|
|
currWeekending >= project.StartDate && currWeekending <= projectEndDateWeekending)) {
|
|
if (!$scope.data.Headers[i].IsMonth && firstWeekIndex < 0) {
|
|
firstWeekIndex = i;
|
|
}
|
|
lastWeekIndex = i;
|
|
}
|
|
}
|
|
|
|
var totalWeeksQuantity = 0;
|
|
var totalWeeks = 0;
|
|
//In case when resource hire dates are later then project dates
|
|
if (firstWeekIndex > -1 && lastWeekIndex > -1) {
|
|
for (var i = firstWeekIndex; i <= lastWeekIndex; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
totalWeeksQuantity += (i == colIndex) ? newQuantity : resource.ActualQuantityValues[i];
|
|
totalWeeks++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Calculate grand total
|
|
if (avg) {
|
|
resource.GrandActualTotalQuantity = Math.round(totalWeeksQuantity / totalWeeks * 1000) / 1000;
|
|
} else {
|
|
resource.GrandActualTotalQuantity = totalWeeksQuantity;
|
|
}
|
|
|
|
oldQuantity = resource.ActualQuantityValues[monthEndIndex];
|
|
|
|
//Get current month total
|
|
var monthTotal = 0;
|
|
for (var i = monthStartIndex; i < monthEndIndex; i++) {
|
|
monthTotal += (colIndex == i) ? newQuantity : resource.ActualQuantityValues[i];
|
|
}
|
|
|
|
//Calculate current month total
|
|
if (avg) {
|
|
newQuantity = Math.round(monthTotal / weeks * 1000) / 1000;
|
|
} else {
|
|
newQuantity = monthTotal;
|
|
}
|
|
|
|
//Change quantity for month
|
|
resource.ActualQuantityValues[monthEndIndex] = newQuantity;
|
|
}
|
|
|
|
function recalcButtomPartRows(resourceTotal, expCatTotal, monthEndIndex) {
|
|
//recalc AVG for month
|
|
var monthIndex = $scope.data.Headers[monthEndIndex].MonthIndex;
|
|
var resourceValue = 0,
|
|
resourceAllocatedValue = 0,
|
|
allocatedValue = 0;
|
|
|
|
for (var i = 0; i < monthEndIndex; i++) {
|
|
if ($scope.data.Headers[i].MonthIndex == monthIndex) {
|
|
resourceValue += resourceTotal.QuantityValues[i];
|
|
resourceAllocatedValue += resourceTotal.AllocatedQuantityValues[i];
|
|
allocatedValue += expCatTotal.QuantityTotalAllocatedValue[i];
|
|
}
|
|
}
|
|
resourceTotal.QuantityValues[monthEndIndex] = resourceValue / $scope.data.Headers[monthEndIndex].Weeks.length;
|
|
resourceTotal.AllocatedQuantityValues[monthEndIndex] = resourceAllocatedValue / $scope.data.Headers[monthEndIndex].Weeks.length;
|
|
expCatTotal.QuantityTotalAllocatedValue[monthEndIndex] = allocatedValue / $scope.data.Headers[monthEndIndex].Weeks.length;
|
|
|
|
//recalc AVG for resource total
|
|
resourceValue = 0
|
|
var weeksCount = 0;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
resourceValue += resourceTotal.QuantityValues[i];
|
|
weeksCount++;
|
|
}
|
|
|
|
}
|
|
resourceTotal.GrandTotalQuantity = resourceValue / weeksCount;
|
|
//recalc AVG for expcat total
|
|
}
|
|
|
|
function allocateResource(resource, expCat, create, allocateRest, reset) {
|
|
if (resource != null) {
|
|
|
|
var scenarioCalendarRow = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == $scope.RowType.Project && $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId) {
|
|
scenarioCalendarRow = $scope.data.Calendar[i];
|
|
break;
|
|
}
|
|
}
|
|
// TODO: ENV-1649. Seems like resource.Teams contains all teams resource have been ever assigned to
|
|
// and expCat.Teams contains all teams from calendar, so we cannot get one team for entire calendar
|
|
// we should get it separately in a headers for loop
|
|
var team = null;
|
|
for (i = 0; i < expCat.Teams.length; i++) {
|
|
if (findTeamInResourceTeams(resource.Teams, expCat.Teams[i].Id)) {
|
|
team = expCat.Teams[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var res = getResourceById(resource.Id);
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
var cellReadonly = resource.ReadOnlyWeeks[i] || scenarioCalendarRow.ReadOnly[i];
|
|
if ($scope.data.Headers[i].IsMonth || (!reset && cellReadonly))
|
|
continue;
|
|
|
|
var quantity = 0;
|
|
if (create || reset) //Reset
|
|
{
|
|
if (create)
|
|
resource.QuantityValues[i] = 0;
|
|
if (reset && cellReadonly && resource.QuantityValues[i] == 0) // reset readonly cells only if any data exists in it
|
|
continue;
|
|
quantity = 0;
|
|
|
|
} else if (allocateRest) { //AssignRest
|
|
if (team != null) {
|
|
var needToAssign = Math.max(team.QuantityValues[i] - team.AllocatedByResources[i], 0);
|
|
} else {
|
|
var needToAssign = 0;
|
|
}
|
|
var canBeAssigned = Math.max(res.CapacityQuantityValues[i] - res.AllocatedQuantityValues[i], 0);
|
|
quantity = Math.min(needToAssign, canBeAssigned);
|
|
if (quantity == 0) {
|
|
continue;
|
|
}
|
|
quantity += resource.QuantityValues[i];
|
|
|
|
} else { //AssignAll
|
|
if (team != null) {
|
|
var needToAssign = Math.max(team.QuantityValues[i] - team.AllocatedByResources[i] + resource.QuantityValues[i], 0);
|
|
} else {
|
|
var needToAssign = 0;
|
|
}
|
|
var canBeAssigned = Math.max(res.CapacityQuantityValues[i], 0);
|
|
quantity = Math.min(needToAssign, canBeAssigned);
|
|
if (quantity == 0) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
changeResourceValue(quantity, expCat.ScenarioId, expCat.ExpCatId, resource.Id, expCat.TeamId, i, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex) {
|
|
var i;
|
|
if (expCat != null) {
|
|
var scenarioCalendarRow = getProjectById(expCat.ProjectId, expCat.TeamId);
|
|
var resTotal = 0;
|
|
for (i = 0; i < expCat.Resources.length; i++) {
|
|
resTotal += expCat.Resources[i].QuantityValues[colIndex];
|
|
}
|
|
|
|
//Validate team allocation upper
|
|
var compareRes = cellHighlightingService.compare(resTotal, expCat.QuantityValues[colIndex]);
|
|
|
|
expCat.SpreadVal[colIndex] = compareRes == null ? $scope.SpreadType.Notspecified :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Over;
|
|
|
|
updateCSSClass(expCat, null, colIndex);
|
|
|
|
var projectClass = $scope.SpreadType.Notspecified;
|
|
for (i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ProjectId == expCat.ProjectId && $scope.data.Calendar[i].ExpCatId != null
|
|
&& $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId
|
|
&& (!$scope.calendarFilters.GroupByTeam || $scope.data.Calendar[i].TeamId == expCat.TeamId)) {
|
|
|
|
if ($scope.data.Calendar[i].SpreadVal[colIndex] == $scope.SpreadType.Over) {
|
|
projectClass = $scope.SpreadType.Over;
|
|
break;
|
|
} else if ($scope.data.Calendar[i].SpreadVal[colIndex] == $scope.SpreadType.Less) {
|
|
projectClass = $scope.SpreadType.Less;
|
|
}
|
|
}
|
|
}
|
|
|
|
//Validate SD allocation
|
|
scenarioCalendarRow.SpreadVal[colIndex] = projectClass;
|
|
updateCSSClass(scenarioCalendarRow, null, colIndex);
|
|
}
|
|
|
|
var isMonth = $scope.data.Headers[colIndex].IsMonth;
|
|
var startIndex = colIndex;
|
|
if (isMonth)
|
|
{
|
|
for (var mIndex = colIndex - 1; mIndex >= 0; mIndex--)
|
|
{
|
|
if ($scope.data.Headers[mIndex].IsMonth)
|
|
break;
|
|
startIndex--;
|
|
}
|
|
}
|
|
|
|
//calc exp cat total row
|
|
if (expCatTotal != null) {
|
|
expCatTotal.SpreadVal[colIndex] = $scope.SpreadType.Notspecified;
|
|
//Validate resource allocation bottom
|
|
for (i = 0; i < expCatTotal.Resources.length; i++) {
|
|
var res = expCatTotal.Resources[i];
|
|
if (isMonth) {
|
|
var resMonthSpreadVal = $scope.SpreadType.Notspecified;
|
|
for (var mIndex = startIndex; mIndex < colIndex; mIndex++) {
|
|
if (res.SpreadVal[mIndex] == $scope.SpreadType.Over)
|
|
resMonthSpreadVal = res.SpreadVal[mIndex];
|
|
else if (resMonthSpreadVal != $scope.SpreadType.Over && resMonthSpreadVal != $scope.SpreadType.Less && res.SpreadVal[mIndex] == $scope.SpreadType.Less)
|
|
resMonthSpreadVal = res.SpreadVal[mIndex];
|
|
else if (resMonthSpreadVal != $scope.SpreadType.Over && resMonthSpreadVal != $scope.SpreadType.Less)
|
|
resMonthSpreadVal = res.SpreadVal[mIndex];
|
|
}
|
|
res.SpreadVal[colIndex] = resMonthSpreadVal;
|
|
updateCSSClass(expCatTotal, res, colIndex);
|
|
|
|
} else {
|
|
var resValue = res.QuantityTotalResValue[colIndex];
|
|
|
|
var compareRes = cellHighlightingService.compare(res.QuantityValues[colIndex], resValue);
|
|
|
|
res.SpreadVal[colIndex] = compareRes == null ? $scope.SpreadType.Notspecified :
|
|
compareRes == 0 ? $scope.SpreadType.Equal :
|
|
compareRes < 0 ? $scope.SpreadType.Less : $scope.SpreadType.Over;
|
|
|
|
updateCSSClass(expCatTotal, res, colIndex);
|
|
setParentCSSClass(colIndex, expCatTotal, res, null);
|
|
updateCSSClass(expCatTotal, null, colIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!expCatTotal.IsSuperEC) {
|
|
|
|
for (i = 0; i < expCatTotal.Resources.length; i++) {
|
|
var resBottom = expCatTotal.Resources[i];
|
|
for (var k = 0; k < $scope.data.Calendar.length; k++) {
|
|
if ($scope.data.Calendar[k].ProjectId != null && $scope.data.Calendar[k].ExpCatId != null && $scope.data.Calendar[k].ScenarioId != null) {
|
|
var nextExpCat = $scope.data.Calendar[k];
|
|
var project = getProjectById(nextExpCat.ProjectId, nextExpCat.TeamId);
|
|
if (nextExpCat != null && nextExpCat.Resources != null) {
|
|
for (var j = 0; j < nextExpCat.Resources.length; j++) {
|
|
var resUpper = nextExpCat.Resources[j];
|
|
|
|
if (resUpper.Id == resBottom.Id && resUpper.QuantityValues[colIndex] > 0) {
|
|
//Validate resource allocation upper when capacity exceeded
|
|
//Upper resource allocation is red when exceeds capacity or not painted
|
|
resUpper.SpreadVal[colIndex] = expCatTotal.SpreadVal[colIndex] == $scope.SpreadType.Over ? $scope.SpreadType.Over :
|
|
$scope.SpreadType.Notspecified;
|
|
updateCSSClass(nextExpCat, resUpper, colIndex);
|
|
|
|
setParentCSSClass(colIndex, nextExpCat, resUpper, project);
|
|
updateCSSClass(nextExpCat, null, colIndex);
|
|
updateCSSClass(project, null, colIndex);
|
|
|
|
//Validate resource allocation upper when resources allocation sum exceeded team allocation when resource capacity is not over allocated
|
|
if (resUpper.SpreadVal[colIndex] != $scope.SpreadType.Over) {
|
|
if (nextExpCat != null && nextExpCat.Resources != null) {
|
|
var teamValue1 = nextExpCat.QuantityValues[colIndex];
|
|
var resValue1Sum = 0;
|
|
for (var l = 0; l < nextExpCat.Resources.length; l++) {
|
|
var res1 = nextExpCat.Resources[l];
|
|
resValue1Sum += res1.QuantityValues[colIndex];
|
|
}
|
|
compareRes = cellHighlightingService.compare(resValue1Sum, teamValue1);
|
|
|
|
for (var l = 0; l < nextExpCat.Resources.length; l++) {
|
|
var res1 = nextExpCat.Resources[l];
|
|
res1.SpreadVal[colIndex] = compareRes == null || compareRes < 0 ? $scope.SpreadType.Notspecified :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Over;
|
|
updateCSSClass(nextExpCat, res1, colIndex);
|
|
|
|
setParentCSSClass(colIndex, nextExpCat, res1, project);
|
|
updateCSSClass(nextExpCat, null, colIndex);
|
|
updateCSSClass(project, null, colIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function setParentCSSClass(colIndex, expCat, res, project)
|
|
{
|
|
if (expCat.SpreadVal[colIndex] != $scope.SpreadType.Over) {
|
|
if (expCat.SpreadVal[colIndex] != $scope.SpreadType.Less) {
|
|
if (res.SpreadVal[colIndex] != $scope.SpreadType.Notspecified) {
|
|
expCat.SpreadVal[colIndex] = res.SpreadVal[colIndex];
|
|
if(project != null)
|
|
project.SpreadVal[colIndex] = expCat.SpreadVal[colIndex];
|
|
}
|
|
}
|
|
else {
|
|
if (res.SpreadVal[colIndex] == $scope.SpreadType.Over) {
|
|
expCat.SpreadVal[colIndex] = res.SpreadVal[colIndex];
|
|
if (project != null)
|
|
project.SpreadVal[colIndex] = expCat.SpreadVal[colIndex];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateCSSClass(row, resRow, colIndex) {
|
|
if (resRow == null) { // updating project/scenario/category row
|
|
if (row == null || colIndex == null || row.SpreadVal == null || row.SpreadVal.length <= colIndex)
|
|
return;
|
|
row.CSSClass[colIndex] = (row.CSSClass[colIndex] || '').replace(/cellover/g, '').replace(/cellless/g, '').replace(/cellequal/g, '');;
|
|
if (!row.ReadOnly[colIndex]) {
|
|
if (row.SpreadVal[colIndex] == $scope.SpreadType.Equal)
|
|
row.CSSClass[colIndex] = 'cellequal';
|
|
else if (row.SpreadVal[colIndex] == $scope.SpreadType.Over)
|
|
row.CSSClass[colIndex] = 'cellover';
|
|
else if (row.SpreadVal[colIndex] == $scope.SpreadType.Less)
|
|
row.CSSClass[colIndex] = 'cellless';
|
|
|
|
if (row.RowType == $scope.RowType.Project) {
|
|
if (row.Color != null && row.Color.length > 0 && $scope.calendarFilters.IsBarMode) {
|
|
row.BarStyle[colIndex] = "border-bottom: 1px solid " + row.Color + " !important;border-right-color: " + row.Color + " !important;background-color: " + row.Color + ";";
|
|
} else {
|
|
row.BarStyle[colIndex] = null;
|
|
}
|
|
}
|
|
}
|
|
if (row.ProjectId == null && row.ExpCatId != null && row.RowType == $scope.RowType.BottomCategory)
|
|
row.CSSClass[colIndex] += ' capacity-total';
|
|
// assign more classes if needed
|
|
} else { // updating resource row
|
|
if (row == null || colIndex == null || row.ReadOnly[colIndex])
|
|
return;
|
|
|
|
if (resRow.SpreadVal == null || resRow.SpreadVal.length <= colIndex)
|
|
return;
|
|
resRow.CSSClass[colIndex] = (resRow.CSSClass[colIndex] || '').replace(/cellover/g, '').replace(/cellless/g, '').replace(/cellequal/g, '');;
|
|
if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Equal)
|
|
resRow.CSSClass[colIndex] = 'cellequal';
|
|
else if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Over)
|
|
resRow.CSSClass[colIndex] = 'cellover';
|
|
else if (resRow.SpreadVal[colIndex] == $scope.SpreadType.Less)
|
|
resRow.CSSClass[colIndex] = 'cellless';
|
|
// assign more classes if needed
|
|
}
|
|
setOverAllocated();
|
|
}
|
|
|
|
function setOverAllocated() {
|
|
var isOverAllocated = false;
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ExpCatId != null && $scope.data.Calendar[i].ScenarioId != null) {
|
|
for (var j = 0; j < $scope.data.Calendar[i].SpreadVal.length; j++) {
|
|
if ($scope.data.Calendar[i].SpreadVal[j] == $scope.SpreadType.Over && isInEdited($scope.data.Calendar[i].ExpCatId, $scope.data.Calendar[i].ScenarioId, $scope.data.Headers[j].Milliseconds)) {
|
|
isOverAllocated = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (isOverAllocated)
|
|
break;
|
|
}
|
|
|
|
$scope.isOverAllocated = isOverAllocated;
|
|
}
|
|
|
|
function isInEdited(expCatId, scenarioId, milliseconds) {
|
|
for (var ix = 0; ix < $scope.data2Update.ChangedExpCats.length; ix++) {
|
|
if ($scope.data2Update.ChangedExpCats[ix].Id == expCatId && $scope.data2Update.ChangedExpCats[ix].ScenarioId == scenarioId) {
|
|
for (var res in $scope.data2Update.ChangedExpCats[ix].Resources) {
|
|
var resource = $scope.data2Update.ChangedExpCats[ix].Resources[res];
|
|
for (var val in resource.Values) {
|
|
if (resource.Values[val].Milliseconds == milliseconds)
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function recalcRest(expCat, colIndex) {
|
|
var sum = 0;
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
sum += expCat.Resources[i].QuantityValues[colIndex];
|
|
}
|
|
if (expCat.QuantityValues[colIndex] < sum)
|
|
expCat.RestQuantity[colIndex] = 0;
|
|
else
|
|
expCat.RestQuantity[colIndex] = expCat.QuantityValues[colIndex] - sum;
|
|
}
|
|
|
|
function changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex, isRemoved) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
var resource = getResourceByExpCat(expCat, resId);
|
|
var resourceTotal = getResourceByExpCat(expCatTotal, resId);
|
|
var header = $scope.data.Headers[colIndex];
|
|
|
|
if (expCat != null && resource != null) {
|
|
var team = null;
|
|
// adjust team allocations
|
|
for (var i = 0; i < expCat.Teams.length; i++) {
|
|
var resTeam = findTeamInResourceTeams(resource.Teams, expCat.Teams[i].Id);
|
|
if (resTeam == null || header.Milliseconds < resTeam.TeamStartDate || (resTeam.TeamEndDate != null && header.Milliseconds > resTeam.TeamEndDate))
|
|
continue;
|
|
team = expCat.Teams[i];
|
|
team.AllocatedByResources[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
}
|
|
var res = getResourceById(resource.Id);
|
|
|
|
res.AllocatedQuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
|
|
if (expCatTotal && resourceTotal) {
|
|
expCatTotal.QuantityTotalAllocatedValue[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
expCatTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
resourceTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
}
|
|
|
|
var totalUpdateResult = {};
|
|
var totalECsWithResource = getECsThatContainResource(resId);
|
|
if (totalECsWithResource) {
|
|
for (var i = 0; i < totalECsWithResource.length; i++) {
|
|
var totalEC = totalECsWithResource[i];
|
|
var totalResource = getResourceByExpCat(totalEC, resId);
|
|
|
|
if (totalResource) {
|
|
totalResource.AllocatedQuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
}
|
|
|
|
totalUpdateResult = updateTotals(expCat, totalEC, totalResource, resource, colIndex, newValue, resource.QuantityValues[colIndex], 0, 0);
|
|
}
|
|
}
|
|
|
|
resource.QuantityValues[colIndex] = newValue;
|
|
|
|
if (totalUpdateResult) {
|
|
resource.QuantityValues[totalUpdateResult.MonthEndIndex] = totalUpdateResult.NewQuantity;
|
|
//recalcSpreading(expCat, expCatTotal, resourceTotal, totalUpdateResult.MonthEndIndex);
|
|
//updateCSSClass(expCat, resource, totalUpdateResult.MonthEndIndex);
|
|
}
|
|
|
|
recalcRest(expCat, colIndex);
|
|
|
|
applyCellChange(scenarioId, expCatId, $scope.data.Headers[colIndex].Milliseconds, expCat.DetailIds[colIndex],
|
|
newValue, 0, resId, false, isRemoved, false, false, teamId);
|
|
}
|
|
//Recalc spreading for current cell
|
|
recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex);
|
|
updateCSSClass(expCat, resource, colIndex);
|
|
//Recalc spreading for month cell
|
|
recalcSpreading(expCat, expCatTotal, resourceTotal, totalUpdateResult.MonthEndIndex);
|
|
updateCSSClass(expCat, resource, totalUpdateResult.MonthEndIndex);
|
|
|
|
recalcBottomPartTotals();
|
|
refreshTotalSpreadVal(expCatTotal);
|
|
}
|
|
|
|
function changeActualValue(newValue, scenarioId, expCatId, resId, teamId, colIndex, isRemoved) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
var actual = getResourceActualByExpCat(expCat, resId);
|
|
var actualTotal = getResourceByExpCat(expCatTotal, resId);
|
|
var header = $scope.data.Headers[colIndex];
|
|
|
|
if (expCat != null && actual != null) {
|
|
|
|
updateActualTotals(expCat, expCatTotal, actualTotal, actual, colIndex, newValue, actual.ActualQuantityValues[colIndex]);
|
|
actual.ActualQuantityValues[colIndex] = newValue;
|
|
|
|
applyCellChange(scenarioId, expCatId, $scope.data.Headers[colIndex].Milliseconds, expCat.DetailIds[colIndex],
|
|
newValue, 0, resId, false, isRemoved, true, false, teamId);
|
|
}
|
|
}
|
|
|
|
function changeNonProjectTimeValue(newValue, nonProjectTimeId, nonProjectTimeCategoryId, resId, colIndex) {
|
|
var category = getNonProjectTimeCatById(nonProjectTimeCategoryId);
|
|
var nonProjectTimeTotal = getNonProjectTimeCatById(null);
|
|
var nonProjectTime = getNonProjectTimeById(nonProjectTimeId);
|
|
var resource = getResourceByNonProjectTime(nonProjectTime, resId);
|
|
var header = $scope.data.Headers[colIndex];
|
|
|
|
if (category != null) {
|
|
if (nonProjectTime.IsTeamMode) { // update Team-level NPT cell
|
|
updateNonProjectTimeTotals(category, nonProjectTimeTotal, nonProjectTime, null, colIndex, newValue, nonProjectTime.QuantityValues[colIndex]);
|
|
}
|
|
else if (resource != null && resource.QuantityValues[colIndex] != null) { // update resource-level NPT cell
|
|
updateNonProjectTimeTotals(category, nonProjectTimeTotal, nonProjectTime, resource, colIndex, newValue, resource.QuantityValues[colIndex]);
|
|
resource.QuantityValues[colIndex] = newValue;
|
|
}
|
|
applyCellChange(null, nonProjectTimeId, $scope.data.Headers[colIndex].Milliseconds, null,
|
|
newValue, 0, resId, false, false, false, true);
|
|
}
|
|
}
|
|
function applyResourceCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved, isActual) {
|
|
var resIndex = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dx].Id == resId) {
|
|
resIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (resIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[$scope.data2Update.ChangedExpCats[catIndex].Resources.length] = {
|
|
Id: resId,
|
|
Values: [],
|
|
Actuals: [],
|
|
IsAdded: isAdded,
|
|
IsRemoved: isRemoved
|
|
};
|
|
resIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources.length - 1;
|
|
if (isAdded || isRemoved)
|
|
return;
|
|
} else {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].IsRemoved = isRemoved;
|
|
if (isRemoved) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].IsAdded) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources.splice(resIndex, 1);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
var dateIndex = -1;
|
|
if (isActual) {
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals[dx].Milliseconds == cellMilliseconds) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals[$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals.length - 1;
|
|
}
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Actuals[dateIndex].Quantity = cellQuantity;
|
|
} else {
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values[dx].Milliseconds == cellMilliseconds) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values.length - 1;
|
|
}
|
|
//$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values[dateIndex].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[resIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
}
|
|
}
|
|
function applyNPTCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved) {
|
|
var resIndex = -1;
|
|
var dateIndex = -1;
|
|
if (resId != null) {
|
|
for (var dx = 0; dx < $scope.data2Update.NonProjectTimeCats[catIndex].Resources.length; dx++) {
|
|
if ($scope.data2Update.NonProjectTimeCats[catIndex].Resources[dx].Id == resId) {
|
|
resIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (resIndex == -1) {
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Resources[$scope.data2Update.NonProjectTimeCats[catIndex].Resources.length] = {
|
|
Id: resId,
|
|
Values: [],
|
|
Actuals: [],
|
|
IsAdded: isAdded,
|
|
IsRemoved: isRemoved
|
|
};
|
|
resIndex = $scope.data2Update.NonProjectTimeCats[catIndex].Resources.length - 1;
|
|
} else {
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].IsRemoved = isRemoved;
|
|
if (isRemoved) {
|
|
if ($scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].IsAdded) {
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Resources.splice(resIndex, 1);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (resIndex != -1) // update cell value for resource-level NPT
|
|
{
|
|
for (var dx = 0; dx < $scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values[dx].Milliseconds == cellMilliseconds) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values[$scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex = $scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values.length - 1;
|
|
}
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Resources[resIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
}
|
|
else // update cell value for team-level NPT
|
|
{
|
|
for (var dx = 0; dx < $scope.data2Update.NonProjectTimeCats[catIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.NonProjectTimeCats[catIndex].Values[dx].Milliseconds == cellMilliseconds) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Values[$scope.data2Update.NonProjectTimeCats[catIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex = $scope.data2Update.NonProjectTimeCats[catIndex].Values.length - 1;
|
|
}
|
|
var perTeamQuantity = cellQuantity;
|
|
var nonProjectTime = getNonProjectTimeById($scope.data2Update.NonProjectTimeCats[catIndex].Id);
|
|
if (nonProjectTime != null && nonProjectTime.Resources != null && nonProjectTime.Resources.length != 0)
|
|
perTeamQuantity = perTeamQuantity / nonProjectTime.Resources.length;
|
|
$scope.data2Update.NonProjectTimeCats[catIndex].Values[dateIndex].Quantity = perTeamQuantity;
|
|
}
|
|
}
|
|
function applyExpCatCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost) {
|
|
var dateIndex = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Values[dx].Id == cellId) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Values.length - 1;
|
|
}
|
|
$scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
}
|
|
function applyCellChange(scenarioId, rowId, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved, isActual, isNonProjectTime, teamId) {
|
|
var catIndex = -1;
|
|
if (isNonProjectTime) {
|
|
for (var ix = 0; ix < $scope.data2Update.NonProjectTimeCats.length; ix++) {
|
|
if ($scope.data2Update.NonProjectTimeCats[ix].Id == rowId) {
|
|
catIndex = ix;
|
|
break;
|
|
}
|
|
}
|
|
if (catIndex == -1) {
|
|
$scope.data2Update.NonProjectTimeCats[$scope.data2Update.NonProjectTimeCats.length] = {
|
|
ScenarioId: scenarioId,
|
|
Id: rowId,
|
|
Values: [],
|
|
Resources: []
|
|
};
|
|
catIndex = $scope.data2Update.NonProjectTimeCats.length - 1;
|
|
}
|
|
} else {
|
|
for (var ix = 0; ix < $scope.data2Update.ChangedExpCats.length; ix++) {
|
|
if ($scope.data2Update.ChangedExpCats[ix].Id == rowId && $scope.data2Update.ChangedExpCats[ix].ScenarioId == scenarioId) {
|
|
catIndex = ix;
|
|
break;
|
|
}
|
|
}
|
|
if (catIndex == -1) {
|
|
var expCat = getExpCatById(scenarioId, rowId, teamId);
|
|
$scope.data2Update.ChangedExpCats[$scope.data2Update.ChangedExpCats.length] = {
|
|
ScenarioId: scenarioId,
|
|
Id: rowId,
|
|
Values: [],
|
|
Resources: [],
|
|
AllowResourceAssignment: expCat.AllowResourceAssignment
|
|
};
|
|
catIndex = $scope.data2Update.ChangedExpCats.length - 1;
|
|
|
|
if (isProjectHaveSupperExpCat(expCat.ProjectId)) {
|
|
var project = getProjectById(expCat.ProjectId);
|
|
|
|
var itemInArray = false;
|
|
for (var i = 0; i < $scope.data2Update.ChangedSupperExpCatProjects.length; i++) {
|
|
if (expCat.ProjectId == $scope.data2Update.ChangedSupperExpCatProjects[i].ProjectId) {
|
|
itemInArray = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!itemInArray)
|
|
$scope.data2Update.ChangedSupperExpCatProjects[$scope.data2Update.ChangedSupperExpCatProjects.length] = {
|
|
ProjectId: expCat.ProjectId,
|
|
Name: project.Name
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (isNonProjectTime) {
|
|
applyNPTCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved);
|
|
} else {
|
|
if (resId == null) {
|
|
applyExpCatCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost);
|
|
} else {
|
|
applyResourceCellChange(catIndex, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved, isActual);
|
|
}
|
|
}
|
|
}
|
|
|
|
function refreshTotalSpreadVal(expCatTotal) {
|
|
if (expCatTotal.RowType == $scope.RowType.BottomCategory) {
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
|
|
if(expCatTotal.IsSuperEC)
|
|
{
|
|
expCatTotal.SpreadVal[colIndex] = $scope.SpreadType.Equal;
|
|
} else {
|
|
|
|
var resValue = expCatTotal.QuantityTotalResValue[colIndex];
|
|
|
|
var total = 0;
|
|
var allocated = 0;
|
|
if ($scope.calendarFilters.ShowCapacity == 1) { // Allocated/Capacity
|
|
allocated = expCatTotal.QuantityTotalAllocatedValue[colIndex];
|
|
total = expCatTotal.QuantityTotalResValue[colIndex];
|
|
} else if ($scope.calendarFilters.ShowCapacity == 2) { // Need/Capacity
|
|
allocated = expCatTotal.QuantityValues[colIndex];
|
|
total = expCatTotal.QuantityTotalResValue[colIndex];
|
|
} else if ($scope.calendarFilters.ShowCapacity == 3) { // Allocated/Need
|
|
allocated = expCatTotal.QuantityTotalAllocatedValue[colIndex];
|
|
total = expCatTotal.QuantityValues[colIndex];
|
|
} else if ($scope.calendarFilters.ShowCapacity == 4) { // Remaining/Capacity, display similar to Allocated/Capacity
|
|
allocated = expCatTotal.QuantityValues[colIndex];
|
|
total = expCatTotal.QuantityTotalResValue[colIndex];
|
|
}
|
|
|
|
var compareRes = cellHighlightingService.compare(allocated, total);
|
|
|
|
expCatTotal.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
|
|
//var ecClass = $scope.SpreadType.Notspecified;
|
|
//for (var j in expCatTotal.Resources)
|
|
//{
|
|
// if (ecClass != $scope.SpreadType.Over) {
|
|
// if (ecClass != $scope.SpreadType.Less) {
|
|
// if (expCatTotal.Resources[j].SpreadVal[colIndex] != $scope.SpreadType.Notspecified) {
|
|
// ecClass = expCatTotal.Resources[j].SpreadVal[colIndex];
|
|
// }
|
|
// } else {
|
|
// if (expCatTotal.Resources[j].SpreadVal[colIndex] == $scope.SpreadType.Over) {
|
|
// ecClass = expCatTotal.Resources[j].SpreadVal[colIndex] ;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
//}
|
|
//expCatTotal.SpreadVal[colIndex] = ecClass;
|
|
}
|
|
|
|
// this code sets Equal by default. It means that 2 zeros will be displayed as green
|
|
// so I decided to remove it to keep zeros without highligthing
|
|
//var expCatSpread = $scope.SpreadType.Equal;
|
|
//if (expCatTotal.SpreadVal[colIndex] == $scope.SpreadType.Over) {
|
|
// expCatSpread = $scope.SpreadType.Over;
|
|
//} else if (expCatTotal.SpreadVal[colIndex] == $scope.SpreadType.Less) {
|
|
// expCatSpread = $scope.SpreadType.Less;
|
|
//}
|
|
//expCatTotal.SpreadVal[colIndex] = expCatSpread;
|
|
|
|
updateCSSClass(expCatTotal, null, colIndex);
|
|
}
|
|
}
|
|
//updateCSSClass(expCatTotal, null, colIndex);
|
|
}
|
|
function initCmMenuItems() {
|
|
var menu = $('#' + $scope.calendarFilters.MenuId);
|
|
menu.html("");
|
|
|
|
$.each($("#menuCalendarOptionsPrint li"), function (i, o) {
|
|
$(o).appendTo(menu);
|
|
});
|
|
|
|
$.each($("#menuCalendarOptions li"), function (i, o) {
|
|
$(o).clone(true).appendTo(menu).change(function () {
|
|
if (typeof onCMPreferencesItemClick === 'function')
|
|
onCMPreferencesItemClick(menu);
|
|
});
|
|
});
|
|
|
|
// SA. ENV-815
|
|
$("#menuCalendarOptions").find('*[data-key]').removeAttr('data-key');
|
|
}
|
|
|
|
$scope.init = function (initData) {
|
|
$scope.calendarFilters.ShowUpper = initData.ShowUpper;
|
|
$scope.calendarFilters.ShowLower = initData.ShowLower;
|
|
$scope.calendarFilters.IsUOMHours = initData.IsUOMHours;
|
|
$scope.calendarFilters.PreferredTotalsDisplaying = initData.PreferredTotalsDisplaying;
|
|
$scope.calendarFilters.IsBarMode = initData.IsBarMode;
|
|
$scope.calendarFilters.IsViewModeMonth = initData.IsViewModeMonth;
|
|
$scope.calendarFilters.IsCapacityModeActuals = initData.IsCapacityModeActuals;
|
|
$scope.calendarFilters.GroupByTeam = initData.GroupByTeam;
|
|
$scope.calendarFilters.ShowCapacity = initData.ShowCapacity;
|
|
$scope.calendarFilters.StartDate = initData.StartDate;
|
|
$scope.calendarFilters.EndDate = initData.EndDate;
|
|
$scope.calendarFilters.ModelType = initData.ModelType;
|
|
$scope.calendarFilters.MenuId = initData.MenuId;
|
|
$scope.dataSection = initData.DataSection;
|
|
$scope.pageTitle = initData.PageTitle; // SA. ENV-905
|
|
$scope.availableFilterOptions = initData.FilterOptions; // SA. ENV-799
|
|
initCmMenuItems();
|
|
var pagePrefArray;
|
|
|
|
if (initData.PagePreferences && initData.PagePreferences.length > 0) {
|
|
// SA. ENV-799
|
|
var filterModeInit = "";
|
|
var filterSelectedItemId = null;
|
|
|
|
pagePrefArray = JSON.parse(initData.PagePreferences);
|
|
$scope.preferences = pagePrefArray;
|
|
|
|
for (var i = 0; i < pagePrefArray.length; i++) {
|
|
switch (pagePrefArray[i].Key) {
|
|
case "showChart":
|
|
$scope.calendarFilters.ShowUpper = pagePrefArray[i].Value || (initData.ResourceId && (initData.ResourceId.length > 0));
|
|
break;
|
|
case "showCriteria":
|
|
$scope.calendarFilters.ShowLower = pagePrefArray[i].Value && !(initData.ResourceId && (initData.ResourceId.length > 0));
|
|
break;
|
|
case "showOption":
|
|
$scope.calendarFilters.ShowCapacity = pagePrefArray[i].Value != null ? pagePrefArray[i].Value : 1; //"Total Allocated/Total Need";
|
|
break;
|
|
case "uomMode":
|
|
$scope.calendarFilters.IsUOMHours = pagePrefArray[i].Value;
|
|
break;
|
|
case "capBarMode":
|
|
$scope.calendarFilters.IsBarMode = pagePrefArray[i].Value;
|
|
break;
|
|
case "defaultView":
|
|
$scope.calendarFilters.IsViewModeMonth = pagePrefArray[i].Value;
|
|
break;
|
|
case "groupByTeam":
|
|
if ($scope.calendarFilters.ModelType != 'TeamboardModel')
|
|
$scope.calendarFilters.GroupByTeam = pagePrefArray[i].Value;
|
|
else
|
|
$scope.calendarFilters.GroupByTeam = false;
|
|
break;
|
|
case "capacityView":
|
|
$scope.calendarFilters.IsCapacityModeActuals = pagePrefArray[i].Value;
|
|
break;
|
|
case "capacityFilterStartDate":
|
|
$scope.calendarFilters.StartDate = pagePrefArray[i].Value;
|
|
break;
|
|
case "capacityFilterEndDate":
|
|
$scope.calendarFilters.EndDate = pagePrefArray[i].Value;
|
|
break;
|
|
|
|
case "filterCompanyList":
|
|
if ((pagePrefArray[i].Value) && (filterModeInit.length < 1))
|
|
filterModeInit = "Company";
|
|
break;
|
|
|
|
case "filterViewList":
|
|
if ((pagePrefArray[i].Value) && (filterModeInit.length < 1))
|
|
filterModeInit = "View";
|
|
break;
|
|
|
|
case "filterTeamList":
|
|
if ((pagePrefArray[i].Value) && (filterModeInit.length < 1))
|
|
filterModeInit = "Team";
|
|
break;
|
|
|
|
case "filteredCompany":
|
|
filterSelectedItemId = pagePrefArray[i].Value;
|
|
break;
|
|
|
|
case "sortBy":
|
|
$scope.calendarFilters.sortBy = pagePrefArray[i].Value;
|
|
break;
|
|
case "sortOrder":
|
|
$scope.calendarFilters.sortOrder = pagePrefArray[i].Value;
|
|
break;
|
|
|
|
default:
|
|
console.log("Restore page preferences (Activity calendar): data key not found in parsing loaded preferences (datakey=" +
|
|
pagePrefArray[i].Key + ", dataSection=" + $scope.dataSection + ")");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
pagePrefArray = [];
|
|
pagePrefArray.push({ Key: "showChart", Value: $scope.calendarFilters.ShowUpper });
|
|
pagePrefArray.push({ Key: "showCriteria", Value: $scope.calendarFilters.ShowLower });
|
|
pagePrefArray.push({ Key: "sortBy", Value: $scope.calendarFilters.sortBy });
|
|
pagePrefArray.push({ Key: "sortOrder", Value: $scope.calendarFilters.sortOrder });
|
|
pagePrefArray.push({ Key: "showOption", Value: $scope.calendarFilters.ShowCapacity });
|
|
pagePrefArray.push({ Key: "uomMode", Value: $scope.calendarFilters.IsUOMHours });
|
|
pagePrefArray.push({ Key: "capBarMode", Value: $scope.calendarFilters.IsBarMode });
|
|
pagePrefArray.push({ Key: "defaultView", Value: $scope.calendarFilters.IsViewModeMonth });
|
|
pagePrefArray.push({ Key: "groupByTeam", Value: $scope.calendarFilters.GroupByTeam });
|
|
pagePrefArray.push({ Key: "capacityView", Value: $scope.calendarFilters.IsCapacityModeActuals });
|
|
pagePrefArray.push({ Key: "capacityFilterStartDate", Value: $scope.calendarFilters.StartDate });
|
|
pagePrefArray.push({ Key: "capacityFilterEndDate", Value: $scope.calendarFilters.EndDate });
|
|
// pagePrefArray.push({ Key: "filteredCompany", Value: $scope.calendarFilters.CompanyId });
|
|
|
|
restorePreferences($scope.dataSection, pagePrefArray);
|
|
|
|
$('#' + $scope.calendarFilters.MenuId).click(function (event) {
|
|
event.stopPropagation();
|
|
});
|
|
|
|
// SA. ENV-799
|
|
if ($scope.IsEmpty(initData.CompanyId) && $scope.IsEmpty(initData.ViewId) &&
|
|
$scope.IsEmpty(initData.TeamId) && $scope.IsEmpty(initData.ResourceId)) {
|
|
if (filterModeInit == "Company")
|
|
initData.CompanyId = filterSelectedItemId;
|
|
|
|
if (filterModeInit == "View")
|
|
initData.ViewId = filterSelectedItemId;
|
|
|
|
if (filterModeInit == "Team")
|
|
initData.TeamId = filterSelectedItemId;
|
|
|
|
if (filterModeInit == "Resource")
|
|
initData.ResourceId = filterSelectedItemId;
|
|
}
|
|
|
|
var filterAttached = false;
|
|
|
|
// if ($scope.calendarFilters.ModelType && ($scope.calendarFilters.ModelType == "EnVisage.Models.CapacityDetailsModel")) {
|
|
if (initData.CompanyId && (initData.CompanyId.length > 0)) {
|
|
$scope.CalendarFilterMode.SelectedItemId = initData.CompanyId;
|
|
$scope.switchCompanyFilterMode(true);
|
|
filterAttached = true;
|
|
}
|
|
|
|
if (initData.ViewId && (initData.ViewId.length > 0)) {
|
|
$scope.CalendarFilterMode.SelectedItemId = initData.ViewId;
|
|
$scope.switchViewFilterMode(true);
|
|
filterAttached = true;
|
|
|
|
}
|
|
|
|
if (initData.TeamId && (initData.TeamId.length > 0)) {
|
|
$scope.CalendarFilterMode.SelectedItemId = initData.TeamId;
|
|
$scope.switchTeamFilterMode(true);
|
|
filterAttached = true;
|
|
}
|
|
|
|
if (initData.ResourceId && (initData.ResourceId.length > 0)) {
|
|
$scope.CalendarFilterMode.SelectedItemId = initData.ResourceId;
|
|
$scope.switchResourceFilterMode(true);
|
|
filterAttached = true;
|
|
}
|
|
|
|
if (!filterAttached) {
|
|
$scope.switchCompanyFilterMode();
|
|
}
|
|
// }
|
|
|
|
// SA. ENV-799
|
|
$scope.loadCalendarData();
|
|
};
|
|
|
|
$scope.IsEmpty = function (value) {
|
|
return !value || (value == null) || (value == "");
|
|
}
|
|
|
|
$scope.getCalendar = function () {
|
|
$("#loader").hide();
|
|
|
|
if ($scope.IsEmpty($scope.calendarFilters.CompanyId) && $scope.IsEmpty($scope.calendarFilters.TeamId) &&
|
|
$scope.IsEmpty($scope.calendarFilters.ViewId) && $scope.IsEmpty($scope.calendarFilters.ResourceId)) {
|
|
return;
|
|
}
|
|
blockUI();
|
|
$scope.data = null;
|
|
$("#loader").show();
|
|
var postData = JSON.parse(JSON.stringify($scope.calendarFilters));
|
|
$http.post('/CapacityManagement/LoadJsonCalendar', postData).
|
|
success(function (data, status, headers, config) {
|
|
if (data == null)
|
|
$("#loader").hide();
|
|
if (data != null && data.Headers == null || data.Headers.length < 1) {
|
|
$("#loader").hide();
|
|
unblockUI();
|
|
return;
|
|
}
|
|
|
|
$scope.data = data;
|
|
$scope.calendarFilters.ShowAvgTotals = data.PreferredTotalsDisplaying;
|
|
$scope.calendarFilters.IsUOMHours = data.IsUOMHours;
|
|
swithViewMode();
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
var row = $scope.data.Calendar[i];
|
|
row.IsUpperHidden = !$scope.calendarFilters.ShowUpper;
|
|
row.IsLowerHidden = !$scope.calendarFilters.ShowLower;
|
|
|
|
if (row.RowType != $scope.RowType.Team && row.ScenarioId && row.ExpCatId) {
|
|
row.AvailableResources = getExpCatResources(row, row.TeamId);
|
|
}
|
|
if ($scope.calendarFilters.ResourceId != null && row.RowType == $scope.RowType.Project) {
|
|
$scope.isReadOnly = !row.IsEdited;
|
|
}
|
|
}
|
|
// initial setup css classes
|
|
for (var rowIndex = 0; rowIndex < $scope.data.Calendar.length; rowIndex++) {
|
|
if ($scope.data.Calendar[rowIndex].CSSClass == null)
|
|
$scope.data.Calendar[rowIndex].CSSClass = new Array($scope.data.Headers.length);
|
|
if ($scope.data.Calendar[rowIndex].BarStyle == null)
|
|
$scope.data.Calendar[rowIndex].BarStyle = new Array($scope.data.Headers.length);
|
|
refreshTotalSpreadVal($scope.data.Calendar[rowIndex]);
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if ($scope.data.Calendar[rowIndex].RowType != $scope.RowType.BottomCategory)
|
|
updateCSSClass($scope.data.Calendar[rowIndex], null, colIndex);
|
|
|
|
if ($scope.data.Calendar[rowIndex].Resources != null && $scope.data.Calendar[rowIndex].Resources.length > 0) {
|
|
for (var resIndex = 0; resIndex < $scope.data.Calendar[rowIndex].Resources.length; resIndex++) {
|
|
if ($scope.data.Calendar[rowIndex].Resources[resIndex].CSSClass == null)
|
|
$scope.data.Calendar[rowIndex].Resources[resIndex].CSSClass = new Array($scope.data.Headers.length);
|
|
updateCSSClass($scope.data.Calendar[rowIndex], $scope.data.Calendar[rowIndex].Resources[resIndex], colIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].IsTotals && $scope.data.Calendar[i].RowType == $scope.RowType.Total) {
|
|
$scope.grandtotalrow = $scope.data.Calendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
recalcBottomPartTotals();
|
|
|
|
$("#loader").hide();
|
|
$timeout(function () {
|
|
//To-Do: Replace it with ngSelect2 directive
|
|
angular.element('[ng-model="row.ResourceToAssignId"]').select2({
|
|
allowClear: true,
|
|
dropdownAutoWidth: true,
|
|
placeholder: 'Select a person',
|
|
dropdownCss: { 'font-size': '9pt' },
|
|
minimumResultsForSearch: 5,
|
|
formatResult: $scope.formatPeopleResourceOption
|
|
});
|
|
//To-Do: Remove
|
|
if ($scope.CalendarFilterMode.SelectedItemId)
|
|
$('[name="selFilterElement"]').select2('val', $scope.CalendarFilterMode.SelectedItemId);
|
|
|
|
$scope.onResize();
|
|
});
|
|
unblockUI();
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
// called asynchronously if an error occurs
|
|
// or server returns response with an error status.
|
|
var errorMessage = 'An error occurred while loading calendar. ErrorCode = 000003';
|
|
showErrorModal('Oops!', errorMessage);
|
|
$("#loader").hide();
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.checkEditable = function (useType) {
|
|
if (3 === useType) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
$scope.watchKeyInput = function (t) {
|
|
$timeout(function () {
|
|
if (t.$editable.inputEl.select)
|
|
t.$editable.inputEl.select();
|
|
else if (t.$editable.inputEl.setSelectionRange)
|
|
t.$editable.inputEl.setSelectionRange(0, t.$editable.inputEl.val().length);
|
|
}, 3);
|
|
|
|
t.$editable.inputEl.on('keydown', function (e) {
|
|
if (e.which == 9) { //when tab key is pressed
|
|
e.preventDefault();
|
|
var tab2Cell;
|
|
if (e.shiftKey) { // when shift + tab use with 'onblur' set to 'submit' for automatic submission find the parent of the editable before this one in the markup grab the editable and display it
|
|
tab2Cell = $(this).parentsUntil('table#table').prevAll(":has(.editable:visible):first").find(".editable:visible:last");
|
|
t.$form.$submit();
|
|
tab2Cell.click();
|
|
} else { // when just tab use with 'onblur' set to 'submit' for automatic submission find the parent of the editable after this one in the markup grab the editable and display it
|
|
tab2Cell = $(this).parentsUntil('table#table').nextAll(":has(.editable:visible):first").find(".editable:visible:first");
|
|
t.$form.$submit();
|
|
tab2Cell.click();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
$scope.onTxtBlur = function (txt) {
|
|
txt.$form.$submit();
|
|
};
|
|
$scope.saveChanges = function () {
|
|
// if user saves as new and selected TD or BU type for new scenarios
|
|
if ($scope.SaveAs == "1" && $scope.saveType != "0") {
|
|
var message = "Your new Scenario will be created for the full duration as the current Active Scenario.";
|
|
if ($scope.saveType == "1")
|
|
message = "Your new Scenario will be created for the full duration as the current Active Scenario. <b>Please note:</b> Only current resource-level allocations will be saved as project estimates.";
|
|
|
|
bootbox.confirm({
|
|
message: message,
|
|
callback: function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
saveChangesCallback();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
saveChangesCallback();
|
|
}
|
|
};
|
|
function saveChangesCallback() {
|
|
blockUI();
|
|
$scope.data2Update.IsOverAllocated = $scope.isOverAllocated,
|
|
$scope.data2Update.IsMatchChecked = $scope.isMatchChecked;
|
|
$scope.data2Update.SaveType = $scope.saveType;
|
|
$scope.data2Update.SaveAs = $scope.SaveAs;
|
|
$scope.data2Update.IsActiveScenario = $scope.isActiveScenario;
|
|
$scope.data2Update.ScenarioName = $scope.ScenarioName;
|
|
$scope.data2Update.ScenarioFilters = $scope.calendarFilters;
|
|
|
|
$http.post('/CapacityManagement/SaveChanges', $scope.data2Update)
|
|
.success(function (data, status, headers, config) {
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: [],
|
|
NonProjectTimeCats: [],
|
|
ChangedSupperExpCatProjects: []
|
|
};
|
|
$scope.getCalendar();
|
|
$document.trigger('calendar.scenario-saved');
|
|
unblockUI();
|
|
}).error(function (data, status, headers, config) {
|
|
var errorMessage = 'An error occurred while saving calendar changes. ErrorCode = 000001';
|
|
showErrorModal('Oops!', errorMessage);
|
|
console.error(errorMessage);
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.takeAll = function (scenarioId, resId, expCatId, teamId) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
if (expCat != null) {
|
|
var create = false;
|
|
var allocateRest = false;
|
|
var reset = false;
|
|
allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset);
|
|
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
}
|
|
};
|
|
$scope.takeRemaining = function (scenarioId, resId, expCatId, teamId) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
if (expCat != null) {
|
|
var create = false;
|
|
var allocateRest = true;
|
|
var reset = false;
|
|
allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset);
|
|
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
}
|
|
};
|
|
$scope.zeroResource = function (scenarioId, resId, expCatId, teamId) {
|
|
bootbox.confirm({
|
|
message: "Are you sure you want to fill this resource quantities with 0s?",
|
|
callback: function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var create = false;
|
|
var allocateRest = false;
|
|
var reset = true;
|
|
allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset);
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
}
|
|
});
|
|
},
|
|
className: "bootbox-sm"
|
|
});
|
|
};
|
|
$scope.assignResource = function (row, $event) {
|
|
if (!row || !row.ResourceToAssignId || !row.ExpCatId || !row.TeamId)
|
|
return;
|
|
|
|
var resource = getResourceById(row.ResourceToAssignId);
|
|
if (resource != null) {
|
|
|
|
var project = getProjectById(row.ProjectId);
|
|
var expCat = getExpCatById(row.ScenarioId, row.ExpCatId, row.TeamId);
|
|
var expCatTotal = getExpCatById(null, row.ExpCatId, null);
|
|
|
|
//Check the same resource assignment
|
|
if (getResourceByExpCat(expCat, resource.Id) != null) {
|
|
alert("The " + resource.Name + " has been assigned to the " + expCat.Name);
|
|
return;
|
|
}
|
|
|
|
//Add exp cat resource
|
|
//todo: just added resources are not validated against capacity values
|
|
var newResource = {
|
|
'Id': resource.Id,
|
|
'Name': resource.Name,
|
|
'QuantityValues': new Array($scope.data.Headers.length),
|
|
'SpreadVal': new Array($scope.data.Headers.length),
|
|
'CSSClass': new Array($scope.data.Headers.length),
|
|
'CapacityQuantityValues': new Array($scope.data.Headers.length),
|
|
'AllocatedQuantityValues': new Array($scope.data.Headers.length),
|
|
'ReadOnlyWeeks': new Array($scope.data.Headers.length),
|
|
'ReadOnlyWeeksActuals': new Array($scope.data.Headers.length),
|
|
'Teams': resource.Teams,
|
|
'StartDate': resource.StartDate,
|
|
'EndDate': resource.EndDate,
|
|
'GrandTotalReadOnly': false,
|
|
'GrandTotalQuantity': 0
|
|
};
|
|
var i;
|
|
for (i = 0; i < newResource.QuantityValues.length; i++) {
|
|
if (isNaN(newResource.QuantityValues[i]))
|
|
newResource.QuantityValues[i] = 0;
|
|
}
|
|
expCat.Resources.push(newResource);
|
|
|
|
if (expCatTotal != null) {
|
|
var resourceTotal = getResourceByExpCat(expCatTotal, resource.Id);
|
|
var colIndex;
|
|
if (resourceTotal == null) {
|
|
//Add total exp cat resource
|
|
resourceTotal = {
|
|
'Id': resource.Id,
|
|
'Name': resource.Name,
|
|
'QuantityValues': new Array($scope.data.Headers.length),
|
|
'SpreadVal': new Array($scope.data.Headers.length),
|
|
'CSSClass': new Array($scope.data.Headers.length),
|
|
'Teams': resource.Teams,
|
|
'QuantityTotalResValue': new Array($scope.data.Headers.length),
|
|
'AllocatedQuantityValues': new Array($scope.data.Headers.length)
|
|
};
|
|
for (i = 0; i < resourceTotal.QuantityValues.length; i++) {
|
|
if (isNaN(resourceTotal.QuantityValues[i]))
|
|
resourceTotal.QuantityValues[i] = 0;
|
|
}
|
|
expCatTotal.QuantityTotalResValue = expCatTotal.QuantityResValue * (expCatTotal.Resources.length + 1);
|
|
expCatTotal.Resources.push(resourceTotal);
|
|
}
|
|
|
|
var grandTotalReadOnly = true;
|
|
var resourceMonthReadOnly = false;
|
|
for (colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if (!$scope.data.Headers[colIndex].IsMonth) {
|
|
newResource.ReadOnlyWeeks[colIndex] = resource.ReadOnlyWeeks[colIndex] || project.ReadOnly[colIndex];
|
|
newResource.ReadOnlyWeeksActuals[colIndex] = resource.ReadOnlyWeeksActuals[colIndex] || project.ReadOnly[colIndex];
|
|
if (!newResource.ReadOnlyWeeks[colIndex]) {
|
|
var groupByTeamMode = $scope.calendarFilters.GroupByTeam && isGuidEmpty($scope.calendarFilters.TeamId) && isGuidEmpty($scope.calendarFilters.ResourceId);
|
|
if (groupByTeamMode) {
|
|
var resTeamItem = findTeamInResourceTeams(newResource.Teams, expCat.TeamId);
|
|
if (resTeamItem) {
|
|
newResource.ReadOnlyWeeks[colIndex] = resTeamItem.TeamStartDate > $scope.data.Headers[colIndex].Milliseconds ||
|
|
$scope.data.Headers[colIndex].Milliseconds > (resTeamItem.TeamEndDate || Number.MAX_VALUE);
|
|
newResource.ReadOnlyWeeksActuals[colIndex] |= newResource.ReadOnlyWeeks[colIndex];
|
|
newResource.StartDate = resTeamItem.TeamStartDate;
|
|
newResource.EndDate = resTeamItem.TeamEndDate || newResource.EndDate;
|
|
}
|
|
} else {
|
|
var rdnly = true;
|
|
for (var i = 0; i < (newResource.Teams || []).length; i++) {
|
|
var rt = newResource.Teams[i];
|
|
if (rt.TeamStartDate < $scope.data.Headers[colIndex].Milliseconds &&
|
|
$scope.data.Headers[colIndex].Milliseconds <= (rt.TeamEndDate || Number.MAX_VALUE)) {
|
|
rdnly = false;
|
|
break;
|
|
}
|
|
}
|
|
newResource.ReadOnlyWeeks[colIndex] = rdnly;
|
|
newResource.ReadOnlyWeeksActuals[colIndex] |= rdnly;
|
|
}
|
|
}
|
|
resourceMonthReadOnly |= newResource.ReadOnlyWeeks[colIndex];
|
|
grandTotalReadOnly &= newResource.ReadOnlyWeeks[colIndex];
|
|
} else {
|
|
newResource.ReadOnlyWeeks[colIndex] = resourceMonthReadOnly;
|
|
resourceMonthReadOnly = false;
|
|
}
|
|
}
|
|
newResource.GrandTotalReadOnly = grandTotalReadOnly;
|
|
}
|
|
|
|
var create = true;
|
|
var allocateRest = false;
|
|
var reset = false;
|
|
allocateResource(newResource, expCat, create, allocateRest, reset); //true, false, false);
|
|
expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0;
|
|
row.AvailableResources = getExpCatResources(row, row.TeamId);
|
|
//refreshAssignResourceSelect(row.TeamId, row.ProjectId, row.ExpCatId);
|
|
|
|
resizeCalendar();
|
|
}
|
|
|
|
row.ResourceToAssignId = null;
|
|
};
|
|
$scope.removeResource = function (scenarioId, resId, expCatId, teamId) {
|
|
bootbox.confirm({
|
|
message: "Are you sure you want to remove this resource?",
|
|
callback: function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var create = false;
|
|
var allocateRest = false;
|
|
var reset = true;
|
|
allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset);
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
|
|
//var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
for (var k = 0; k < expCat.QuantityValues.length; k++) {
|
|
changeResourceValue(0, expCat.ScenarioId, expCat.ExpCatId, expCat.Resources[i].Id, teamId, k, true);
|
|
}
|
|
expCat.Resources.splice(i, 1);
|
|
|
|
applyCellChange(scenarioId, expCatId, 0, 0, 0, 0, resId, false, true, false, false);
|
|
expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0;
|
|
expCat.AvailableResources = getExpCatResources(expCat, teamId);
|
|
//refreshAssignResourceSelect(expCat.TeamId, expCat.ProjectId, expCat.ExpCatId, teamId);
|
|
return;
|
|
}
|
|
}
|
|
resizeCalendar();
|
|
}
|
|
});
|
|
},
|
|
className: "bootbox-sm"
|
|
});
|
|
};
|
|
function getNearestWeekending(date) {
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].Milliseconds >= date)
|
|
return $scope.data.Headers[i].Milliseconds;
|
|
}
|
|
return date;
|
|
}
|
|
|
|
$scope.checkActualValue = function (data, scenarioId, expCatId, resId, teamId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
//alert("That is not implemented yet!")
|
|
//return false;
|
|
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
//var resource = getResourceByExpCat(expCat, resId);
|
|
var actual = getResourceActualByExpCat(expCat, resId);
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
var project = getProjectById(expCat.ProjectId);
|
|
|
|
var resourceEndDateWeekending = getNearestWeekending(actual.EndDate);
|
|
var projectEndDateWeekending = getNearestWeekending(project.EndDate);
|
|
//Edit month or week cell
|
|
if (colIndex >= 0) {
|
|
if ($scope.data.Headers[colIndex].IsMonth) {
|
|
var oldValue = actual.QuantityValues[colIndex];
|
|
var weeks = 0;
|
|
var coef = avg ? (newValue / (oldValue || 1)) : (oldValue > 0 ? newValue / oldValue : 1);
|
|
//Get weekendings in entire month
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= actual.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending && !actual.ReadOnlyWeeksActuals[j]) {
|
|
weeks++;
|
|
}
|
|
}
|
|
|
|
var totalWeeks = $scope.data.Headers[colIndex].Weeks.length;
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= actual.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending && !actual.ReadOnlyWeeksActuals[j]) {
|
|
var val = avg ? (oldValue > 0 ? actual.QuantityValues[j] * coef : newValue / weeks * totalWeeks)
|
|
: (oldValue > 0 ? actual.QuantityValues[j] * coef : newValue / weeks);
|
|
changeActualValue(val, scenarioId, expCatId, resId, teamId, j, false);
|
|
}
|
|
}
|
|
} else {
|
|
changeActualValue(newValue, scenarioId, expCatId, resId, teamId, colIndex, false);
|
|
}
|
|
//Edit total cell
|
|
} else {
|
|
var weeks = 0;
|
|
var part1Val = 0;
|
|
var part2Val = 0;
|
|
var part1Week = 0;
|
|
var part2Week = 0;
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= actual.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending) {
|
|
if (!$scope.data.Headers[j].IsMonth) {
|
|
if (actual.ReadOnlyWeeksActuals[j]) {
|
|
part1Val += actual.ActualQuantityValues[j];
|
|
part1Week++;
|
|
} else {
|
|
part2Val += actual.ActualQuantityValues[j];
|
|
part2Week++;
|
|
weeks += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var newWeekValue = newValue / part2Week;
|
|
|
|
//Calc avg for non r/o cells
|
|
var coef = (actual.GrandActualTotalQuantity > 0 ? newValue / actual.GrandActualTotalQuantity : -1);
|
|
var newTotal = part1Val + part2Val;
|
|
if (coef > 0)
|
|
coef = (coef * newTotal - part1Val) / part2Val;
|
|
else
|
|
newValue = (newValue * (part1Week + part2Week)) / part2Week;
|
|
|
|
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= actual.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending &&
|
|
!$scope.data.Headers[j].IsMonth && !actual.ReadOnlyWeeksActuals[j]) {
|
|
var oldValue = actual.ActualQuantityValues[j];
|
|
$scope.checkActualValue(avg ? (coef > 0 ? oldValue * coef : newValue) :
|
|
coef > 0 ? oldValue * coef : newWeekValue,
|
|
scenarioId, expCatId, resId, teamId, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
//recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
|
|
return false;
|
|
};
|
|
|
|
$scope.checkNonProjectTimeValue = function (data, nptId, catId, resId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
var category = getNonProjectTimeById(nptId);
|
|
var resource = getResourceByNonProjectTime(category, resId);
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
if (colIndex >= 0) {
|
|
if ($scope.data.Headers[colIndex].IsMonth) {
|
|
var oldValue = category.IsTeamMode ? category.QuantityValues[colIndex] : resource.QuantityValues[colIndex];
|
|
if (oldValue == null)
|
|
return;
|
|
|
|
var weeks = $scope.data.Headers[colIndex].Weeks.length;
|
|
var coef = avg ? (newValue / (oldValue != 0 ? oldValue : 1 || 1)) : (oldValue > 0 ? newValue / (oldValue != 0 ? oldValue : 1) : 1);
|
|
var totalWeeks = $scope.data.Headers[colIndex].Weeks.length;
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var val = 0;
|
|
if (category.IsTeamMode) {
|
|
val = avg ? (oldValue > 0 ? category.QuantityValues[j] * coef : newValue / ((weeks * totalWeeks) != 0 ? weeks * totalWeeks : 1))
|
|
: (oldValue > 0 ? category.QuantityValues[j] * coef : newValue / (weeks == 0 ? 1 : weeks));
|
|
} else {
|
|
val = avg ? (oldValue > 0 ? resource.QuantityValues[j] * coef : newValue / ((weeks * totalWeeks) != 0 ? weeks * totalWeeks : 1))
|
|
: (oldValue > 0 ? resource.QuantityValues[j] * coef : newValue / (weeks == 0 ? 1 : weeks));
|
|
}
|
|
changeNonProjectTimeValue(val, nptId, catId, resId, j);
|
|
}
|
|
} else {
|
|
changeNonProjectTimeValue(newValue, nptId, catId, resId, colIndex);
|
|
}
|
|
//Edit total cell
|
|
} else {
|
|
var weeks = 0;
|
|
var readOnlyRowSum = 0;
|
|
var editableRowSum = 0;
|
|
var readonlyWeekCount = 0;
|
|
var editableWeekCount = 0;
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
if (!$scope.data.Headers[j].IsMonth) {
|
|
if (!category.IsTeamMode) {
|
|
if (resource.ReadOnlyWeeks[j]) {
|
|
readOnlyRowSum += (resource.QuantityValues[j] == null ? 0 : resource.QuantityValues[j]);
|
|
readonlyWeekCount++;
|
|
} else {
|
|
editableRowSum += (resource.QuantityValues[j] == null ? 0 : resource.QuantityValues[j]);
|
|
editableWeekCount++;
|
|
weeks += 1;
|
|
}
|
|
}
|
|
else {
|
|
if (category.ReadOnly[j]) {
|
|
readOnlyRowSum += (category.QuantityValues[j] == null ? 0 : category.QuantityValues[j]);
|
|
readonlyWeekCount++;
|
|
} else {
|
|
editableRowSum += (category.QuantityValues[j] == null ? 0 : category.QuantityValues[j]);
|
|
editableWeekCount++;
|
|
weeks += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var newWeekValue = newValue / editableWeekCount;
|
|
|
|
//Calc avg for non r/o cells
|
|
var coef = -1;
|
|
if (!category.IsTeamMode)
|
|
coef = (resource.GrandTotalQuantity > 0 ? newValue / resource.GrandTotalQuantity : -1);
|
|
else
|
|
coef = (category.GrandTotalQuantity > 0 ? newValue / category.GrandTotalQuantity : -1);
|
|
var newTotal = readOnlyRowSum + editableRowSum;
|
|
if (coef > 0)
|
|
coef = (coef * newTotal - readOnlyRowSum) / editableRowSum;
|
|
else
|
|
newValue = (newValue * (readonlyWeekCount + editableWeekCount)) / editableWeekCount;
|
|
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
if (!$scope.data.Headers[j].IsMonth) {
|
|
if (category.IsTeamMode && category.ReadOnly[j])
|
|
continue;
|
|
if (!category.IsTeamMode && resource.ReadOnlyWeeks[j])
|
|
continue;
|
|
var oldValue = 0;
|
|
if (category.IsTeamMode)
|
|
oldValue = category.QuantityValues[j];
|
|
else
|
|
oldValue = resource.QuantityValues[j];
|
|
$scope.checkNonProjectTimeValue(avg ? (coef > 0 ? oldValue * coef : newValue) :
|
|
coef > 0 ? oldValue * coef : newWeekValue,
|
|
nptId, catId, resId, j);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
$scope.checkResourceValue = function (data, scenarioId, expCatId, resId, teamId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var resource = getResourceByExpCat(expCat, resId);
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
var project = getProjectById(expCat.ProjectId);
|
|
|
|
var resourceEndDateWeekending = getNearestWeekending(resource.EndDate);
|
|
var projectEndDateWeekending = getNearestWeekending(project.EndDate);
|
|
//Edit month or week cell
|
|
if (colIndex >= 0) {
|
|
if ($scope.data.Headers[colIndex].IsMonth) {
|
|
var oldValue = resource.QuantityValues[colIndex];
|
|
var weeks = 0;
|
|
var coef = avg ? (newValue / (oldValue || 1)) : (oldValue > 0 ? newValue / oldValue : 1);
|
|
//Get weekendings in entire month
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= resource.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending && !resource.ReadOnlyWeeks[j]) {
|
|
weeks++;
|
|
}
|
|
}
|
|
|
|
var totalWeeks = $scope.data.Headers[colIndex].Weeks.length;
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= resource.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending && !resource.ReadOnlyWeeks[j]) {
|
|
var val = avg ? (oldValue > 0 ? resource.QuantityValues[j] * coef : newValue / weeks * totalWeeks)
|
|
: (oldValue > 0 ? resource.QuantityValues[j] * coef : newValue / weeks);
|
|
changeResourceValue(val, scenarioId, expCatId, resId, teamId, j, false);
|
|
}
|
|
}
|
|
} else {
|
|
changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex, false);
|
|
}
|
|
//Edit total cell
|
|
} else {
|
|
var weeks = 0;
|
|
var part1Val = 0;
|
|
var part2Val = 0;
|
|
var part1Week = 0;
|
|
var part2Week = 0;
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= resource.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending) {
|
|
if (!$scope.data.Headers[j].IsMonth) {
|
|
if (resource.ReadOnlyWeeks[j]) {
|
|
part1Val += resource.QuantityValues[j];
|
|
part1Week++;
|
|
} else {
|
|
part2Val += resource.QuantityValues[j];
|
|
part2Week++;
|
|
weeks += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var newWeekValue = newValue / part2Week;
|
|
|
|
//Calc avg for non r/o cells
|
|
var coef = (resource.GrandTotalQuantity > 0 ? newValue / resource.GrandTotalQuantity : -1);
|
|
var newTotal = part1Val + part2Val;
|
|
if (coef > 0)
|
|
coef = (coef * newTotal - part1Val) / part2Val;
|
|
else
|
|
newValue = (newValue * (part1Week + part2Week)) / part2Week;
|
|
|
|
for (var j = 0; j < $scope.data.Headers.length; j++) {
|
|
var currWeekending = $scope.data.Headers[j].Milliseconds;
|
|
if (currWeekending >= resource.StartDate && currWeekending >= project.StartDate &&
|
|
currWeekending <= resourceEndDateWeekending && currWeekending <= projectEndDateWeekending &&
|
|
!$scope.data.Headers[j].IsMonth && !resource.ReadOnlyWeeks[j]) {
|
|
var oldValue = resource.QuantityValues[j];
|
|
$scope.checkResourceValue(avg ? (coef > 0 ? oldValue * coef : newValue) :
|
|
coef > 0 ? oldValue * coef : newWeekValue,
|
|
scenarioId, expCatId, resId, teamId, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
// we should recalculate availability of changed resource for entire calendar
|
|
recalculateAvailability4ResourceInEntireCalendar(resId);
|
|
|
|
return false;
|
|
};
|
|
function getExpCatResources(expCat, teamId) {
|
|
var resources = [];
|
|
for (var i = 0; i < $scope.data.AllResources.length; i++) {
|
|
var resource = $scope.data.AllResources[i];
|
|
var resourceMatch = resource.ExpedentureCategoryId == expCat.ExpCatId && resource.IsActiveEmployee; // condition for general EC
|
|
if (expCat.AllowResourceAssignment == false) {
|
|
resourceMatch = resource.IsActiveEmployee; // condition for Super EC
|
|
}
|
|
if (resourceMatch) {
|
|
var isProjectFound = false;
|
|
for (var j = 0; j < resource.ProjectIds.length; j++) {
|
|
|
|
if (resource.ProjectIds[j] == expCat.ProjectId &&
|
|
(!$scope.calendarFilters.GroupByTeam || $scope.CalendarFilterMode.IsTeam || findTeamInResourceTeams(resource.Teams, expCat.TeamId))) {
|
|
isProjectFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isProjectFound) {
|
|
var isFound = false;
|
|
if (expCat.Resources != null) {
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == resource.Id &&
|
|
(!$scope.calendarFilters.GroupByTeam || teamsAnyOf(expCat.Resources[j].Teams, resource.Teams))) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!isFound) {
|
|
for (var j = 0; j < resources.length; j++) {
|
|
if (resources[j].Id == resource.Id &&
|
|
(!$scope.calendarFilters.GroupByTeam || teamsAnyOf(resources[j].Teams, resource.Teams))) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!isFound && resource.AssignedToTeam) {
|
|
if ($scope.calendarFilters.ResourceId == null || resource.Id == $scope.calendarFilters.ResourceId) {
|
|
resources.push(resource);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Calculation of availability for resources */
|
|
return getResources4Assign(resources, expCat.ProjectId, teamId);
|
|
};
|
|
function getResources4Assign(resources, projectId, teamId) {
|
|
var resources4Assign = {};
|
|
if (!resources || resources.length <= 0 || !projectId)
|
|
return null;
|
|
|
|
var project = getProjectById(projectId);
|
|
if (project) {
|
|
var startDate = project.StartDate,
|
|
endDate = getNearestWeekending(project.EndDate);
|
|
|
|
for (var i = 0; i < resources.length; i++) {
|
|
var resource4Assign = getResource4Assign(resources[i], startDate, endDate, teamId);
|
|
if (resource4Assign)
|
|
resources4Assign[resource4Assign.id] = resource4Assign;
|
|
}
|
|
}
|
|
|
|
return Object.keys(resources4Assign).length > 0 ? resources4Assign : null;
|
|
};
|
|
function getResource4Assign(resource, startDate, endDate, teamId) {
|
|
if (!resource || (startDate || 0) <= 0 || (endDate || 0) <= 0)
|
|
return;
|
|
|
|
var returnFlag = false;
|
|
for (var count = 0; count < resource.Teams.length; count++) {
|
|
if (resource.Teams[count].TeamStartDate > endDate || (resource.Teams[count].TeamEndDate || Number.MAX_VALUE) < startDate) {
|
|
returnFlag = false || returnFlag;
|
|
} else {
|
|
returnFlag = true;
|
|
}
|
|
}
|
|
|
|
if (!returnFlag) {
|
|
return null;
|
|
}
|
|
|
|
var resource4Assign = {
|
|
id: resource.Id,
|
|
name: resource.Name,
|
|
minAvailability: Number.MAX_VALUE,
|
|
maxAvailability: -Number.MAX_VALUE,
|
|
avgAvailability: 0
|
|
}
|
|
var expCats = dataSources.getExpenditures();
|
|
var uomValue = 0;
|
|
if (expCats != null) {
|
|
var expCat = expCats[resource.ExpedentureCategoryId];
|
|
if (expCat != null)
|
|
uomValue = expCat.UOMValue || 0;
|
|
|
|
// UOMValue always in hours and we should convert it in resources depending on activity calendar mode
|
|
if (!$scope.calendarFilters.IsUOMHours && uomValue > 0)
|
|
uomValue /= uomValue;
|
|
}
|
|
var today = new Date();
|
|
today = new Date(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
|
|
var UTCmilliseconds = today.getTime() - today.getTimezoneOffset() * 60 * 1000;
|
|
var weeks = 0;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
var header = $scope.data.Headers[i];
|
|
if (!header || header.IsMonth || header.Milliseconds < startDate || header.Milliseconds > endDate)
|
|
continue;
|
|
if (UTCmilliseconds > header.Milliseconds + 86400000 - 1)
|
|
continue;
|
|
|
|
var availability = 0;
|
|
if (resource.ReadOnlyWeeks[i])
|
|
availability = 0;
|
|
else {
|
|
var isTeamFound = false;
|
|
for (var teamIndex = 0; teamIndex < resource.Teams.length; teamIndex++) {
|
|
if (resource.Teams[teamIndex].TeamStartDate <= header.Milliseconds && (resource.Teams[teamIndex].TeamEndDate || Number.MAX_VALUE) >= header.Milliseconds) {
|
|
if (!isGuidEmpty(teamId))
|
|
{
|
|
if (resource.Teams[teamIndex].TeamId == teamId)
|
|
{
|
|
isTeamFound = true;
|
|
break;
|
|
}
|
|
} else {
|
|
isTeamFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!isTeamFound)
|
|
{
|
|
availability = 0;
|
|
}
|
|
else {
|
|
var remainingCapacity = uomValue - resource.AllocatedQuantityValues[i];
|
|
if (resource.NonProjectTime) {
|
|
for (var npCategoryId in resource.NonProjectTime)
|
|
remainingCapacity -= resource.NonProjectTime[npCategoryId][i] || 0;
|
|
}
|
|
availability = Math.round(100 * (uomValue > 0 ? (remainingCapacity / uomValue) : 0));
|
|
}
|
|
}
|
|
|
|
if (resource4Assign.minAvailability > availability)
|
|
resource4Assign.minAvailability = availability;
|
|
if (resource4Assign.maxAvailability < availability)
|
|
resource4Assign.maxAvailability = availability;
|
|
resource4Assign.avgAvailability += availability;
|
|
weeks++;
|
|
}
|
|
|
|
if (weeks <= 0)
|
|
resource4Assign.avgAvailability = 0;
|
|
else
|
|
resource4Assign.avgAvailability = Math.round(resource4Assign.avgAvailability / weeks);
|
|
|
|
return resource4Assign;
|
|
};
|
|
function recalculateAvailability4ResourceInEntireCalendar(resourceId) {
|
|
if (!resourceId)
|
|
return;
|
|
|
|
var resource = getResourceById(resourceId);
|
|
if (!resource)
|
|
return;
|
|
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
var row = $scope.data.Calendar[i];
|
|
if (!row || !row.AvailableResources || !row.AvailableResources[resourceId])
|
|
continue;
|
|
|
|
var project = getProjectById(row.ProjectId);
|
|
if (!project)
|
|
continue;
|
|
|
|
var startDate = project.StartDate,
|
|
endDate = getNearestWeekending(project.EndDate);
|
|
row.AvailableResources[resourceId] = getResource4Assign(resource, startDate, endDate, row.TeamId);
|
|
}
|
|
};
|
|
$scope.isTakeAllDisabled = function (expCat, res) {
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].ReadOnly) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
|
|
$scope.hideCalendarPart = function (upper) {
|
|
if (upper)
|
|
$scope.calendarFilters.ShowUpper = !$scope.calendarFilters.ShowUpper;
|
|
else
|
|
$scope.calendarFilters.ShowLower = !$scope.calendarFilters.ShowLower;
|
|
|
|
if (upper && !$scope.calendarFilters.ShowUpper)
|
|
$("#showButtomMode").switcher('disable');
|
|
else
|
|
$("#showButtomMode").switcher('enable');
|
|
|
|
|
|
if (!upper && !$scope.calendarFilters.ShowLower)
|
|
$("#showTopMode").switcher('disable');
|
|
else
|
|
$("#showTopMode").switcher('enable');
|
|
|
|
if ($scope.data != null) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
$scope.data.Calendar[i].IsLowerHidden = !$scope.calendarFilters.ShowLower;
|
|
$scope.data.Calendar[i].IsUpperHidden = !$scope.calendarFilters.ShowUpper;
|
|
}
|
|
}
|
|
// force digest cycle as this method could being called from JS
|
|
$scope.$digest();
|
|
};
|
|
$scope.switchUOMMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsUOMHours;
|
|
$scope.calendarFilters.IsUOMHours = newValue;
|
|
$scope.getCalendar();
|
|
};
|
|
$scope.switchGroupByTeam = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.GroupByTeam;
|
|
$scope.calendarFilters.GroupByTeam = newValue;
|
|
$scope.getCalendar();
|
|
};
|
|
$scope.switchCapacityVew = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsCapacityModeActuals;
|
|
$scope.calendarFilters.IsCapacityModeActuals = newValue;
|
|
$scope.getCalendar();
|
|
};
|
|
$scope.switchViewMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsViewModeMonth;
|
|
$scope.calendarFilters.IsViewModeMonth = newValue;
|
|
|
|
swithViewMode();
|
|
// force digest cycle as this method could being called from JS
|
|
$scope.$digest();
|
|
|
|
resizeCalendar();
|
|
};
|
|
function swithViewMode() {
|
|
if (!$scope.data)
|
|
return;
|
|
var newValue = $scope.calendarFilters.IsViewModeMonth;
|
|
var j;
|
|
for (j = 0; j < $scope.data.YearHeaders.length; j++) {
|
|
|
|
$scope.data.YearHeaders[j].SpanCount = 0;
|
|
}
|
|
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
var header = $scope.data.Headers[i];
|
|
if (header.IsMonth) {
|
|
header.Collapsed = newValue;
|
|
header.Show = newValue;
|
|
header.CollapsedClass = newValue ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
|
|
for (j = 0; j < $scope.data.YearHeaders.length; j++) {
|
|
if ($scope.data.YearHeaders[j].Title == header.Year) {
|
|
if (newValue) {
|
|
$scope.data.YearHeaders[j].SpanCount++; // -= header.Weeks.length - 1;
|
|
} else {
|
|
$scope.data.YearHeaders[j].SpanCount += header.Weeks.length;
|
|
}
|
|
//break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
header.Collapsed = newValue;
|
|
header.Show = !newValue;
|
|
}
|
|
header.Initialized = header.Initialized || header.Show;
|
|
}
|
|
getVisibleCellCount();
|
|
}
|
|
function getVisibleCellCount() {
|
|
var count = 0;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
var header = $scope.data.Headers[i];
|
|
if (header.Show)
|
|
count++;
|
|
}
|
|
$scope.data.VisibleCellCount = count;
|
|
}
|
|
$scope.switchBarMode = function () {
|
|
var newValue = !$scope.calendarFilters.IsBarMode;
|
|
$scope.calendarFilters.IsBarMode = newValue;
|
|
if (!$scope.data)
|
|
return;
|
|
|
|
// update project rows CSS
|
|
for (var rowIndex = 0; rowIndex < $scope.data.Calendar.length; rowIndex++) {
|
|
if ($scope.data.Calendar[rowIndex].RowType == $scope.RowType.Project)
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
updateCSSClass($scope.data.Calendar[rowIndex], null, colIndex);
|
|
}
|
|
}
|
|
// force digest cycle as this method could being called from JS
|
|
$scope.$digest();
|
|
};
|
|
$scope.changeCapacity = function (value) {
|
|
$scope.calendarFilters.ShowCapacity = value;
|
|
if (!$scope.data)
|
|
return;
|
|
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == $scope.RowType.BottomCategory) {
|
|
var expCatTotal = $scope.data.Calendar[i];
|
|
refreshTotalSpreadVal(expCatTotal);
|
|
}
|
|
}
|
|
recalcBottomPartTotals();
|
|
};
|
|
|
|
$scope.changeSortBy = function (value) {
|
|
$scope.calendarFilters.sortBy = value;
|
|
$scope.getCalendar();
|
|
};
|
|
$scope.switchSortOrder = function () {
|
|
var newValue = !$scope.calendarFilters.sortOrder;
|
|
$scope.calendarFilters.sortOrder = newValue;
|
|
$scope.getCalendar();
|
|
};
|
|
|
|
$scope.onMonthHeaderClick = function (header) {
|
|
header.Collapsed = !header.Collapsed;
|
|
header.Show = !header.Show;
|
|
header.CollapsedClass = header.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
header.Initialized = header.Initialized || header.Show;
|
|
var i;
|
|
if (header.Weeks && header.Weeks.length > 0)
|
|
for (i = 0; i < header.Weeks.length; i++) {
|
|
$scope.data.Headers[header.Weeks[i]].Collapsed = header.Collapsed;
|
|
$scope.data.Headers[header.Weeks[i]].Show = !header.Collapsed;
|
|
$scope.data.Headers[header.Weeks[i]].Initialized = $scope.data.Headers[header.Weeks[i]].Initialized || $scope.data.Headers[header.Weeks[i]].Show;
|
|
}
|
|
for (i = 0; i < $scope.data.YearHeaders.length; i++) {
|
|
if ($scope.data.YearHeaders[i].Title == header.Year) {
|
|
if (header.Collapsed) {
|
|
$scope.data.YearHeaders[i].SpanCount -= header.Weeks.length - 1;
|
|
} else {
|
|
$scope.data.YearHeaders[i].SpanCount += header.Weeks.length - 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
getVisibleCellCount();
|
|
resizeCalendar();
|
|
};
|
|
|
|
$scope.anyUpdated = function () {
|
|
return ($scope.data2Update && (($scope.data2Update.ChangedExpCats && $scope.data2Update.ChangedExpCats.length > 0) ||
|
|
($scope.data2Update.NonProjectTimeCats && $scope.data2Update.NonProjectTimeCats.length > 0)));
|
|
};
|
|
$scope.onParentNodeClick = function (row, $event) {
|
|
if ($($event.target).parents('.scenario-name').length > 0 || $($event.target).parents('.menuGroup').length > 0)
|
|
return;
|
|
if (row.ProjectId != null && row.ExpCatId == null) {
|
|
row.ProjectCollapsed = !row.ProjectCollapsed;
|
|
row.CollapsedClass = row.ProjectCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
} else if (row.ExpCatId != null) {
|
|
row.ExpCatCollapsed = !row.ExpCatCollapsed;
|
|
if (row.ScenarioId != null)
|
|
row.CollapsedClass = row.ExpCatCollapsed ? $scope.ExpCatCollapsedIcon : $scope.ExpCatNonCollapsedIcon;
|
|
else
|
|
row.CollapsedClass = row.ExpCatCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
}
|
|
|
|
setChildrenCollapsed(row, false, row.IsParentCollapsed);
|
|
resizeCalendar();
|
|
};
|
|
$scope.toggleNonProjectTotalRow = function (row) {
|
|
if (!row ||
|
|
(row.RowType != $scope.RowType.NonProjectTimeTotal && row.RowType != $scope.RowType.NonProjectTimeCategory && row.RowType != $scope.RowType.NonProjectTime) ||
|
|
(row.RowType == $scope.RowType.NonProjectTime && row.IsTeamMode))
|
|
return;
|
|
|
|
row.IsCollapsed = !row.IsCollapsed;
|
|
row.CollapsedClass = row.IsCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
|
|
if (row.RowType == $scope.RowType.NonProjectTimeCategory) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == $scope.RowType.NonProjectTimeTotal) {
|
|
var parent = $scope.data.Calendar[i];
|
|
for (var j = 0; j < parent.Categories.length; j++) {
|
|
var category = parent.Categories[j];
|
|
if (category.ParentId == row.Id)
|
|
category.IsParentCollapsed = row.IsCollapsed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
resizeCalendar();
|
|
};
|
|
|
|
$scope.toggleTotalRow = function (row) {
|
|
if (!row || (row.RowType != $scope.RowType.Total))
|
|
return;
|
|
|
|
row.IsCollapsed = !row.IsCollapsed;
|
|
row.CollapsedClass = row.IsCollapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
};
|
|
|
|
$scope.CheckLock = function ($event, tableId, fieldId, url) {
|
|
if (CheckLock(getEventTargetId($event), tableId, fieldId)) {
|
|
// SA. ENV-905. Added backurl to navigation link
|
|
var currentUrl = document.location.pathname + document.location.search;
|
|
var backUrl = "backUrl=" + encodeURIComponent(currentUrl);
|
|
var backName = "";
|
|
var navigateToUrl = url + '/' + fieldId + "?" + backUrl;
|
|
|
|
if ($scope.pageTitle && ($scope.pageTitle.length > 0))
|
|
// SA. The title of the page to return. Used to display in scenario form button
|
|
backName = "&backName=" + encodeURIComponent($scope.pageTitle);
|
|
|
|
var navigateToUrl = url + '/' + fieldId + "?" + backUrl + backName;
|
|
document.location.href = navigateToUrl;
|
|
}
|
|
};
|
|
$scope.ToggleStatus = function ($event, tableId, fieldId) {
|
|
if (CheckLock(getEventTargetId($event), tableId, fieldId)) {
|
|
if (fieldId == null || fieldId == "")
|
|
return "";
|
|
var url = "/ForecastDashboard/CheckIfActive/";
|
|
var request = {
|
|
'scenarioId': fieldId
|
|
};
|
|
$.get(url, request, function (data) {
|
|
if (data == null || data == "") {
|
|
$scope.ToggleStatusConfirmed(fieldId);
|
|
return '';
|
|
} else {
|
|
bootbox.confirm({
|
|
message: "There is an active scenario for this project already. Are you sure you want to activate this scenario instead of active one?",
|
|
callback: function (result) {
|
|
$scope.$apply(function () {
|
|
if (result) {
|
|
$scope.ToggleStatusConfirmed(fieldId);
|
|
}
|
|
});
|
|
},
|
|
className: "bootbox-sm"
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
$scope.ToggleStatusConfirmed = function (scenarioId) {
|
|
if (scenarioId == null || scenarioId == "")
|
|
return "";
|
|
var url = "/ForecastDashboard/ToggleStatus/";
|
|
var request = {
|
|
'scenarioId': scenarioId
|
|
};
|
|
$.get(url, request, function (data) {
|
|
$scope.getCalendar();
|
|
});
|
|
return '';
|
|
};
|
|
$scope.CalcRemainingCapacity = function (capacity, index) {
|
|
return (capacity - $scope.grandtotalrow.QuantityValues[index]);
|
|
};
|
|
|
|
$scope.CalcRemainingCapacityTotal = function (capacityTotal) {
|
|
return (capacityTotal - $scope.grandtotalrow.GrandTotalQuantity);
|
|
};
|
|
|
|
function recalcBottomPartTotals() {
|
|
//Skip totals calculating for bottom part of the people resource calendar
|
|
if ($scope.calendarFilters.ResourceId != null)
|
|
return;
|
|
|
|
var avg = ($scope.calendarFilters.ShowAvgTotals && !$scope.calendarFilters.IsUOMHours);
|
|
for (var i in $scope.data.Calendar) {
|
|
var expCatTotal = $scope.data.Calendar[i];
|
|
if (expCatTotal.RowType == $scope.RowType.BottomCategory) {
|
|
var allocated = 0;
|
|
var weeksCount = 0;
|
|
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if (colIndex == 0)
|
|
expCatTotal.GrandTotalQuantity = 0;
|
|
|
|
if (!$scope.data.Headers[colIndex].IsMonth) {
|
|
switch ($scope.calendarFilters.ShowCapacity) {
|
|
case "1": // Allocated/Capacity
|
|
expCatTotal.GrandTotalQuantity += expCatTotal.QuantityTotalAllocatedValue[colIndex];
|
|
break;
|
|
case "2": // Need/Capacity
|
|
expCatTotal.GrandTotalQuantity += expCatTotal.QuantityValues[colIndex];
|
|
break;
|
|
case "3": // Allocated/Need
|
|
expCatTotal.GrandTotalQuantity += expCatTotal.QuantityTotalAllocatedValue[colIndex];
|
|
break;
|
|
case "4": // Remaining/Capacity, display similar to Allocated/Capacity
|
|
expCatTotal.GrandTotalQuantity += (expCatTotal.QuantityTotalResValue[colIndex] - expCatTotal.QuantityValues[colIndex]);
|
|
break;
|
|
}
|
|
for (var j in expCatTotal.Resources) {
|
|
var resourceTotal = expCatTotal.Resources[j];
|
|
if (colIndex == 0)
|
|
resourceTotal.GrandTotalQuantity = 0;
|
|
|
|
switch ($scope.calendarFilters.ShowCapacity) {
|
|
case "1": // Allocated/Capacity
|
|
resourceTotal.GrandTotalQuantity += resourceTotal.QuantityValues[colIndex];
|
|
break;
|
|
case "2": // Need/Capacity
|
|
resourceTotal.GrandTotalQuantity += resourceTotal.QuantityValues[colIndex];
|
|
break;
|
|
case "3": // Allocated/Need
|
|
resourceTotal.GrandTotalQuantity += resourceTotal.QuantityValues[colIndex];
|
|
break;
|
|
case "4": // Remaining/Capacity, display similar to Allocated/Capacity
|
|
resourceTotal.GrandTotalQuantity += (resourceTotal.QuantityTotalResValue[colIndex] - resourceTotal.AllocatedQuantityValues[colIndex]);
|
|
break;
|
|
}
|
|
}
|
|
weeksCount++;
|
|
}
|
|
}
|
|
if (avg) {
|
|
expCatTotal.GrandTotalQuantity = expCatTotal.GrandTotalQuantity / weeksCount;
|
|
for (var j in expCatTotal.Resources) {
|
|
var resourceTotal = expCatTotal.Resources[j];
|
|
resourceTotal.GrandTotalQuantity = resourceTotal.GrandTotalQuantity / weeksCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$scope.CopyScenario = function ($event, scenarioId) {
|
|
if (CheckLock(getEventTargetId($event), 'Scenario', scenarioId)) {
|
|
if (scenarioId == null || scenarioId == "")
|
|
return "";
|
|
var url = "/Scenarios/Details/" + scenarioId + '?ptab=copy';
|
|
var backUrl = '&backUrl=' + encodeURIComponent('/CapacityManagement');
|
|
if (!!$scope.calendarFilters.TeamId)
|
|
backUrl = '&backUrl=' + encodeURIComponent('/Team/Board?ptab=calendar');
|
|
else if (!!$scope.calendarFilters.ViewId)
|
|
backUrl = '&backUrl=' + encodeURIComponent('/View/Board?ptab=calendar');
|
|
document.location.href = url; //+backUrl;
|
|
}
|
|
};
|
|
$scope.AddScenario = function ($event, projectId) {
|
|
if (typeof loadScenario === 'function')
|
|
loadScenario(projectId);
|
|
};
|
|
|
|
function getEventTargetId($event) {
|
|
if (!$event.target.id || $event.target.id === '')
|
|
return $event.target.parentElement.id;
|
|
|
|
return $event.target.id;
|
|
}
|
|
|
|
$scope.SelectedFilterElementChanged = function () {
|
|
if ($scope.CalendarFilterMode.SelectedItemId && ($scope.CalendarFilterMode.SelectedItemId.length > 0)) {
|
|
if ($scope.dataSection && ($scope.dataSection.length > 0)) {
|
|
var prefs = collectPreferences($scope.dataSection);
|
|
|
|
prefs.push({
|
|
Key: "filteredCompany",
|
|
Value: $scope.CalendarFilterMode.SelectedItemId
|
|
});
|
|
|
|
saveUserPagePreferences(prefs, $scope.dataSection);
|
|
}
|
|
}
|
|
|
|
// SA. ENV-799
|
|
$scope.loadCalendarData();
|
|
// ENV-539. For some reason select2 jQuery control loose selected value just after $scope.digest()
|
|
// so we need to set value again on next JS iteration.
|
|
$timeout(function () {
|
|
$('[name=selFilterElement]').select2("val", $scope.CalendarFilterMode.SelectedItemId);
|
|
}, 0, false);
|
|
}
|
|
|
|
$scope.loadCalendarData = function () {
|
|
// SA. ENV-799. Begin
|
|
if (!$('#filterForm').valid()) return;
|
|
$scope.calendarFilters.CompanyId = null;
|
|
$scope.calendarFilters.ViewId = null;
|
|
$scope.calendarFilters.TeamId = null;
|
|
$scope.calendarFilters.ResourceId = null;
|
|
|
|
if ($scope.CalendarFilterMode.IsCompany)
|
|
$scope.calendarFilters.CompanyId = $scope.CalendarFilterMode.SelectedItemId;
|
|
|
|
if ($scope.CalendarFilterMode.IsView)
|
|
$scope.calendarFilters.ViewId = $scope.CalendarFilterMode.SelectedItemId;
|
|
|
|
if ($scope.CalendarFilterMode.IsTeam)
|
|
$scope.calendarFilters.TeamId = $scope.CalendarFilterMode.SelectedItemId;
|
|
|
|
if ($scope.CalendarFilterMode.IsResource)
|
|
$scope.calendarFilters.ResourceId = $scope.CalendarFilterMode.SelectedItemId;
|
|
// SA. ENV-799. End
|
|
|
|
$scope.getCalendar();
|
|
}
|
|
|
|
// SA. ENV-799. Begin
|
|
$scope.switchCompanyFilterMode = function (preserverSelection) {
|
|
if (!$scope.CalendarFilterMode.IsCompany)
|
|
$scope.CalendarFilterMode.IsCompany = true;
|
|
|
|
$scope.CalendarFilterMode.IsView = false;
|
|
$scope.CalendarFilterMode.IsTeam = false;
|
|
$scope.CalendarFilterMode.IsResource = false;
|
|
$scope.CalendarFilterMode.FilteredEntityTitle = "Company";
|
|
|
|
if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Companies != null)) {
|
|
$scope.displayedOptions = $scope.availableFilterOptions.Companies;
|
|
for (var i = 0; i < $scope.displayedOptions.length; i++) {
|
|
var option = $scope.displayedOptions[i];
|
|
option.CSSClass = 'ddl-level-item';
|
|
if (option.Group && option.Group.Name && option.Group.Name.length > 0) {
|
|
option.CSSClass += ' pad-left';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!preserverSelection) {
|
|
$scope.CalendarFilterMode.SelectedItemId = null;
|
|
$scope.$broadcast('selectedSourceChanged');
|
|
}
|
|
};
|
|
|
|
$scope.switchViewFilterMode = function (preserverSelection) {
|
|
if (!$scope.CalendarFilterMode.IsView)
|
|
$scope.CalendarFilterMode.IsView = true;
|
|
|
|
$scope.CalendarFilterMode.IsCompany = false;
|
|
$scope.CalendarFilterMode.IsTeam = false;
|
|
$scope.CalendarFilterMode.IsResource = false;
|
|
$scope.CalendarFilterMode.FilteredEntityTitle = "View";
|
|
|
|
if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Views != null))
|
|
$scope.displayedOptions = $scope.availableFilterOptions.Views;
|
|
|
|
if (!preserverSelection) {
|
|
$scope.CalendarFilterMode.SelectedItemId = null;
|
|
$scope.$broadcast('selectedSourceChanged');
|
|
}
|
|
};
|
|
|
|
$scope.switchTeamFilterMode = function (preserverSelection) {
|
|
if (!$scope.CalendarFilterMode.IsTeam)
|
|
$scope.CalendarFilterMode.IsTeam = true;
|
|
|
|
$scope.CalendarFilterMode.IsCompany = false;
|
|
$scope.CalendarFilterMode.IsView = false;
|
|
$scope.CalendarFilterMode.IsResource = false;
|
|
$scope.CalendarFilterMode.FilteredEntityTitle = "Team";
|
|
|
|
if (($scope.availableFilterOptions != null) && ($scope.availableFilterOptions.Teams != null))
|
|
$scope.displayedOptions = $scope.availableFilterOptions.Teams;
|
|
|
|
if (!preserverSelection) {
|
|
$scope.CalendarFilterMode.SelectedItemId = null;
|
|
$scope.$broadcast('selectedSourceChanged');
|
|
}
|
|
};
|
|
|
|
$scope.switchResourceFilterMode = function (preserverSelection) {
|
|
if (!$scope.CalendarFilterMode.IsResource)
|
|
$scope.CalendarFilterMode.IsResource = true;
|
|
|
|
$scope.CalendarFilterMode.IsCompany = false;
|
|
$scope.CalendarFilterMode.IsView = false;
|
|
$scope.CalendarFilterMode.IsTeam = false;
|
|
$scope.CalendarFilterMode.FilteredEntityTitle = "Resource";
|
|
|
|
$scope.IsCapacityModeActuals = true; // SA. ENV-886. Individual resource calendar shows actuals only
|
|
|
|
if (!preserverSelection) {
|
|
$scope.CalendarFilterMode.SelectedItemId = null;
|
|
$scope.$broadcast('selectedSourceChanged');
|
|
}
|
|
};
|
|
|
|
$scope.scrollHeader = function (evt) {
|
|
//if (flag) {
|
|
// return;
|
|
//}
|
|
var e = evt ? evt : window.event;
|
|
var t = e.target ? e.target : e.srcElement;
|
|
if (t.nodeType == 3) {
|
|
t = t.parentNode;
|
|
}
|
|
var tid = t.id.replace(':scroller', '');
|
|
var fh = ge$(tid + ':scroller:fx');
|
|
var sd = ge$(tid + ':scroller');
|
|
fh.style.left = (0 - sd.scrollLeft) + 'px';
|
|
var cf = ge$(tid + '_CFB');
|
|
if (cf) {
|
|
cf.style.marginTop = (0 - (sd.scrollTop)) + 'px';
|
|
}
|
|
};
|
|
|
|
function ge$(d) { return document.getElementById(d); }
|
|
$scope.clearWidth = function () {
|
|
$scope.monthCol = [];
|
|
$scope.weekCol = [];
|
|
}
|
|
|
|
$scope.onResize = function () {
|
|
if ($scope.data) {
|
|
//resize conteiner height
|
|
var isAC = angular.element(".ac").length > 0,
|
|
firstCellWidth = angular.element("div[id*='fxcol']").width(),
|
|
capacityTable = angular.element("#capacity-table"),
|
|
capacityTableHeight = capacityTable.height() || 0,
|
|
capacityTableWidth = capacityTable.width() || 0,
|
|
browserNonIE = ["ie", "ie1"].indexOf(checkBrowser()) < 0, //IE places scrollbars above the content and does not need additional space for scrollbar
|
|
heightContainer = angular.element(".height-container"),
|
|
heightContainerHeight = heightContainer.height(),
|
|
widthContainer = angular.element(".width-container");
|
|
|
|
var noVScroll = ($(".ac-no-v-scroll").length > 0);
|
|
if (noVScroll || (heightContainerHeight <= $scope.calendarViewSettings.tableHeightMin && capacityTableHeight > 0)) {
|
|
heightContainerHeight = capacityTableHeight + $scope.calendarViewSettings.scrollHeight;
|
|
heightContainer.height(heightContainerHeight);
|
|
}
|
|
|
|
//resize conteiner width
|
|
var vertScrollShown = capacityTableHeight > heightContainerHeight;
|
|
if (isAC) {
|
|
widthContainer.width(Math.min(($scope.calendarViewSettings.headerWidth * $scope.data.VisibleCellCount) + (browserNonIE && vertScrollShown ? $scope.calendarViewSettings.scrollWidth : 0) + 1,
|
|
$("#controller1").outerWidth() - firstCellWidth));
|
|
} else {
|
|
widthContainer.width(Math.min($scope.calendarViewSettings.headerWidth * $scope.data.VisibleCellCount + (browserNonIE && vertScrollShown ? $scope.calendarViewSettings.scrollWidth : 0),
|
|
$("#controller1").outerWidth() - firstCellWidth - 1));
|
|
}
|
|
|
|
//resize conteiner height again when horizont scroll bar appears
|
|
if (noVScroll && browserNonIE) {
|
|
var heightContainerWidth = heightContainer.width();
|
|
var horizontScrollShown = capacityTableWidth > heightContainerWidth;
|
|
|
|
if (horizontScrollShown) {
|
|
heightContainerHeight += $scope.calendarViewSettings.scrollHeight;
|
|
heightContainer.height(heightContainerHeight);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function refreshSelect2(obj) {
|
|
$timeout(function () { // You might need this timeout to be sure its run after DOM render.
|
|
obj.trigger("change");
|
|
}, 0, false);
|
|
};
|
|
//function refreshAssignResourceSelect(teamId, projectId, expCatId) {
|
|
// var control = angular.element('#assign-resource-select-' + teamId + '-' + projectId + '-' + expCatId);
|
|
// control.select2('val', '');
|
|
// refreshSelect2(control);
|
|
//};
|
|
$scope.formatPeopleResourceOption = function (result, container, query, escapeMarkup) {
|
|
var $optionScope = angular.element(result.element).scope();
|
|
/* $optionScope.resource property is declared in the expression in the view: (resourceId, resource) in row.AvailableResources track by $index */
|
|
if ($optionScope && $optionScope.resource) {
|
|
return scenarioDetailsService.getAssignableResourceOptionHtml($optionScope.resource);
|
|
}
|
|
};
|
|
function findTeamInResourceTeams(teams, teamId) {
|
|
if (teams == null || teams.length == null || teams.length <= 0 || teamId == null)
|
|
return null;
|
|
for (var i = 0; i < teams.length; i++) {
|
|
if (teams[i].TeamId == teamId)
|
|
return teams[i];
|
|
}
|
|
return null;
|
|
}
|
|
function teamsAnyOf(existingTeams, teams2Search) {
|
|
if (existingTeams == null || existingTeams.length == null || existingTeams.length <= 0 ||
|
|
teams2Search == null || teams2Search.length == null || teams2Search.length <= 0)
|
|
return false;
|
|
for (var i = 0; i < existingTeams.length; i++) {
|
|
for (var j = 0; j < teams2Search.length; j++) {
|
|
if (existingTeams[i].TeamId == teams2Search[j].TeamId)
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
function resizeCalendar() {
|
|
$timeout(function () {
|
|
$scope.onResize();
|
|
});
|
|
};
|
|
}])
|
|
.directive('scrollHeader', function () {
|
|
return {
|
|
restrict: 'A',
|
|
link: function (scope, elem, attr, ctrl) {
|
|
elem.bind('scroll', function (e) {
|
|
scope.scrollHeader(e);
|
|
});
|
|
}
|
|
};
|
|
});
|