EnVisageOnline/Main/Source/EnVisage/Views/Scenarios/Details.cshtml

541 lines
28 KiB
Plaintext

@using EnVisage.Code
@using EnVisage.Models
@model ScenarioDetailModel
@{
ViewBag.Title = (!string.IsNullOrEmpty(Model.PartName) ? Model.PartName + ": " : "") + Model.ProjectName + " Scenario Details" + (string.IsNullOrEmpty(Model.Name) ? "" : " - " + Model.Name);
var userId = SecurityManager.GetUserPrincipal();
var scenarioUIManager = DependencyResolver.Current.GetService<ScenarioUIManager>();
var detailsModel = scenarioUIManager.CreateScenarioDetailsCalendarModel(userId, Model, ScenarioDetailsCalendarModel.ScenarioCalendarOpener.Details);
// need to init angular header controller
var jsmodel =new
{
id = Model.Id,
name = Model.Name,
parentId = Model.ParentId,
templateId = Model.TemplateId.Equals(Guid.Empty) ? (Guid?)null : Model.TemplateId,
startDate = (Model.StartDate ?? DateTime.Today).ToString("MM/dd/yyyy"),
endDate = (Model.EndDate ?? DateTime.Today).ToString("MM/dd/yyyy"),
growthScenario = Model.GrowthScenario,
expense = Model.FinInfo.TDDirectCosts,
revenue = Model.FinInfo.ProjectedRevenue ?? 0,
useLMMargin = Model.FinInfo.UseLMMargin,
grossMargin = Model.FinInfo.GrossMargin ?? 0,
lmMargin = Model.FinInfo.LMMargin ?? 0,
isActiveScenario = Model.IsActiveScenario,
isBottomUp = Model.IsBottomUp,
duration = Model.Duration,
dateForStartOfChanges = Model.FinInfo.DateForStartOfChanges.HasValue ? Model.FinInfo.DateForStartOfChanges.Value.ToString("MM/dd/yyyy") : string.Empty,
activeTab = Model.ActiveTab,
Model.UserDefinedFields,
DeadlineDate = Model.ProjectDeadline.HasValue ? Model.ProjectDeadline.Value.ToString("MM/dd/yyyy") : null,
projectHasDependencies = Model.ProjectHasDependencies,
startDateConstraint = Model.StartDateConstraintMs,
endDateConstraint = Model.EndDateConstraintMs,
workflowScheme = Model.WorkFlowScheme
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(jsmodel);
}
@section stylesheets
{
@Styles.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_STYLES_BASE_PATH, "prevu-scenariodetailsstyles"))
}
@section Scripts
{
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "flot-scripts"))
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "prevu-angularservices"))
@Scripts.Render(String.Format("{0}/{1}", Constants.C_BUNDLE_SCRIPTS_BASE_PATH, "prevu-scenariodetails"))
<script type="text/javascript">
var projectHasDependencies = @(Model.ProjectHasDependencies ? "true" : "false");
var projectId = "@(Model.ParentId.ToString())";
//fix modal force focus
$.fn.modal.Constructor.prototype.enforceFocus = function () {
var that = this;
$(document).on('focusin.modal', function (e) {
if ($(e.target).hasClass('select2-input')) {
return true;
}
if (that.$element[0] !== e.target && !that.$element.has(e.target).length) {
that.$element.focus();
}
});
};
var changesMade = false;
var autoclick = false;
function onDataChanged() {
changesMade = true;
}
function onDataSaved() {
changesMade = false;
}
function setupUnload() {
$(window).on('beforeunload', function () {
if (changesMade) {
return '@Resources.Messages.Scenario_Edit_Confirm';
}
});
}
emulateNavUrl = "/Scenarios";
init.push(function () {
setupUnload();
initScenarioFinInfoModel();
@if (Model.Id != Guid.Empty)
{
@:StartEdit('Scenario', '@Model.Id', "#btnDelete", "#btnsave", "erorMsgPlaceholder");
}
$('#visibilitydropdown').click(function (event) {
if (event.target == null || event.target.nodeName == null || (event.target.nodeName != 'A' && event.target.parentNode.nodeName != 'A')) {
event.stopPropagation();
}
});
$('#btnCopySubmit').click(function () {
if (!changesMade) {
if ($(this).parents('form').valid()) {
$(window).off('beforeunload');
}
return true;
} else {
bootbox.confirm({
message: '@Resources.Messages.Scenario_Edit_Confirm',
callback: function(result) {
if (result) {
$(this).parents('form').submit();
}
}
});
return false;
}
});
var tab = $.QueryString["ptab"];
if (tab == "copy")
$('#btnCopyTo').click();
if (tab == "Details")
$('#scenario-details-container a[href="#scenarios"]').tab('show');
$('#@Html.IdFor(x=> x.IsActiveScenario)').switcher({
on_state_content: 'Active',
off_state_content: 'Inactive'
}).parent().css('width', '100px');
$('#@Html.IdFor(x=> x.IsBottomUp)').switcher({
on_state_content: 'Bottom Up',
off_state_content: 'Top Down'
}).switcher("disable").parent().css("width", "100px");
var options = {
format: 'mm/dd/yyyy',
autoclose: true,
orientation: $('body').hasClass('right-to-left') ? "auto right" : 'auto auto',
startDate: '@Constants.MIN_SELECTABLE_DATE',
endDate: '@(!string.IsNullOrWhiteSpace(jsmodel.DeadlineDate) ? jsmodel.DeadlineDate : Constants.MAX_SELECTABLE_DATE)'
};
$('#bs-datepicker-scenario-range').datepicker(options);
$("#scenario-details-container .forselect2").select2({
allowClear: true,
minimumResultsForSearch: 5
});
initScenarioDetails();
onActivateScenarioDetails();
initProjectDependencies();
$(document).on('hide.bs.modal', '#copyTo', function (e) {
// skip modal hide event from datepickers
if ($(e.target).attr('id') !== 'copyTo')
return true; // close modal form
// check that form has been changed
if (typeof isCTDataChanged === 'function')
// if form has been changed
if (isCTDataChanged()) {
// ask user for confirmation of form close
bootbox.confirm("@Resources.Messages.Scenario_Create_Confirm", function (result) {
if (result) {
if (typeof resetCTDataChanged === 'function') {
resetCTDataChanged();
}
$('#copyTo').modal('hide');
}
});
return false; // DO NOT close modal form
}
return true; // close modal form
});
$(document).on('hide.bs.modal', '#createTemplate', function (e) {
if ($(e.target).attr('id') != 'createTemplate')
return true; // close modal form
if (typeof isTemplateDataChanged === 'function')
if (isTemplateDataChanged()) {
bootbox.confirm("@Resources.Messages.Template_Edit_UnsavedChanges", function (result) {
if (result) {
if (typeof resetTemplateDataChanged === 'function') {
resetTemplateDataChanged();
}
$('#createTemplate').modal('hide');
}
});
return false; // DO NOT close modal form
}
return true; // close modal form
});
$('#scenario-header').find('input[type=checkbox],input[type=text],select,textarea').on("change", function () {
if (typeof onDataChanged === 'function')
onDataChanged();
});
});
function initProjectDependencies(dataFunction) {
if (projectHasDependencies) {
var elem = $('div.date-dependency-constraints');
if (elem && elem.length) {
elem.scenarioDependencyInformer({
projectId: projectId,
dataUrl: '@Url.Action("GetDependencies", "Project")',
externalDataFunction: dataFunction && (typeof dataFunction === 'function') ? dataFunction : undefined,
});
}
$('#resolveConflictsContents').resolveForm({
projectId: projectId,
minStartDate: '@Constants.MIN_SELECTABLE_DATE',
maxEndDate: '@Constants.MAX_SELECTABLE_DATE'
});
$('#@Html.IdFor(x=> x.IsActiveScenario)').on('change', onScenarioStatusChanged);
$('#@Html.IdFor(x=> x.IsActiveScenario)').trigger('change');
}
}
function onScenarioStatusChanged(e) {
if (!projectHasDependencies)
return;
var newScenarioStatusIsActive = $('#@Html.IdFor(x=> x.IsActiveScenario)').is(':checked');
var elem = $('div.date-dependency-constraints');
if (newScenarioStatusIsActive)
elem.scenarioDependencyInformer('show');
else
elem.scenarioDependencyInformer('hide');
var scope = angular.element(document.getElementById('scenarioHeader')).scope();
setTimeout(function () {
scope.scenarioStatusChanged(newScenarioStatusIsActive);
}, 100);
};
function onCreateTemplateFailure(xhr) {
unblockUI();
showErrorModal('@Resources.Messages.Common_Oops', '@Resources.Messages.Common_YourRequestError');
}
function onCreateTemplateSuccess(data) {
unblockUI();
bootbox.alert('@Resources.Messages.Template_Create_Success', function () {
$('#createTemplate').modal('hide');
});
}
function onCopyToFailure(xhr) {
showErrorModal();
}
function onCopyToSuccess(result) {
handleAjaxResponse(result, function () {
var url = '@Url.Action("Details", new { Id = "VarId" , tab=string.Empty, backUrl=Model.BackUrl, backName=Model.BackName })';
document.location.href = url.replace('VarId', result.Content);
}, null, null, $('#copyToForm'));
}
var dependenciesValidated = false;
function isValid() {
if (!$('#scenario-header').valid())
return false;
if (dependenciesValidated) { return true; }
else {
var validateDepend = validateDependencies(function(valid, hasConflicts) {
if (hasConflicts) {
$('#resolveConflicts').modalDialogForm("show");
} else {
finishSavingAction();
}
});
return validateDepend; // dependencies form is opened
}
}
function showDetailsGraph() {
var scope = angular.element(document.getElementById('controller-details-grid')).scope();
setTimeout(scope.showGraph, 300);
}
function validateDependencies(fnCallback) {
if (!projectHasDependencies)
return true;
var isActive = $("#@Html.IdFor(t=>t.IsActiveScenario)").prop('checked');
if (!isActive)
return true;
var txtStartDate = $("#@Html.IdFor(t=>t.StartDate)");
var txtEndDate = $("#@Html.IdFor(t=>t.EndDate)");
$('#resolveConflictsContents').resolveForm('validate', [txtStartDate.val(), txtEndDate.val(), fnCallback]);
return false;
}
function submitResolveConflictsForm() {
var form = $('form[name=frmResolveConflicts]');
if (form.valid())
{
validateDependencies(function (valid) {
if (valid)
{
if ($('#resolveConflicts').is(':visible'))
{
// todo: serialize data to hidden field to pass it to server on save
$('#resolveConflicts').modalDialogForm("hide");
finishSavingAction();
}
}
});
}
return false;
}
function finishSavingAction() {
var data = $('#resolveConflictsContents').data('resolveForm').getData();
triggerBroadcastFromRootScope('dependenciesvalidated', data);
dependenciesValidated = true;
$('#btnsave').trigger("click");
}
</script>
}
<div id="erorMsgPlaceholder"></div>
<div id="scenarioHeader" ng-controller="scenarioHeaderController" ng-init="init(@json)">
<div class="alert alert-warning" id="dates-constraints-warning" ng-cloak ng-show="DateConstraintsWarningVisible" style="margin-bottom: 6px;">
Scenario dates violate project's dependencies date constraints
</div>
<div class="tab-content tab-content-bordered" id="scenario-details-container">
<ul id="uidemo-tabs-default-demo" class="nav nav-tabs">
<li ng-class="getTabClass('general')">
<a href="#general" data-toggle="tab" ng-disabled="HeaderIsChanged">Scenario Header<span class="badge badge-primary"></span></a>
</li>
<li ng-class="getTabClass('scenarios')">
<a href="#scenarios" data-toggle="tab" ng-disabled="IsChanged && !HeaderIsChanged" onclick="showDetailsGraph();">Scenario Details<span class="badge badge-primary"></span></a>
</li>
<li ng-class="getTabClass('rateTable')">
<a href="#rateTable" data-toggle="tab" ng-disabled="IsChanged">Rates<span class="badge badge-primary"></span></a>
</li>
<li ng-class="getTabClass('notes')">
<a href="#notes" data-toggle="tab" ng-disabled="IsChanged">Notes<span class="badge badge-primary"></span></a>
</li>
</ul>
<div class="tab-pane fade @(string.IsNullOrEmpty(Model.ActiveTab) || Model.ActiveTab == "general" ? "in active" : string.Empty)" id="general">
<form style="border:0;" id="scenario-header" editable-form>
@Html.HiddenFor(t => t.Id)
@Html.HiddenFor(t => t.ParentId)
@Html.HiddenFor(t => t.BackUrl)
@Html.HiddenFor(t => t.BackName)
<div class="panel-body" style="border: 0;" id="headerController">
<fieldset id="fsHead" class="form-group-margin">
<div class="row">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-8">
<span class="text-bold text-lg">Scenario Information</span>
@Html.CheckBoxFor(model => model.IsActiveScenario, new { @class = "form-control", ng_model = "changedData.isActiveScenario", ng_change = "modelChanged()" })
</div>
<div class="col-sm-4">
<a target="_blank" href="@Url.Action("Edit", "Project", new {id = Model.ProjectId})" class="btn btn-primary pull-right">@Resources.Buttons.Scenario_OpenProject</a>
</div>
</div>
<hr/>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group no-margin-hr">
@Html.LabelFor(model => model.ProjectName, new { @class = "control-label" })
@Html.TextBoxFor(model => model.ProjectName, new { @class = "form-control", @readonly = "readonly" })
</div>
</div>
@if (!string.IsNullOrWhiteSpace(Model.PartName))
{
<div class="col-sm-6">
<div class="form-group no-margin-hr">
@Html.LabelFor(model => model.PartName, new { @class = "control-label" })
@Html.TextBoxFor(model => model.PartName, new { @class = "form-control", @readonly = "readonly" })
</div>
</div>
}
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group no-margin-hr">
@Html.LabelFor(model => model.Name, new { @class = "control-label" })
@Html.TextBoxFor(model => model.Name, new { @class = "form-control", ng_model = "changedData.name", ng_change = "modelChanged()" })
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="col-sm-6">
<div class="form-group no-margin-hr">
<label class="control-label">Scenario Dates</label>
<div class="input-daterange input-group" id="bs-datepicker-scenario-range">
@Html.TextBoxFor(x => x.StartDate, new { @class = "form-control", ng_model = "changedData.startDate", ng_change = "modelChanged()", ng_model_options = "{ updateOn: 'change' }" })
<div class="input-group-addon">to</div>
@Html.TextBoxFor(x => x.EndDate, new { @class = "form-control", ng_model = "changedData.endDate", ng_change = "modelChanged()", ng_model_options = "{ updateOn: 'change' }" })
</div>
@Html.ValidationMessageFor(model => model.StartDate)
@Html.ValidationMessageFor(model => model.EndDate)
@if (Model.ProjectDeadline.HasValue)
{
<div><i>@Html.LabelFor(x => x.ProjectDeadline) @Html.DisplayFor(x => x.ProjectDeadline)</i></div>
}
<div class="date-dependency-constraints"></div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<div class="form-group no-margin-hr">
@Html.LabelFor(x => x.TemplateId, new { @class = "control-label" })
<select id="@Html.IdFor(x=> x.TemplateId)"
name="@Html.NameFor(x=> x.TemplateId)"
class="form-control forselect2" ng-model="changedData.templateId" ng-change="modelChanged()"
data-val="true" data-val-required="The Template field is required."
ng-disabled="changedData.isBottomUp">
@Utils.GetTemplates(Model.TemplateId, Model.IsBottomUp)
</select>
@Html.ValidationMessageFor(x => x.TemplateId)
</div>
</div>
<div class="col-sm-2">
<div class="form-group no-margin-hr">
<div>
@Html.LabelFor(x => x.IsBottomUp, new { @class = "control-label" })
</div>
@Html.CheckBoxFor(x => x.IsBottomUp, new { @class = "control-label" })
</div>
</div>
<div class="col-sm-3">
<div class="form-group no-margin-hr">
@Html.LabelFor(x => x.Duration, new { @class = "control-label" })
@Html.TextBoxFor(x => x.Duration, new { disabled = "disabled", @class = "form-control", ng_model = "changedData.duration" })
</div>
</div>
@{
IEnumerable<SelectListItem> workFlowList = Utils.GetWorkFlowSchemas(WorkFlowArea.Scenarios.GetHashCode(), new Guid(User.Identity.GetID()));
if (workFlowList.Count() > 1)
{
<div class="col-sm-3">
<div class="form-group no-margin-hr">
@Html.LabelFor(x => x.WorkFlowScheme, new { @class = "control-label" })
@Html.DropDownListFor(model => model.WorkFlowScheme, workFlowList, new { @class = "form-control forselect2", ng_model = "changedData.workflowScheme", ng_change = "modelChanged()" })
</div>
</div>
}
}
</div>
<div class="row">
@if (Model.WorkFlowState != null)
{
<div class="col-sm-3">
<div class="form-group no-margin-hr">
@Html.LabelFor(x => x.WorkFlowState, new { @class = "control-label" })
@Html.TextBoxFor(x => x.WorkFlowState, new { disabled = "disabled", @class = "form-control" })
</div>
</div>
}
</div>
</fieldset>
@Html.EditorFor(x => x.FinInfo)
@if (Model.UserDefinedFields.Count > 0)
{
<fieldset id="fsProjectUDFs">
<legend class="text-bold small-bottom-margin" id="detailsUdfLegend">@Resources.Labels.Common_UserDefinedFields</legend>
<div class="row">
@Html.EditorFor(t => t.UserDefinedFields, new { @class = "form-control" })
</div>
</fieldset>
}
@Html.ValidationSummary(false, Resources.Messages.Scenario_Validation_Common, new { id = "header-val-summary" })
<div class="form-group" style="margin-bottom: 0;">
<div class="col-sm-offset-3 col-sm-9">
<a class="btn btn-primary" href='@Model.BackUrl'><i class="fa fa-backward"></i> @Resources.Buttons.Common_BackTo_ @Model.BackName</a>
<button id="btnCopyTo" type="button" class="btn btn-warning lockable" data-toggle="modal" data-target="#copyTo">@Resources.Buttons.Common_Copy</button>
<button type="button" class="btn btn-warning lockable" data-toggle="modal" data-target="#createTemplate">@Resources.Buttons.Common_CreateTemplate</button>
<button type="button" class="btn btn-success lockable" id="btnAdjustFinancials" ng-disabled="!canAdjustFinancial()" ng-click="adjustFinancial()">
<i class="fa fa-adjust"></i> @Resources.Buttons.Common_AdjustFinancials
</button>
<button type="button" class="btn btn-success" id="btnsave" ng-disabled="!IsChanged" ng-click="recalculateCalendar()">
<i class="fa fa-save"></i> @Resources.Buttons.Common_SubmitChanges
</button>
</div>
</div>
</div>
</form>
</div>
<div class="tab-pane @(Model.ActiveTab == "scenarios" ? "in active" : string.Empty)" id="scenarios" data-section="scenarioCalendar">
@{
Html.RenderPartial("_scenarioCalendar", detailsModel);
}
</div>
<div class="tab-pane fade @(Model.ActiveTab == "rateTable" ? "in active" : string.Empty)" id="rateTable">
@Html.Partial("_rates", Model.RatesModel)
</div>
<div class="tab-pane fade @(Model.ActiveTab == "notes" ? "in active" : string.Empty)" id="notes">
@Html.Partial("_notes", Model.Id)
</div>
</div>
</div>
<div id="createTemplate" class="modal fade" tabindex="-2" role="dialog" style="display: none;" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content" id="createTemplateModal">
@Html.Partial("_createTemplateModal", new ScenarioTemplateCreationModel(Model))
</div> <!-- / .modal-content -->
</div> <!-- / .modal-dialog -->
</div> <!-- /.modal -->
<!-- / Modal -->
<!-- Modal -->
<div id="copyTo" class="modal fade" tabindex="-1" role="dialog" style="display: none;" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content" id="copyToModal">
@Html.Partial("_copyToModal", new ScenarioCopyModel
{
TargetProjectId = Model.ParentId,
ScenarioId = Model.Id,
TargetStatus = ScenarioStatus.Inactive,
hasCostSavings = Model.FinInfo != null && Model.FinInfo.CostSaving != null && Model.FinInfo.CostSaving.CostSavingStartDate.HasValue,
Projects = Model.Projects
})
</div> <!-- / .modal-content -->
</div> <!-- / .modal-dialog -->
</div> <!-- /.modal -->
<div id="resolveConflicts" class="modal fade" role="dialog" style="display: none;" data-backdrop="static">
<div class="modal-dialog" style="width:730px;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
<h4 class="modal-title">Resolve Project Dependency Conflicts</h4>
</div>
<div class="modal-body" style="padding: 0 15px;">
<form name="frmResolveConflicts" id="frmResolveConflicts" action="#" method="post">
<div class="panel-body form-horizontal" id="resolveConflictsContents">
</div>
@Html.ValidationSummary()
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" onclick="return submitResolveConflictsForm()">@Resources.Buttons.Common_Ok</button>
<button type="button" class="btn btn-default" data-dismiss="modal">@Resources.Buttons.Common_Cancel</button>
</div>
</div>
</div>
</div>