'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; } } }; }]);