768 lines
42 KiB
JavaScript
768 lines
42 KiB
JavaScript
'use strict';
|
|
|
|
app
|
|
.controller('resourceCalendarController', ['$scope', '$q', 'activityCalendarService', 'teamInfoService', 'activityCalendarUIService', 'dataSources', 'hoursResourcesConverter', 'roundService', '$filter', function ($scope, $q, activityCalendarService, teamInfoService, activityCalendarUIService, dataSources, hoursResourcesConverter, roundService, $filter) {
|
|
var commonErrorMessage = 'An error occurred while processing your request. Please, try again later.';
|
|
var calendarDataUrl = '/CapacityManagement/GetActivityCalendar';
|
|
var projectsByResourceCache = {}; // cache for aggregated ECs by project for "group by teams" mode
|
|
var resourceCache = {}; // cache for the resource info, this calendar is displayed for
|
|
var nonProjectTimeCache = {}; // cache for non-project time data.
|
|
var nonProjectTimeCategoryCache = {}; // cache for non-project time data.
|
|
|
|
$scope.ViewModel = {
|
|
DisplayMode: null,
|
|
Header: null,
|
|
Rows: null,
|
|
CurrentlyAssignedRow: null,
|
|
TotalRow: null,
|
|
RemainingCapacityRow: null,
|
|
NonProjectTimeTotalRow: null,
|
|
DataLoaded: false,
|
|
Visibility: {
|
|
ShowForecast: false,
|
|
ShowActuals: false,
|
|
ForecastEditable: false,
|
|
ActualsEditable: false
|
|
},
|
|
};
|
|
$scope.Filter = null;
|
|
|
|
/* Event listeners */
|
|
$scope.$on('ac.rebuild-calendar', rebuildCalendarHandler);
|
|
$scope.$on('ac.options-changed', optionsChangedHandler);
|
|
|
|
/* Methods for interaction with view */
|
|
$scope.init = function (filter, displayMode) {
|
|
rebuildCalendarHandler(null, filter, displayMode);
|
|
};
|
|
$scope.toggleMonth = function (monthIndex) {
|
|
$scope.ViewModel.Header.toggleMonth(monthIndex);
|
|
};
|
|
$scope.toggleRow = function (uiRow, $event) {
|
|
if ($($event.target).parents('.menuGroup').length > 0)
|
|
return;
|
|
|
|
// to-do: we should keep collapsed state in data-model items between possible future postbacks
|
|
var dataModel = activityCalendarService.dataItemStub || {};
|
|
activityCalendarUIService.toggleRow(uiRow, dataModel);
|
|
};
|
|
$scope.ToggleStatus = function ($event, projectId, scenario) {
|
|
var btn = $($event.target).closest('.popover-warning');
|
|
if (btn.length == 1) {
|
|
activityCalendarUIService.toggleStatus(btn, projectId, scenario)
|
|
.then(function (result) {
|
|
if (!!result)
|
|
rebuildCalendarHandler($event, $scope.Filter, $scope.ViewModel.DisplayMode, true);
|
|
})
|
|
.then(null, function () {
|
|
showErrorModal(null, 'An error occurred while toggling scenario status', '000009');
|
|
});
|
|
}
|
|
};
|
|
$scope.AddScenario = function ($event, projectId) {
|
|
activityCalendarUIService.openCreateScenarioWz(projectId);
|
|
};
|
|
$scope.checkResourceValue = function (row, $index, $data) {
|
|
if (!row || !row.ExpenditureCategoryId || !row.ExpenditureCategoryId.length || row.IsMultipleECs || !$scope.Filter.EntityId) {
|
|
return;
|
|
}
|
|
|
|
var resourceId = $scope.Filter.EntityId;
|
|
var filter = $scope.Filter,
|
|
header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
var result = activityCalendarUIService.checkResourceValue(filter, header, row.Id, { Id: row.ExpenditureCategoryId[0] }, resourceId, row, isUOMHours, isAvgMode, $index, $data, false);
|
|
if (typeof result === 'object' && angular.isArray(result) && result.length > 0) {
|
|
updateProjectRows(result, row.Id);
|
|
updateTotalRows(result);
|
|
refreshResourceStyles(result);
|
|
dataChanged();
|
|
return false;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
$scope.checkResourceGrandTotalValue = function (row, $data) {
|
|
if (!row || !row.ExpenditureCategoryId || !row.ExpenditureCategoryId.length || row.IsMultipleECs || !row.ActiveScenario) {
|
|
return;
|
|
}
|
|
|
|
var resourceId = $scope.Filter.EntityId;
|
|
var filter = $scope.Filter,
|
|
header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
var result = activityCalendarUIService.checkResourceGrandTotalValue(filter, header, row.Id, row.ActiveScenario.StartDate, row.ActiveScenario.EndDate, { Id: row.ExpenditureCategoryId[0] }, resourceId, row, isUOMHours, isAvgMode, $data, false);
|
|
if (typeof result === 'object' && angular.isArray(result) && result.length > 0) {
|
|
updateProjectRows(result, row.Id);
|
|
updateTotalRows(result);
|
|
refreshResourceStyles(result);
|
|
dataChanged();
|
|
return false;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
$scope.checkResourceActualsValue = function (row, $index, $data) {
|
|
if (!row || !row.ExpenditureCategory || !row.ExpenditureCategory.Id || !$scope.Filter.EntityId) {
|
|
return;
|
|
}
|
|
|
|
var resourceId = $scope.Filter.EntityId;
|
|
var filter = $scope.Filter,
|
|
header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
var result = activityCalendarUIService.checkResourceValue(filter, header, row.Id, { Id: row.ExpenditureCategory.Id }, resourceId, row, isUOMHours, isAvgMode, $index, $data, true);
|
|
if (typeof result === 'object' && angular.isArray(result) && result.length > 0) {
|
|
updateActualTotalRow(result);
|
|
dataChanged();
|
|
return false;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
$scope.checkResourceActualsGrandTotalValue = function (row, $data) {
|
|
if (!row || !row.ExpenditureCategory || !row.ExpenditureCategory.Id || !row.ActiveScenario || !$scope.Filter.EntityId) {
|
|
return;
|
|
}
|
|
|
|
var resourceId = $scope.Filter.EntityId;
|
|
var filter = $scope.Filter,
|
|
header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
var result = activityCalendarUIService.checkResourceGrandTotalValue(filter, header, row.Id, row.ActiveScenario.StartDate, row.ActiveScenario.EndDate, { Id: row.ExpenditureCategory.Id }, resourceId, row, isUOMHours, isAvgMode, $data, true);
|
|
if (typeof result === 'object' && angular.isArray(result) && result.length > 0) {
|
|
updateActualTotalRow(result);
|
|
dataChanged();
|
|
return false;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
$scope.checkNptResourceValue = function (nptCatRow, nptItemRow, $index, $data) {
|
|
if (!nptCatRow || !nptItemRow || nptItemRow.IsTeamWide || !nptItemRow.Children || !nptItemRow.Children.length)
|
|
return;
|
|
|
|
var nptResourceRow = nptItemRow.Children[0];
|
|
|
|
var filter = $scope.Filter,
|
|
header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode(),
|
|
nptTotalRow = $scope.ViewModel.NonProjectTimeTotalRow;
|
|
|
|
var rollupRows = [];
|
|
rollupRows.push(nptTotalRow);
|
|
rollupRows.push(nptCatRow);
|
|
rollupRows.push(nptItemRow);
|
|
rollupRows.push($scope.ViewModel.TotalRow);
|
|
|
|
var result = activityCalendarUIService.checkNptResourceValue(filter, header, $scope.ViewModel.RemainingCapacityRow,
|
|
rollupRows, nptCatRow, nptItemRow, nptResourceRow, isUOMHours, isAvgMode, $index, $data);
|
|
|
|
// if result is not false it is incorrect one and we do not need to recalculate availability in this case
|
|
if (typeof result === 'object' && angular.isArray(result) && result.length > 0) {
|
|
dataChanged();
|
|
return false;
|
|
}
|
|
|
|
return result;
|
|
};
|
|
$scope.watchKeyInput = function (t) {
|
|
activityCalendarUIService.watchKeyInput(t);
|
|
};
|
|
$scope.onTxtBlur = function (t) {
|
|
activityCalendarUIService.onTxtBlur(t);
|
|
};
|
|
|
|
/* Event handlers */
|
|
function rebuildCalendarHandler(event, filter, displayMode, forceDataReload, successCallback) {
|
|
// if filter is changed we need to invalidate cache
|
|
if ($scope.Filter && !activityCalendarService.cacheKeysEqual($scope.Filter, filter)) {
|
|
activityCalendarService.invalidateCache($scope.Filter);
|
|
}
|
|
|
|
$scope.ViewModel.DataLoaded = false;
|
|
$scope.ViewModel.DisplayMode = angular.copy(displayMode || {});
|
|
$scope.Filter = angular.copy(filter || {});
|
|
|
|
blockUI();
|
|
|
|
hoursResourcesConverter.load(forceDataReload).then(function () {
|
|
var loadCalendarTask = activityCalendarService.getActivityCalendar(calendarDataUrl, filter, forceDataReload);
|
|
var nptCategoriesTask = dataSources.getNonProjectTimeCategories();
|
|
var rdRightsTask = activityCalendarService.getResourceDetailsRights();
|
|
var resourceLoadTask = dataSources.loadResourcesByResourceIds([filter.EntityId]);
|
|
var cachedTemplates = activityCalendarUIService.cacheTemplates();
|
|
var dateRangeTask = dataSources.loadAvailableDateRange();
|
|
var allTasks = [loadCalendarTask, nptCategoriesTask, rdRightsTask, resourceLoadTask, dateRangeTask].concat(cachedTemplates);
|
|
|
|
$q.all(allTasks)
|
|
.then(function (asyncResults) {
|
|
var calendar = asyncResults[0]; // get calendar from loadCalendarTask
|
|
var rdRights = asyncResults[2]; // get resource details rights from rdRightsTask
|
|
nonProjectTimeCategoryCache = asyncResults[1]; // get npt categories from nptCategoriesTask
|
|
|
|
createViewModel4Visibility(rdRights);
|
|
createViewModel(calendar);
|
|
fillViewModelWithData(calendar);
|
|
toggleParts();
|
|
toggleHoursResourcesMode();
|
|
toggleSortBy();
|
|
toggleSecurityMode();
|
|
toggleBarsValuesMode();
|
|
toggleMonths();
|
|
|
|
unblockUI();
|
|
|
|
if (typeof successCallback === 'function') {
|
|
successCallback();
|
|
}
|
|
|
|
if (angular.isObject(calendar))
|
|
$scope.ViewModel.DataLoaded = true;
|
|
})
|
|
.then(null, function () {
|
|
unblockUI();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
});
|
|
}).then(null, function () {
|
|
unblockUI();
|
|
showErrorModal('Oops!', commonErrorMessage);
|
|
});
|
|
};
|
|
function optionsChangedHandler(event, displayMode, key, newValue) {
|
|
$scope.ViewModel.DisplayMode = displayMode || {};
|
|
switch (key) {
|
|
case 'uomMode':
|
|
toggleHoursResourcesMode();
|
|
$scope.$broadcast('changeUOMMode', newValue);
|
|
break;
|
|
case 'capBarMode':
|
|
toggleBarsValuesMode();
|
|
break;
|
|
case 'defaultView':
|
|
toggleMonths();
|
|
break;
|
|
case 'sortBy':
|
|
case 'sortOrder':
|
|
toggleSortBy();
|
|
break;
|
|
case 'showParts':
|
|
toggleParts();
|
|
toggleSortBy();
|
|
toggleHoursResourcesMode();
|
|
break;
|
|
case 'capacityView':
|
|
toggleCapacityType();
|
|
$scope.$broadcast('capacityViewChanged', newValue);
|
|
break;
|
|
default:
|
|
break;
|
|
};
|
|
};
|
|
function dataChanged() {
|
|
$scope.$emit('ac.calendarDataChanged');
|
|
};
|
|
|
|
/* Methods for creating view models */
|
|
function createViewModel4Visibility(rdRights) {
|
|
if (!rdRights || !Object.keys(rdRights).length) {
|
|
return;
|
|
}
|
|
|
|
$scope.ViewModel.Visibility.ShowForecast = (rdRights.Read === true || rdRights.Write === true) &&
|
|
(rdRights.ForecastRead === true || rdRights.ForecastWrite === true);
|
|
|
|
$scope.ViewModel.Visibility.ShowActuals = (rdRights.Read === true || rdRights.Write === true) &&
|
|
(rdRights.ActualsRead === true || rdRights.ActualsWrite === true);
|
|
|
|
$scope.ViewModel.Visibility.ForecastEditable = (rdRights.Write === true && rdRights.ForecastWrite === true);
|
|
$scope.ViewModel.Visibility.ActualsEditable = (rdRights.Write === true && rdRights.ActualsWrite === true);
|
|
};
|
|
function createViewModel(model) {
|
|
var startDate = new Date().getTime();
|
|
|
|
createHeaderViewModel(model.WeekEndings);
|
|
createRowsViewModel(model);
|
|
|
|
var endDate = new Date().getTime();
|
|
console.log('creating view model: ' + (endDate - startDate) + ' ms');
|
|
};
|
|
function createHeaderViewModel(weekEndings) {
|
|
$scope.ViewModel.Header = (new GridHeader(weekEndings || {}).create());
|
|
};
|
|
function createRowsViewModel(model) {
|
|
if (!model || !model.Projects)
|
|
return;
|
|
|
|
$scope.ViewModel.Rows = [];
|
|
projectsByResourceCache = activityCalendarService.getResourcesWithAssignedProjects($scope.Filter);
|
|
|
|
if (projectsByResourceCache && projectsByResourceCache[$scope.Filter.EntityId]) {
|
|
var currentResource = projectsByResourceCache[$scope.Filter.EntityId];
|
|
|
|
if (currentResource && currentResource.Projects && (Object.keys(currentResource.Projects).length > 0)) {
|
|
var sortedProjects = $filter('sortObjectsBy')(currentResource.Projects, 'Name', false);
|
|
|
|
for (var index = 0; index < sortedProjects.length; index++) {
|
|
var project = sortedProjects[index];
|
|
var projectModel = activityCalendarUIService.createViewModel4Project(project, null, $scope.Filter);
|
|
var projectEditableModel = angular.extend({}, projectModel, activityCalendarUIService.createViewModelEditableBasic());
|
|
|
|
if (projectEditableModel) {
|
|
var actualsViewModel = angular.copy(projectEditableModel);
|
|
|
|
projectEditableModel.IsMultipleECs = project.IsMultipleECs;
|
|
projectEditableModel.ExpenditureCategoryId = project.ExpenditureCategoryId;
|
|
projectEditableModel.Teams = [];
|
|
projectEditableModel.Children = [];
|
|
|
|
// Set custom row teamplates
|
|
projectEditableModel.Templates.Main = activityCalendarUIService.viewRowTemplates.projectRcRowTemplate;
|
|
projectEditableModel.Templates.Numbers = activityCalendarUIService.viewRowTemplates.projectRcRowNumbersTemplate;
|
|
$scope.ViewModel.Rows.push(projectEditableModel);
|
|
|
|
if ($scope.ViewModel.Visibility.ShowActuals) {
|
|
if (!$scope.ViewModel.Visibility.ShowForecast) {
|
|
var projectFullName = actualsViewModel.Name;
|
|
|
|
if ((actualsViewModel.ParentProjectId != actualsViewModel.Id) && (actualsViewModel.ParentName)) {
|
|
// Name for part in project with parts
|
|
projectFullName = actualsViewModel.PartName + ": " + actualsViewModel.ParentName;
|
|
}
|
|
|
|
actualsViewModel.Name = 'Actual ' + projectFullName;
|
|
actualsViewModel.Initialized = true;
|
|
actualsViewModel.Show = true;
|
|
}
|
|
else {
|
|
actualsViewModel.Name = 'Actual';
|
|
}
|
|
actualsViewModel.RowType = 'ProjectResourceActuals',
|
|
actualsViewModel.IsMultipleECs = false;
|
|
actualsViewModel.Teams = [];
|
|
actualsViewModel.ExpenditureCategory = {
|
|
Id: currentResource.OwnExpenditureCategoryId
|
|
};
|
|
|
|
// Set custom row teamplates
|
|
actualsViewModel.Templates.Main = activityCalendarUIService.viewRowTemplates.projectActualsRowTemplate;
|
|
actualsViewModel.Templates.Numbers = activityCalendarUIService.viewRowTemplates.projectActualsRowNumbersTemplate;
|
|
projectEditableModel.Children.push(actualsViewModel);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create non-project time rows
|
|
nonProjectTimeCache = activityCalendarUIService.getNonProjectTimeDataModel(nonProjectTimeCategoryCache, $scope.DisplayMode.GroupBy.Value);
|
|
createNonProjectTimeRowModels();
|
|
|
|
// Create total rows
|
|
createTotalRowModels();
|
|
};
|
|
function createNonProjectTimeRowModels() {
|
|
$scope.ViewModel.NonProjectTimeTotalRow = activityCalendarUIService.createViewModel4NptTotalRow('Non-Project Time', nonProjectTimeCache[$scope.Filter.EntityId]);
|
|
};
|
|
function createTotalRowModels() {
|
|
$scope.ViewModel.RemainingCapacityRow = activityCalendarUIService.createViewModel4TotalRow('Remaining Capacity');
|
|
$scope.ViewModel.CurrentlyAssignedRow = activityCalendarUIService.createViewModel4TotalRow('Currently Assigned');
|
|
|
|
$scope.ViewModel.TotalRow = activityCalendarUIService.createViewModel4TotalRow('Total');
|
|
$scope.ViewModel.TotalRow.Collapsed = true;
|
|
|
|
if ($scope.ViewModel.Visibility.ShowActuals && $scope.ViewModel.Rows && ($scope.ViewModel.Rows.length > 0)) {
|
|
var actualsTotalRow = activityCalendarUIService.createViewModel4TotalRow('Actual');
|
|
if (!$scope.ViewModel.Visibility.ShowForecast) {
|
|
actualsTotalRow.Name += ' Total';
|
|
actualsTotalRow.Initialized = true;
|
|
actualsTotalRow.Show = true;
|
|
}
|
|
$scope.ViewModel.TotalRow.Children = [actualsTotalRow];
|
|
}
|
|
};
|
|
function getTotalRows() {
|
|
var rows = [];
|
|
|
|
if ($scope.ViewModel.NonProjectTimeTotalRow) {
|
|
rows.push($scope.ViewModel.NonProjectTimeTotalRow);
|
|
}
|
|
if ($scope.ViewModel.CurrentlyAssignedRow) {
|
|
rows.push($scope.ViewModel.CurrentlyAssignedRow);
|
|
}
|
|
if ($scope.ViewModel.TotalRow) {
|
|
rows.push($scope.ViewModel.TotalRow);
|
|
|
|
if ($scope.ViewModel.TotalRow.Children && $scope.ViewModel.TotalRow.Children.length) {
|
|
// Actual child row for Total row
|
|
rows.push($scope.ViewModel.TotalRow.Children[0]);
|
|
}
|
|
}
|
|
if ($scope.ViewModel.RemainingCapacityRow) {
|
|
rows.push($scope.ViewModel.RemainingCapacityRow);
|
|
}
|
|
return rows;
|
|
};
|
|
|
|
/* Root methods for creating view models and filling them with data */
|
|
function fillViewModelWithData(model) {
|
|
var startDate = new Date().getTime();
|
|
|
|
if ($scope.ViewModel.Rows && projectsByResourceCache && (Object.keys(projectsByResourceCache).length > 0)) {
|
|
var resourceData = projectsByResourceCache[$scope.Filter.EntityId];
|
|
if (!resourceData)
|
|
return;
|
|
|
|
for (var i = 0; i < $scope.ViewModel.Rows.length; i++) {
|
|
var projectRow = $scope.ViewModel.Rows[i];
|
|
var projectData = resourceData.Projects[projectRow.Id];
|
|
var expenditureCategoryId = (!projectRow.IsMultipleECs && projectRow.ExpenditureCategoryId && projectRow.ExpenditureCategoryId.length) ? projectRow.ExpenditureCategoryId[0] : resourceData.OwnExpenditureCategoryId;
|
|
|
|
activityCalendarUIService.fillResourceRowWithData($scope.ViewModel.Header, null, expenditureCategoryId, $scope.Filter.EntityId, projectRow,
|
|
projectData, null, projectRow.ActiveScenario.StartDate, projectRow.ActiveScenario.EndDate, true, projectRow.DisableResourceEdit);
|
|
|
|
if (projectRow.Children && (projectRow.Children.length == 1)) {
|
|
// Fill Resource actuals row
|
|
var actualsRow = projectRow.Children[0];
|
|
activityCalendarUIService.fillResourceActualsRowWithData($scope.ViewModel.Header, actualsRow, projectData,
|
|
projectRow.ActiveScenario.StartDate, projectRow.ActiveScenario.EndDate, projectRow.DisableResourceEdit);
|
|
}
|
|
}
|
|
}
|
|
projectsByResourceCache = {};
|
|
|
|
// Fill NPT-rows with data and clear NPT caches. Caches not need more
|
|
fillNonProjectTimeRowsWithData();
|
|
nonProjectTimeCache = {};
|
|
nonProjectTimeCategoryCache = {};
|
|
|
|
// Fill total rows with data
|
|
fillTotalRowsWithData();
|
|
|
|
var endDate = new Date().getTime();
|
|
console.log('filling model with data: ' + (endDate - startDate) + ' ms');
|
|
};
|
|
function fillNonProjectTimeRowsWithData() {
|
|
activityCalendarUIService.fillTotalNptRowData($scope.ViewModel.NonProjectTimeTotalRow, nonProjectTimeCache[$scope.Filter.EntityId], $scope.ViewModel.Header);
|
|
};
|
|
function fillCurrentlyAssignedRowWithData() {
|
|
var rowsForCurrentlyAssigned = angular.copy($scope.ViewModel.Rows) || [];
|
|
activityCalendarUIService.fillTotalRowData(rowsForCurrentlyAssigned, $scope.ViewModel.CurrentlyAssignedRow, $scope.ViewModel.Header);
|
|
};
|
|
function fillActualTotalRowWithData() {
|
|
if (!$scope.ViewModel.TotalRow || !$scope.ViewModel.TotalRow.Children || !$scope.ViewModel.TotalRow.Children.length)
|
|
return;
|
|
|
|
var actualTotalRow = $scope.ViewModel.TotalRow.Children[0];
|
|
var projectRows = angular.copy($scope.ViewModel.Rows) || [];
|
|
var actualProjectRows = [];
|
|
|
|
for (var index = 0; index < projectRows.length; index++) {
|
|
var projectRow = projectRows[index];
|
|
if (projectRow.Children && projectRow.Children.length && (projectRow.Children[0].RowType == 'ProjectResourceActuals')) {
|
|
actualProjectRows.push(angular.copy(projectRow.Children[0]));
|
|
}
|
|
}
|
|
|
|
activityCalendarUIService.fillTotalRowData(actualProjectRows, actualTotalRow, $scope.ViewModel.Header);
|
|
};
|
|
function fillTotalRowsWithData() {
|
|
var startDate = new Date().getTime();
|
|
|
|
// Fill Currently Assigned row
|
|
fillCurrentlyAssignedRowWithData();
|
|
|
|
// Fill Total row (as CurrentlyAssigned + NPT)
|
|
var rowsForTotal = angular.copy($scope.ViewModel.Rows) || [];
|
|
rowsForTotal.push(angular.copy($scope.ViewModel.NonProjectTimeTotalRow));
|
|
|
|
activityCalendarUIService.fillTotalRowData(rowsForTotal, $scope.ViewModel.TotalRow, $scope.ViewModel.Header);
|
|
activityCalendarUIService.fillResourceRemainingCapacityRowData($scope.ViewModel.TotalRow,
|
|
$scope.ViewModel.RemainingCapacityRow, $scope.Filter.EntityId, $scope.ViewModel.Header);
|
|
|
|
// Fill Actual total row - a child row for Total
|
|
fillActualTotalRowWithData();
|
|
|
|
var endDate = new Date().getTime();
|
|
console.log('filling total rows with data: ' + (endDate - startDate) + ' ms');
|
|
};
|
|
|
|
/* Methods for toggling display modes */
|
|
function toggleHoursResourcesMode() {
|
|
var totalRows = getTotalRows();
|
|
activityCalendarUIService.toggleGridSource($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.IsUOMHours);
|
|
activityCalendarUIService.toggleGridSource(totalRows, $scope.ViewModel.DisplayMode.IsUOMHours);
|
|
if ($scope.ViewModel.DisplayMode.IsAvgMode()) {
|
|
activityCalendarUIService.applyAvgMode($scope.ViewModel.Rows, $scope.ViewModel.Header);
|
|
activityCalendarUIService.applyAvgMode(totalRows, $scope.ViewModel.Header);
|
|
}
|
|
};
|
|
function toggleBarsValuesMode() {
|
|
if (!$scope.ViewModel.Rows || !$scope.ViewModel.Rows.length) {
|
|
return;
|
|
}
|
|
|
|
activityCalendarUIService.toggleBarsValuesMode($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.IsBarMode);
|
|
for (var i = 0; i < $scope.ViewModel.Rows.length; i++) {
|
|
activityCalendarUIService.toggleBarsValuesMode($scope.ViewModel.Rows[i].Children, $scope.ViewModel.DisplayMode.IsBarMode);
|
|
}
|
|
};
|
|
function toggleMonths() {
|
|
if ($scope.ViewModel.DisplayMode.IsViewModeMonth) {
|
|
$scope.ViewModel.Header.collapseMonthes();
|
|
}
|
|
else {
|
|
$scope.ViewModel.Header.expandMonthes();
|
|
}
|
|
};
|
|
function toggleParts() {
|
|
if (!$scope.ViewModel.Visibility.ShowForecast)
|
|
return;
|
|
|
|
$scope.ViewModel.Rows = activityCalendarUIService.toggleParts($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.ShowParts.Value);
|
|
};
|
|
function toggleSortBy() {
|
|
$scope.ViewModel.Rows = activityCalendarUIService.toggleSortBy($scope.ViewModel.Rows, $scope.ViewModel.DisplayMode.SortBy, $scope.ViewModel.DisplayMode.SortOrder);
|
|
};
|
|
function toggleCapacityType() {
|
|
// reset total row values
|
|
createTotalRowModels();
|
|
// recalculate total row UI data
|
|
fillTotalRowsWithData();
|
|
toggleHoursResourcesMode();
|
|
};
|
|
function toggleSecurityMode() {
|
|
if (!$scope.ViewModel.Rows || !$scope.ViewModel.Rows.length)
|
|
return;
|
|
|
|
if (!$scope.ViewModel.Visibility.ShowForecast && !$scope.ViewModel.Visibility.ShowActuals) {
|
|
$scope.ViewModel.Rows = [];
|
|
return;
|
|
}
|
|
|
|
if (!$scope.ViewModel.Visibility.ShowActuals) {
|
|
for (var index = 0; index < $scope.ViewModel.Rows.length; index++) {
|
|
var projectRow = $scope.ViewModel.Rows[index];
|
|
|
|
if (projectRow) {
|
|
if (projectRow.IsMaster) {
|
|
if (projectRow.Children && angular.isArray(projectRow.Children))
|
|
for (var partIndex = 0; partIndex < projectRow.Children.length; partIndex++) {
|
|
var projectPartRow = projectRow.Children[partIndex];
|
|
projectPartRow.Children = [];
|
|
}
|
|
}
|
|
else {
|
|
projectRow.Children = [];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$scope.ViewModel.Visibility.ShowForecast) {
|
|
for (var index = $scope.ViewModel.Rows.length - 1; index >= 0; index--) {
|
|
var projectRow = $scope.ViewModel.Rows[index];
|
|
|
|
if (projectRow && projectRow.Children && projectRow.Children.length) {
|
|
$scope.ViewModel.Rows[index] = projectRow.Children[0];
|
|
}
|
|
else {
|
|
$scope.ViewModel.Rows.splice(index, 1);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function refreshResourceStyles(data) {
|
|
if (typeof data !== 'object' || !angular.isArray(data)) {
|
|
return;
|
|
}
|
|
|
|
if ($scope.ViewModel.Rows && $scope.ViewModel.Rows.length) {
|
|
// Add master project rows to the collection of top-level rows
|
|
var rows = $scope.ViewModel.Rows;
|
|
for (var index = 0; index < $scope.ViewModel.Rows.length; index++) {
|
|
var currentRow = $scope.ViewModel.Rows[index];
|
|
|
|
if (currentRow.IsMaster && currentRow.Children) {
|
|
for (var partIndex = 0; partIndex < currentRow.Children.length; partIndex++) {
|
|
rows.push(currentRow.Children[partIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
activityCalendarUIService.updateResourceStyles($scope.ViewModel.Header, $scope.Filter.EntityId, rows, data);
|
|
}
|
|
};
|
|
function updateTotalRows(data) {
|
|
if (typeof data !== 'object' || !angular.isArray(data)) {
|
|
return;
|
|
}
|
|
|
|
var header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var cell = data[i];
|
|
var month = header.Months[cell.MonthIndex];
|
|
var monthWeeksCount = month.Childs.length;
|
|
var deltaResourceValue = hoursResourcesConverter.convertToResources(cell.ExpenditureCategoryId, cell.DeltaHoursValue);
|
|
|
|
if ($scope.ViewModel.CurrentlyAssignedRow) {
|
|
$scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[cell.WeekIndex] || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[month.SelfIndexInWeeks] || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.CurrentlyAssignedRow.TotalHoursValue = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.TotalHoursValue || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[cell.WeekIndex] || 0) + (deltaResourceValue || 0));
|
|
$scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[month.SelfIndexInWeeks] || 0) + (deltaResourceValue || 0));
|
|
$scope.ViewModel.CurrentlyAssignedRow.TotalResourcesValue = roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.TotalResourcesValue || 0) + (deltaResourceValue || 0));
|
|
}
|
|
|
|
if ($scope.ViewModel.TotalRow) {
|
|
$scope.ViewModel.TotalRow.QuantityHoursValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.TotalRow.QuantityHoursValues[cell.WeekIndex] || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.TotalRow.QuantityHoursValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.TotalRow.QuantityHoursValues[month.SelfIndexInWeeks] || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.TotalRow.TotalHoursValue = roundService.roundQuantity(($scope.ViewModel.TotalRow.TotalHoursValue || 0) + (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.TotalRow.QuantityResourcesValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.TotalRow.QuantityResourcesValues[cell.WeekIndex] || 0) + (deltaResourceValue || 0));
|
|
$scope.ViewModel.TotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.TotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] || 0) + (deltaResourceValue || 0));
|
|
$scope.ViewModel.TotalRow.TotalResourcesValue = roundService.roundQuantity(($scope.ViewModel.TotalRow.TotalResourcesValue || 0) + (deltaResourceValue || 0));
|
|
}
|
|
|
|
if ($scope.ViewModel.RemainingCapacityRow) {
|
|
$scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[cell.WeekIndex] || 0) - (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[month.SelfIndexInWeeks] || 0) - (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.RemainingCapacityRow.TotalHoursValue = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.TotalHoursValue || 0) - (cell.DeltaHoursValue || 0));
|
|
$scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[cell.WeekIndex] = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[cell.WeekIndex] || 0) - (deltaResourceValue || 0));
|
|
$scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[month.SelfIndexInWeeks] = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[month.SelfIndexInWeeks] || 0) - (deltaResourceValue || 0));
|
|
$scope.ViewModel.RemainingCapacityRow.TotalResourcesValue = roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.TotalResourcesValue || 0) - (deltaResourceValue || 0));
|
|
}
|
|
|
|
if (isUOMHours) {
|
|
if ($scope.ViewModel.CurrentlyAssignedRow) {
|
|
$scope.ViewModel.CurrentlyAssignedRow.Cells[cell.WeekIndex] = $scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[cell.WeekIndex];
|
|
$scope.ViewModel.CurrentlyAssignedRow.Cells[month.SelfIndexInWeeks] = $scope.ViewModel.CurrentlyAssignedRow.QuantityHoursValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.CurrentlyAssignedRow.TotalValue = $scope.ViewModel.CurrentlyAssignedRow.TotalHoursValue;
|
|
}
|
|
|
|
if ($scope.ViewModel.TotalRow) {
|
|
$scope.ViewModel.TotalRow.Cells[cell.WeekIndex] = $scope.ViewModel.TotalRow.QuantityHoursValues[cell.WeekIndex];
|
|
$scope.ViewModel.TotalRow.Cells[month.SelfIndexInWeeks] = $scope.ViewModel.TotalRow.QuantityHoursValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.TotalRow.TotalValue = $scope.ViewModel.TotalRow.TotalHoursValue;
|
|
}
|
|
|
|
if ($scope.ViewModel.RemainingCapacityRow) {
|
|
$scope.ViewModel.RemainingCapacityRow.Cells[cell.WeekIndex] = $scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[cell.WeekIndex];
|
|
$scope.ViewModel.RemainingCapacityRow.Cells[month.SelfIndexInWeeks] = $scope.ViewModel.RemainingCapacityRow.QuantityHoursValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.RemainingCapacityRow.TotalValue = $scope.ViewModel.RemainingCapacityRow.TotalHoursValue;
|
|
}
|
|
}
|
|
else {
|
|
if ($scope.ViewModel.CurrentlyAssignedRow) {
|
|
$scope.ViewModel.CurrentlyAssignedRow.Cells[cell.WeekIndex] = $scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[cell.WeekIndex];
|
|
$scope.ViewModel.CurrentlyAssignedRow.Cells[month.SelfIndexInWeeks] = isAvgMode ? roundService.roundQuantity($scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[month.SelfIndexInWeeks] / monthWeeksCount) : $scope.ViewModel.CurrentlyAssignedRow.QuantityResourcesValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.CurrentlyAssignedRow.TotalValue = isAvgMode ? roundService.roundQuantity(($scope.ViewModel.CurrentlyAssignedRow.TotalResourcesValue / header.TotalWeeks)) : $scope.ViewModel.CurrentlyAssignedRow.TotalResourcesValue;
|
|
}
|
|
|
|
if ($scope.ViewModel.TotalRow) {
|
|
$scope.ViewModel.TotalRow.Cells[cell.WeekIndex] = $scope.ViewModel.TotalRow.QuantityResourcesValues[cell.WeekIndex];
|
|
$scope.ViewModel.TotalRow.Cells[month.SelfIndexInWeeks] = isAvgMode ? roundService.roundQuantity($scope.ViewModel.TotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] / monthWeeksCount) : $scope.ViewModel.TotalRow.QuantityResourcesValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.TotalRow.TotalValue = isAvgMode ? roundService.roundQuantity(($scope.ViewModel.TotalRow.TotalResourcesValue / header.TotalWeeks)) : $scope.ViewModel.TotalRow.TotalResourcesValue;
|
|
}
|
|
|
|
if ($scope.ViewModel.RemainingCapacityRow) {
|
|
$scope.ViewModel.RemainingCapacityRow.Cells[cell.WeekIndex] = $scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[cell.WeekIndex];
|
|
$scope.ViewModel.RemainingCapacityRow.Cells[month.SelfIndexInWeeks] = isAvgMode ? roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[month.SelfIndexInWeeks] / monthWeeksCount)) : $scope.ViewModel.RemainingCapacityRow.QuantityResourcesValues[month.SelfIndexInWeeks];
|
|
$scope.ViewModel.RemainingCapacityRow.TotalValue = isAvgMode ? roundService.roundQuantity(($scope.ViewModel.RemainingCapacityRow.TotalResourcesValue / header.TotalWeeks)) : $scope.ViewModel.RemainingCapacityRow.TotalResourcesValue;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function updateActualTotalRow(data) {
|
|
if (typeof data !== 'object' || !angular.isArray(data)) {
|
|
return;
|
|
}
|
|
|
|
var header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
|
|
var actualTotalRow = null;
|
|
if ($scope.ViewModel.TotalRow && $scope.ViewModel.TotalRow.Children && $scope.ViewModel.TotalRow.Children.length) {
|
|
actualTotalRow = $scope.ViewModel.TotalRow.Children[0];
|
|
}
|
|
|
|
if (!actualTotalRow)
|
|
return;
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var cell = data[i];
|
|
var month = header.Months[cell.MonthIndex];
|
|
var monthWeeksCount = month.Childs.length;
|
|
var deltaResourceValue = hoursResourcesConverter.convertToResources(cell.ExpenditureCategoryId, cell.DeltaHoursValue);
|
|
|
|
actualTotalRow.QuantityHoursValues[cell.WeekIndex] = roundService.roundQuantity((actualTotalRow.QuantityHoursValues[cell.WeekIndex] || 0) + (cell.DeltaHoursValue || 0));
|
|
actualTotalRow.QuantityHoursValues[month.SelfIndexInWeeks] = roundService.roundQuantity((actualTotalRow.QuantityHoursValues[month.SelfIndexInWeeks] || 0) + (cell.DeltaHoursValue || 0));
|
|
actualTotalRow.TotalHoursValue = roundService.roundQuantity((actualTotalRow.TotalHoursValue || 0) + (cell.DeltaHoursValue || 0));
|
|
actualTotalRow.QuantityResourcesValues[cell.WeekIndex] = roundService.roundQuantity((actualTotalRow.QuantityResourcesValues[cell.WeekIndex] || 0) + (deltaResourceValue || 0));
|
|
actualTotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] = roundService.roundQuantity((actualTotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] || 0) + (deltaResourceValue || 0));
|
|
actualTotalRow.TotalResourcesValue = roundService.roundQuantity((actualTotalRow.TotalResourcesValue || 0) + (deltaResourceValue || 0));
|
|
|
|
if (isUOMHours) {
|
|
actualTotalRow.Cells[cell.WeekIndex] = actualTotalRow.QuantityHoursValues[cell.WeekIndex];
|
|
actualTotalRow.Cells[month.SelfIndexInWeeks] = actualTotalRow.QuantityHoursValues[month.SelfIndexInWeeks];
|
|
actualTotalRow.TotalValue = actualTotalRow.TotalHoursValue;
|
|
}
|
|
else {
|
|
actualTotalRow.Cells[cell.WeekIndex] = actualTotalRow.QuantityResourcesValues[cell.WeekIndex];
|
|
actualTotalRow.Cells[month.SelfIndexInWeeks] = isAvgMode ? roundService.roundQuantity(actualTotalRow.QuantityResourcesValues[month.SelfIndexInWeeks] / monthWeeksCount) : actualTotalRow.QuantityResourcesValues[month.SelfIndexInWeeks];
|
|
actualTotalRow.TotalValue = isAvgMode ? roundService.roundQuantity(actualTotalRow.TotalResourcesValue / header.TotalWeeks) : actualTotalRow.TotalResourcesValue;
|
|
}
|
|
}
|
|
};
|
|
function updateProjectRows(data, projectId) {
|
|
if (!projectId || (typeof data !== 'object') || !angular.isArray(data)) {
|
|
return;
|
|
}
|
|
|
|
var projectRows = activityCalendarUIService.getProjectRows($scope.ViewModel.Rows, projectId);
|
|
if (!projectRows || !projectRows.masterProjectRow)
|
|
return;
|
|
|
|
var header = $scope.ViewModel.Header,
|
|
isUOMHours = $scope.ViewModel.DisplayMode.IsUOMHours,
|
|
isAvgMode = $scope.ViewModel.DisplayMode.IsAvgMode();
|
|
var row = projectRows.masterProjectRow;
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
var cell = data[i];
|
|
var month = header.Months[cell.MonthIndex];
|
|
var monthWeeksCount = month.Childs.length;
|
|
var deltaResourceValue = hoursResourcesConverter.convertToResources(cell.ExpenditureCategoryId, cell.DeltaHoursValue);
|
|
|
|
row.QuantityHoursValues[cell.WeekIndex] = roundService.roundQuantity((row.QuantityHoursValues[cell.WeekIndex] || 0) + (cell.DeltaHoursValue || 0));
|
|
row.QuantityHoursValues[month.SelfIndexInWeeks] = roundService.roundQuantity((row.QuantityHoursValues[month.SelfIndexInWeeks] || 0) + (cell.DeltaHoursValue || 0));
|
|
row.TotalHoursValue = roundService.roundQuantity((row.TotalHoursValue || 0) + (cell.DeltaHoursValue || 0));
|
|
row.QuantityResourcesValues[cell.WeekIndex] = roundService.roundQuantity((row.QuantityResourcesValues[cell.WeekIndex] || 0) + (deltaResourceValue || 0));
|
|
row.QuantityResourcesValues[month.SelfIndexInWeeks] = roundService.roundQuantity((row.QuantityResourcesValues[month.SelfIndexInWeeks] || 0) + (deltaResourceValue || 0));
|
|
row.TotalResourcesValue = roundService.roundQuantity((row.TotalResourcesValue || 0) + (deltaResourceValue || 0));
|
|
|
|
if (isUOMHours) {
|
|
row.Cells[cell.WeekIndex] = row.QuantityHoursValues[cell.WeekIndex];
|
|
row.Cells[month.SelfIndexInWeeks] = row.QuantityHoursValues[month.SelfIndexInWeeks];
|
|
row.TotalValue = row.TotalHoursValue;
|
|
}
|
|
else {
|
|
row.Cells[cell.WeekIndex] = row.QuantityResourcesValues[cell.WeekIndex];
|
|
row.Cells[month.SelfIndexInWeeks] = isAvgMode ? roundService.roundQuantity(row.QuantityResourcesValues[month.SelfIndexInWeeks] / monthWeeksCount) : row.QuantityResourcesValues[month.SelfIndexInWeeks];
|
|
row.TotalValue = isAvgMode ? roundService.roundQuantity(row.TotalResourcesValue / header.TotalWeeks) : row.TotalResourcesValue;
|
|
}
|
|
}
|
|
};
|
|
}]); |