3758 lines
175 KiB
JavaScript
3758 lines
175 KiB
JavaScript
'use strict';
|
|
|
|
/* Controllers */
|
|
|
|
var controllers = angular.module('controllers', ["xeditable"]);
|
|
|
|
controllers.directive('resizeFreez', function($timeout) {
|
|
return {
|
|
restrict: 'A',
|
|
link: function(scope, elem, attrs) {
|
|
|
|
if (scope.$last) {
|
|
$timeout(function() {
|
|
//resizeFreez();
|
|
scope.resizeFreezAng();
|
|
$("#loader").hide();
|
|
unblockUI();
|
|
}, 0);
|
|
}
|
|
}
|
|
};
|
|
});
|
|
|
|
controllers.controller('scenarioDetailsCalendarController', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
|
|
$scope.CollapsedIcon = 'fa-plus-square';
|
|
$scope.NonCollapsedIcon = 'fa-minus-square';
|
|
|
|
$scope.id = $location.absUrl().substr($location.absUrl().lastIndexOf('ls/') + 3, 36);
|
|
$scope.calendarFilters = {
|
|
CategoryType: null,
|
|
LaborMaterials: null,
|
|
IncomeType: null,
|
|
GLAccount: null,
|
|
CreditDepartment: null,
|
|
SelectedExpCats: null,
|
|
IsTableModeQuantity: true,
|
|
IsViewModeMonth: true,
|
|
IsUOMHours: null,
|
|
ScenarioId: $scope.id
|
|
};
|
|
$scope.typeOptions = [
|
|
{ name: 'Quantity', value: 'Quantity' },
|
|
{ name: 'Cost', value: 'Cost' }
|
|
];
|
|
$scope.reallocator = {
|
|
SourceExpCat: null,
|
|
TargetExpCat: null,
|
|
SourceWeekEnding: null,
|
|
TargetWeekEnding: null,
|
|
Percentage: 100,
|
|
ReallocateBy: $scope.typeOptions[0].value,
|
|
CurveType: 'source',
|
|
OtherCurve: null,
|
|
};
|
|
$scope.pushpuller = {
|
|
weeks: 1,
|
|
push: true,
|
|
resource: null,
|
|
startdate: null
|
|
};
|
|
|
|
$scope.quickPushPull = function (push, weeks) {
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].Checked)
|
|
$scope.pushPullExpCat($scope.data.ScenarioCalendar[i], i, weeks, push);
|
|
}
|
|
};
|
|
|
|
$scope.editTotal = {
|
|
ExpCat: null,
|
|
SeatsCost: $scope.typeOptions[0].value,
|
|
CurrentTotal: null,
|
|
NewTotal: null,
|
|
Curve: 'source',
|
|
OtherCurve: null,
|
|
};
|
|
|
|
$scope.formatCells = {
|
|
ExpCats: [],
|
|
SelectedExpCats: null,
|
|
StartDate: null,
|
|
EndDate: null,
|
|
DecimalPlaces: 2,
|
|
DecimalCalcCostPlaces: 4,
|
|
DecimalCalcQtyPlaces: 6
|
|
};
|
|
|
|
$scope.categoryTypes = [];
|
|
$http.get('/Utils/GetExpentitureCategoryTypes').success(function(data) {
|
|
$scope.categoryTypes = data;
|
|
}).error(function(data, status, headers, config) {
|
|
console.log("an error occurred while loading category types");
|
|
});
|
|
$scope.CGEFX = [];
|
|
$http.get('/Utils/GetCGEFX').success(function (data) {
|
|
$scope.CGEFX = data;
|
|
});
|
|
$scope.incomeTypes = [];
|
|
$http.get('/Utils/GetIncomeTypes').success(function (data) {
|
|
$scope.incomeTypes = data;
|
|
});
|
|
$scope.glAccounts = [];
|
|
$http.get('/Utils/GetGLAccounts').success(function (data) {
|
|
$scope.glAccounts = data;
|
|
});
|
|
$scope.creditDepartments = [];
|
|
$http.get('/Utils/GetCreditDepartments').success(function (data) {
|
|
$scope.creditDepartments = data;
|
|
});
|
|
$scope.availableExpenditures = [];
|
|
$http.get('/Scenarios/GetScenarioAvailableExpCategories?id=' + $scope.id).success(function (data) {
|
|
$scope.availableExpenditures = data;
|
|
if ($scope.availableExpenditures != null && $scope.availableExpenditures.length > 0) {
|
|
$scope.reallocator.SourceExpCat = $scope.availableExpenditures[0].Id;
|
|
$scope.reallocator.TargetExpCat = $scope.availableExpenditures.length > 1 ? $scope.availableExpenditures[1].Id : null;
|
|
$scope.reallocator.OtherCurve = $scope.availableExpenditures[0].Id;
|
|
$scope.editTotal = {
|
|
ExpCat: $scope.availableExpenditures[0].Id,
|
|
OtherCurve: $scope.availableExpenditures[0].Id,
|
|
SeatsCost: $scope.typeOptions[0].value,
|
|
Curve: 'source'
|
|
};
|
|
}
|
|
});
|
|
$scope.rates = [];
|
|
$http.post('/Scenarios/GetRates', { scenarioId: $scope.id, uomMode: $scope.calendarFilters.IsUOMHours }).success(function (responseData) {
|
|
$scope.rates = responseData;
|
|
}).error(function (data, status, headers, config) {
|
|
console.log("an error occurred while loading rates");
|
|
});
|
|
$scope.data = null;
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
|
|
function getExpCatById(ExpCatId)
|
|
{
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId == ExpCatId) {
|
|
return $scope.data.ScenarioCalendar[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
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 clearResource(expCat, resource) {
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
|
|
var scenarioCalendarRow = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCat.ExpCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
expCat.RestQuantity[i] += resource.QuantityValues[i];
|
|
resource.QuantityValues[i] = 0;
|
|
|
|
applyCellChange(expCat.ExpCatId, $scope.data.Headers[i].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[i],
|
|
resource.QuantityValues[i], 0, resource.Id, false, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateTotals(resource, colIndex, newQuantity, oldQuantity, newCost, oldCost) {
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
//update month cell
|
|
resource.QuantityValues[i] += (newQuantity - oldQuantity);
|
|
resource.GrandTotalQuantity[i] += (newQuantity - oldQuantity);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function allocateResource(resource, expCat, create, allocateRest, reset)
|
|
{
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
resource.GrandTotalCost = 0;
|
|
|
|
var scenarioCalendarRow = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCat.ExpCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
var quantity = create || reset ? 0 : allocateRest ? resource.QuantityValues[i] + expCat.RestQuantity[i] : expCat.QuantityValues[i];
|
|
if (create)
|
|
resource.QuantityValues[i] = 0;
|
|
|
|
expCat.RestQuantity[i] -= quantity - resource.QuantityValues[i];
|
|
updateTotals(resource, i, quantity, resource.QuantityValues[i], 0, 0);
|
|
resource.QuantityValues[i] = quantity;
|
|
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
resource.GrandTotalQuantity += quantity;
|
|
|
|
applyCellChange(expCat.ExpCatId, $scope.data.Headers[i].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[i],
|
|
resource.QuantityValues[i], resource.CostValues[i], resource.Id, create, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$scope.getCalendar = function () {
|
|
if (changesMade)
|
|
if (!confirm("Changes have been made. Reloading will cause unsaved data loss.")) {
|
|
return;
|
|
}
|
|
blockUI();
|
|
$scope.data = null;
|
|
var postData = JSON.parse(JSON.stringify($scope.calendarFilters));
|
|
$http.post('/Scenarios/LoadJsonScenarioCalendar', postData).
|
|
success(function (data, status, headers, config) {
|
|
if (data.Headers.length < 1) {
|
|
unblockUI();
|
|
return;
|
|
}
|
|
$scope.data = data;
|
|
$scope.calendarFilters.IsUOMHours = data.IsUOMHours;
|
|
$scope.switchViewMode($scope.calendarFilters.IsViewModeMonth);
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
var dec = Math.pow(10, parseInt ($scope.formatCells.DecimalPlaces));
|
|
$scope.reallocator.SourceWeekEnding = $scope.data.Headers[0].Title;
|
|
$scope.reallocator.TargetWeekEnding = $scope.data.Headers[$scope.data.Headers.length - 2].Title;
|
|
$scope.editTotal.CurrentTotal = Math.round($scope.data.ScenarioCalendar[1].GrandTotalQuantity * dec) / dec;
|
|
|
|
var dt = new Date($scope.data.Headers[0].Milliseconds);
|
|
$scope.formatCells.StartDate = (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
|
|
if ($scope.data.Headers.length > 3)
|
|
dt = new Date($scope.data.Headers[$scope.data.Headers.length - 2].Milliseconds);
|
|
else
|
|
dt = new Date($scope.data.Headers[$scope.data.Headers.length - 2].Milliseconds);
|
|
$scope.formatCells.EndDate = (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
|
|
|
|
$scope.getResourceData();
|
|
$scope.prefillAllocateResource();
|
|
$scope.checkedExpenditures = [];
|
|
applyChecked();
|
|
$('#btnSaveChanges').attr('disabled', true);
|
|
unblockUI();
|
|
}).
|
|
error(function(data, status, headers, config) {
|
|
// called asynchronously if an error occurs
|
|
// or server returns response with an error status.
|
|
console.log("an error occurred while loading calendar");
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.getRates = function() {
|
|
$http.post('/Scenarios/GetRates', { scenarioId: $scope.id, uomMode: $scope.calendarFilters.IsUOMHours }).success(function (data) {
|
|
$scope.rates = data;
|
|
}).error(function (data, status, headers, config) {
|
|
console.log("an error occurred while loading rates");
|
|
});
|
|
};
|
|
$scope.onPercentageChange = function(val) {
|
|
$scope.reallocator.Percentage = val;
|
|
};
|
|
$scope.checkEditable = function(useType) {
|
|
if (3 === useType) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
$scope.checkValue = function (data, rowId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
var isMonth = $scope.data.Headers[colIndex].IsMonth;
|
|
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === rowId) {
|
|
if (isMonth) {
|
|
var ec = $scope.data.ScenarioCalendar[i];
|
|
var ec_val = $scope.calendarFilters.IsTableModeQuantity ? ec.QuantityValues[colIndex] : ec.CostValues[colIndex];
|
|
var weeks = 0;
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
weeks++;
|
|
}
|
|
var coef = ec_val > 0 ? newValue / ec_val : 1;
|
|
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var val = ec_val > 0 ? ($scope.calendarFilters.IsTableModeQuantity ? ec.QuantityValues[j] : ec.CostValues[j]) * coef : newValue/ weeks;
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(rowId, i, j, val, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(rowId, i, j, null, val, false);
|
|
}
|
|
}
|
|
}
|
|
//} else {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(rowId, i, colIndex, newValue, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(rowId, i, colIndex, null, newValue, false);
|
|
}
|
|
//}
|
|
break;
|
|
}
|
|
}
|
|
//required to be false by xeditable grid
|
|
return false;
|
|
};
|
|
$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();
|
|
};
|
|
function updateQuantityOrCostCell(expCatId, rowIndex, colIndex, newQuantity, newCost, isUpdateQuantity) {
|
|
/* isUpdateQuantity - indicates whether to update by quantity or by cost.
|
|
* true - Quantity will be updated from newQuantity, Cost will be recalculated as newQuantity * rate
|
|
* false - Cost will be updated from newCost, Quantity will be recalculated as newCost / rate
|
|
* null - Quantity will be updated from newQuantity, Cost will be updated from newCost
|
|
*/
|
|
onDataChanged();
|
|
var dec = Math.pow(10, true === isUpdateQuantity ? parseInt($scope.formatCells.DecimalCalcQtyPlaces) : parseInt($scope.formatCells.DecimalCalcCostPlaces));
|
|
|
|
var oldQuantity = $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex];
|
|
var oldCost = $scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex];
|
|
|
|
if (true === isUpdateQuantity) { // update quantity, recalculate cost based on exp cat rate
|
|
if (oldQuantity === newQuantity || newQuantity < 0)
|
|
return;
|
|
newCost = Math.round(newQuantity * $scope.getRate(expCatId, $scope.data.Headers[colIndex].Milliseconds) * dec) / dec;
|
|
} else if (false === isUpdateQuantity) { // update cost, recalculate quantity based on exp cat rate
|
|
if (oldCost === newCost || newCost < 0)
|
|
return;
|
|
newQuantity = Math.round(newCost / $scope.getRate(expCatId, $scope.data.Headers[colIndex].Milliseconds) * dec) / dec;
|
|
}
|
|
// update modified cell
|
|
$scope.data.ScenarioCalendar[rowIndex].RestQuantity[colIndex] += newQuantity - $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex];
|
|
$scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex] = newCost;
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex] = newQuantity;
|
|
// update row grand totals
|
|
$scope.data.ScenarioCalendar[rowIndex].GrandTotalCost = calcWithSamePresicion($scope.data.ScenarioCalendar[rowIndex].GrandTotalCost, (newCost - oldCost), true);
|
|
$scope.data.ScenarioCalendar[rowIndex].GrandTotalQuantity = calcWithSamePresicion($scope.data.ScenarioCalendar[rowIndex].GrandTotalQuantity, (newQuantity - oldQuantity), false);
|
|
// update column totals
|
|
$scope.data.ScenarioCalendar[0].CostValues[colIndex] += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[0].QuantityValues[colIndex] += (newQuantity - oldQuantity);
|
|
// update table totals
|
|
$scope.data.ScenarioCalendar[0].GrandTotalCost += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[0].GrandTotalQuantity += (newQuantity - oldQuantity);
|
|
// update month cell and month total cell
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
//update month cell
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[i] = calcWithSamePresicion($scope.data.ScenarioCalendar[rowIndex].QuantityValues[i], (newQuantity - oldQuantity), false);
|
|
$scope.data.ScenarioCalendar[rowIndex].CostValues[i] = calcWithSamePresicion($scope.data.ScenarioCalendar[rowIndex].CostValues[i], (newCost - oldCost), true);
|
|
// update month column totals
|
|
$scope.data.ScenarioCalendar[0].CostValues[i]= calcWithSamePresicion($scope.data.ScenarioCalendar[0].CostValues[i], (newCost - oldCost), true);
|
|
$scope.data.ScenarioCalendar[0].QuantityValues[i]= calcWithSamePresicion($scope.data.ScenarioCalendar[0].QuantityValues[i], (newQuantity - oldQuantity), false);
|
|
break;
|
|
}
|
|
applyCellChange(expCatId, $scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[rowIndex].ScenarioDetailIds[colIndex],
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex], $scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex], null, false, false);
|
|
}
|
|
function applyCellChange(rowId, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved) {
|
|
var catIndex = -1;
|
|
for (var ix = 0; ix < $scope.data2Update.ChangedExpCats.length; ix++) {
|
|
if ($scope.data2Update.ChangedExpCats[ix].Id == rowId) {
|
|
catIndex = ix;
|
|
break;
|
|
}
|
|
}
|
|
if (catIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[$scope.data2Update.ChangedExpCats.length] = {
|
|
Id: rowId,
|
|
Values: [],
|
|
Resources: []
|
|
};
|
|
catIndex = $scope.data2Update.ChangedExpCats.length - 1;
|
|
}
|
|
if (resId == null) {
|
|
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].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
} else {
|
|
var dateIndex = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dx].Id == resId) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[$scope.data2Update.ChangedExpCats[catIndex].Resources.length] = {
|
|
Id: resId,
|
|
Values: [],
|
|
IsAdded: isAdded,
|
|
IsRemoved: isRemoved
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources.length - 1;
|
|
if (isAdded || isRemoved)
|
|
return;
|
|
} else {
|
|
if (isRemoved){
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].IsAdded) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources.splice(dateIndex, 1);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
var dateIndex1 = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dx].Id == cellId) {
|
|
dateIndex1 = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex1 == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex1 = $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length - 1;
|
|
}
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Quantity = cellQuantity;
|
|
}
|
|
$('#btnSaveChanges').removeAttr('disabled');
|
|
}
|
|
function calcWithSamePresicion(val1, val2, isCost) {
|
|
var dec = Math.pow(10, parseInt(isCost ? $scope.formatCells.DecimalCalcCostPlaces : $scope.formatCells.DecimalCalcQtyPlaces));
|
|
return Math.round(val1 * dec) / dec + Math.round(val2 * dec)/dec;
|
|
};
|
|
|
|
$scope.saveChanges = function () {
|
|
blockUI();
|
|
onDataSaved();
|
|
var postData = JSON.parse(JSON.stringify($scope.data2Update));
|
|
postData.ScenarioFilters = $scope.calendarFilters;
|
|
$http.post('/Scenarios/SaveChanges', postData).
|
|
success(function (data, status, headers, config) {
|
|
//$scope.data = data;
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
//alert("data saved successfully");
|
|
var tab = $("#uidemo-tabs-default-demo li.active a").attr("href");
|
|
var retUrl = window.location.href;
|
|
if (retUrl.indexOf("&tab=") > 0)
|
|
{
|
|
retUrl = retUrl.substr(0, retUrl.indexOf("&tab="));
|
|
}
|
|
if (retUrl.indexOf("?") > 0) {
|
|
window.location.href = retUrl + "&tab=" + tab.replace("#", "");
|
|
}
|
|
else {
|
|
window.location.href = retUrl + "?tab=" + tab.replace("#", "");
|
|
}
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
console.log("an error occurred while saving calendar changes");
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.getRate = function (expCatId, date)
|
|
{
|
|
if ($scope.rates && $scope.rates.length > 0) {
|
|
for (var i = 0; i < $scope.rates.length; i++) {
|
|
if ($scope.rates[i].expCatId === expCatId) {
|
|
if ($scope.rates[i].rateValues && $scope.rates[i].rateValues.length > 0) {
|
|
for (var rIndex = 0; rIndex < $scope.rates[i].rateValues.length; rIndex++) {
|
|
if (date <= $scope.rates[i].rateValues[rIndex].weekEndDate)
|
|
return $scope.rates[i].rateValues[rIndex].rateValue;
|
|
}
|
|
return $scope.rates[i].rateValues[$scope.rates[i].rateValues.length - 1].rateValue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
$scope.graphData = [];
|
|
$scope.maxGraphValue = 0;
|
|
$scope.showGraph = function() {
|
|
// prepare data
|
|
$scope.maxGraphValue = 0;
|
|
$scope.graphData = [];
|
|
|
|
var startDate = new Date($scope.data.StartDate.replace('/Date(', '').replace(')/', '') * 1);
|
|
var endDate = new Date($scope.data.EndDate.replace('/Date(', '').replace(')/', '') * 1);
|
|
var days = (endDate - startDate) / (1000 * 60 * 60 * 24);
|
|
var i;
|
|
if (days <= 400) {
|
|
for (i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
|
|
var expCatData = new Array();
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if ($scope.data.Headers[colIndex].IsMonth)
|
|
continue;
|
|
expCatData[expCatData.length] = [$scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[i].QuantityValues[colIndex]];
|
|
if (true !== $scope.calendarFilters.IsTableModeQuantity) {
|
|
expCatData[expCatData.length - 1][1] = $scope.data.ScenarioCalendar[i].CostValues[colIndex];
|
|
}
|
|
if (expCatData[expCatData.length - 1][1] > $scope.maxGraphValue)
|
|
$scope.maxGraphValue = expCatData[expCatData.length - 1][1];
|
|
expCatData[expCatData.length - 1][1] = expCatData[expCatData.length - 1][1].toFixed(2);
|
|
}
|
|
$scope.graphData[$scope.graphData.length] = {
|
|
label: $scope.data.ScenarioCalendar[i].ExpCatName,
|
|
data: expCatData,
|
|
lines: { show: true, fill: true, steps: false },
|
|
filledPoints: true,
|
|
stack: true
|
|
};
|
|
}
|
|
} else {
|
|
$.get('/Scenarios/GetMonthEndDates', {
|
|
'StartDate': startDate.getMonth() + 1 + '/' + startDate.getDate() + '/' + startDate.getFullYear(),
|
|
'EndDate': endDate.getMonth() + 1 + '/' + endDate.getDate() + '/' + endDate.getFullYear()
|
|
}).done(function(data) {
|
|
var dates = data;
|
|
|
|
for (i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
|
|
var expCatData = new Array();
|
|
var currentIndex = 0;
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if ($scope.data.Headers[colIndex].IsMonth)
|
|
continue;
|
|
for (var index = 0; index < dates.length; index++) {
|
|
if (dates[index] == $scope.data.Headers[colIndex].Milliseconds) {
|
|
expCatData[currentIndex] = [$scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[i].QuantityValues[colIndex]];
|
|
if (true !== $scope.calendarFilters.IsTableModeQuantity) {
|
|
expCatData[currentIndex][1] = $scope.data.ScenarioCalendar[i].CostValues[colIndex];
|
|
}
|
|
if (expCatData[currentIndex][1] > $scope.maxGraphValue)
|
|
$scope.maxGraphValue = expCatData[currentIndex][1];
|
|
expCatData[currentIndex][1] = expCatData[currentIndex][1].toFixed(2);
|
|
currentIndex++;
|
|
}
|
|
}
|
|
}
|
|
$scope.graphData[$scope.graphData.length] = {
|
|
label: $scope.data.ScenarioCalendar[i].ExpCatName,
|
|
data: expCatData,
|
|
lines: { show: true, fill: true, steps: false },
|
|
filledPoints: true,
|
|
stack: true
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
// show graph
|
|
$('#DetailsGraphContainer').html('<div id="divDetailsGraph"></div>');
|
|
$("#modalGraph").modal("show");
|
|
setTimeout($scope.initGraph, 500);
|
|
};
|
|
$scope.initGraph = function() {
|
|
// Init Chart
|
|
$('#divDetailsGraph').pixelPlot($scope.graphData, {
|
|
//var plot = $.plot($('#jq-flot-graph2'), graphData, {
|
|
series: {
|
|
points: {
|
|
show: false
|
|
},
|
|
lines: {
|
|
show: true,
|
|
}
|
|
},
|
|
xaxis: {
|
|
mode: "time",
|
|
tickSize: [1, "month"],
|
|
tickLength: 0,
|
|
axisLabel: "time",
|
|
axisLabelUseCanvas: true,
|
|
axisLabelFontSizePixels: 12,
|
|
axisLabelFontFamily: 'Verdana, Arial',
|
|
axisLabelPadding: 10
|
|
},
|
|
yaxis: {
|
|
//tickSize: $scope.maxGraphValue / 5
|
|
}
|
|
}, {
|
|
height: 405,
|
|
width: 405,
|
|
tooltipText: "y + ' units at ' + (new Date(x)).toString()"
|
|
});
|
|
};
|
|
$scope.checkedExpenditures = [];
|
|
$scope.collectchecked = function(obj) {
|
|
$scope.checkedExpenditures = [];
|
|
if ($scope.data == null || $scope.data.ScenarioCalendar == null || obj == null)
|
|
return;
|
|
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if (($scope.data.ScenarioCalendar[i].Checked && obj.ExpCatId != $scope.data.ScenarioCalendar[i].ExpCatId) ||
|
|
(!obj.Checked && obj.ExpCatId == $scope.data.ScenarioCalendar[i].ExpCatId))
|
|
$scope.checkedExpenditures.push($scope.data.ScenarioCalendar[i]);
|
|
}
|
|
applyChecked();
|
|
};
|
|
$scope.checkAll = function () {
|
|
$scope.checkedExpenditures = [];
|
|
var checked = !$scope.data.ScenarioCalendar[0].Checked;
|
|
if ($scope.data == null || $scope.data.ScenarioCalendar == null)
|
|
return;
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
$scope.data.ScenarioCalendar[i].Checked = checked;
|
|
if (checked)
|
|
$scope.checkedExpenditures.push($scope.data.ScenarioCalendar[i]);
|
|
}
|
|
applyChecked();
|
|
};
|
|
function applyChecked() {
|
|
if ($scope.checkedExpenditures.length > 0) {
|
|
$('#btnPushPull').removeAttr('disabled');
|
|
$('#btnFormatCells').removeAttr('disabled');
|
|
$('#btnShowGraph').removeAttr('disabled');
|
|
} else {
|
|
$('#btnPushPull').attr('disabled', true);
|
|
$('#btnFormatCells').attr('disabled', true);
|
|
$('#btnShowGraph').attr('disabled', true);
|
|
}
|
|
|
|
$scope.data.ScenarioCalendar[0].Checked = ($scope.checkedExpenditures.length == ($scope.data.ScenarioCalendar.length - 1));
|
|
}
|
|
|
|
$scope.resizeFreezAng = function() {
|
|
setTimeout(function() {
|
|
resizeFreez();
|
|
}, 0);
|
|
};
|
|
|
|
$scope.takeAll = function (resId, expCatId)
|
|
{
|
|
if (confirm("Are you sure you want to re-assign category quantity and assign everything to this resource?"))
|
|
{
|
|
var expCat = getExpCatById(expCatId);
|
|
var resource = null;
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
|
|
if (expCat.Resources[i].Id == resId) {
|
|
resource = expCat.Resources[i];
|
|
}else{
|
|
clearResource(expCat, expCat.Resources[i]);
|
|
}
|
|
}
|
|
allocateResource(resource, expCat, false, false, false);
|
|
}
|
|
};
|
|
$scope.takeRemaining = function (resId, expCatId) {
|
|
var expCat = getExpCatById(expCatId);
|
|
if (expCat != null)
|
|
{
|
|
for (var i = 0; i < expCat.Resources.length; i++)
|
|
{
|
|
if (expCat.Resources[i].Id == resId)
|
|
{
|
|
allocateResource(expCat.Resources[i], expCat, false, true, false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
$scope.zeroResource = function (resId, expCatId) {
|
|
if (confirm("Are you sure you want fill this resource quantities with 0s?")) {
|
|
var expCat = getExpCatById(expCatId);
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
allocateResource(expCat.Resources[i], expCat, false, false, true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
$scope.assignResource = function (resId, expCatId, $event) {
|
|
if (resId == null || expCatId == null)
|
|
return;
|
|
|
|
var resource = getResourceById(resId);
|
|
if (resource != null) {
|
|
|
|
var expCat = getExpCatById(expCatId);
|
|
if (expCat != null) {
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == resource.Id) {
|
|
alert("The " + resource.Name + " has been assigned to the " + expCat.Name);
|
|
break;
|
|
}
|
|
}
|
|
resource = { 'Id': resource.Id, 'Name': resource.Name, 'QuantityValues': new Array($scope.data.Headers.length), 'CostValues': new Array($scope.data.Headers.length) };
|
|
}
|
|
|
|
allocateResource(resource, expCat, true, false, false);
|
|
expCat.Resources.push(resource);
|
|
var tr = $($event.target).parentsUntil('table').last().parent().find('thead tr:first');
|
|
console.log("tr: " + $(tr).html());
|
|
var thName = tr.find('th:eq(1)');
|
|
console.log("thName: " + $(thName).html());
|
|
resource.width = thName.width() + 'px';
|
|
var thTot = tr.find('th:eq(2)');
|
|
console.log("thTot: " + $(thTot).html());
|
|
resource.left = thTot.css('left');
|
|
$scope.resizeFreezAng();
|
|
}
|
|
};
|
|
$scope.removeResource = function (resId, expCatId) {
|
|
if (confirm("Are you sure you want to remove this resource?")) {
|
|
var expCat = getExpCatById(expCatId);
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
expCat.Resources.splice(i, 1);
|
|
applyCellChange(expCatId, 0, 0, 0, 0, resId, false, true);
|
|
$scope.resizeFreezAng();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.checkResourceValue = function (data, expCatId, resId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
var isMonth = $scope.data.Headers[colIndex].IsMonth;
|
|
|
|
var expCat = getExpCatById(expCatId);
|
|
var resource = null;
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
resource = expCat.Resources[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var scenarioCalendarRow = null;
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
if (expCat != null && resource != null) {
|
|
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
|
|
if (isMonth) {
|
|
var ec_val = resource.QuantityValues[colIndex];
|
|
var weeks = 0;
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
weeks++;
|
|
}
|
|
var coef = ec_val > 0 ? newValue / ec_val : 1;
|
|
|
|
for (var j = colIndex - 1; j >= 0 && !$scope.data.Headers[j].IsMonth; j--) {
|
|
var val = ec_val > 0 ? resource.QuantityValues[j] * coef : newValue / weeks;
|
|
|
|
resource.GrandTotalQuantity += val - resource.QuantityValues[j];
|
|
updateTotals(resource, j, val, resource.QuantityValues[j], 0, 0);
|
|
expCat.RestQuantity[j] -= val - resource.QuantityValues[j];
|
|
resource.QuantityValues[j] = val;
|
|
applyCellChange(expCatId, $scope.data.Headers[j].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[j],
|
|
resource.QuantityValues[j], 0, resId, false, false);
|
|
}
|
|
} else {
|
|
|
|
resource.GrandTotalQuantity += newValue - resource.QuantityValues[colIndex];
|
|
updateTotals(resource, colIndex, newValue, resource.QuantityValues[colIndex], 0, 0);
|
|
expCat.RestQuantity[colIndex] -= newValue - resource.QuantityValues[colIndex];
|
|
resource.QuantityValues[colIndex] = newValue;
|
|
|
|
|
|
applyCellChange(expCatId, $scope.data.Headers[colIndex].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[colIndex],
|
|
resource.QuantityValues[colIndex], 0, resId, false, false);
|
|
}
|
|
}
|
|
}
|
|
//required to be false by xeditable grid
|
|
return false;
|
|
};
|
|
$scope.getExpCatResources = function(expCat) {
|
|
var resources = [];
|
|
for (var i = 0; i < $scope.data.AllResources.length; i++) {
|
|
if ($scope.data.AllResources[i].ExpedentureCategoryId == expCat.ExpCatId && $scope.data.AllResources[i].IsActiveEmployee) {
|
|
var isFound = false;
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == $scope.data.AllResources[i].Id) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFound)
|
|
resources.push($scope.data.AllResources[i]);
|
|
}
|
|
}
|
|
|
|
return resources;
|
|
};
|
|
$scope.switchViewMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsViewModeMonth;
|
|
$scope.calendarFilters.IsViewModeMonth = newValue;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth) {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = newValue;
|
|
$scope.data.Headers[i].CollapsedClass = newValue ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
} else {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = !newValue;
|
|
}
|
|
}
|
|
$scope.resizeFreezAng();
|
|
};
|
|
$scope.switchUOMMode = function (value) {
|
|
if (autoclick)
|
|
{
|
|
autoclick = false;
|
|
return;
|
|
}
|
|
if (changesMade)
|
|
if (!confirm("Changes have been made. Changing UOM will cause unsaved data loss.")) {
|
|
autoclick = true;
|
|
window.setTimeout(toggleUomMode, 10);
|
|
return;
|
|
}
|
|
onDataSaved();
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsUOMHours;
|
|
$scope.calendarFilters.IsUOMHours = newValue;
|
|
$scope.getCalendar();
|
|
$scope.getRates();
|
|
};
|
|
$scope.switchTableMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsTableModeQuantity;
|
|
$scope.calendarFilters.IsTableModeQuantity = newValue;
|
|
};
|
|
$scope.reallocateResource = function () {
|
|
var sourceQuantity = 0;
|
|
var sourceCost = 0;
|
|
if ($scope.reallocator.Percentage == 0) {
|
|
alert('Percentage is 0, nothing to reallocate.');
|
|
return;
|
|
}
|
|
var sourceRowIndex, targetRowIndex, curveRowIndex, sourceColIndex, targetColIndex;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++)
|
|
{
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.SourceExpCat)
|
|
sourceRowIndex = i;
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.TargetExpCat)
|
|
targetRowIndex = i;
|
|
if ($scope.reallocator.CurveType == 'other' && $scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.OtherCurve)
|
|
curveRowIndex = i;
|
|
}
|
|
if (sourceRowIndex == targetRowIndex)
|
|
{
|
|
alert('Cant reallocate within same expenditure category.');
|
|
return;
|
|
}
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if ($scope.data.Headers[i].Title === $scope.reallocator.SourceWeekEnding)
|
|
sourceColIndex = i;
|
|
if ($scope.data.Headers[i].Title === $scope.reallocator.TargetWeekEnding)
|
|
targetColIndex = i;
|
|
}
|
|
if (sourceColIndex == null || targetColIndex == null) {
|
|
alert('Please check selected dates to match valid week endings.');
|
|
return;
|
|
} else if (targetColIndex < sourceColIndex) {
|
|
alert('Please select To week ending date later than From week ending date.');
|
|
return;
|
|
}
|
|
|
|
var sourceSumCost = 0, sourceSumQuantity = 0, targetSumCost = 0, targetSumQuantity = 0, otherSumCost = 0, otherSumQuantity = 0;
|
|
var percentageMult = $scope.reallocator.Percentage / 100;
|
|
for (i = sourceColIndex; i <= targetColIndex ; i++)
|
|
{
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
sourceSumQuantity += $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceSumCost += $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
targetSumQuantity += $scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i];
|
|
targetSumCost += $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i];
|
|
if ($scope.reallocator.CurveType == 'other') {
|
|
otherSumQuantity += $scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i];
|
|
otherSumCost += $scope.data.ScenarioCalendar[curveRowIndex].CostValues[i];
|
|
}
|
|
}
|
|
|
|
if ((sourceSumQuantity == 0 || sourceSumCost == 0)) { alert('Source is zero, nothing to reallocate.'); return; }
|
|
if ((targetSumQuantity == 0 || targetSumCost == 0) && $scope.reallocator.CurveType == 'target') { alert('Target curve is zero. Please select a different curve.'); return; }
|
|
if ((otherSumQuantity == 0 || otherSumCost == 0) && $scope.reallocator.CurveType == 'other') { alert('Different curve is zero. Please select a another curve.'); return; }
|
|
var quantity2Move = 0;
|
|
var cost2Move = 0;
|
|
for (i = sourceColIndex; i <= targetColIndex ; i++)
|
|
{
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if ($scope.reallocator.CurveType == 'source') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), sourceCost * (1 - percentageMult), null);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + sourceQuantity * percentageMult, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), sourceCost * (1 - percentageMult), null);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + sourceCost * percentageMult, false);
|
|
}
|
|
}
|
|
else if ($scope.reallocator.CurveType == 'target') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
quantity2Move = (percentageMult * sourceSumQuantity) * ($scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] / targetSumQuantity);
|
|
cost2Move = (percentageMult * sourceSumCost) * ($scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] / targetSumCost);
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
// we cannot reallocate more than source quantity
|
|
if (quantity2Move > $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i])
|
|
quantity2Move = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
if (quantity2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), null, true);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + quantity2Move, null, true);
|
|
}
|
|
} else {
|
|
// we cannot reallocate more than source quantity
|
|
if (cost2Move > $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i])
|
|
cost2Move = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
if (cost2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
null, sourceCost * (1 - percentageMult), false);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + cost2Move, false);
|
|
}
|
|
}
|
|
}
|
|
else if ($scope.reallocator.CurveType == 'other') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
quantity2Move = (percentageMult * sourceSumQuantity) * ($scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i] / otherSumQuantity);
|
|
cost2Move = (percentageMult * sourceSumCost) * ($scope.data.ScenarioCalendar[curveRowIndex].CostValues[i] / otherSumCost);
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
// we cannot reallocate more than source quantity
|
|
if (quantity2Move > $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i])
|
|
quantity2Move = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
if (quantity2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), null, true);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + quantity2Move, null, true);
|
|
}
|
|
} else {
|
|
// we cannot reallocate more than source quantity
|
|
if (cost2Move > $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i])
|
|
cost2Move = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
if (cost2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
null, sourceCost * (1 - percentageMult), false);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + cost2Move, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$("#reallocator").modal("hide");
|
|
};
|
|
$scope.pushPull = function () {
|
|
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if($scope.data.ScenarioCalendar[i].Checked)
|
|
$scope.pushPullExpCat($scope.data.ScenarioCalendar[i], i, $scope.pushpuller.weeks, $scope.pushpuller.push);
|
|
}
|
|
$("#push_pull").modal("hide");
|
|
};
|
|
$scope.pushPullExpCat = function (data, sourceRowIndex, weeks, push) {
|
|
var oldQuantity = 0;
|
|
var oldCost = 0;
|
|
var i;
|
|
var j;
|
|
var handledWeeks = 0;
|
|
var leftMargin; // index of the cell next to the last modified cell from the left side of the table. E.g. if we push 2 weeks, then it will be [2], or [3] if there is only one week in the first month
|
|
var rightMargin; // index of the cell previous to the first modified cell from the right side of the table. E.g. if we pull 2 weeks, then it will be [length-3], or [length-4] if there is only one week in the last month
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
leftMargin = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
handledWeeks = 0;
|
|
for (i = $scope.data.Headers.length-1; i >= 0; i--) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if (i < leftMargin) {
|
|
alert('Error occurred while calculating right margin of required changes.');
|
|
return;
|
|
}
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
rightMargin = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
if (push) {
|
|
for (i = $scope.data.Headers.length - 1; i >= 0; i--) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = 0;
|
|
oldCost = 0;
|
|
|
|
if (i < leftMargin) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, 0, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, 0, false);
|
|
}
|
|
} else { //copy data from [i+weeks] cell
|
|
handledWeeks = 0;
|
|
for (j = i - 1; j >= 0; j--) {
|
|
if ($scope.data.Headers[j].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
oldQuantity = data.QuantityValues[j];
|
|
oldCost = data.CostValues[j];
|
|
break;
|
|
}
|
|
}
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, oldQuantity, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, oldCost, false);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = 0;
|
|
oldCost = 0;
|
|
|
|
if (i <= rightMargin) { //copy data from [i+weeks] cell
|
|
handledWeeks = 0;
|
|
for (j = i + 1; j < $scope.data.Headers.length; j++) {
|
|
if ($scope.data.Headers[j].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
oldQuantity = data.QuantityValues[j];
|
|
oldCost = data.CostValues[j];
|
|
break;
|
|
}
|
|
}
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, oldQuantity, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, oldCost, false);
|
|
}
|
|
} else if (i > rightMargin) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, 0, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, 0, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.editTotalFunc = function () {
|
|
var oldQuantity = 0;
|
|
var oldCost = 0;
|
|
if ($scope.editTotal.CurrentTotal == $scope.editTotal.NewTotal && $scope.editTotal.Curve != 'other')
|
|
{
|
|
$("#editTotal").modal("hide");
|
|
return;
|
|
}
|
|
var changeMult = $scope.editTotal.NewTotal / $scope.editTotal.CurrentTotal;
|
|
var sourceRowIndex = null;
|
|
var curveRowIndex = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.ExpCat)
|
|
sourceRowIndex = i;
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.OtherCurve)
|
|
curveRowIndex = i;
|
|
}
|
|
if (null === sourceRowIndex) {
|
|
alert('Cannot find expenditure category to update.');
|
|
return;
|
|
}
|
|
if (null === curveRowIndex) {
|
|
alert('Cannot find expenditure category to use as a curve.');
|
|
return;
|
|
}
|
|
|
|
var sourceSumCost = 0, sourceSumQuantity = 0, curveSumCost = 0, curveSumQuantity = 0;
|
|
for (i = 0; i < $scope.data.Headers.length ; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
sourceSumQuantity += $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceSumCost += $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
curveSumQuantity += $scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i];
|
|
curveSumCost += $scope.data.ScenarioCalendar[curveRowIndex].CostValues[i];
|
|
}
|
|
|
|
if (curveSumQuantity == 0 || sourceSumQuantity == 0) {
|
|
changeMult = $scope.editTotal.NewTotal;
|
|
}
|
|
|
|
//console.log("sourceSumQuantity: " + sourceSumQuantity + "; curveSumQuantity: " + curveSumQuantity + "; changeMult: " + changeMult);
|
|
var numberOfWeeks = 0;
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
numberOfWeeks++;
|
|
}
|
|
if (curveSumQuantity > 0)
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
oldCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
if ($scope.editTotal.Curve == 'other') {
|
|
var targetQuantity = $scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i];
|
|
var targetCost = $scope.data.ScenarioCalendar[curveRowIndex].CostValues[i];
|
|
if (sourceSumQuantity != 0)
|
|
updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, Math.abs(sourceSumQuantity * (targetQuantity / curveSumQuantity) * changeMult), Math.abs(sourceSumCost * (targetCost / curveSumCost) * changeMult), null);
|
|
else
|
|
updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, Math.abs((targetQuantity / curveSumQuantity) * changeMult), Math.abs(sourceSumCost * (targetCost / curveSumCost) * changeMult), null);
|
|
}
|
|
else updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, Math.abs(oldQuantity * changeMult), Math.abs(oldCost * changeMult), null);
|
|
}
|
|
else {
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, Math.abs(changeMult / numberOfWeeks), Math.abs(changeMult * $scope.getRate($scope.editTotal.ExpCat, $scope.data.Headers[i].Milliseconds) / numberOfWeeks), null);
|
|
}
|
|
}
|
|
$scope.editTotal.CurrentTotal = $scope.editTotal.NewTotal;
|
|
$("#editTotal").modal("hide");
|
|
};
|
|
$scope.recalcTotal = function () {
|
|
var dec = Math.pow(10, parseInt($scope.formatCells.DecimalPlaces));
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.ExpCat) {
|
|
if ($scope.editTotal.SeatsCost == 'Quantity')
|
|
$scope.editTotal.CurrentTotal = Math.round($scope.data.ScenarioCalendar[i].GrandTotalQuantity* dec) / dec;
|
|
else
|
|
$scope.editTotal.CurrentTotal = Math.round($scope.data.ScenarioCalendar[i].GrandTotalCost*dec)/dec;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
$scope.isOtherSelectedReallocator = function () {
|
|
return $scope.reallocator.CurveType == 'other';
|
|
};
|
|
$scope.isOtherSelectedTotal = function () {
|
|
return $scope.editTotal.Curve == 'other';
|
|
};
|
|
$scope.prefillFormatCells = function() {
|
|
$scope.formatCells.ExpCats = [];
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
$scope.formatCells.ExpCats[$scope.formatCells.ExpCats.length] = {
|
|
Id: $scope.data.ScenarioCalendar[i].ExpCatId,
|
|
Name: $scope.data.ScenarioCalendar[i].ExpCatName
|
|
};
|
|
}
|
|
if ($scope.formatCells.ExpCats.length > 0)
|
|
$scope.formatCells.SelectedExpCats = $scope.formatCells.ExpCats[0].Id;
|
|
};
|
|
$scope.submitFormatCells = function () {
|
|
if ($scope.data.ScenarioType === 9)
|
|
return false;
|
|
if (isNaN($scope.formatCells.DecimalPlaces)) {
|
|
alert("Decimal Places is not set.");
|
|
return false;
|
|
}
|
|
var colIndexes2Update = [];
|
|
// gather column indexes which we're going to update
|
|
var dtStart = $scope.formatCells.StartDate.split('/');
|
|
var msStart = new Date(dtStart[2], dtStart[0] - 1, dtStart[1]).getTime();
|
|
var dtEnd = $scope.formatCells.EndDate.split('/');
|
|
var msEnd = new Date(dtEnd[2], dtEnd[0] - 1, dtEnd[1]).getTime();
|
|
for (var headerIndex = 0; headerIndex < $scope.data.Headers.length; headerIndex++) {
|
|
if ($scope.data.Headers[headerIndex].IsMonth)
|
|
continue;
|
|
if ($scope.data.Headers[headerIndex].Milliseconds >= msStart &&
|
|
$scope.data.Headers[headerIndex].Milliseconds <= msEnd &&
|
|
$scope.data.Headers[headerIndex].Milliseconds > $scope.data.ActualsEndDateMs) {
|
|
colIndexes2Update[colIndexes2Update.length] = headerIndex;
|
|
}
|
|
}
|
|
var oldQuantity = 0;
|
|
var newQuantity = 0;
|
|
var newCost = 0;
|
|
var dec = Math.pow(10, parseInt ($scope.formatCells.DecimalPlaces));
|
|
for (var rowIndex = 0; rowIndex < $scope.data.ScenarioCalendar.length; rowIndex++) {
|
|
for (var catIndex = 0; catIndex < $scope.formatCells.ExpCats.length; catIndex++) {
|
|
if ($scope.formatCells.ExpCats[catIndex].Id === $scope.data.ScenarioCalendar[rowIndex].ExpCatId) {
|
|
for (var colIndex = 0; colIndex < colIndexes2Update.length; colIndex++) {
|
|
oldQuantity = $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndexes2Update[colIndex]];
|
|
newQuantity = Math.round(oldQuantity * dec) / dec;
|
|
newCost = Math.round(newQuantity * $scope.getRate($scope.formatCells.ExpCats[catIndex].Id, $scope.data.Headers[colIndexes2Update[colIndex]].Milliseconds) * dec) / dec;
|
|
if (oldQuantity === newQuantity)
|
|
continue;
|
|
updateQuantityOrCostCell($scope.formatCells.ExpCats[catIndex].Id, rowIndex, colIndexes2Update[colIndex], newQuantity, newCost, null);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$("#modalFormatCells").modal("hide");
|
|
return true;
|
|
};
|
|
$scope.onMonthHeaderClick = function (header) {
|
|
header.Collapsed = !header.Collapsed;
|
|
header.Show = !header.Show;
|
|
header.CollapsedClass = header.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
if (header.Weeks && header.Weeks.length > 0)
|
|
for (var 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.resizeFreezAng();
|
|
};
|
|
$scope.onExpCatClick = function (row) {
|
|
row.Collapsed = !row.Collapsed;
|
|
//row.Show = !row.Show;
|
|
row.CollapsedClass = row.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
};
|
|
$scope.prefillAllocateResource = function () {
|
|
$scope.allocateResource = new Object();
|
|
};
|
|
$scope.getResourceData = function () {
|
|
var url = '/Scenarios/GetScenarioResources';
|
|
$.post(url, { 'scenarioId': $scope.data.ScenarioId }, function(data) {
|
|
if (data.Status == 'Ok') {
|
|
$scope.allocateResource.allResourceList = data.Data;
|
|
|
|
$scope.allocateResource.TeamsList = new Array();
|
|
for (var i = 0; i < data.Data.length; i++) {
|
|
var item = data.Data[i];
|
|
if (item.Team != null) {
|
|
for (var t = 0; t < item.Team.length; t++) {
|
|
var team = item.Team[t];
|
|
|
|
if ($scope.allocateResource.TeamsList.length == 0)
|
|
$scope.allocateResource.TeamsList.push(team);
|
|
|
|
var inArray = false;
|
|
for (var index = 0; index < $scope.allocateResource.TeamsList.length; index++) {
|
|
if ($scope.allocateResource.TeamsList[index].Id == team.Id)
|
|
inArray = true;
|
|
}
|
|
if (!inArray)
|
|
$scope.allocateResource.TeamsList.push(team);
|
|
}
|
|
}
|
|
}
|
|
} else if (data.Status == 'Error') {
|
|
console.error(data.Msg);
|
|
}
|
|
|
|
});
|
|
};
|
|
$scope.getResourcesByTeam = function() {
|
|
$scope.allocateResource.ResourceList = new Array();
|
|
var teamId = $scope.allocateResource.SelectedTeam;
|
|
for (var i = 0; i < $scope.allocateResource.allResourceList.length; i++) {
|
|
var res = $scope.allocateResource.allResourceList[i];
|
|
var inTeam = false;
|
|
var j;
|
|
for (j = 0; j < res.Team.length; j++) {
|
|
var team = res.Team[j];
|
|
if (team.Id == teamId)
|
|
inTeam = true;
|
|
}
|
|
if (inTeam) {
|
|
var inList = false;
|
|
for (j = 0; j < $scope.allocateResource.ResourceList.length; j++) {
|
|
var r = $scope.allocateResource.ResourceList[j];
|
|
if (r.Id == res.Id)
|
|
inList = true;
|
|
}
|
|
if (!inList)
|
|
$scope.allocateResource.ResourceList.push(res);
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
$scope.fillTeamsByResources = function() {
|
|
$scope.allocateResource.TeamsList = new Array();
|
|
|
|
for (var i = 0; i < $scope.allocateResource.ResourceList.length; i++) {
|
|
var res = $scope.allocateResource.ResourceList[i];
|
|
if($scope.allocateResource.TeamsList.indexOf(res.Team) == -1) {
|
|
$scope.allocateResource.TeamsList.push(res.Team);
|
|
}
|
|
}
|
|
};
|
|
}]);
|
|
|
|
controllers.controller('teamDetailsCalendarController', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
|
|
$scope.CollapsedIcon = 'fa-plus-square';
|
|
$scope.NonCollapsedIcon = 'fa-minus-square';
|
|
$scope.availableExpenditures = [];
|
|
$scope.rates = [];
|
|
$scope.id;
|
|
$scope.teamId;
|
|
$scope.calendarFilters = {
|
|
IsTableModeQuantity: true,
|
|
IsViewModeMonth: true,
|
|
ScenarioId: $scope.id,
|
|
IsUOMHours: false,
|
|
};
|
|
$scope.typeOptions = [
|
|
{ name: 'Quantity', value: 'Quantity' },
|
|
{ name: 'Cost', value: 'Cost' }
|
|
];
|
|
$scope.reallocator = {
|
|
SourceExpCat: null,
|
|
TargetExpCat: null,
|
|
SourceWeekEnding: null,
|
|
TargetWeekEnding: null,
|
|
Percentage: 100,
|
|
ReallocateBy: $scope.typeOptions[0].value,
|
|
CurveType: 'source',
|
|
OtherCurve: null,
|
|
};
|
|
$scope.pushpuller = {
|
|
weeks: 1,
|
|
push: true,
|
|
resource: null,
|
|
startdate: null
|
|
};
|
|
|
|
$scope.quickPushPull = function (push, weeks) {
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].Checked)
|
|
$scope.pushPullExpCat($scope.data.ScenarioCalendar[i], i, weeks, push);
|
|
}
|
|
};
|
|
|
|
$scope.editTotal = {
|
|
ExpCat: null,
|
|
SeatsCost: $scope.typeOptions[0].value,
|
|
CurrentTotal: null,
|
|
NewTotal: null,
|
|
Curve: 'source',
|
|
OtherCurve: null,
|
|
};
|
|
|
|
$scope.formatCells = {
|
|
ExpCats: [],
|
|
SelectedExpCats: null,
|
|
StartDate: null,
|
|
EndDate: null,
|
|
DecimalPlaces: 2
|
|
};
|
|
|
|
$scope.data = null;
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
|
|
$scope.teamChanged = function() {
|
|
$http.get('/Scenarios/GetTeamCapacityScenarioId?teamId=' + $scope.teamId).success(function(scenarioId) {
|
|
$scope.id = scenarioId.replace(/"/g, '');
|
|
$scope.calendarFilters.ScenarioId = $scope.id;
|
|
$http.get('/Scenarios/GetScenarioAvailableExpCategories?id=' + $scope.id).success(function(expData) {
|
|
$scope.availableExpenditures = expData;
|
|
if ($scope.availableExpenditures != null && $scope.availableExpenditures.length > 0) {
|
|
$scope.reallocator.SourceExpCat = $scope.availableExpenditures[0].Id;
|
|
$scope.reallocator.TargetExpCat = $scope.availableExpenditures.length > 1 ? $scope.availableExpenditures[1].Id : null;
|
|
$scope.reallocator.OtherCurve = $scope.availableExpenditures[0].Id;
|
|
$scope.editTotal = {
|
|
ExpCat: $scope.availableExpenditures[0].Id,
|
|
OtherCurve: $scope.availableExpenditures[0].Id,
|
|
SeatsCost: $scope.typeOptions[0].value,
|
|
Curve: 'source'
|
|
};
|
|
}
|
|
});
|
|
|
|
$scope.getRates();
|
|
$scope.getCalendar();
|
|
});
|
|
};
|
|
$scope.getRates = function () {
|
|
$http.post('/Scenarios/GetRates', { scenarioId: $scope.id, uomMode: $scope.calendarFilters.IsUOMHours }).success(function (data) {
|
|
$scope.rates = data;
|
|
}).error(function (data, status, headers, config) {
|
|
console.log("an error occurred while loading rates");
|
|
});
|
|
};
|
|
$scope.switchUOMMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsUOMHours;
|
|
$scope.calendarFilters.IsUOMHours = newValue;
|
|
$scope.getCalendar();
|
|
$scope.getRates();
|
|
};
|
|
|
|
function getExpCatById(ExpCatId) {
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId == ExpCatId) {
|
|
return $scope.data.ScenarioCalendar[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
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 clearResource(expCat, resource) {
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
|
|
var scenarioCalendarRow = null;
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCat.ExpCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
expCat.RestQuantity[i] += resource.QuantityValues[i];
|
|
resource.QuantityValues[i] = 0;
|
|
|
|
applyCellChange(expCat.ExpCatId, $scope.data.Headers[i].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[i],
|
|
resource.QuantityValues[i], 0, resource.Id, false, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
function updateTotals(resource, colIndex, newQuantity, oldQuantity, newCost, oldCost) {
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
//update month cell
|
|
resource.QuantityValues[i] += (newQuantity - oldQuantity);
|
|
resource.GrandTotalQuantity[i] += (newQuantity - oldQuantity);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function allocateResource(resource, expCat, create, allocateRest, reset) {
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
resource.GrandTotalCost = 0;
|
|
|
|
var scenarioCalendarRow = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCat.ExpCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
var quantity = create || reset ? 0 : allocateRest ? resource.QuantityValues[i] + expCat.RestQuantity[i] : expCat.QuantityValues[i];
|
|
if (create)
|
|
resource.QuantityValues[i] = 0;
|
|
|
|
expCat.RestQuantity[i] -= quantity - resource.QuantityValues[i];
|
|
updateTotals(resource, i, quantity, resource.QuantityValues[i], 0, 0);
|
|
resource.QuantityValues[i] = quantity;
|
|
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
resource.GrandTotalQuantity += quantity;
|
|
|
|
applyCellChange(expCat.ExpCatId, $scope.data.Headers[i].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[i],
|
|
resource.QuantityValues[i], resource.CostValues[i], resource.Id, create, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$scope.getCalendar = function () {
|
|
if ($scope.id === undefined || $scope.id == "" || $scope.id == "0") return;
|
|
blockUI();
|
|
$scope.data = null;
|
|
var postData = JSON.parse(JSON.stringify($scope.calendarFilters));
|
|
$http.post('/Scenarios/LoadJsonScenarioCalendar', postData).
|
|
success(function (data, status, headers, config) {
|
|
if (data.Headers.length < 1) {
|
|
unblockUI();
|
|
return;
|
|
}
|
|
$scope.data = data;
|
|
$scope.calendarFilters.IsUOMHours = data.IsUOMHours;
|
|
$scope.switchViewMode($scope.calendarFilters.IsViewModeMonth);
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
$scope.reallocator.SourceWeekEnding = $scope.data.Headers[0].Title;
|
|
$scope.reallocator.TargetWeekEnding = $scope.data.Headers[$scope.data.Headers.length - 2].Title;
|
|
$scope.editTotal.CurrentTotal = $scope.data.ScenarioCalendar[1].GrandTotalQuantity;
|
|
|
|
var dt = new Date($scope.data.Headers[0].Milliseconds);
|
|
$scope.formatCells.StartDate = (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
|
|
if ($scope.data.Headers.length > 3)
|
|
dt = new Date($scope.data.Headers[$scope.data.Headers.length - 2].Milliseconds);
|
|
else
|
|
dt = new Date($scope.data.Headers[$scope.data.Headers.length - 2].Milliseconds);
|
|
$scope.formatCells.EndDate = (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
|
|
|
|
$scope.getResourceData();
|
|
$scope.prefillAllocateResource();
|
|
unblockUI();
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
// called asynchronously if an error occurs
|
|
// or server returns response with an error status.
|
|
console.log("an error occurred while loading calendar");
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.onPercentageChange = function (val) {
|
|
$scope.reallocator.Percentage = val;
|
|
};
|
|
$scope.checkEditable = function (useType) {
|
|
if (3 === useType) {
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
$scope.checkValue = function (data, rowId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === rowId) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(rowId, i, colIndex, newValue, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(rowId, i, colIndex, null, newValue, false);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//required to be false by xeditable grid
|
|
return false;
|
|
};
|
|
$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();
|
|
};
|
|
function updateQuantityOrCostCell(expCatId, rowIndex, colIndex, newQuantity, newCost, isUpdateQuantity) {
|
|
/* isUpdateQuantity - indicates whether to update by quantity or by cost.
|
|
* true - Quantity will be updated from newQuantity, Cost will be recalculated as newQuantity * rate
|
|
* false - Cost will be updated from newCost, Quantity will be recalculated as newCost / rate
|
|
* null - Quantity will be updated from newQuantity, Cost will be updated from newCost
|
|
*/
|
|
var oldQuantity = $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex];
|
|
var oldCost = $scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex];
|
|
|
|
if (true === isUpdateQuantity) { // update quantity, recalculate cost based on exp cat rate
|
|
if (oldQuantity === newQuantity || newQuantity < 0)
|
|
return;
|
|
newCost = Math.round(newQuantity * $scope.getRate(expCatId, $scope.data.Headers[colIndex].Milliseconds) * 10000) / 10000;
|
|
} else if (false === isUpdateQuantity) { // update cost, recalculate quantity based on exp cat rate
|
|
if (oldCost === newCost || newCost < 0)
|
|
return;
|
|
newQuantity = Math.round(newCost / $scope.getRate(expCatId, $scope.data.Headers[colIndex].Milliseconds) * 10000) / 10000;
|
|
}
|
|
// update modified cell
|
|
$scope.data.ScenarioCalendar[rowIndex].RestQuantity[colIndex] += newQuantity - $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex];
|
|
$scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex] = newCost;
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex] = newQuantity;
|
|
// update row grand totals
|
|
$scope.data.ScenarioCalendar[rowIndex].GrandTotalCost += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[rowIndex].GrandTotalQuantity += (newQuantity - oldQuantity);
|
|
// update column totals
|
|
$scope.data.ScenarioCalendar[0].CostValues[colIndex] += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[0].QuantityValues[colIndex] += (newQuantity - oldQuantity);
|
|
// update table totals
|
|
$scope.data.ScenarioCalendar[0].GrandTotalCost += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[0].GrandTotalQuantity += (newQuantity - oldQuantity);
|
|
// update month cell and month total cell
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
//update month cell
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[i] += (newQuantity - oldQuantity);
|
|
$scope.data.ScenarioCalendar[rowIndex].CostValues[i] += (newCost - oldCost);
|
|
// update month column totals
|
|
$scope.data.ScenarioCalendar[0].CostValues[i] += (newCost - oldCost);
|
|
$scope.data.ScenarioCalendar[0].QuantityValues[i] += (newQuantity - oldQuantity);
|
|
break;
|
|
}
|
|
applyCellChange(expCatId, $scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[rowIndex].ScenarioDetailIds[colIndex],
|
|
$scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndex], $scope.data.ScenarioCalendar[rowIndex].CostValues[colIndex], null, false, false);
|
|
}
|
|
function applyCellChange(rowId, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved) {
|
|
var catIndex = -1;
|
|
for (var ix = 0; ix < $scope.data2Update.ChangedExpCats.length; ix++) {
|
|
if ($scope.data2Update.ChangedExpCats[ix].Id == rowId) {
|
|
catIndex = ix;
|
|
break;
|
|
}
|
|
}
|
|
if (catIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[$scope.data2Update.ChangedExpCats.length] = {
|
|
Id: rowId,
|
|
Values: [],
|
|
Resources: []
|
|
};
|
|
catIndex = $scope.data2Update.ChangedExpCats.length - 1;
|
|
}
|
|
|
|
if (resId == null) {
|
|
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].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
|
|
} else {
|
|
|
|
var dateIndex = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dx].Id == resId) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[$scope.data2Update.ChangedExpCats[catIndex].Resources.length] = {
|
|
Id: resId,
|
|
Values: [],
|
|
IsAdded: isAdded,
|
|
IsRemoved: isRemoved
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources.length - 1;
|
|
if (isAdded || isRemoved)
|
|
return;
|
|
} else {
|
|
if (isRemoved) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].IsAdded) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources.splice(dateIndex, 1);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
var dateIndex1 = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dx].Id == cellId) {
|
|
dateIndex1 = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex1 == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex1 = $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length - 1;
|
|
}
|
|
//$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Quantity = cellQuantity;
|
|
}
|
|
}
|
|
$scope.saveChanges = function () {
|
|
blockUI();
|
|
var postData = JSON.parse(JSON.stringify($scope.data2Update));
|
|
postData.ScenarioFilters = $scope.calendarFilters;
|
|
$http.post('/Scenarios/SaveChanges', postData).
|
|
success(function (data, status, headers, config) {
|
|
//$scope.data = data;
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
InitGraph($scope.teamId);
|
|
if (typeof LoadGraphData === 'function')
|
|
LoadGraphData();
|
|
unblockUI();
|
|
//var tab = $("#uidemo-tabs-default-demo li.active a").attr("href");
|
|
//var retUrl = window.location.href;
|
|
//if (retUrl.indexOf("&tab=") > 0) {
|
|
// retUrl = retUrl.substr(0, retUrl.indexOf("&tab="));
|
|
//}
|
|
|
|
//window.location.href = retUrl + "&tab=" + tab.replace("#", "");
|
|
onDataSaved();
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
console.log("an error occurred while saving calendar changes");
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.getRate = function (expCatId, date) {
|
|
if ($scope.rates && $scope.rates.length > 0) {
|
|
for (var i = 0; i < $scope.rates.length; i++) {
|
|
if ($scope.rates[i].expCatId === expCatId) {
|
|
if ($scope.rates[i].rateValues && $scope.rates[i].rateValues.length > 0) {
|
|
for (var rIndex = 0; rIndex < $scope.rates[i].rateValues.length; rIndex++) {
|
|
if (date <= $scope.rates[i].rateValues[rIndex].weekEndDate)
|
|
return $scope.rates[i].rateValues[rIndex].rateValue;
|
|
}
|
|
return $scope.rates[i].rateValues[$scope.rates[i].rateValues.length - 1].rateValue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
$scope.graphData = [];
|
|
$scope.maxGraphValue = 0;
|
|
$scope.showGraph = function () {
|
|
// prepare data
|
|
$scope.maxGraphValue = 0;
|
|
$scope.graphData = [];
|
|
|
|
var startDate = new Date($scope.data.StartDate.replace('/Date(', '').replace(')/', '') * 1);
|
|
var endDate = new Date($scope.data.EndDate.replace('/Date(', '').replace(')/', '') * 1);
|
|
var days = (endDate - startDate) / (1000 * 60 * 60 * 24);
|
|
var i;
|
|
if (days <= 400) {
|
|
for (i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
|
|
var expCatData = new Array();
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if ($scope.data.Headers[colIndex].IsMonth)
|
|
continue;
|
|
expCatData[expCatData.length] = [$scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[i].QuantityValues[colIndex]];
|
|
if (true !== $scope.calendarFilters.IsTableModeQuantity) {
|
|
expCatData[expCatData.length - 1][1] = $scope.data.ScenarioCalendar[i].CostValues[colIndex];
|
|
}
|
|
if (expCatData[expCatData.length - 1][1] > $scope.maxGraphValue)
|
|
$scope.maxGraphValue = expCatData[expCatData.length - 1][1];
|
|
expCatData[expCatData.length - 1][1] = expCatData[expCatData.length - 1][1].toFixed(2);
|
|
}
|
|
$scope.graphData[$scope.graphData.length] = {
|
|
label: $scope.data.ScenarioCalendar[i].ExpCatName,
|
|
data: expCatData,
|
|
lines: { show: true, fill: true, steps: false },
|
|
filledPoints: true,
|
|
stack: true
|
|
};
|
|
}
|
|
} else {
|
|
$.get('/Scenarios/GetMonthEndDates', {
|
|
'StartDate': startDate.getMonth() + 1 + '/' + startDate.getDate() + '/' + startDate.getFullYear(),
|
|
'EndDate': endDate.getMonth() + 1 + '/' + endDate.getDate() + '/' + endDate.getFullYear()
|
|
}).done(function (data) {
|
|
var dates = data;
|
|
|
|
for (i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
|
|
var expCatData = new Array();
|
|
var currentIndex = 0;
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if ($scope.data.Headers[colIndex].IsMonth)
|
|
continue;
|
|
for (var index = 0; index < dates.length; index++) {
|
|
if (dates[index] == $scope.data.Headers[colIndex].Milliseconds) {
|
|
expCatData[currentIndex] = [$scope.data.Headers[colIndex].Milliseconds, $scope.data.ScenarioCalendar[i].QuantityValues[colIndex]];
|
|
if (true !== $scope.calendarFilters.IsTableModeQuantity) {
|
|
expCatData[currentIndex][1] = $scope.data.ScenarioCalendar[i].CostValues[colIndex];
|
|
}
|
|
if (expCatData[currentIndex][1] > $scope.maxGraphValue)
|
|
$scope.maxGraphValue = expCatData[currentIndex][1];
|
|
expCatData[currentIndex][1] = expCatData[currentIndex][1].toFixed(2);
|
|
currentIndex++;
|
|
}
|
|
}
|
|
}
|
|
$scope.graphData[$scope.graphData.length] = {
|
|
label: $scope.data.ScenarioCalendar[i].ExpCatName,
|
|
data: expCatData,
|
|
lines: { show: true, fill: true, steps: false },
|
|
filledPoints: true,
|
|
stack: true
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
// show graph
|
|
$('#DetailsGraphContainer').html('<div id="divDetailsGraph"></div>');
|
|
$("#modalGraph").modal("show");
|
|
setTimeout($scope.initGraph, 500);
|
|
};
|
|
$scope.initGraph = function () {
|
|
// Init Chart
|
|
$('#divDetailsGraph').pixelPlot($scope.graphData, {
|
|
//var plot = $.plot($('#jq-flot-graph2'), graphData, {
|
|
series: {
|
|
points: {
|
|
show: false
|
|
},
|
|
lines: {
|
|
show: true,
|
|
}
|
|
},
|
|
xaxis: {
|
|
mode: "time",
|
|
tickSize: [1, "month"],
|
|
tickLength: 0,
|
|
axisLabel: "time",
|
|
axisLabelUseCanvas: true,
|
|
axisLabelFontSizePixels: 12,
|
|
axisLabelFontFamily: 'Verdana, Arial',
|
|
axisLabelPadding: 10
|
|
},
|
|
yaxis: {
|
|
//tickSize: $scope.maxGraphValue / 5
|
|
}
|
|
}, {
|
|
height: 405,
|
|
width: 405,
|
|
tooltipText: "y + ' units at ' + (new Date(x)).toString()"
|
|
});
|
|
};
|
|
$scope.anyChecked = function () {
|
|
if ($scope.data == null || $scope.data.ScenarioCalendar == null)
|
|
return false;
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].Checked)
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
$scope.checkedExpenditures = [];
|
|
$scope.collectchecked = function (obj) {
|
|
$scope.checkedExpenditures = [];
|
|
if ($scope.data == null || $scope.data.ScenarioCalendar == null)
|
|
return;
|
|
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].Checked ||
|
|
(obj != null && !obj.Checked && obj.ExpCatId == $scope.data.ScenarioCalendar[i].ExpCatId))
|
|
$scope.checkedExpenditures.push($scope.data.ScenarioCalendar[i]);
|
|
}
|
|
};
|
|
|
|
$scope.resizeFreezAng = function () {
|
|
setTimeout(function () {
|
|
resizeFreez();
|
|
}, 0);
|
|
};
|
|
|
|
$scope.takeAll = function (resId, expCatId) {
|
|
if (confirm("Are you sure you want to re-assign category quantity and assign everything to this resource?")) {
|
|
var expCat = getExpCatById(expCatId);
|
|
var resource = null;
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
|
|
if (expCat.Resources[i].Id == resId) {
|
|
resource = expCat.Resources[i];
|
|
} else {
|
|
clearResource(expCat, expCat.Resources[i]);
|
|
}
|
|
}
|
|
allocateResource(resource, expCat, false, false, false);
|
|
}
|
|
};
|
|
$scope.takeRemaining = function (resId, expCatId) {
|
|
var expCat = getExpCatById(expCatId);
|
|
if (expCat != null) {
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
allocateResource(expCat.Resources[i], expCat, false, true, false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
};
|
|
$scope.zeroResource = function (resId, expCatId) {
|
|
if (confirm("Are you sure you want fill this resource quantities with 0s?")) {
|
|
var expCat = getExpCatById(expCatId);
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
allocateResource(expCat.Resources[i], expCat, false, false, true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
$scope.assignResource = function (resId, expCatId, $event) {
|
|
if (resId == null || expCatId == null)
|
|
return;
|
|
|
|
var resource = getResourceById(resId);
|
|
if (resource != null) {
|
|
|
|
var expCat = getExpCatById(expCatId);
|
|
if (expCat != null) {
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == resource.Id) {
|
|
alert("The " + resource.Name + " has been assigned to the " + expCat.Name);
|
|
break;
|
|
}
|
|
}
|
|
resource = { 'Id': resource.Id, 'Name': resource.Name, 'QuantityValues': new Array($scope.data.Headers.length), 'CostValues': new Array($scope.data.Headers.length) };
|
|
}
|
|
|
|
allocateResource(resource, expCat, true, false, false);
|
|
expCat.Resources.push(resource);
|
|
var tr = $($event.target).parentsUntil('table').last().parent().find('thead tr:first');
|
|
console.log("tr: " + $(tr).html());
|
|
var thName = tr.find('th:eq(1)');
|
|
console.log("thName: " + $(thName).html());
|
|
resource.width = thName.width() + 'px';
|
|
var thTot = tr.find('th:eq(2)');
|
|
console.log("thTot: " + $(thTot).html());
|
|
resource.left = thTot.css('left');
|
|
$scope.resizeFreezAng();
|
|
}
|
|
};
|
|
$scope.removeResource = function (resId, expCatId) {
|
|
if (confirm("Are you sure you want to remove this resource?")) {
|
|
var expCat = getExpCatById(expCatId);
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
expCat.Resources.splice(i, 1);
|
|
applyCellChange(expCatId, 0, 0, 0, 0, resId, false, true);
|
|
$scope.resizeFreezAng();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.checkResourceValue = function (data, expCatId, resId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
|
|
var expCat = getExpCatById(expCatId);
|
|
var resource = null;
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
resource = expCat.Resources[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var scenarioCalendarRow = null;
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === expCatId) {
|
|
scenarioCalendarRow = $scope.data.ScenarioCalendar[i];
|
|
break;
|
|
}
|
|
}
|
|
if (expCat != null && resource != null) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
resource.GrandTotalQuantity += newValue - resource.QuantityValues[colIndex];
|
|
updateTotals(resource, colIndex, newValue, resource.QuantityValues[colIndex], 0, 0);
|
|
expCat.RestQuantity[colIndex] -= newValue - resource.QuantityValues[colIndex];
|
|
resource.QuantityValues[colIndex] = newValue;
|
|
}
|
|
|
|
applyCellChange(expCatId, $scope.data.Headers[colIndex].Milliseconds, scenarioCalendarRow.ScenarioDetailIds[colIndex],
|
|
resource.QuantityValues[colIndex], 0, resId, false, false);
|
|
}
|
|
//required to be false by xeditable grid
|
|
return false;
|
|
};
|
|
$scope.getExpCatResources = function (expCat) {
|
|
var resources = [];
|
|
for (var i = 0; i < $scope.data.AllResources.length; i++) {
|
|
if ($scope.data.AllResources[i].ExpedentureCategoryId == expCat.ExpCatId && $scope.data.AllResources[i] && $scope.data.AllResources[i].IsActiveEmployee) {
|
|
var isFound = false;
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == $scope.data.AllResources[i].Id) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFound)
|
|
resources.push($scope.data.AllResources[i]);
|
|
}
|
|
}
|
|
|
|
return resources;
|
|
};
|
|
$scope.checkAll = function () {
|
|
$scope.checkedExpenditures = [];
|
|
var checked = !$scope.data.ScenarioCalendar[0].Checked;
|
|
if ($scope.data == null || $scope.data.ScenarioCalendar == null)
|
|
return;
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
$scope.data.ScenarioCalendar[i].Checked = checked;
|
|
if (checked)
|
|
$scope.checkedExpenditures.push($scope.data.ScenarioCalendar[i]);
|
|
}
|
|
};
|
|
$scope.switchViewMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsViewModeMonth;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth) {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = newValue;
|
|
$scope.data.Headers[i].CollapsedClass = newValue ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
} else {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = !newValue;
|
|
}
|
|
}
|
|
$scope.resizeFreezAng();
|
|
};
|
|
$scope.anyUpdated = function () {
|
|
return ($scope.data2Update && $scope.data2Update.ChangedExpCats && $scope.data2Update.ChangedExpCats.length > 0);
|
|
};
|
|
$scope.reallocateResource = function () {
|
|
var sourceQuantity = 0;
|
|
var sourceCost = 0;
|
|
if ($scope.reallocator.Percentage == 0) {
|
|
alert('Percentage is 0, nothing to reallocate.');
|
|
return;
|
|
}
|
|
var sourceRowIndex, targetRowIndex, curveRowIndex, sourceColIndex, targetColIndex;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.SourceExpCat)
|
|
sourceRowIndex = i;
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.TargetExpCat)
|
|
targetRowIndex = i;
|
|
if ($scope.reallocator.CurveType == 'other' && $scope.data.ScenarioCalendar[i].ExpCatId === $scope.reallocator.OtherCurve)
|
|
curveRowIndex = i;
|
|
}
|
|
if (sourceRowIndex == targetRowIndex) {
|
|
alert('Cant reallocate within same expenditure category.');
|
|
return;
|
|
}
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if ($scope.data.Headers[i].Title === $scope.reallocator.SourceWeekEnding)
|
|
sourceColIndex = i;
|
|
if ($scope.data.Headers[i].Title === $scope.reallocator.TargetWeekEnding)
|
|
targetColIndex = i;
|
|
}
|
|
if (sourceColIndex == null || targetColIndex == null) {
|
|
alert('Please check selected dates to match valid week endings.');
|
|
return;
|
|
} else if (targetColIndex < sourceColIndex) {
|
|
alert('Please select To week ending date later than From week ending date.');
|
|
return;
|
|
}
|
|
|
|
var sourceSumCost = 0, sourceSumQuantity = 0, targetSumCost = 0, targetSumQuantity = 0, otherSumCost = 0, otherSumQuantity = 0;
|
|
var percentageMult = $scope.reallocator.Percentage / 100;
|
|
for (i = sourceColIndex; i <= targetColIndex ; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
sourceSumQuantity += $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceSumCost += $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
targetSumQuantity += $scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i];
|
|
targetSumCost += $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i];
|
|
if ($scope.reallocator.CurveType == 'other') {
|
|
otherSumQuantity += $scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i];
|
|
otherSumCost += $scope.data.ScenarioCalendar[curveRowIndex].CostValues[i];
|
|
}
|
|
}
|
|
|
|
if ((sourceSumQuantity == 0 || sourceSumCost == 0)) { alert('Source is zero, nothing to reallocate.'); return; }
|
|
if ((targetSumQuantity == 0 || targetSumCost == 0) && $scope.reallocator.CurveType == 'target') { alert('Target curve is zero. Please select a different curve.'); return; }
|
|
if ((otherSumQuantity == 0 || otherSumCost == 0) && $scope.reallocator.CurveType == 'other') { alert('Different curve is zero. Please select a another curve.'); return; }
|
|
var quantity2Move = 0;
|
|
var cost2Move = 0;
|
|
for (i = sourceColIndex; i <= targetColIndex ; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if ($scope.reallocator.CurveType == 'source') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), sourceCost * (1 - percentageMult), null);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + sourceQuantity * percentageMult, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity * (1 - percentageMult), sourceCost * (1 - percentageMult), null);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + sourceCost * percentageMult, false);
|
|
}
|
|
}
|
|
else if ($scope.reallocator.CurveType == 'target') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
quantity2Move = (percentageMult * sourceSumQuantity) * ($scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] / targetSumQuantity);
|
|
cost2Move = (percentageMult * sourceSumCost) * ($scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] / targetSumCost);
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
// we cannot reallocate more than source quantity
|
|
if (quantity2Move > $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i])
|
|
quantity2Move = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
if (quantity2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity - quantity2Move, null, true);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + quantity2Move, null, true);
|
|
}
|
|
} else {
|
|
// we cannot reallocate more than source quantity
|
|
if (cost2Move > $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i])
|
|
cost2Move = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
if (cost2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
null, sourceCost - cost2Move, false);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + cost2Move, false);
|
|
}
|
|
}
|
|
}
|
|
else if ($scope.reallocator.CurveType == 'other') {
|
|
sourceQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
quantity2Move = (percentageMult * sourceSumQuantity) * ($scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i] / otherSumQuantity);
|
|
cost2Move = (percentageMult * sourceSumCost) * ($scope.data.ScenarioCalendar[curveRowIndex].CostValues[i] / otherSumCost);
|
|
// update column values in model
|
|
if ($scope.reallocator.ReallocateBy == 'Quantity') {
|
|
// we cannot reallocate more than source quantity
|
|
if (quantity2Move > $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i])
|
|
quantity2Move = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
if (quantity2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
sourceQuantity - quantity2Move, null, true);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
$scope.data.ScenarioCalendar[targetRowIndex].QuantityValues[i] + quantity2Move, null, true);
|
|
}
|
|
} else {
|
|
// we cannot reallocate more than source quantity
|
|
if (cost2Move > $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i])
|
|
cost2Move = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
if (cost2Move > 0) {
|
|
updateQuantityOrCostCell($scope.reallocator.SourceExpCat, sourceRowIndex, i,
|
|
null, sourceCost - cost2Move, false);
|
|
updateQuantityOrCostCell($scope.reallocator.TargetExpCat, targetRowIndex, i,
|
|
null, $scope.data.ScenarioCalendar[targetRowIndex].CostValues[i] + cost2Move, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$("#reallocator").modal("hide");
|
|
};
|
|
$scope.pushPull = function () {
|
|
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].Checked)
|
|
$scope.pushPullExpCat($scope.data.ScenarioCalendar[i], i, $scope.pushpuller.weeks, $scope.pushpuller.push);
|
|
}
|
|
$("#push_pull").modal("hide");
|
|
};
|
|
$scope.pushPullExpCat = function (data, sourceRowIndex, weeks, push) {
|
|
var oldQuantity = 0;
|
|
var oldCost = 0;
|
|
var i;
|
|
var j;
|
|
var handledWeeks = 0;
|
|
var leftMargin; // index of the cell next to the last modified cell from the left side of the table. E.g. if we push 2 weeks, then it will be [2], or [3] if there is only one week in the first month
|
|
var rightMargin; // index of the cell previous to the first modified cell from the right side of the table. E.g. if we pull 2 weeks, then it will be [length-3], or [length-4] if there is only one week in the last month
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
leftMargin = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
handledWeeks = 0;
|
|
for (i = $scope.data.Headers.length - 1; i >= 0; i--) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
if (i < leftMargin) {
|
|
alert('Error occurred while calculating right margin of required changes.');
|
|
return;
|
|
}
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
rightMargin = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
if (push) {
|
|
for (i = $scope.data.Headers.length - 1; i >= 0; i--) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = 0;
|
|
oldCost = 0;
|
|
|
|
if (i < leftMargin) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, 0, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, 0, false);
|
|
}
|
|
} else { //copy data from [i+weeks] cell
|
|
handledWeeks = 0;
|
|
for (j = i - 1; j >= 0; j--) {
|
|
if ($scope.data.Headers[j].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
oldQuantity = data.QuantityValues[j];
|
|
oldCost = data.CostValues[j];
|
|
break;
|
|
}
|
|
}
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, oldQuantity, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, oldCost, false);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = 0;
|
|
oldCost = 0;
|
|
|
|
if (i <= rightMargin) { //copy data from [i+weeks] cell
|
|
handledWeeks = 0;
|
|
for (j = i + 1; j < $scope.data.Headers.length; j++) {
|
|
if ($scope.data.Headers[j].IsMonth)
|
|
continue;
|
|
handledWeeks++;
|
|
if (handledWeeks == weeks) {
|
|
oldQuantity = data.QuantityValues[j];
|
|
oldCost = data.CostValues[j];
|
|
break;
|
|
}
|
|
}
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, oldQuantity, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, oldCost, false);
|
|
}
|
|
} else if (i > rightMargin) {
|
|
if ($scope.calendarFilters.IsTableModeQuantity) {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, 0, null, true);
|
|
} else {
|
|
updateQuantityOrCostCell(data.ExpCatId, sourceRowIndex, i, null, 0, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.editTotalFunc = function () {
|
|
var oldQuantity = 0;
|
|
var oldCost = 0;
|
|
if ($scope.editTotal.CurrentTotal == $scope.editTotal.NewTotal) {
|
|
$("#editTotal").modal("hide");
|
|
return;
|
|
}
|
|
var changeMult = $scope.editTotal.NewTotal / $scope.editTotal.CurrentTotal;
|
|
var sourceRowIndex = null;
|
|
var curveRowIndex = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.ExpCat)
|
|
sourceRowIndex = i;
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.OtherCurve)
|
|
curveRowIndex = i;
|
|
}
|
|
if (null === sourceRowIndex) {
|
|
alert('Cannot find expenditure category to update.');
|
|
return;
|
|
}
|
|
if (null === curveRowIndex) {
|
|
alert('Cannot find expenditure category to use as a curve.');
|
|
return;
|
|
}
|
|
|
|
var sourceSumCost = 0, sourceSumQuantity = 0, curveSumCost = 0, curveSumQuantity = 0;
|
|
for (i = 0; i < $scope.data.Headers.length ; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
sourceSumQuantity += $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
sourceSumCost += $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
curveSumQuantity += $scope.data.ScenarioCalendar[curveRowIndex].QuantityValues[i];
|
|
curveSumCost += $scope.data.ScenarioCalendar[curveRowIndex].CostValues[i];
|
|
}
|
|
|
|
if (curveSumQuantity == 0) {
|
|
changeMult = $scope.editTotal.NewTotal;
|
|
}
|
|
|
|
var numberOfWeeks = 0;
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
numberOfWeeks++;
|
|
}
|
|
if (curveSumQuantity == 0 && $scope.editTotal.Curve == 'other') {
|
|
alert('Curve is zero. Please select a different curve.');
|
|
return;
|
|
}
|
|
if (curveSumQuantity > 0)
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
oldQuantity = $scope.data.ScenarioCalendar[sourceRowIndex].QuantityValues[i];
|
|
oldCost = $scope.data.ScenarioCalendar[sourceRowIndex].CostValues[i];
|
|
updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, oldQuantity * changeMult, oldCost * changeMult, null);
|
|
}
|
|
else
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
updateQuantityOrCostCell($scope.editTotal.ExpCat, sourceRowIndex, i, changeMult / numberOfWeeks, changeMult * $scope.getRate($scope.editTotal.ExpCat, $scope.data.Headers[i].Milliseconds) / numberOfWeeks, null);
|
|
}
|
|
$("#editTotal").modal("hide");
|
|
};
|
|
$scope.recalcTotal = function () {
|
|
for (var i = 0; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
if ($scope.data.ScenarioCalendar[i].ExpCatId === $scope.editTotal.ExpCat) {
|
|
if ($scope.editTotal.SeatsCost == 'Quantity')
|
|
$scope.editTotal.CurrentTotal = $scope.data.ScenarioCalendar[i].GrandTotalQuantity;
|
|
else
|
|
$scope.editTotal.CurrentTotal = $scope.data.ScenarioCalendar[i].GrandTotalCost;
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
$scope.isOtherSelectedReallocator = function () {
|
|
return $scope.reallocator.CurveType == 'other';
|
|
};
|
|
$scope.isOtherSelectedTotal = function () {
|
|
return $scope.editTotal.Curve == 'other';
|
|
};
|
|
$scope.prefillFormatCells = function () {
|
|
$scope.formatCells.ExpCats = [];
|
|
for (var i = 1; i < $scope.data.ScenarioCalendar.length; i++) {
|
|
// skip this row if it is not checked
|
|
if (!$scope.data.ScenarioCalendar[i].Checked)
|
|
continue;
|
|
$scope.formatCells.ExpCats[$scope.formatCells.ExpCats.length] = {
|
|
Id: $scope.data.ScenarioCalendar[i].ExpCatId,
|
|
Name: $scope.data.ScenarioCalendar[i].ExpCatName
|
|
};
|
|
}
|
|
if ($scope.formatCells.ExpCats.length > 0)
|
|
$scope.formatCells.SelectedExpCats = $scope.formatCells.ExpCats[0].Id;
|
|
};
|
|
$scope.submitFormatCells = function () {
|
|
if ($scope.data.ScenarioType === 9)
|
|
return false;
|
|
if (isNaN($scope.formatCells.DecimalPlaces)) {
|
|
alert("Decimal Places is not set.");
|
|
return false;
|
|
}
|
|
var colIndexes2Update = [];
|
|
// gather column indexes which we're going to update
|
|
var dtStart = $scope.formatCells.StartDate.split('/');
|
|
var msStart = new Date(dtStart[2], dtStart[0] - 1, dtStart[1]).getTime();
|
|
var dtEnd = $scope.formatCells.EndDate.split('/');
|
|
var msEnd = new Date(dtEnd[2], dtEnd[0] - 1, dtEnd[1]).getTime();
|
|
for (var headerIndex = 0; headerIndex < $scope.data.Headers.length; headerIndex++) {
|
|
if ($scope.data.Headers[headerIndex].IsMonth)
|
|
continue;
|
|
if ($scope.data.Headers[headerIndex].Milliseconds >= msStart &&
|
|
$scope.data.Headers[headerIndex].Milliseconds <= msEnd &&
|
|
$scope.data.Headers[headerIndex].Milliseconds > $scope.data.ActualsEndDateMs) {
|
|
colIndexes2Update[colIndexes2Update.length] = headerIndex;
|
|
}
|
|
}
|
|
var oldQuantity = 0;
|
|
var newQuantity = 0;
|
|
var newCost = 0;
|
|
var dec = Math.pow(10, parseInt($scope.formatCells.DecimalPlaces));
|
|
for (var rowIndex = 0; rowIndex < $scope.data.ScenarioCalendar.length; rowIndex++) {
|
|
for (var catIndex = 0; catIndex < $scope.formatCells.ExpCats.length; catIndex++) {
|
|
if ($scope.formatCells.ExpCats[catIndex].Id === $scope.data.ScenarioCalendar[rowIndex].ExpCatId) {
|
|
for (var colIndex = 0; colIndex < colIndexes2Update.length; colIndex++) {
|
|
oldQuantity = $scope.data.ScenarioCalendar[rowIndex].QuantityValues[colIndexes2Update[colIndex]];
|
|
newQuantity = Math.round(oldQuantity * dec) / dec;
|
|
newCost = Math.round(newQuantity * $scope.getRate($scope.formatCells.ExpCats[catIndex].Id, $scope.data.Headers[colIndexes2Update[colIndex]].Milliseconds) * dec) / dec;
|
|
if (oldQuantity === newQuantity)
|
|
continue;
|
|
updateQuantityOrCostCell($scope.formatCells.ExpCats[catIndex].Id, rowIndex, colIndexes2Update[colIndex], newQuantity, newCost, null);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$("#modalFormatCells").modal("hide");
|
|
return true;
|
|
};
|
|
$scope.onMonthHeaderClick = function (header) {
|
|
header.Collapsed = !header.Collapsed;
|
|
header.Show = !header.Show;
|
|
header.CollapsedClass = header.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
if (header.Weeks && header.Weeks.length > 0)
|
|
for (var 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.resizeFreezAng();
|
|
};
|
|
$scope.onExpCatClick = function (row) {
|
|
row.Collapsed = !row.Collapsed;
|
|
//row.Show = !row.Show;
|
|
row.CollapsedClass = row.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
};
|
|
$scope.prefillAllocateResource = function () {
|
|
$scope.allocateResource = new Object();
|
|
};
|
|
$scope.getResourceData = function () {
|
|
var url = '/Scenarios/GetTeamScenarioResources';
|
|
$.post(url, { 'scenarioId': $scope.data.ScenarioId }, function (data) {
|
|
if (data.Status == 'Ok') {
|
|
$scope.allocateResource.allResourceList = data.Data;
|
|
|
|
$scope.allocateResource.TeamsList = new Array();
|
|
for (var i = 0; i < data.Data.length; i++) {
|
|
var item = data.Data[i];
|
|
if (item.Team != null) {
|
|
for (var t = 0; t < item.Team.length; t++) {
|
|
var team = item.Team[t];
|
|
|
|
if ($scope.allocateResource.TeamsList.length == 0)
|
|
$scope.allocateResource.TeamsList.push(team);
|
|
|
|
var inArray = false;
|
|
for (var index = 0; index < $scope.allocateResource.TeamsList.length; index++) {
|
|
if ($scope.allocateResource.TeamsList[index].Id == team.Id)
|
|
inArray = true;
|
|
}
|
|
if (!inArray)
|
|
$scope.allocateResource.TeamsList.push(team);
|
|
}
|
|
}
|
|
}
|
|
} else if (data.Status == 'Error') {
|
|
console.error(data.Msg);
|
|
}
|
|
|
|
});
|
|
};
|
|
$scope.getResourcesByTeam = function () {
|
|
$scope.allocateResource.ResourceList = new Array();
|
|
var teamId = $scope.allocateResource.SelectedTeam;
|
|
for (var i = 0; i < $scope.allocateResource.allResourceList.length; i++) {
|
|
var res = $scope.allocateResource.allResourceList[i];
|
|
var inTeam = false;
|
|
var j;
|
|
for (j = 0; j < res.Team.length; j++) {
|
|
var team = res.Team[j];
|
|
if (team.Id == teamId)
|
|
inTeam = true;
|
|
}
|
|
if (inTeam) {
|
|
var inList = false;
|
|
for (j = 0; j < $scope.allocateResource.ResourceList.length; j++) {
|
|
var r = $scope.allocateResource.ResourceList[j];
|
|
if (r.Id == res.Id)
|
|
inList = true;
|
|
}
|
|
if (!inList)
|
|
$scope.allocateResource.ResourceList.push(res);
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
$scope.fillTeamsByResources = function () {
|
|
$scope.allocateResource.TeamsList = new Array();
|
|
|
|
for (var i = 0; i < $scope.allocateResource.ResourceList.length; i++) {
|
|
var res = $scope.allocateResource.ResourceList[i];
|
|
if ($scope.allocateResource.TeamsList.indexOf(res.Team) == -1) {
|
|
$scope.allocateResource.TeamsList.push(res.Team);
|
|
}
|
|
}
|
|
};
|
|
}]);
|
|
|
|
controllers.controller('capacityManagementController', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
|
|
$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.calendarFilters = {
|
|
CompanyId: null,
|
|
ViewId: null,
|
|
TeamId: null,
|
|
IsUOMHours: null,
|
|
ShowUpper: true,
|
|
ShowLower: true,
|
|
IsBarMode: true,
|
|
ShowCapacity: 1, //"Total Allocated/Total Capacity"
|
|
GroupByTeam: true,
|
|
IsViewModeMonth: true
|
|
};
|
|
|
|
$scope.SpreadType = {
|
|
Notspecified: -1,
|
|
Equal: 0,
|
|
Less: 1,
|
|
Over: 2
|
|
};
|
|
|
|
$scope.companies = [];
|
|
$http.post('/CapacityManagement/GetCompanies').success(function (data) {
|
|
$scope.companies = data;
|
|
}).error(function (data, status, headers, config) {
|
|
console.log("an error occurred while loading rates");
|
|
});
|
|
|
|
$scope.data = null;
|
|
$scope.data2Update = {
|
|
ChangedExpCats: []
|
|
};
|
|
|
|
$scope.grandtotalrow = null;
|
|
|
|
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.data.Calendar[i].TeamId == teamId)) {
|
|
return $scope.data.Calendar[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
function getRowByType(type, expCatId) {
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == type) {
|
|
if (expCatId != null) {
|
|
if ($scope.data.Calendar[i].ExpCatId == expCatId)
|
|
return $scope.data.Calendar[i]; //return expCat by type+expCatId
|
|
} else
|
|
return $scope.data.Calendar[i]; //return expCat by type
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
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 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) {
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
changeResourceValue(0, scenarioId, expCatId, resource.Id, i);
|
|
}
|
|
}
|
|
}
|
|
function updateTotals(expCat, expCatTotal, resourceTotal, resource, colIndex, newQuantity, oldQuantity, newCost, oldCost) {
|
|
for (var i = colIndex + 1; i < $scope.data.Headers.length; i++) {
|
|
if (!$scope.data.Headers[i].IsMonth)
|
|
continue;
|
|
//update month cell
|
|
resource.QuantityValues[i] += (newQuantity - oldQuantity);
|
|
resource.GrandTotalQuantity[i] += (newQuantity - oldQuantity);
|
|
if (resourceTotal != null) {
|
|
resourceTotal.QuantityValues[i] += (newQuantity - oldQuantity);
|
|
expCatTotal.QuantityValues[i] += (newQuantity - oldQuantity);
|
|
}
|
|
recalcSpreading(expCat, expCatTotal, resourceTotal, i);
|
|
updateCSSClass(expCat, resource, colIndex);
|
|
break;
|
|
}
|
|
}
|
|
function allocateResource(resource, expCat, create, allocateRest, reset) {
|
|
if (resource != null) {
|
|
resource.GrandTotalQuantity = 0;
|
|
resource.GrandTotalCost = 0;
|
|
|
|
var scenarioCalendarRow = null;
|
|
var i;
|
|
for (i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].ExpCatId == expCat.ExpCatId && $scope.data.Calendar[i].ScenarioId == expCat.ScenarioId) {
|
|
scenarioCalendarRow = $scope.data.Calendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < $scope.data.Headers.length; i++) {
|
|
var quantity = create || reset ? 0 : allocateRest ? resource.QuantityValues[i] + expCat.RestQuantity[i] : expCat.QuantityValues[i];
|
|
if (create)
|
|
resource.QuantityValues[i] = 0;
|
|
|
|
if (!$scope.data.Headers[i].IsMonth) {
|
|
changeResourceValue(quantity, expCat.ScenarioId, expCat.ExpCatId, resource.Id, resource.TeamId, i);
|
|
resource.GrandTotalQuantity += quantity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex) {
|
|
var i;
|
|
if (expCat != null) {
|
|
var scenarioCalendarRow = null;
|
|
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) {
|
|
scenarioCalendarRow = $scope.data.Calendar[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
var resTotal = 0;
|
|
for (i = 0; i < expCat.Resources.length; i++) {
|
|
resTotal += expCat.Resources[i].QuantityValues[colIndex];
|
|
}
|
|
|
|
resTotal = Math.round(resTotal * 1000000) / 1000000;
|
|
|
|
var compareRes = compareValues(resTotal, expCat.QuantityValues[colIndex]);
|
|
|
|
expCat.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
updateCSSClass(expCat, null, colIndex);
|
|
|
|
var projectClass = $scope.SpreadType.Equal;
|
|
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) {
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
scenarioCalendarRow.SpreadVal[colIndex] = projectClass;
|
|
updateCSSClass(scenarioCalendarRow, null, colIndex);
|
|
}
|
|
|
|
//calc exp cat total row
|
|
if (expCatTotal != null) {
|
|
//var expCatSpread = $scope.SpreadType.Equal;
|
|
|
|
for (i = 0; i < expCatTotal.Resources.length; i++) {
|
|
var res = expCatTotal.Resources[i];
|
|
var resValue = res.QuantityTotalResValue[colIndex]; //expCatTotal.QuantityTotalResValue[colIndex];
|
|
var compareRes = compareValues(res.QuantityValues[colIndex], resValue);
|
|
res.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
updateCSSClass(expCatTotal, res, colIndex);
|
|
|
|
//if (res.SpreadVal[colIndex] == $scope.SpreadType.Over) {
|
|
// expCatSpread = $scope.SpreadType.Over;
|
|
// break;
|
|
//} else if (res.SpreadVal[colIndex] == $scope.SpreadType.Less) {
|
|
// expCatSpread = $scope.SpreadType.Less;
|
|
//}
|
|
}
|
|
|
|
//var resValue = expCatTotal.QuantityTotalResValue[colIndex];
|
|
//expCatTotal.SpreadVal[colIndex] = expCatTotal.QuantityValues[colIndex] > resValue ? $scope.SpreadType.Over :
|
|
// expCatTotal.QuantityValues[colIndex] < resValue ? $scope.SpreadType.Less :
|
|
// expCatTotal.QuantityValues[colIndex] == resValue ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
|
|
//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;
|
|
//}
|
|
|
|
var resValue = expCatTotal.QuantityTotalResValue[colIndex];
|
|
var compareRes = compareValues(expCatTotal.QuantityValues[colIndex], resValue);
|
|
expCatTotal.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
function compareValues(val1, val2)
|
|
{
|
|
if (!isNaN(parseFloat(val1)) && !isNaN(parseFloat(val2)))
|
|
{
|
|
var val1_ = Math.round(parseFloat(val1) * 1000) / 1000;
|
|
var val2_ = Math.round(parseFloat(val2) * 1000) / 1000;
|
|
if ((-0.005 > (val1_ - val2_)))
|
|
return -1;
|
|
else
|
|
if ((0.005 < (val1_ - val2_)))
|
|
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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;
|
|
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 == 0) {
|
|
if (row.Color != null && row.Color.length > 0 && $scope.calendarFilters.IsBarMode)
|
|
row.BarStyle[colIndex] = "background-color: " + row.Color +";border-right-color: " + row.Color + " !important;"; //"{'background-color': '"+ row.Color +"','border-right-color': '"+ row.Color +" !important'}"; //{"background-color": "' + row.Color + '","border-right-color": "' + row.Color + ' !important;"}';
|
|
//row.BarStyle[colIndex] = 'background-color: ' + row.Color + ';border-right-color: ' + row.Color + ' !important;';
|
|
else
|
|
row.BarStyle[colIndex] = null;
|
|
}
|
|
}
|
|
//TODO: assign more classes if needed
|
|
} else { // updating resource row
|
|
if (row == null || colIndex == null || row.ReadOnly[colIndex])
|
|
return;
|
|
|
|
if (row.RowType == 1) { // top part of the grid
|
|
//if(!$scope.data.Headers[colIndex].IsMonth && resRow.QuantityValues[colIndex] > resRow.CapacityQuantityValues[colIndex])
|
|
// resRow.CSSClass[colIndex] = 'cellover';
|
|
} else { // bottom part of the grid
|
|
if (resRow.SpreadVal == null || resRow.SpreadVal.length <= colIndex)
|
|
return;
|
|
|
|
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';
|
|
}
|
|
//TODO: assign more classes if needed
|
|
}
|
|
}
|
|
function changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex)
|
|
{
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
var resource = getResourceByExpCat(expCat, resId);
|
|
var resourceTotal = getResourceByExpCat(expCatTotal, resId);;
|
|
|
|
if (expCat != null && resource != null) {
|
|
|
|
resource.GrandTotalQuantity += (newValue - resource.QuantityValues[colIndex]);
|
|
updateTotals(expCat, expCatTotal, resourceTotal, resource, colIndex, newValue, resource.QuantityValues[colIndex], 0, 0);
|
|
expCat.RestQuantity[colIndex] -= newValue - resource.QuantityValues[colIndex];
|
|
|
|
if (expCatTotal != null && resourceTotal != null) {
|
|
resourceTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
expCatTotal.QuantityValues[colIndex] += (newValue - resource.QuantityValues[colIndex]);
|
|
}
|
|
resource.QuantityValues[colIndex] = newValue;
|
|
|
|
applyCellChange(scenarioId, expCatId, $scope.data.Headers[colIndex].Milliseconds, expCat.DetailIds[colIndex],
|
|
newValue, 0, resId, false, false);
|
|
}
|
|
recalcSpreading(expCat, expCatTotal, resourceTotal, colIndex);
|
|
updateCSSClass(expCat, resource, colIndex);
|
|
}
|
|
function applyCellChange(scenarioId, rowId, cellMilliseconds, cellId, cellQuantity, cellCost, resId, isAdded, isRemoved) {
|
|
var catIndex = -1;
|
|
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) {
|
|
$scope.data2Update.ChangedExpCats[$scope.data2Update.ChangedExpCats.length] = {
|
|
ScenarioId: scenarioId,
|
|
Id: rowId,
|
|
Values: [],
|
|
Resources: []
|
|
};
|
|
catIndex = $scope.data2Update.ChangedExpCats.length - 1;
|
|
}
|
|
|
|
if (resId == null) {
|
|
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].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Values[dateIndex].Quantity = cellQuantity;
|
|
|
|
} else {
|
|
|
|
var dateIndex = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dx].Id == resId) {
|
|
dateIndex = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[$scope.data2Update.ChangedExpCats[catIndex].Resources.length] = {
|
|
Id: resId,
|
|
Values: [],
|
|
IsAdded: isAdded,
|
|
IsRemoved: isRemoved
|
|
};
|
|
dateIndex = $scope.data2Update.ChangedExpCats[catIndex].Resources.length - 1;
|
|
if (isAdded || isRemoved)
|
|
return;
|
|
} else {
|
|
if (isRemoved) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].IsAdded) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources.splice(dateIndex, 1);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
var dateIndex1 = -1;
|
|
for (var dx = 0; dx < $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length; dx++) {
|
|
if ($scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dx].Milliseconds == cellMilliseconds) {
|
|
dateIndex1 = dx;
|
|
break;
|
|
}
|
|
}
|
|
if (dateIndex1 == -1) {
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length] = {
|
|
Id: cellId,
|
|
Milliseconds: cellMilliseconds,
|
|
Values: []
|
|
};
|
|
dateIndex1 = $scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values.length - 1;
|
|
}
|
|
//$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Cost = cellCost;
|
|
$scope.data2Update.ChangedExpCats[catIndex].Resources[dateIndex].Values[dateIndex1].Quantity = cellQuantity;
|
|
}
|
|
}
|
|
function RefreshTotalSpreadVal(expCatTotal) {
|
|
if (expCatTotal.RowType == 7) {
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
var resValue = expCatTotal.QuantityTotalResValue[colIndex];
|
|
|
|
var total = 0;
|
|
var allocated = 0;
|
|
if ($scope.calendarFilters.ShowCapacity == 1) {
|
|
allocated = expCatTotal.QuantityValues[colIndex];
|
|
total = expCatTotal.QuantityTotalResValue[colIndex];
|
|
}
|
|
else if ($scope.calendarFilters.ShowCapacity == 2) {
|
|
allocated = expCatTotal.QuantityExpCatTotalValue[colIndex];
|
|
total = expCatTotal.QuantityTotalResValue[colIndex];
|
|
} else {
|
|
allocated = expCatTotal.QuantityValues[colIndex];
|
|
total = expCatTotal.QuantityExpCatTotalValue[colIndex];
|
|
}
|
|
|
|
var compareRes = compareValues(allocated, total);
|
|
|
|
expCatTotal.SpreadVal[colIndex] = compareRes > 0 ? $scope.SpreadType.Over :
|
|
compareRes < 0 ? $scope.SpreadType.Less :
|
|
compareRes == 0 ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
|
|
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);
|
|
}
|
|
|
|
$scope.getCalendar = function () {
|
|
$("#loader").hide();
|
|
if ($scope.calendarFilters.CompanyId == null && $scope.calendarFilters.TeamId == null && $scope.calendarFilters.ViewId == null) {
|
|
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;
|
|
}
|
|
|
|
if (data.Calendar.length == 5) {
|
|
$("#loader").hide();
|
|
resizeFreezCapacity();
|
|
}
|
|
|
|
$scope.data = data;
|
|
$scope.calendarFilters.IsUOMHours = data.IsUOMHours;
|
|
$scope.switchViewMode($scope.calendarFilters.IsViewModeMonth);
|
|
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].IsTotal && $scope.data.Calendar[i].RowType == 5) {
|
|
$scope.grandtotalrow = $scope.data.Calendar[i];
|
|
//break;
|
|
}
|
|
$scope.data.Calendar[i].IsUpperHidden = !$scope.calendarFilters.ShowUpper;
|
|
$scope.data.Calendar[i].IsLowerHidden = !$scope.calendarFilters.ShowLower;
|
|
}
|
|
// 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 == 7) // buttom row
|
|
//{
|
|
|
|
//var row = $scope.data.Calendar[rowIndex];
|
|
//var total = 0;
|
|
//var allocated = 0;
|
|
//if ($scope.calendarFilters.ShowCapacity == 1)
|
|
//{
|
|
// allocated = row.QuantityValues[colIndex];
|
|
// total = row.QuantityTotalResValue[colIndex];
|
|
//}
|
|
//else if ($scope.calendarFilters.ShowCapacity == 2)
|
|
//{
|
|
// allocated = row.QuantityExpCatTotalValue[colIndex];
|
|
// total = row.QuantityTotalResValue[colIndex];
|
|
//} else {
|
|
// allocated = row.QuantityValues[colIndex];
|
|
// total = row.QuantityExpCatTotalValue[colIndex];
|
|
//}
|
|
|
|
//row.SpreadVal[colIndex] = allocated > total ? $scope.SpreadType.Over :
|
|
// allocated < total ? $scope.SpreadType.Less :
|
|
// allocated == total ? $scope.SpreadType.Equal : $scope.SpreadType.Notspecified;
|
|
|
|
|
|
//}
|
|
if ($scope.data.Calendar[rowIndex].RowType != 7)
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unblockUI();
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
// called asynchronously if an error occurs
|
|
// or server returns response with an error status.
|
|
console.log("an error occurred while loading calendar");
|
|
$("#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 () {
|
|
blockUI();
|
|
var postData = JSON.parse(JSON.stringify($scope.data2Update));
|
|
postData.ScenarioFilters = $scope.calendarFilters;
|
|
$http.post('/CapacityManagement/SaveChanges', postData).
|
|
success(function (data, status, headers, config) {
|
|
$scope.data2Update = {
|
|
ScenarioId: $scope.id,
|
|
ChangedExpCats: []
|
|
};
|
|
alert("data saved successfully");
|
|
//var tab = $("#uidemo-tabs-default-demo li.active a").attr("href");
|
|
//var retUrl = window.location.href;
|
|
//if (retUrl.indexOf("&tab=") > 0) {
|
|
// retUrl = retUrl.substr(0, retUrl.indexOf("&tab="));
|
|
//}
|
|
//window.location.href = retUrl; // + "&tab=" + tab.replace("#", "");
|
|
$scope.getCalendar();
|
|
}).
|
|
error(function (data, status, headers, config) {
|
|
console.log("an error occurred while saving calendar changes");
|
|
unblockUI();
|
|
});
|
|
};
|
|
$scope.resizeFreezAng = function () {
|
|
setTimeout(function () {
|
|
resizeFreezCapacity();
|
|
}, 0);
|
|
};
|
|
$scope.takeAll = function (scenarioId, resId, expCatId, teamId) {
|
|
if (confirm("Are you sure you want to re-assign category quantity and assign everything to this resource?")) {
|
|
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var resource = null;
|
|
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
|
|
if (expCat.Resources[i].Id == resId) {
|
|
resource = expCat.Resources[i];
|
|
} else {
|
|
clearResource(expCat.ScenarioId, expCat.ExpCatId, expCat.Resources[i]);
|
|
}
|
|
}
|
|
var create = false;
|
|
var allocateRest = false;
|
|
var reset = false;
|
|
allocateResource(resource, expCat, create, allocateRest, reset); //false, false, false);
|
|
}
|
|
};
|
|
$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); //false, true, false);
|
|
}
|
|
};
|
|
$scope.zeroResource = function (scenarioId, resId, expCatId, teamId) {
|
|
if (confirm("Are you sure you want fill this resource quantities with 0s?")) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var create = false;
|
|
var allocateRest = false;
|
|
var reset = true;
|
|
allocateResource(getResourceByExpCat(expCat, resId), expCat, create, allocateRest, reset); //false, false, true);
|
|
}
|
|
};
|
|
$scope.assignResource = function (resId, scenarioId, expCatId, teamId, $event) {
|
|
if (resId == null || expCatId == null || teamId == null)
|
|
return;
|
|
|
|
var resource = getResourceById(resId);
|
|
if (resource != null) {
|
|
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
var rowCapacity = getRowByType(6);
|
|
var rowVacation = getRowByType(2);
|
|
var rowTraining = getRowByType(3);
|
|
//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), 'TeamId': resource.TeamId
|
|
};
|
|
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)
|
|
};
|
|
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);
|
|
for (colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if (rowCapacity != null) {
|
|
rowCapacity.QuantityValues[colIndex] += expCatTotal.QuantityResValue;
|
|
}
|
|
}
|
|
}
|
|
for (colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if (rowVacation != null) {
|
|
rowVacation.QuantityValues[colIndex] += resource.VacationQuantityValues[colIndex];
|
|
}
|
|
if (rowTraining != null) {
|
|
rowTraining.QuantityValues[colIndex] += resource.TrainingQuantityValues[colIndex];
|
|
}
|
|
newResource.CapacityQuantityValues[colIndex] = expCatTotal.QuantityResValue - resource.VacationQuantityValues[colIndex] - resource.TrainingQuantityValues[colIndex];
|
|
}
|
|
}
|
|
|
|
var create = true;
|
|
var allocateRest = false;
|
|
var reset = false;
|
|
allocateResource(newResource, expCat, create, allocateRest, reset); //true, false, false);
|
|
expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0;
|
|
|
|
var tr = $($event.target).parentsUntil('table').last().parent().find('thead tr:first');
|
|
console.log("tr: " + $(tr).html());
|
|
var thName = tr.find('th:eq(0)');
|
|
console.log("thName: " + $(thName).html());
|
|
newResource.width = thName.width() + 'px';
|
|
|
|
$scope.resizeFreezAng();
|
|
}
|
|
};
|
|
$scope.removeResource = function (scenarioId, resId, expCatId, teamId) {
|
|
if (confirm("Are you sure you want to remove this resource?")) {
|
|
var expCat = getExpCatById(scenarioId, expCatId, teamId);
|
|
var expCatTotal = getExpCatById(null, expCatId, null);
|
|
var rowVacation = getRowByType(2);
|
|
var rowTraining = getRowByType(3);
|
|
var resource = getResourceById(resId);
|
|
|
|
for (var i = 0; i < expCat.Resources.length; i++) {
|
|
if (expCat.Resources[i].Id == resId) {
|
|
for (var k = 0; k < expCat.QuantityValues.length; k++) {
|
|
//expCat.RestQuantity[k] += expCat.Resources[i].QuantityValues[k];
|
|
changeResourceValue(0, expCat.ScenarioId, expCat.ExpCatId, expCat.Resources[i].Id, k);
|
|
}
|
|
expCat.Resources.splice(i, 1);
|
|
|
|
applyCellChange(scenarioId, expCatId, 0, 0, 0, 0, resId, false, true);
|
|
expCatTotal.EmptyScenario = expCatTotal.Resources.length == 0;
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
if (rowVacation != null) {
|
|
rowVacation.QuantityValues[colIndex] -= resource.VacationQuantityValues[colIndex];
|
|
if (rowVacation.QuantityValues[colIndex] < 0)
|
|
rowVacation.QuantityValues[colIndex] = 0;
|
|
}
|
|
if (rowTraining != null) {
|
|
rowTraining.QuantityValues[colIndex] -= resource.TrainingQuantityValues[colIndex];
|
|
if (rowTraining.QuantityValues[colIndex] < 0)
|
|
rowTraining.QuantityValues[colIndex] = 0;
|
|
}
|
|
}
|
|
|
|
$scope.resizeFreezAng();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
$scope.checkResourceValue = function (data, scenarioId, expCatId, resId, teamId, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
changeResourceValue(newValue, scenarioId, expCatId, resId, teamId, colIndex);
|
|
return false;
|
|
};
|
|
$scope.getExpCatResources = function (expCat) {
|
|
var resources = [];
|
|
for (var i = 0; i < $scope.data.AllResources.length; i++) {
|
|
if ($scope.data.AllResources[i].ExpedentureCategoryId == expCat.ExpCatId && $scope.data.AllResources[i].IsActiveEmployee) {
|
|
var isProjectFound = false;
|
|
for (var j = 0; j < $scope.data.AllResources[i].ProjectIds.length; j++) {
|
|
|
|
if ($scope.data.AllResources[i].ProjectIds[j] == expCat.ProjectId &&
|
|
(!$scope.calendarFilters.GroupByTeam || $scope.data.AllResources[i].TeamId == expCat.TeamId))
|
|
{
|
|
isProjectFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isProjectFound) {
|
|
var isFound = false;
|
|
for (var j = 0; j < expCat.Resources.length; j++) {
|
|
if (expCat.Resources[j].Id == $scope.data.AllResources[i].Id &&
|
|
(!$scope.calendarFilters.GroupByTeam || expCat.Resources[j].TeamId == $scope.data.AllResources[i].TeamId)) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!isFound) {
|
|
for (var j = 0; j < resources.length; j++) {
|
|
if (resources[j].Id == $scope.data.AllResources[i].Id &&
|
|
(!$scope.calendarFilters.GroupByTeam || resources[j].TeamId == $scope.data.AllResources[i].TeamId)) {
|
|
isFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!isFound && $scope.data.AllResources[i].AssignedToTeam)
|
|
resources.push($scope.data.AllResources[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
$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;
|
|
}
|
|
}
|
|
|
|
onCMPreferencesItemClick($("#showButtomMode"));
|
|
onCMPreferencesItemClick($("#showTopMode"));
|
|
};
|
|
$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;
|
|
onCMPreferencesItemClick($("#groupTeam"));
|
|
$scope.getCalendar();
|
|
};
|
|
$scope.switchViewMode = function (value) {
|
|
var newValue = value != null ? value : !$scope.calendarFilters.IsViewModeMonth;
|
|
$scope.calendarFilters.IsViewModeMonth = newValue;
|
|
for (var i = 0; i < $scope.data.Headers.length; i++) {
|
|
if ($scope.data.Headers[i].IsMonth) {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = newValue;
|
|
$scope.data.Headers[i].CollapsedClass = newValue ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
} else {
|
|
$scope.data.Headers[i].Collapsed = newValue;
|
|
$scope.data.Headers[i].Show = !newValue;
|
|
}
|
|
}
|
|
$scope.resizeFreezAng();
|
|
onCMPreferencesItemClick($("#defaultView"));
|
|
};
|
|
$scope.switchBarMode = function () {
|
|
var newValue = !$scope.calendarFilters.IsBarMode;
|
|
$scope.calendarFilters.IsBarMode = newValue;
|
|
// update project rows CSS
|
|
for (var rowIndex = 0; rowIndex < $scope.data.Calendar.length; rowIndex++) {
|
|
if ($scope.data.Calendar[rowIndex].RowType == 0)
|
|
for (var colIndex = 0; colIndex < $scope.data.Headers.length; colIndex++) {
|
|
updateCSSClass($scope.data.Calendar[rowIndex], null, colIndex);
|
|
}
|
|
}
|
|
onCMPreferencesItemClick($("#capBarMode"));
|
|
};
|
|
|
|
$scope.changeCapacity = function (value) {
|
|
$scope.calendarFilters.ShowCapacity = value;
|
|
|
|
for (var i = 0; i < $scope.data.Calendar.length; i++) {
|
|
if ($scope.data.Calendar[i].RowType == 7) {
|
|
var expCatTotal = $scope.data.Calendar[i];
|
|
RefreshTotalSpreadVal(expCatTotal);
|
|
}
|
|
}
|
|
onCMPreferencesItemClick($("#selectOptions"));
|
|
};
|
|
|
|
$scope.anyUpdated = function () {
|
|
return ($scope.data2Update && $scope.data2Update.ChangedExpCats && $scope.data2Update.ChangedExpCats.length > 0);
|
|
};
|
|
$scope.onMonthHeaderClick = function (header) {
|
|
header.Collapsed = !header.Collapsed;
|
|
header.Show = !header.Show;
|
|
header.CollapsedClass = header.Collapsed ? $scope.CollapsedIcon : $scope.NonCollapsedIcon;
|
|
if (header.Weeks && header.Weeks.length > 0)
|
|
for (var 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;
|
|
}
|
|
for (var 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;
|
|
}
|
|
}
|
|
$scope.resizeFreezAng();
|
|
};
|
|
$scope.onParentNodeClick = function (row) {
|
|
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;
|
|
}
|
|
//else if (row.ExpCatId == null) {
|
|
// row.ScenarioCollapsed = !row.ScenarioCollapsed;
|
|
// row.CollapsedClass = row.ScenarioCollapsed ? $scope.ScenarioCollapsedIcon : $scope.ScenarioNonCollapsedIcon;
|
|
//}
|
|
|
|
setChildrenCollapsed(row, false, row.IsParentCollapsed);
|
|
};
|
|
$scope.CheckLock = function ($event, tableId, fieldId, url) {
|
|
//TODO: uncomment when name column UI will be fixed
|
|
if (CheckLock(event.target.id, tableId, fieldId))
|
|
document.location.href = url + '/' + fieldId;
|
|
};
|
|
}]);
|
|
|
|
controllers.controller('costSavingController', ['$scope', '$http', '$location', '$timeout', function ($scope, $http, $location, $timeout) {
|
|
$scope.CollapsedIcon = 'fa-plus-square';
|
|
$scope.NonCollapsedIcon = 'fa-minus-square';
|
|
$scope.Dec = Math.pow(10, 3);//precision decimals
|
|
$scope.data = null;
|
|
|
|
//$scope.id = $location.absUrl().substr($location.absUrl().lastIndexOf('ls/') + 3, 36);
|
|
$scope.filters = {
|
|
CollapsedClass: $scope.CollapsedIcon,
|
|
Show: false,
|
|
Months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
StartDate: null,
|
|
EndDate: null,
|
|
CostSavings: null,
|
|
IsCostChanging: false
|
|
};
|
|
$scope.$watch("filters.StartDate", function (newValue, oldValue) {
|
|
if (newValue != oldValue) {
|
|
$scope.getYears();
|
|
}
|
|
});
|
|
$scope.$watch("filters.EndDate", function (newValue, oldValue) {
|
|
if (newValue != oldValue) {
|
|
$scope.getYears();
|
|
}
|
|
});
|
|
$scope.$watch("filters.CostSavings", function (newValue, oldValue) {
|
|
if (newValue != oldValue && !$scope.filters.IsCostChanging) {
|
|
$scope.getYears();
|
|
}
|
|
$scope.filters.IsCostChanging = false;
|
|
});
|
|
$scope.setStartDate = function(value) {
|
|
$scope.filters.StartDate = value;
|
|
$scope.getYears();
|
|
};
|
|
$scope.getYears = function() {
|
|
$scope.data = null;
|
|
if ($scope.filters.StartDate == null || $scope.filters.StartDate.length == 0 ||
|
|
$scope.filters.EndDate == null || $scope.filters.EndDate.length == 0 ||
|
|
$scope.filters.CostSavings == null || $scope.filters.CostSavings.length == 0) {
|
|
return;
|
|
}
|
|
var sd = new Date($scope.filters.StartDate);
|
|
var ed = new Date($scope.filters.EndDate);
|
|
var cs = parseFloat($scope.filters.CostSavings);
|
|
if (isNaN(sd) || isNaN(ed) || isNaN(cs) || cs <= 0) {
|
|
return;
|
|
}
|
|
blockUI();
|
|
if (ed - sd > 3155760000000)
|
|
ed = new Date(sd + 3155760000000);
|
|
var sdYear = sd.getFullYear();
|
|
var edYear = ed.getFullYear();
|
|
var data = new Array();
|
|
var startMonth = sd.getMonth();
|
|
var endMonth = ed.getMonth();
|
|
var monthNum = 0;
|
|
for (var yearIndex = 0; yearIndex <= edYear - sdYear; yearIndex++) {
|
|
var arrYear = new Array();
|
|
arrYear.push(0);
|
|
for (var monthIndex = 0; monthIndex < 12; monthIndex++) {
|
|
if (yearIndex == 0 && monthIndex < startMonth) {// before start date
|
|
arrYear.push(null);
|
|
} else if (yearIndex == (edYear - sdYear) && monthIndex > endMonth) {// after end date
|
|
arrYear.push(null);
|
|
} else {// inside date range
|
|
arrYear.push(0);
|
|
monthNum++;
|
|
}
|
|
}
|
|
data.push({Year: sdYear+yearIndex, Costs: arrYear});
|
|
}
|
|
var dec = Math.pow(10, 3);//precision decimals
|
|
var itemCost = Math.round(cs * dec / monthNum) / dec;
|
|
for (var i = 0; i < data.length; i++) {
|
|
for (var j = 1; j < data[i].Costs.length; j++) {
|
|
if (data[i].Costs[j] != null) {
|
|
data[i].Costs[j] = itemCost;
|
|
data[i].Costs[0] += itemCost;
|
|
}
|
|
}
|
|
data[i].Costs[0] = Math.round(data[i].Costs[0] * dec) / dec;
|
|
}
|
|
$scope.data = data;
|
|
unblockUI();
|
|
};
|
|
|
|
$scope.onMonthHeaderClick = function () {
|
|
$scope.filters.Show = !$scope.filters.Show;
|
|
$scope.filters.CollapsedClass = $scope.filters.Show ? $scope.NonCollapsedIcon : $scope.CollapsedIcon;
|
|
};
|
|
|
|
$scope.onTxtBlur = function (txt) {
|
|
txt.$form.$submit();
|
|
};
|
|
|
|
$scope.watchKeyInput = function (t) {
|
|
//TODO: костыль, проблема во вложенных формах
|
|
// попробовать это https://github.com/vitalets/x-editable/issues/384
|
|
try {
|
|
//$.validator(t.$editable.editorEl);
|
|
t.$editable.editorEl.validate();
|
|
}
|
|
catch (ex)
|
|
{ }
|
|
|
|
$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#costSaving-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#costSaving-table').nextAll(":has(.editable:visible):first").find(".editable:visible:first");
|
|
t.$form.$submit();
|
|
tab2Cell.click();
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
$scope.checkValue = function (data, yearIndex, colIndex) {
|
|
var newValue = parseFloat(data);
|
|
if (isNaN(newValue))
|
|
newValue = 0;
|
|
if (newValue < 0) {
|
|
return "Value should not be less than zero";
|
|
}
|
|
if (colIndex == 0) {
|
|
$scope.data[yearIndex].Costs[0] = Math.round(newValue * $scope.Dec) / $scope.Dec;
|
|
var num = 0;
|
|
var j;
|
|
for (j = 1; j <= 12; j++) {
|
|
if ($scope.data[yearIndex].Costs[j] != null)
|
|
num++;
|
|
}
|
|
var val = Math.round(newValue * $scope.Dec / num) / $scope.Dec;
|
|
for (j = 1; j <= 12; j++) {
|
|
if ($scope.data[yearIndex].Costs[j] != null)
|
|
$scope.data[yearIndex].Costs[j] = val;
|
|
}
|
|
} else {
|
|
var oldValue = $scope.data[yearIndex].Costs[colIndex];
|
|
$scope.data[yearIndex].Costs[colIndex] = Math.round(newValue * $scope.Dec) / $scope.Dec;
|
|
$scope.data[yearIndex].Costs[0] += Math.round((newValue - oldValue) * $scope.Dec) / $scope.Dec;
|
|
if ($scope.data[yearIndex].Costs[0] < 0)
|
|
$scope.data[yearIndex].Costs[0] = 0;
|
|
}
|
|
var sum = 0;
|
|
for (var i = 0; i < $scope.data.length; i++) {
|
|
sum += $scope.data[i].Costs[0];
|
|
}
|
|
sum = Math.round(sum * 100) / 100;
|
|
$scope.filters.IsCostChanging = true;
|
|
$scope.filters.CostSavings = sum;
|
|
//required to be false by xeditable grid
|
|
return false;
|
|
};
|
|
}]); |