1787 lines
89 KiB
Plaintext
1787 lines
89 KiB
Plaintext
@page "/pcrb/{planNumber}"
|
|
@page "/pcrb/new"
|
|
@using System.Text
|
|
|
|
@inject ISnackbar snackbar
|
|
@inject IPCRBService pcrbService
|
|
@inject IUserService userService
|
|
@inject IMemoryCache cache
|
|
@inject IConfiguration config
|
|
@inject IDialogService dialogService
|
|
@inject IApprovalService approvalService
|
|
@inject NavigationManager navigationManager
|
|
@inject MesaFabApprovalAuthStateProvider authStateProvider
|
|
|
|
<PageTitle>PCRB @planNumber</PageTitle>
|
|
|
|
<MudPaper Class="p-2 m-2 d-flex flex-row justify-content-between">
|
|
<MudIconButton Icon="@Icons.Material.Filled.ChevronLeft"
|
|
Variant="Variant.Outlined"
|
|
Color="Color.Dark"
|
|
OnClick="@ReturnToAllPcrbs"
|
|
Size="Size.Large" />
|
|
<MudText Typo="Typo.h3" Align="Align.Center">PCRB @planNumber</MudText>
|
|
<MudPaper Height="100%" Width="0.1%" Square="true" />
|
|
</MudPaper>
|
|
|
|
@if (pcrb is not null) {
|
|
<MudTimeline Class="mt-2 pt-2" TimelineOrientation="TimelineOrientation.Horizontal"
|
|
TimelinePosition="TimelinePosition.Bottom">
|
|
@for (int i = 0; i < PCRB.Stages.Length; i++) {
|
|
Color color;
|
|
if (pcrb.CurrentStep > i || pcrb.CurrentStep == (PCRB.Stages.Length - 1)) {
|
|
color = Color.Success;
|
|
} else if (pcrb.CurrentStep == i) {
|
|
color = Color.Info;
|
|
} else {
|
|
color = Color.Dark;
|
|
}
|
|
|
|
string stageName = PCRB.Stages[i];
|
|
|
|
<MudTimelineItem Color="@color" Variant="Variant.Filled">
|
|
<MudText Align="Align.Center" Color="@color">@stageName</MudText>
|
|
</MudTimelineItem>
|
|
}
|
|
</MudTimeline>
|
|
|
|
bool pcrbIsSubmitted = pcrb.CurrentStep > 0 && pcrb.InsertTimeStamp > DateTimeUtilities.MIN_DT;
|
|
bool pcrbIsComplete = pcrb.ClosedDate < DateTimeUtilities.MAX_DT && pcrb.CurrentStep == (PCRB.Stages.Length - 1);
|
|
bool userIsOriginator = pcrb.OwnerID == authStateProvider.CurrentUser?.UserID;
|
|
bool userIsAdmin = authStateProvider.CurrentUser is null ? false : authStateProvider.CurrentUser.IsAdmin;
|
|
bool userIsApprover = UserIsApprover();
|
|
|
|
@if ((!pcrbIsSubmitted && !string.IsNullOrWhiteSpace(pcrb.Title) && (userIsOriginator || userIsAdmin)) ||
|
|
(!pcrbIsSubmitted && pcrb.PlanNumber > 0 && (userIsOriginator || userIsAdmin))) {
|
|
<MudPaper Outlined="true"
|
|
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-center"
|
|
Elevation="10">
|
|
@if (!pcrbIsSubmitted && !string.IsNullOrWhiteSpace(pcrb.Title) && (userIsOriginator || userIsAdmin)) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
Disabled="@saveInProcess"
|
|
OnClick=SavePCRB>
|
|
@if (saveInProcess) {
|
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
|
<MudText>Processing</MudText>
|
|
} else {
|
|
<MudText>Save</MudText>
|
|
}
|
|
</MudButton>
|
|
}
|
|
@if (!pcrbIsSubmitted && pcrb.PlanNumber > 0 && (userIsOriginator || userIsAdmin)) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Secondary"
|
|
Disabled="@deleteInProcess"
|
|
OnClick=DeletePCRB>
|
|
@if (deleteInProcess) {
|
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
|
<MudText>Processing</MudText>
|
|
} else {
|
|
<MudText>Delete</MudText>
|
|
}
|
|
</MudButton>
|
|
}
|
|
</MudPaper>
|
|
}
|
|
|
|
@if (!pcrbIsSubmitted && GetIncompleteFields().Count() > 0) {
|
|
IEnumerable<string> incompleteFields = GetIncompleteFields();
|
|
StringBuilder errorBuilder = new();
|
|
errorBuilder.Append($"Incomplete fields: {incompleteFields.First()}");
|
|
for (int i = 1; i < incompleteFields.Count(); i++) {
|
|
errorBuilder.Append($", {incompleteFields.ElementAt(i)}");
|
|
}
|
|
|
|
<MudPaper Outlined Class="p-2 m-2">
|
|
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.h6">
|
|
@errorBuilder.ToString()
|
|
</MudText>
|
|
</MudPaper>
|
|
}
|
|
|
|
<MudPaper Outlined="true"
|
|
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-start"
|
|
Elevation="10">
|
|
<MudTextField @bind-Value=pcrb.PlanNumber
|
|
Text="@pcrb.PlanNumber.ToString()"
|
|
T="int"
|
|
Disabled="true"
|
|
Label="Change#"
|
|
Required
|
|
Variant="Variant.Outlined" />
|
|
<MudTextField @bind-Value=pcrb.Title
|
|
Text="@pcrb.Title"
|
|
Disabled="@(pcrbIsSubmitted)"
|
|
T="string"
|
|
AutoGrow
|
|
AutoFocus
|
|
Immediate
|
|
Clearable
|
|
Required
|
|
Variant="Variant.Outlined"
|
|
Label="Project Name" />
|
|
<MudSelect T="User"
|
|
Label="Originator"
|
|
Variant="Variant.Outlined"
|
|
Required
|
|
Clearable
|
|
AnchorOrigin="Origin.BottomCenter"
|
|
ToStringFunc="@UserToNameConverter"
|
|
Disabled=@(pcrbIsSubmitted)
|
|
@bind-Value=@selectedOwner>
|
|
@foreach (User user in allActiveUsers.OrderBy(u => u.LastName)) {
|
|
<MudSelectItem T="User" Value="@(user)" />
|
|
}
|
|
</MudSelect>
|
|
<MudSelect T="string"
|
|
Variant="Variant.Outlined"
|
|
Required
|
|
Clearable
|
|
AnchorOrigin="Origin.BottomCenter"
|
|
Disabled="@pcrbIsSubmitted"
|
|
@bind-Value="@pcrb.ChangeLevel"
|
|
Text="@pcrb.ChangeLevel"
|
|
Label="Change Level">
|
|
<MudSelectItem Value="@("Global - Class 1")" />
|
|
<MudSelectItem Value="@("Other Site + Mesa - Class 2")" />
|
|
<MudSelectItem Value="@("Mesa - Class 3")" />
|
|
</MudSelect>
|
|
<MudCheckBox Disabled="@pcrbIsSubmitted"
|
|
Color="Color.Tertiary"
|
|
@bind-Value=pcrb.IsITAR
|
|
Label="Export Controlled"
|
|
LabelPosition="LabelPosition.Start" />
|
|
<MudTextField Disabled="true"
|
|
T="string"
|
|
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.InsertTimeStamp)"
|
|
Label="Submit Date"
|
|
Variant="Variant.Outlined" />
|
|
<MudTextField Disabled="true"
|
|
T="string"
|
|
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.LastUpdateDate)"
|
|
Label="Last Update"
|
|
Variant="Variant.Outlined" />
|
|
</MudPaper>
|
|
|
|
<MudPaper Outlined="true"
|
|
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-start"
|
|
Elevation="10">
|
|
<MudTextField @bind-Value=pcrb.ChangeDescription
|
|
Text="@pcrb.ChangeDescription"
|
|
Disabled="@(pcrbIsSubmitted)"
|
|
T="string"
|
|
AutoGrow
|
|
Immediate
|
|
Clearable
|
|
Required
|
|
Variant="Variant.Outlined"
|
|
Label="Description Of Change" />
|
|
<MudTextField @bind-Value=pcrb.ReasonForChange
|
|
Text="@pcrb.ReasonForChange"
|
|
Disabled="@(pcrbIsSubmitted)"
|
|
T="string"
|
|
AutoGrow
|
|
Immediate
|
|
Clearable
|
|
Required
|
|
Variant="Variant.Outlined"
|
|
Label="Reason For Change" />
|
|
</MudPaper>
|
|
|
|
@if (pcrb.PlanNumber > 0 && pcrb.CurrentStep > 0) {
|
|
<MudExpansionPanels MultiExpansion="true">
|
|
@for (int i = 1; i < 4; i++) {
|
|
int current_i = i;
|
|
|
|
bool previousStageSubmitted = current_i == 1;
|
|
|
|
IEnumerable<Approval> previousStageApprovals = approvals.Where(a => a.Step == (current_i - 1));
|
|
int previousStageUnsubmittedApprovalCount = previousStageApprovals.Where(a => a.AssignedDate <= DateTimeUtilities.MIN_DT).Count();
|
|
int previousStagePendingApprovalCount = previousStageApprovals.Where(a => a.ItemStatus == 0 && a.AssignedDate > DateTimeUtilities.MIN_DT).Count();
|
|
int previousStageApprovedApprovalCount = previousStageApprovals.Where(a => a.ItemStatus == 1).Count();
|
|
int previousStageDeniedApprovalCount = previousStageApprovals.Where(a => a.ItemStatus == -1).Count();
|
|
|
|
bool previousStageApproved = current_i == 1;
|
|
if (!previousStageApproved) {
|
|
if (previousStageApprovals.Count() > 0 && previousStageUnsubmittedApprovalCount == 0 &&
|
|
previousStagePendingApprovalCount == 0 && previousStageApprovedApprovalCount >= 4)
|
|
previousStageApproved = true;
|
|
}
|
|
|
|
if (!previousStageSubmitted) {
|
|
if (((previousStagePendingApprovalCount > 0 || previousStageApprovedApprovalCount >= 4) &&
|
|
previousStageDeniedApprovalCount < previousStageApprovals.Count()) || previousStageApproved)
|
|
previousStageSubmitted = true;
|
|
}
|
|
|
|
IEnumerable<Approval> currentStageApprovals = approvals.Where(a => a.Step == current_i);
|
|
int currentStageUnsubmittedApprovalCount = currentStageApprovals.Where(a => a.AssignedDate <= DateTimeUtilities.MIN_DT).Count();
|
|
int currentStagePendingApprovalsCount = currentStageApprovals.Where(a => a.ItemStatus == 0 && a.AssignedDate > DateTimeUtilities.MIN_DT).Count();
|
|
int currentStageApprovedApprovalsCount = currentStageApprovals.Where(a => a.ItemStatus == 1).Count();
|
|
int currentStageDeniedApprovalsCount = currentStageApprovals.Where(a => a.ItemStatus == -1).Count();
|
|
|
|
bool currentStageApproved = currentStageApprovedApprovalsCount >= 4 && currentStageUnsubmittedApprovalCount == 0 &&
|
|
currentStagePendingApprovalsCount == 0;
|
|
bool currentStageSubmitted = (currentStageApprovals.Count() > 0 && currentStagePendingApprovalsCount > 0 &&
|
|
currentStageDeniedApprovalsCount < currentStageApprovals.Count()) || currentStageApproved;
|
|
|
|
IEnumerable<PCRBAttachment> currentStageAttachments = attachments.Where(a => a.Step == current_i);
|
|
|
|
bool previousStageHasOpenGatedActionItems = actionItems.Where(a => a.Step == (current_i - 1) &&
|
|
a.ClosedStatus == false &&
|
|
a.Gating == true).Count() > 0;
|
|
|
|
IEnumerable<PCRBActionItem> currentStageActionItems = actionItems.Where(a => a.Step == current_i);
|
|
int currentStagePendingActionItemCount = currentStageActionItems.Where(a => a.ClosedStatus == false).Count();
|
|
|
|
bool allActionItemsComplete = current_i < 3 || actionItems.Where(a => a.ClosedStatus == false).Count() == 0;
|
|
bool actionItemsAreComplete = actionItems.Where(a => a.ClosedStatus == false).Count() == 0;
|
|
|
|
bool attachmentsMissing = currentStageAttachments.Count() == 0;
|
|
bool actionItemsIncomplete = current_i < 3 && currentStagePendingActionItemCount > 0;
|
|
bool affectedDocumentsIncomplete = current_i == 3 && pcr3Documents.Where(d => d.CompletedByID <= 0).Count() > 0;
|
|
bool approvalsIncomplete = currentStageApprovals.Count() > 0 && currentStagePendingApprovalsCount > 0;
|
|
|
|
<MudExpansionPanel Class="m-2" Expanded="@(previousStageSubmitted && (attachmentsMissing || actionItemsIncomplete ||
|
|
affectedDocumentsIncomplete || !currentStageSubmitted || approvalsIncomplete))">
|
|
<TitleContent>
|
|
<MudText Typo="Typo.h4" Align="Align.Center">@($"PCR {current_i}")</MudText>
|
|
@if (previousStageSubmitted && (attachmentsMissing || actionItemsIncomplete ||
|
|
affectedDocumentsIncomplete || approvalsIncomplete)) {
|
|
StringBuilder sb = new();
|
|
int missingSectionCount = 0;
|
|
sb.Append("Incomplete sections: ");
|
|
if (attachmentsMissing) {
|
|
missingSectionCount++;
|
|
sb.Append("upload PCRB");
|
|
}
|
|
if (actionItemsIncomplete) {
|
|
if (missingSectionCount > 0) sb.Append(", ");
|
|
missingSectionCount++;
|
|
sb.Append("action items incomplete");
|
|
}
|
|
if (affectedDocumentsIncomplete) {
|
|
if (missingSectionCount > 0) sb.Append(", ");
|
|
missingSectionCount++;
|
|
sb.Append("affected documents not closed");
|
|
}
|
|
if (approvalsIncomplete) {
|
|
if (missingSectionCount > 0) sb.Append(", ");
|
|
sb.Append("approvals still pending");
|
|
}
|
|
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.h6">
|
|
@sb.ToString()
|
|
</MudText>
|
|
}
|
|
@if (actionItemsIncomplete) {
|
|
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.subtitle1">
|
|
All actions must be completed before PCR3 is submitted for approval
|
|
</MudText>
|
|
}
|
|
@if (previousStageHasOpenGatedActionItems) {
|
|
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.subtitle1">
|
|
This stage cannot be submitted for approval until previous stage's gated action items are closed
|
|
</MudText>
|
|
}
|
|
</TitleContent>
|
|
<ChildContent>
|
|
<MudPaper Outlined="true"
|
|
Class="p-2 m-2 d-flex flex-column justify-start">
|
|
|
|
<MudText Typo="Typo.h5" Align="Align.Center">Supporting Documents</MudText>
|
|
|
|
<MudTable Items="@attachments.Where(a => a.Step == current_i)"
|
|
Class="m-2"
|
|
Striped="true"
|
|
SortLabel="Sort By"
|
|
Hover="true">
|
|
<ToolBarContent>
|
|
<MudStack Row="true" Justify="Justify.Center" Spacing="1" Style="width: 100%">
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageSubmitted && !currentStageSubmitted) {
|
|
@if (current_i == 1) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
Href="https://plm.intra.infineon.com/Windchill/netmarkets/jsp/ext/infineon/dcoidreleased.jsp?obid=OR:wt.doc.WTDocument:1477717325"
|
|
Target="_blank">
|
|
Download PCRB Template
|
|
</MudButton>
|
|
}
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
OnClick="@((e) => UploadAttachment(current_i))"
|
|
Disabled="@attachmentUploadInProcess"
|
|
StartIcon="@Icons.Material.Filled.AttachFile">
|
|
@if (attachmentUploadInProcess) {
|
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
|
<MudText>Processing</MudText>
|
|
} else {
|
|
<MudText>Upload Document</MudText>
|
|
}
|
|
</MudButton>
|
|
}
|
|
</MudStack>
|
|
</ToolBarContent>
|
|
<HeaderContent>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBAttachment, object>(x=>x.FileName)">
|
|
File Name
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBAttachment, object>(x=>x.UploadedBy is null ? string.Empty : x.UploadedBy.LastName)">
|
|
Uploaded By
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBAttachment, object>(x=>x.UploadDateTime)">
|
|
Uploaded Date
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd DataLabel="File Name">
|
|
<a href="@(@$"{config["FabApprovalApiBaseUrl"]}/pcrb/attachmentFile?path={context.Path}&fileName={context.FileName}")"
|
|
download="@(context.FileName)"
|
|
target="_top">
|
|
@context.FileName
|
|
</a>
|
|
</MudTd>
|
|
<MudTd DataLabel="Uploaded By">@(context.UploadedBy is null ? string.Empty : context.UploadedBy.GetFullName())</MudTd>
|
|
<MudTd DataLabel="Uploaded Date">@context.UploadDateTime.ToString("yyyy-MM-dd HH:mm")</MudTd>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageSubmitted && !currentStageSubmitted) {
|
|
<MudTd Style="text-align:center;">
|
|
<MudButton Color="Color.Secondary"
|
|
Variant="Variant.Filled"
|
|
Disabled="@deleteAttachmentInProcess"
|
|
OnClick="@((e) => DeleteAttachment(context))">
|
|
@if (deleteAttachmentInProcess) {
|
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
|
<MudText>Deleting</MudText>
|
|
} else {
|
|
<MudText>Delete</MudText>
|
|
}
|
|
</MudButton>
|
|
</MudTd>
|
|
}
|
|
</RowTemplate>
|
|
</MudTable>
|
|
|
|
<MudDivider DividerType="DividerType.Middle" Class="my-1" />
|
|
|
|
@if (current_i < 3) {
|
|
<MudText Typo="Typo.h5" Align="Align.Center">Action Items</MudText>
|
|
@if (!currentStageSubmitted && actionItems.Where(a => a.Step == current_i).Count() == 0) {
|
|
<MudText Typo="Typo.h6" Color="Color.Secondary" Align="Align.Center">
|
|
Add action items if applicable
|
|
</MudText>
|
|
}
|
|
<MudTable Items="@actionItems.Where(a => a.Step == current_i)"
|
|
Class="m-2"
|
|
Striped="true"
|
|
SortLabel="Sort By"
|
|
Hover="true">
|
|
<ToolBarContent>
|
|
<MudStack Row="true" Justify="Justify.Center" Spacing="1" Style="width: 100%">
|
|
@if (previousStageSubmitted && !currentStageSubmitted) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
OnClick="@((e) => CreateNewActionItem(current_i))">
|
|
<MudText>New Action Item</MudText>
|
|
</MudButton>
|
|
}
|
|
@if (currentStagePendingActionItemCount > 0) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
Disabled="@processing"
|
|
OnClick="@((e) => CloseAllActionItems(current_i))">
|
|
<MudText>Complete All Actions</MudText>
|
|
</MudButton>
|
|
}
|
|
</MudStack>
|
|
</ToolBarContent>
|
|
<HeaderContent>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBActionItem, object>(x=>x.Name)">
|
|
Action
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBActionItem, object>(x=>x.ResponsiblePerson is null ?
|
|
string.Empty :
|
|
x.ResponsiblePerson.LastName)">
|
|
Responsible Person
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
Gating
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBActionItem, object>(x=>x.ClosedDate is null ?
|
|
DateTimeUtilities.MAX_DT :
|
|
x.ClosedDate)">
|
|
Closed Date
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd DataLabel="Action">@context.Name</MudTd>
|
|
<MudTd DataLabel="Responsible Person">
|
|
@(context.ResponsiblePerson is null ? string.Empty : context.ResponsiblePerson.GetFullName())
|
|
</MudTd>
|
|
<MudTd DataLabel="Gating">@(context.Gating ? "Yes" : "No")</MudTd>
|
|
<MudTd DataLabel="Closed Date">
|
|
@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)
|
|
</MudTd>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && context.ClosedByID == 0) {
|
|
<MudTd Style="text-align:center;">
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
OnClick="@((e) => UpdateActionItem(context))">
|
|
<MudText>Update</MudText>
|
|
</MudButton>
|
|
@if (!currentStageSubmitted) {
|
|
<MudButton Color="Color.Secondary"
|
|
Variant="Variant.Filled"
|
|
OnClick="@((e) => DeleteActionItem(context))">
|
|
<MudText>Delete</MudText>
|
|
</MudButton>
|
|
}
|
|
</MudTd>
|
|
}
|
|
</RowTemplate>
|
|
</MudTable>
|
|
} else {
|
|
int openPCR3Documents = pcr3Documents.Where(d => d.CompletedByID <= 0).Count();
|
|
|
|
<MudText Typo="Typo.h5" Align="Align.Center">Affected Documents</MudText>
|
|
<MudTable Items="@pcr3Documents"
|
|
Class="m-2"
|
|
Striped="true"
|
|
SortLabel="Sort By"
|
|
Hover="true">
|
|
<HeaderContent>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCR3Document, object>(x=>x.DocType)">
|
|
Document Type
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCR3Document, object>(x=>x.DocNumbers)">
|
|
Document Numbers
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
Comments
|
|
</MudTh>
|
|
<MudTh>
|
|
ECN#
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCR3Document, object>(x=>x.CompletedDate >= DateTimeUtilities.MAX_DT ?
|
|
DateTimeUtilities.MAX_DT :
|
|
x.CompletedDate)">
|
|
Closed Date
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCR3Document, object>(x=>x.CompletedBy is null ?
|
|
string.Empty :
|
|
x.CompletedBy.LastName)">
|
|
Closed By
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd DataLabel="Document Type">@context.DocType</MudTd>
|
|
<MudTd DataLabel="Document Numbers">@context.DocNumbers</MudTd>
|
|
<MudTd DataLabel="Comments">@context.Comment</MudTd>
|
|
<MudTd DataLabel="ECN#">
|
|
@if (string.IsNullOrWhiteSpace(context.GetEcnNumberString())) {
|
|
context.GetEcnNumberString();
|
|
} else {
|
|
<MudLink
|
|
Href=@($"{config["OldFabApprovalUrl"]}/ECN/Edit?IssueID={context.GetEcnNumberString()}")
|
|
Target="_blank">
|
|
@context.GetEcnNumberString()
|
|
</MudLink>
|
|
}
|
|
</MudTd>
|
|
<MudTd DataLabel="Closed Date">@(DateTimeUtilities.GetDateAsStringMaxDefault(context.CompletedDate))</MudTd>
|
|
<MudTd DataLabel="Closed By">
|
|
@(context.CompletedBy is null ? string.Empty : context.CompletedBy.GetFullName())
|
|
</MudTd>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && !currentStageSubmitted) {
|
|
<MudTd Style="text-align:center;">
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
OnClick="@((e) => UpdatePCR3Document(context))">
|
|
<MudText>Update</MudText>
|
|
</MudButton>
|
|
</MudTd>
|
|
}
|
|
</RowTemplate>
|
|
</MudTable>
|
|
}
|
|
|
|
<MudDivider DividerType="DividerType.Middle" Class="my-1" />
|
|
<MudText Typo="Typo.h5" Align="Align.Center">Attendees</MudText>
|
|
<MudTable Items="@attendees.Where(a => a.Step == current_i)"
|
|
Class="m-2"
|
|
Striped="true"
|
|
SortLabel="Sort By"
|
|
Hover="true">
|
|
<ToolBarContent>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && !currentStageSubmitted) {
|
|
<MudStack Row="true" Justify="Justify.Center" Spacing="1" Style="width: 100%">
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
OnClick="@((e) => AddAttendee(current_i))">
|
|
<MudText>Add Attendee</MudText>
|
|
</MudButton>
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
OnClick="@((e) => UpdateAttendees(attendees.Where(a => a.Step == current_i), current_i))">
|
|
<MudText>Save Attendance</MudText>
|
|
</MudButton>
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
OnClick="@((e) => MarkAllAttended(current_i))">
|
|
<MudText>Mark All Attended</MudText>
|
|
</MudButton>
|
|
</MudStack>
|
|
}
|
|
</ToolBarContent>
|
|
<HeaderContent>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<PCRBAttendee, object>(x=>x.Attendee is null ?
|
|
string.Empty :
|
|
x.Attendee.LastName)">
|
|
Attendee Name
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>Attended?</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd DataLabel="Attendee Name">
|
|
@(context.Attendee is null ? string.Empty : context.Attendee.GetFullName())
|
|
</MudTd>
|
|
<MudTd DataLabel="Attended?">
|
|
<MudCheckBox Disabled="@(pcrb.ClosedDate < DateTimeUtilities.MAX_DT || currentStageSubmitted)"
|
|
@bind-Value=context.Attended
|
|
Color="Color.Tertiary" />
|
|
</MudTd>
|
|
</RowTemplate>
|
|
</MudTable>
|
|
|
|
<MudDivider DividerType="DividerType.Middle" Class="my-1" />
|
|
<MudText Typo="Typo.h5" Align="Align.Center">Approvers</MudText>
|
|
@if (!actionItemsAreComplete && current_i == 3) {
|
|
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.subtitle1">
|
|
All actions must be completed before PCR3 is submitted for approval
|
|
</MudText>
|
|
}
|
|
<MudTable Items="@approvals.Where(a => a.Step == current_i).OrderBy(a => a.CompletedDate)"
|
|
Class="m-2"
|
|
Striped="true"
|
|
SortLabel="Sort By"
|
|
Hover="true">
|
|
<ToolBarContent>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageApproved) {
|
|
<MudStack Row="true" Justify="Justify.Center" Spacing="1" Style="width: 100%">
|
|
@if (!currentStageSubmitted) {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
OnClick="@((e) => AddApprover(current_i))">
|
|
<MudText>Add Approver</MudText>
|
|
</MudButton>
|
|
}
|
|
@if (previousStageSubmitted && !currentStageSubmitted && currentStageAttachments.Count() > 0 &&
|
|
!affectedDocumentsIncomplete && allActionItemsComplete &&
|
|
!previousStageHasOpenGatedActionItems) {
|
|
@if (submitInProcess) {
|
|
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
|
|
<MudText>Submitting</MudText>
|
|
} else {
|
|
<MudButton Variant="Variant.Filled"
|
|
Color="Color.Tertiary"
|
|
Disabled="@submitInProcess"
|
|
OnClick="@((e) => SubmitForApproval(current_i))">
|
|
<MudText>Submit For Approval</MudText>
|
|
</MudButton>
|
|
}
|
|
}
|
|
</MudStack>
|
|
}
|
|
</ToolBarContent>
|
|
<HeaderContent>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<Approval, object>(x=>x.User is null ?
|
|
string.Empty :
|
|
x.User.LastName)">
|
|
Approver Name
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>
|
|
<MudTableSortLabel SortBy="new Func<Approval, object>(x=>SubRoleCategoryItemToJobTitleConverter(x.SubRoleCategoryItem))">
|
|
Job Title
|
|
</MudTableSortLabel>
|
|
</MudTh>
|
|
<MudTh>Status</MudTh>
|
|
<MudTh>Assigned Date</MudTh>
|
|
<MudTh>Disposition Date</MudTh>
|
|
<MudTh>Comments</MudTh>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd DataLabel="Approver Name">
|
|
@(context.User is null ? string.Empty : context.User.GetFullName())
|
|
</MudTd>
|
|
<MudTd DataLabel="Job Title">@SubRoleCategoryItemToJobTitleConverter(context.SubRoleCategoryItem)</MudTd>
|
|
<MudTd DataLabel="Status">@GetApprovalStatus(context.ItemStatus)</MudTd>
|
|
<MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd>
|
|
<MudTd DataLabel="Disposition Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CompletedDate)</MudTd>
|
|
<MudTd DataLabel="Comments">@context.Comments</MudTd>
|
|
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && (currentStageUnsubmittedApprovalCount > 0 ||
|
|
currentStagePendingApprovalsCount > 0)) {
|
|
<MudTd Style="text-align:center;">
|
|
@if (context.ItemStatus == 0 && userIsAdmin) {
|
|
<MudButton Color="Color.Warning"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
OnClick="@((e) => UpdateApproval(context))">
|
|
<MudText>Update</MudText>
|
|
</MudButton>
|
|
}
|
|
@if ((current_i < 3 || pcr3Documents.Where(d=>d.CompletedByID == 0).Count() == 0) &&
|
|
(authStateProvider.CurrentUser is not null && context.UserID == authStateProvider.CurrentUser.UserID) &&
|
|
context.ItemStatus == 0 && context.AssignedDate > DateTimeUtilities.MIN_DT) {
|
|
<MudButton Color="Color.Tertiary"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
Disabled="@processing"
|
|
OnClick="@((e) => ApprovePCR(current_i))">
|
|
<MudText>Approve</MudText>
|
|
</MudButton>
|
|
<MudButton Color="Color.Secondary"
|
|
Variant="Variant.Filled"
|
|
Class="m-1"
|
|
Disabled="@processing"
|
|
OnClick="@((e) => DenyPCR(current_i))">
|
|
<MudText>Deny</MudText>
|
|
</MudButton>
|
|
}
|
|
</MudTd>
|
|
}
|
|
</RowTemplate>
|
|
</MudTable>
|
|
</MudPaper>
|
|
</ChildContent>
|
|
</MudExpansionPanel>
|
|
}
|
|
</MudExpansionPanels>
|
|
}
|
|
}
|
|
|
|
<MudOverlay Visible=processing DarkBackground="true" AutoClose="false">
|
|
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
|
|
</MudOverlay>
|
|
|
|
@code {
|
|
[Parameter]
|
|
public string planNumber { get; set; } = "";
|
|
|
|
private int planNumberInt = 0;
|
|
private PCRB pcrb = null;
|
|
|
|
private IEnumerable<Approval> approvals = new List<Approval>();
|
|
private IEnumerable<PCRBAttendee> attendees = new List<PCRBAttendee>();
|
|
private IEnumerable<PCRBAttachment> attachments = new List<PCRBAttachment>();
|
|
private IEnumerable<PCRBActionItem> actionItems = new List<PCRBActionItem>();
|
|
private IEnumerable<PCR3Document> pcr3Documents = new List<PCR3Document>();
|
|
|
|
private IEnumerable<int> qualityApproverUserIds = new List<int>();
|
|
|
|
private IEnumerable<User> allActiveUsers = new List<User>();
|
|
private User selectedOwner = null;
|
|
|
|
private bool processing = false;
|
|
private bool saveInProcess = false;
|
|
private bool deleteInProcess = false;
|
|
private bool submitInProcess = false;
|
|
private bool approvalInProcess = false;
|
|
private bool denialInProcess = false;
|
|
private bool recallInProcess = false;
|
|
private bool attachmentUploadInProcess = false;
|
|
private bool updateAttachmentInProcess = false;
|
|
private bool deleteAttachmentInProcess = false;
|
|
private bool addActionItemInProcess = false;
|
|
|
|
private string attachmentSearchString = "";
|
|
|
|
private string actionItemSearchString = "";
|
|
|
|
protected override async Task OnParametersSetAsync() {
|
|
processing = true;
|
|
try {
|
|
allActiveUsers = await userService.GetAllActiveUsers();
|
|
|
|
if (qualityApproverUserIds.Count() == 0)
|
|
qualityApproverUserIds = await GetQualityApproverUserIds();
|
|
|
|
if (!string.IsNullOrWhiteSpace(planNumber) && Int32.TryParse(planNumber, out planNumberInt)) {
|
|
pcrb = await pcrbService.GetPCRBByPlanNumber(planNumberInt, false);
|
|
approvals = await approvalService.GetApprovalsForIssueId(planNumberInt, false);
|
|
attendees = await pcrbService.GetAttendeesByPlanNumber(planNumberInt, true);
|
|
attachments = await pcrbService.GetAttachmentsByPlanNumber(planNumberInt, false);
|
|
actionItems = await pcrbService.GetActionItemsForPlanNumber(planNumberInt, false);
|
|
pcr3Documents = await pcrbService.GetPCR3DocumentsForPlanNumber(planNumberInt, false);
|
|
|
|
List<Task> createPCR3DocumentTasks = new();
|
|
if (pcr3Documents.Count() <= 0) {
|
|
List<string> docTypes = new() { "FMEA", "SOPs", "Work Instructions", "Forms/OCAPs", "OpenInsight",
|
|
"SPC Charts", "Spare Parts Addition", "Metrology", "Safety (system/documents)",
|
|
"Other"
|
|
};
|
|
|
|
foreach (string docType in docTypes) {
|
|
PCR3Document document = new() {
|
|
PlanNumber = planNumberInt,
|
|
DocType = docType
|
|
};
|
|
|
|
createPCR3DocumentTasks.Add(pcrbService.CreatePCR3Document(document));
|
|
}
|
|
}
|
|
|
|
List<Task> generateAttendeesTasks = new();
|
|
if (attendees.Count() == 0) {
|
|
for (int stepNo = 1; stepNo < 4; stepNo++) {
|
|
generateAttendeesTasks.Add(GenerateAttendeesForStep(stepNo));
|
|
}
|
|
}
|
|
|
|
List<Task> generateApprovalsTasks = new();
|
|
if (approvals.Count() == 0) {
|
|
for (int stepNo = 1; stepNo < 4; stepNo++) {
|
|
generateApprovalsTasks.Add(GenerateApprovalsForStep(stepNo));
|
|
}
|
|
}
|
|
|
|
await Task.WhenAll(createPCR3DocumentTasks);
|
|
|
|
pcr3Documents = await pcrbService.GetPCR3DocumentsForPlanNumber(planNumberInt, true);
|
|
|
|
await Task.WhenAll(generateAttendeesTasks);
|
|
|
|
attendees = await pcrbService.GetAttendeesByPlanNumber(planNumberInt, true);
|
|
|
|
await Task.WhenAll(generateApprovalsTasks);
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(planNumberInt, true);
|
|
|
|
if (pcrb.OwnerID > 0) selectedOwner = await userService.GetUserByUserId(pcrb.OwnerID);
|
|
|
|
if (pcrb.CurrentStep > 0 && pcrb.CurrentStep < 4) {
|
|
bool stageHasAdvanced = false;
|
|
for (int stage = pcrb.CurrentStep; stage < 4; stage++) {
|
|
int current_stage = stage;
|
|
if (pcrb.CurrentStep == current_stage) {
|
|
IEnumerable<Approval> currentStageApprovals = approvals.Where(a => a.Step == current_stage);
|
|
int currentStagePendingApprovalsCount = currentStageApprovals.Where(a => a.ItemStatus == 0).Count();
|
|
int currentStageApprovedApprovalsCount = currentStageApprovals.Where(a => a.ItemStatus == 1).Count();
|
|
bool currentStageApproved = currentStageApprovedApprovalsCount >= 3 && currentStagePendingApprovalsCount == 0;
|
|
|
|
if (currentStageApproved) {
|
|
if (pcrb.CurrentStep == 3) {
|
|
int openActionItemCount = actionItems.Where(a => a.ClosedByID == 0).Count();
|
|
int openAffectedDocumentsCount = pcr3Documents.Where(d => d.CompletedByID == 0).Count();
|
|
|
|
if (openActionItemCount == 0 && openAffectedDocumentsCount == 0) {
|
|
pcrb.CurrentStep++;
|
|
stageHasAdvanced = true;
|
|
}
|
|
} else {
|
|
pcrb.CurrentStep++;
|
|
stageHasAdvanced = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (stageHasAdvanced) {
|
|
if (pcrb.CurrentStep == 4) {
|
|
pcrb.ClosedDate = DateTime.Now;
|
|
|
|
string message = $"PCRB# {pcrb.PlanNumber} - {pcrb.Title} is complete";
|
|
|
|
PCRBNotification notification = new() {
|
|
PCRB = pcrb,
|
|
Message = message
|
|
};
|
|
|
|
await pcrbService.NotifyOriginator(notification);
|
|
}
|
|
|
|
await pcrbService.UpdatePCRB(pcrb);
|
|
pcrb = await pcrbService.GetPCRBByPlanNumber(pcrb.PlanNumber, true);
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
} else {
|
|
int ownerID = 0;
|
|
string ownerName = string.Empty;
|
|
if (authStateProvider.CurrentUser is not null) {
|
|
selectedOwner = authStateProvider.CurrentUser;
|
|
ownerID = authStateProvider.CurrentUser.UserID;
|
|
ownerName = authStateProvider.CurrentUser.GetFullName();
|
|
}
|
|
|
|
pcrb = new() {
|
|
OwnerID = ownerID,
|
|
OwnerName = ownerName,
|
|
CurrentStep = 0
|
|
};
|
|
}
|
|
|
|
processing = false;
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add(ex.Message, Severity.Error);
|
|
}
|
|
}
|
|
|
|
private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
|
|
|
|
private void ReturnToAllPcrbs() {
|
|
cache.Set("redirectUrl", $"pcrb/all");
|
|
navigationManager.NavigateTo("pcrb/all");
|
|
}
|
|
|
|
private IEnumerable<string> GetIncompleteFields() {
|
|
List<string> incompleteFields = new();
|
|
|
|
if (string.IsNullOrWhiteSpace(pcrb.Title))
|
|
incompleteFields.Add("Title");
|
|
if (selectedOwner is null || pcrb.OwnerID <= 0 || string.IsNullOrWhiteSpace(pcrb.OwnerName))
|
|
incompleteFields.Add("Originator");
|
|
if (string.IsNullOrWhiteSpace(pcrb.ChangeLevel))
|
|
incompleteFields.Add("Change Level");
|
|
if (string.IsNullOrWhiteSpace(pcrb.ChangeDescription))
|
|
incompleteFields.Add("Description of Change");
|
|
if (string.IsNullOrWhiteSpace(pcrb.ReasonForChange))
|
|
incompleteFields.Add("Reason For Change");
|
|
|
|
return incompleteFields;
|
|
}
|
|
|
|
private bool PCRBReadyToSubmit(int step) {
|
|
bool readyToSubmit = GetIncompleteFields().Count() <= 0;
|
|
|
|
readyToSubmit = readyToSubmit && pcrb.CurrentStep > 0;
|
|
|
|
readyToSubmit = readyToSubmit && attachments.Where(a => a.Step == step).Count() > 0;
|
|
|
|
return readyToSubmit;
|
|
}
|
|
|
|
private bool UserIsApprover() {
|
|
bool userIsApprover = approvals.Where(a => authStateProvider.CurrentUser is not null &&
|
|
a.UserID == authStateProvider.CurrentUser.UserID &&
|
|
a.ItemStatus == 0).Count() > 0;
|
|
|
|
return userIsApprover;
|
|
}
|
|
|
|
private async void SavePCRB() {
|
|
if (!saveInProcess) {
|
|
saveInProcess = true;
|
|
try {
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
int initialPlanNumber = pcrb.PlanNumber;
|
|
|
|
pcrb.OwnerID = selectedOwner.UserID;
|
|
pcrb.OwnerName = selectedOwner.GetFullName();
|
|
|
|
if (pcrb.CurrentStep == 0 && GetIncompleteFields().Count() <= 0)
|
|
pcrb.CurrentStep++;
|
|
|
|
if (initialPlanNumber <= 0) {
|
|
await pcrbService.CreateNewPCRB(pcrb);
|
|
} else {
|
|
await pcrbService.UpdatePCRB(pcrb);
|
|
}
|
|
|
|
pcrb = await pcrbService.GetPCRBByTitle(pcrb.Title, true);
|
|
|
|
cache.Set("redirectUrl", $"pcrb/{pcrb.PlanNumber}");
|
|
|
|
saveInProcess = false;
|
|
StateHasChanged();
|
|
snackbar.Add($"PCRB {pcrb.PlanNumber} successfully saved", Severity.Success);
|
|
|
|
if (initialPlanNumber <= 0)
|
|
navigationManager.NavigateTo($"pcrb/{pcrb.PlanNumber}");
|
|
} catch (Exception ex) {
|
|
saveInProcess = false;
|
|
snackbar.Add($"Unable to save PCRB, because {ex.Message}", Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task DeletePCRB() {
|
|
if (!deleteInProcess) {
|
|
deleteInProcess = true;
|
|
try {
|
|
bool? result = await dialogService.ShowMessageBox(
|
|
"Warning",
|
|
$"Are you sure you want to delete PCRB# {pcrb.PlanNumber}?",
|
|
yesText: "Yes", noText: "No"
|
|
);
|
|
|
|
if (result == true) {
|
|
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
await pcrbService.DeletePCRB(pcrb.PlanNumber);
|
|
|
|
await pcrbService.GetAllPCRBs(true);
|
|
|
|
deleteInProcess = false;
|
|
|
|
snackbar.Add("PCRB successfully deleted", Severity.Success);
|
|
|
|
cache.Set("redirectUrl", "pcrb/all");
|
|
navigationManager.NavigateTo($"pcrb/all");
|
|
}
|
|
} catch (Exception ex) {
|
|
deleteInProcess = false;
|
|
snackbar.Add(ex.Message, Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task<IEnumerable<int>> GetQualityApproverUserIds() {
|
|
List<int> qualityApproverUserIds = new();
|
|
|
|
try {
|
|
int roleId = await approvalService.GetRoleIdForRoleName("Module Manager");
|
|
|
|
if (roleId <= 0) throw new Exception($"could not find Module Manager role ID");
|
|
|
|
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName("MMSubRole", roleId);
|
|
|
|
foreach (SubRole subRole in subRoles) {
|
|
if (subRole.SubRoleCategoryItem.Equals("Quality", StringComparison.InvariantCultureIgnoreCase)) {
|
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
|
foreach (User user in subRoleMembers) qualityApproverUserIds.Add(user.UserID);
|
|
}
|
|
}
|
|
|
|
string roleName = "QA_PRE_APPROVAL";
|
|
string subRoleName = "QA_PRE_APPROVAL";
|
|
|
|
roleId = await approvalService.GetRoleIdForRoleName(roleName);
|
|
|
|
if (roleId <= 0) throw new Exception($"could not find {roleName} role ID");
|
|
|
|
subRoles = await approvalService.GetSubRolesForSubRoleName(subRoleName, roleId);
|
|
|
|
foreach (SubRole subRole in subRoles) {
|
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
|
foreach (User user in subRoleMembers) qualityApproverUserIds.Add(user.UserID);
|
|
}
|
|
|
|
return qualityApproverUserIds;
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to get Quality approvers, because {ex.Message}", Severity.Error);
|
|
return qualityApproverUserIds;
|
|
}
|
|
}
|
|
|
|
private async Task GenerateApprovalsForStep(int step) {
|
|
try {
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
int roleId = await approvalService.GetRoleIdForRoleName("QA_PRE_APPROVAL");
|
|
|
|
if (roleId <= 0) throw new Exception($"could not find QA_PRE_APPROVAL role ID");
|
|
|
|
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName("QA_PRE_APPROVAL", roleId);
|
|
|
|
foreach (SubRole subRole in subRoles) {
|
|
IEnumerable<User> members = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
|
|
|
foreach (User member in members) {
|
|
Approval approval = new() {
|
|
IssueID = pcrb.PlanNumber,
|
|
RoleName = subRole.SubRoleCategoryItem,
|
|
SubRole = subRole.SubRoleName,
|
|
UserID = member.UserID,
|
|
SubRoleID = subRole.SubRoleID,
|
|
AssignedDate = DateTimeUtilities.MIN_DT,
|
|
Step = step
|
|
};
|
|
|
|
await approvalService.CreateApproval(approval);
|
|
}
|
|
}
|
|
|
|
roleId = await approvalService.GetRoleIdForRoleName("Module Manager");
|
|
|
|
if (roleId <= 0) throw new Exception($"could not find Module Manager role ID");
|
|
|
|
subRoles = await approvalService.GetSubRolesForSubRoleName("MMSubRole", roleId);
|
|
|
|
HashSet<string> subRoleCategoryItems = new() { "Si Production", "Si Engineering", "Quality" };
|
|
foreach (SubRole subRole in subRoles) {
|
|
if (subRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) {
|
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
|
|
|
foreach (User member in subRoleMembers) {
|
|
Approval approval = new() {
|
|
IssueID = pcrb.PlanNumber,
|
|
RoleName = subRole.SubRoleCategoryItem,
|
|
SubRole = subRole.SubRoleName,
|
|
UserID = member.UserID,
|
|
SubRoleID = subRole.SubRoleID,
|
|
AssignedDate = DateTimeUtilities.MIN_DT,
|
|
Step = step
|
|
};
|
|
|
|
await approvalService.CreateApproval(approval);
|
|
}
|
|
}
|
|
}
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to generate approvals for step {step}, because {ex.Message}", Severity.Error);
|
|
}
|
|
}
|
|
|
|
private async Task SubmitForApproval(int step) {
|
|
if (!submitInProcess) {
|
|
try {
|
|
submitInProcess = true;
|
|
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
if (!PCRBReadyToSubmit(step))
|
|
throw new Exception($"PCR {step} not ready to submit");
|
|
|
|
List<Task> attendeeTasks = new();
|
|
foreach (PCRBAttendee attendee in attendees.Where(a => a.Step == step)) {
|
|
attendeeTasks.Add(pcrbService.UpdateAttendee(attendee));
|
|
}
|
|
|
|
await Task.WhenAll(attendeeTasks);
|
|
|
|
List<Task> notifyResponsiblePersonsTasks = new();
|
|
foreach (PCRBActionItem actionItem in actionItems.Where(a => a.Step == step &&
|
|
a.NotifyDate <= DateTimeUtilities.MIN_DT &&
|
|
a.ClosedStatus == false)) {
|
|
StringBuilder messageBuilder = new();
|
|
messageBuilder.Append($"PCRB# {pcrb.PlanNumber} [{pcrb.Title}] PCR{step} has an action item for you to complete. ");
|
|
messageBuilder.Append($"The action is {actionItem.Name}.");
|
|
|
|
PCRBActionItemNotification notification = new() {
|
|
PCRB = pcrb,
|
|
ActionItem = actionItem,
|
|
Message = messageBuilder.ToString()
|
|
};
|
|
|
|
actionItem.NotifyDate = DateTime.Now;
|
|
|
|
notifyResponsiblePersonsTasks.Add(pcrbService.NotifyResponsiblePerson(notification));
|
|
notifyResponsiblePersonsTasks.Add(pcrbService.UpdateActionItem(actionItem));
|
|
}
|
|
|
|
await Task.WhenAll(notifyResponsiblePersonsTasks);
|
|
|
|
IEnumerable<Approval> currentStageApprovals = approvals.Where(a => a.Step == step);
|
|
IEnumerable<Approval> currentStageManagerApprovals = currentStageApprovals.Where(a => !a.SubRoleCategoryItem.Equals("QA Pre Approver"));
|
|
int currentStageUnsubmittedApprovalCount = currentStageManagerApprovals.Where(a => a.AssignedDate <= DateTimeUtilities.MIN_DT).Count();
|
|
int currentStagePendingApprovalsCount = currentStageManagerApprovals.Where(a => a.ItemStatus == 0 && a.AssignedDate > DateTimeUtilities.MIN_DT).Count();
|
|
int currentStageApprovedApprovalsCount = currentStageManagerApprovals.Where(a => a.ItemStatus == 1).Count();
|
|
int currentStageDeniedApprovalsCount = currentStageManagerApprovals.Where(a => a.ItemStatus == -1).Count();
|
|
|
|
Approval? latestQaPreApproval = currentStageApprovals
|
|
.Where(a => a.SubRoleCategoryItem.Equals("QA Pre Approver"))
|
|
.OrderByDescending(a => a.AssignedDate)
|
|
.FirstOrDefault();
|
|
|
|
if (latestQaPreApproval is null) throw new Exception("QA pre approval not found");
|
|
|
|
bool qaPreApprovalDenied = latestQaPreApproval.ItemStatus == -1;
|
|
if (qaPreApprovalDenied && currentStageUnsubmittedApprovalCount >= 3) {
|
|
Approval newApproval = new() {
|
|
IssueID = latestQaPreApproval.IssueID,
|
|
RoleName = latestQaPreApproval.RoleName,
|
|
SubRole = latestQaPreApproval.SubRole,
|
|
UserID = latestQaPreApproval.UserID,
|
|
SubRoleID = latestQaPreApproval.SubRoleID,
|
|
AssignedDate = DateTime.Now,
|
|
Step = latestQaPreApproval.Step
|
|
};
|
|
|
|
await approvalService.CreateApproval(newApproval);
|
|
} else if (currentStageDeniedApprovalsCount > (currentStageUnsubmittedApprovalCount + currentStagePendingApprovalsCount +
|
|
currentStageApprovedApprovalsCount)) {
|
|
HashSet<string> copiedApprovals = new();
|
|
|
|
List<Task> createCopiedApprovalsTasks = new();
|
|
foreach (Approval oldApproval in currentStageApprovals) {
|
|
if (!copiedApprovals.Contains($"{oldApproval.RoleName}{oldApproval.UserID}")) {
|
|
DateTime assignedDate = DateTimeUtilities.MIN_DT;
|
|
|
|
if (oldApproval.RoleName.Equals("QA Pre Approver"))
|
|
assignedDate = DateTime.Now;
|
|
|
|
Approval newApproval = new() {
|
|
IssueID = oldApproval.IssueID,
|
|
RoleName = oldApproval.RoleName,
|
|
SubRole = oldApproval.SubRole,
|
|
UserID = oldApproval.UserID,
|
|
SubRoleID = oldApproval.SubRoleID,
|
|
AssignedDate = assignedDate,
|
|
Step = oldApproval.Step
|
|
};
|
|
|
|
createCopiedApprovalsTasks.Add(approvalService.CreateApproval(newApproval));
|
|
|
|
copiedApprovals.Add($"{oldApproval.RoleName}{oldApproval.UserID}");
|
|
}
|
|
}
|
|
|
|
await Task.WhenAll(createCopiedApprovalsTasks);
|
|
} else {
|
|
Approval? unassignedQaPreApproval = currentStageApprovals.Where(a => a.SubRoleCategoryItem.Equals("QA Pre Approver") &&
|
|
a.AssignedDate <= DateTimeUtilities.MIN_DT).FirstOrDefault();
|
|
|
|
if (unassignedQaPreApproval is null) throw new Exception("unassigned QA pre approval not found");
|
|
|
|
unassignedQaPreApproval.AssignedDate = DateTime.Now;
|
|
await approvalService.UpdateApproval(unassignedQaPreApproval);
|
|
}
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, true);
|
|
|
|
await pcrbService.NotifyNewApprovals(pcrb);
|
|
|
|
if (pcrb.CurrentStep == 1) {
|
|
pcrb.InsertTimeStamp = DateTime.Now;
|
|
await pcrbService.UpdatePCRB(pcrb);
|
|
|
|
pcrb = await pcrbService.GetPCRBByPlanNumber(pcrb.PlanNumber, true);
|
|
}
|
|
|
|
submitInProcess = false;
|
|
|
|
snackbar.Add("PCRB successfully submitted for approval", Severity.Success);
|
|
} catch (Exception ex) {
|
|
submitInProcess = false;
|
|
snackbar.Add($"Unable to submit for approval, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task SetUserForApproval(Approval approval, User user) {
|
|
if (approval is null) throw new ArgumentNullException("approval cannot be null");
|
|
if (user is null) throw new ArgumentNullException("user cannot be null");
|
|
|
|
if (approval.CompletedDate < DateTimeUtilities.MAX_DT || approval.ItemStatus != 0)
|
|
throw new ArgumentException("cannot reassign a complete approval");
|
|
|
|
approval.UserID = user.UserID;
|
|
approval.User = user;
|
|
approval.NotifyDate = DateTimeUtilities.MIN_DT;
|
|
|
|
await approvalService.UpdateApproval(approval);
|
|
await approvalService.GetApprovalsForIssueId(approval.IssueID, true);
|
|
|
|
await pcrbService.NotifyNewApprovals(pcrb);
|
|
}
|
|
|
|
private async Task ApprovePCR(int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (step <= 0 || step > 3)
|
|
throw new Exception($"{step} is not a valid PCR#");
|
|
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
if (pcrb.ClosedDate < DateTimeUtilities.MAX_DT)
|
|
throw new Exception("cannot approve a complete PCRB");
|
|
|
|
if (authStateProvider.CurrentUser is null) {
|
|
await authStateProvider.Logout();
|
|
navigationManager.NavigateTo("login");
|
|
return;
|
|
}
|
|
|
|
IEnumerable<Approval> activeApprovalsForUser = approvals.Where(a => a.UserID == authStateProvider.CurrentUser.UserID &&
|
|
a.AssignedDate > DateTimeUtilities.MIN_DT &&
|
|
a.ItemStatus == 0 &&
|
|
a.Step == step);
|
|
|
|
if (activeApprovalsForUser.Count() <= 0)
|
|
throw new Exception($"you have no active approvals for PCR{step}");
|
|
|
|
string? comments = "";
|
|
|
|
DialogParameters<Comments> parameters = new DialogParameters<Comments> { { x => x.comments, comments } };
|
|
var dialog = dialogService.Show<Comments>($"Approval Comments", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result.Canceled) throw new Exception("you must provide approval comments");
|
|
|
|
comments = result.Data.ToString();
|
|
|
|
foreach (Approval approval in activeApprovalsForUser) {
|
|
approval.CompletedDate = DateTime.Now;
|
|
approval.Comments = comments is null ? "" : comments;
|
|
approval.ItemStatus = 1;
|
|
|
|
await approvalService.UpdateApproval(approval);
|
|
}
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, false);
|
|
|
|
IEnumerable<Approval> unassignedApprovals = approvals.Where(a => a.Step == step && a.AssignedDate <= DateTimeUtilities.MIN_DT);
|
|
if (unassignedApprovals.Count() > 0) {
|
|
List<Task> assignmentTasks = new();
|
|
foreach (Approval approval in unassignedApprovals) {
|
|
approval.AssignedDate = DateTime.Now;
|
|
assignmentTasks.Add(approvalService.UpdateApproval(approval));
|
|
}
|
|
await Task.WhenAll(assignmentTasks);
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, false);
|
|
|
|
await pcrbService.NotifyNewApprovals(pcrb);
|
|
}
|
|
|
|
IEnumerable<Approval> remainingActiveApprovals = approvals.Where(a => a.Step == step &&
|
|
a.ItemStatus == 0);
|
|
|
|
if (remainingActiveApprovals.Count() <= 0) {
|
|
StringBuilder messageBuilder = new();
|
|
messageBuilder.Append($"PCRB# {pcrb.PlanNumber} - {pcrb.Title} - PCR{step} has been approved.");
|
|
|
|
PCRBNotification notification = new() {
|
|
PCRB = pcrb,
|
|
Message = messageBuilder.ToString()
|
|
};
|
|
|
|
await pcrbService.NotifyOriginator(notification);
|
|
}
|
|
|
|
processing = false;
|
|
|
|
snackbar.Add($"PCR{step} successfully approved", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to approve PCR{step}, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task DenyPCR(int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (step <= 0 || step > 3)
|
|
throw new Exception($"{step} is not a valid PCR#");
|
|
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
if (pcrb.ClosedDate < DateTimeUtilities.MAX_DT)
|
|
throw new Exception("cannot deny a complete PCRB");
|
|
|
|
if (authStateProvider.CurrentUser is null) {
|
|
await authStateProvider.Logout();
|
|
navigationManager.NavigateTo("login");
|
|
return;
|
|
}
|
|
|
|
IEnumerable<Approval> activeApprovalsForUser = approvals.Where(a => a.UserID == authStateProvider.CurrentUser.UserID &&
|
|
a.AssignedDate > DateTimeUtilities.MIN_DT &&
|
|
a.ItemStatus == 0 &&
|
|
a.Step == step);
|
|
|
|
if (activeApprovalsForUser.Count() <= 0)
|
|
throw new Exception("you have no active approvals");
|
|
|
|
string? comments = "";
|
|
|
|
DialogParameters<Comments> parameters = new DialogParameters<Comments> { { x => x.comments, comments } };
|
|
var dialog = dialogService.Show<Comments>($"Denial Comments", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result.Canceled) throw new Exception("you must provide a comment");
|
|
|
|
comments = result.Data.ToString();
|
|
|
|
IEnumerable<Approval> outstandingActiveApprovalsForStep = approvals.Where(a => a.Step == step &&
|
|
a.ItemStatus == 0 &&
|
|
a.AssignedDate > DateTimeUtilities.MIN_DT);
|
|
|
|
foreach (Approval approval in outstandingActiveApprovalsForStep) {
|
|
approval.CompletedDate = DateTime.Now;
|
|
approval.Comments = comments is null ? "" : comments;
|
|
approval.ItemStatus = -1;
|
|
|
|
await approvalService.UpdateApproval(approval);
|
|
}
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, false);
|
|
|
|
if (step == 1) {
|
|
pcrb.InsertTimeStamp = DateTimeUtilities.MIN_DT;
|
|
await pcrbService.UpdatePCRB(pcrb);
|
|
}
|
|
|
|
StringBuilder messageBuilder = new();
|
|
messageBuilder.Append($"PCRB# {pcrb.PlanNumber} - {pcrb.Title} - PCR{step} has been denied ");
|
|
messageBuilder.Append($"by {authStateProvider.CurrentUser.GetFullName()}. ");
|
|
messageBuilder.AppendLine("");
|
|
messageBuilder.Append($"Comments: {comments}");
|
|
|
|
PCRBNotification notification = new() {
|
|
PCRB = pcrb,
|
|
Message = messageBuilder.ToString()
|
|
};
|
|
|
|
await pcrbService.NotifyOriginator(notification);
|
|
|
|
processing = false;
|
|
|
|
snackbar.Add($"PCR{step} successfully denied", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to deny PCR{step}, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task UploadAttachment(int step) {
|
|
if (!attachmentUploadInProcess) {
|
|
attachmentUploadInProcess = true;
|
|
try {
|
|
if (step <= 0) throw new ArgumentException($"{step} is not a valid PCRB stage#");
|
|
|
|
DialogParameters<PCRBAttachmentForm> parameters = new DialogParameters<PCRBAttachmentForm> {
|
|
{ x => x.planNumber, pcrb.PlanNumber },
|
|
{ x => x.step, step }
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCRBAttachmentForm>("Upload Attachment", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Attachment successfully uploaded", Severity.Success);
|
|
|
|
attachments = await pcrbService.GetAttachmentsByPlanNumber(planNumberInt, true);
|
|
|
|
attachmentUploadInProcess = false;
|
|
} catch (Exception ex) {
|
|
attachmentUploadInProcess = false;
|
|
snackbar.Add($"Unable to upload attachment, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task DeleteAttachment(PCRBAttachment attachment) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (attachment is null)
|
|
throw new ArgumentNullException("attachment cannot be null");
|
|
|
|
bool? result = await dialogService.ShowMessageBox(
|
|
"Warning",
|
|
$"Are you sure you want to delete PCRB attachment {attachment.FileName}?",
|
|
yesText: "Yes", noText: "No"
|
|
);
|
|
|
|
if (result == true) {
|
|
await pcrbService.DeleteAttachment(attachment);
|
|
|
|
attachments = await pcrbService.GetAttachmentsByPlanNumber(attachment.PlanNumber, true);
|
|
}
|
|
|
|
processing = false;
|
|
|
|
snackbar.Add("Attachment successfully deleted", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to delete attachment, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private async Task CreateNewActionItem(int step) {
|
|
try {
|
|
DialogParameters<PCRBActionItemForm> parameters = new DialogParameters<PCRBActionItemForm> {
|
|
{ x => x.planNumber, pcrb.PlanNumber },
|
|
{ x => x.step, step },
|
|
{ x => x.allActiveUsers, allActiveUsers }
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCRBActionItemForm>("New Action Item", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Action item successfully created", Severity.Success);
|
|
|
|
actionItems = await pcrbService.GetActionItemsForPlanNumber(pcrb.PlanNumber, true);
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to create new action item, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private async Task CloseAllActionItems(int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (authStateProvider.CurrentUser is null) {
|
|
await authStateProvider.Logout();
|
|
navigationManager.NavigateTo("login");
|
|
return;
|
|
}
|
|
|
|
IEnumerable<PCRBActionItem> outstandingActionItemsForStep =
|
|
actionItems.Where(a => a.Step == step && a.ClosedStatus == false);
|
|
|
|
foreach (PCRBActionItem actionItem in outstandingActionItemsForStep) {
|
|
actionItem.ClosedStatus = true;
|
|
actionItem.ClosedDate = DateTime.Now;
|
|
actionItem.ClosedBy = authStateProvider.CurrentUser;
|
|
actionItem.ClosedByID = authStateProvider.CurrentUser.UserID;
|
|
|
|
await pcrbService.UpdateActionItem(actionItem);
|
|
}
|
|
|
|
actionItems = await pcrbService.GetActionItemsForPlanNumber(planNumberInt, true);
|
|
|
|
processing = false;
|
|
|
|
snackbar.Add("Successfully approved all action items", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to approve all action items, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task UpdateActionItem(PCRBActionItem actionItem) {
|
|
try {
|
|
if (actionItem is null)
|
|
throw new ArgumentNullException("action item cannot be null");
|
|
|
|
DialogParameters<PCRBActionItemForm> parameters = new DialogParameters<PCRBActionItemForm> {
|
|
{ x => x.planNumber, pcrb.PlanNumber },
|
|
{ x => x.step, actionItem.Step },
|
|
{ x => x.allActiveUsers, allActiveUsers },
|
|
{ x => x.actionItem, actionItem }
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCRBActionItemForm>("Update Action Item", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Action item successfully updated", Severity.Success);
|
|
|
|
actionItems = await pcrbService.GetActionItemsForPlanNumber(actionItem.PlanNumber, true);
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to update action item, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private async Task DeleteActionItem(PCRBActionItem actionItem) {
|
|
try {
|
|
if (actionItem is null)
|
|
throw new ArgumentNullException("action item cannot be null");
|
|
|
|
bool? result = await dialogService.ShowMessageBox(
|
|
"Warning",
|
|
$"Are you sure you want to delete PCRB action item {actionItem.Name}?",
|
|
yesText: "Yes", noText: "No"
|
|
);
|
|
|
|
if (result == true) {
|
|
await pcrbService.DeleteActionItem(actionItem.ID);
|
|
|
|
actionItems = await pcrbService.GetActionItemsForPlanNumber(pcrb.PlanNumber, true);
|
|
|
|
snackbar.Add("Action item successfully deleted", Severity.Success);
|
|
}
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to delete action item, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private async Task UpdatePCR3Document(PCR3Document document) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (document is null) throw new Exception("affected document cannot be null");
|
|
|
|
DialogParameters<PCR3DocumentForm> parameters = new DialogParameters<PCR3DocumentForm> {
|
|
{ x => x.document, document },
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCR3DocumentForm>("Update Affected Document Type", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
processing = false;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Affected document successfully updated", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to update affected document, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task GenerateAttendeesForStep(int step) {
|
|
try {
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
int roleId = await approvalService.GetRoleIdForRoleName("PCRB Attendee");
|
|
|
|
if (roleId <= 0) throw new Exception($"could not find PCRB Attendee role ID");
|
|
|
|
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName("PCRBAttendee", roleId);
|
|
|
|
foreach (SubRole subRole in subRoles) {
|
|
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
|
|
|
|
foreach (User member in subRoleMembers) {
|
|
PCRBAttendee attendee = new() {
|
|
PlanNumber = pcrb.PlanNumber,
|
|
AttendeeID = member.UserID,
|
|
Attendee = member,
|
|
Step = step
|
|
};
|
|
|
|
await pcrbService.CreateNewAttendee(attendee);
|
|
}
|
|
}
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to generate attendees for step {step}, because {ex.Message}", Severity.Error);
|
|
}
|
|
}
|
|
|
|
private async Task UpdateAttendees(IEnumerable<PCRBAttendee> pcrAttendees, int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
List<Task> attendeeTasks = new();
|
|
foreach(PCRBAttendee attendee in pcrAttendees) {
|
|
attendeeTasks.Add(pcrbService.UpdateAttendee(attendee));
|
|
}
|
|
|
|
await Task.WhenAll(attendeeTasks);
|
|
|
|
processing = false;
|
|
snackbar.Add($"PCR{step} attendees updated", Severity.Success);
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"", Severity.Error);
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task AddAttendee(int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
if (authStateProvider.CurrentUser is null) {
|
|
await authStateProvider.Logout();
|
|
navigationManager.NavigateTo("login");
|
|
return;
|
|
}
|
|
|
|
if (pcrb is null) throw new Exception("PCRB cannot be null");
|
|
|
|
if (pcrb.PlanNumber == 0) throw new Exception("PCRB was never saved");
|
|
|
|
User user = authStateProvider.CurrentUser;
|
|
|
|
DialogParameters<UserSelector> parameters = new DialogParameters<UserSelector> {
|
|
{ x => x.selectedUser, user }
|
|
};
|
|
|
|
var dialog = dialogService.Show<UserSelector>("Add Attendee", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled && result.Data is not null) {
|
|
user = (User)result.Data;
|
|
|
|
if (attendees.Where(a => a.AttendeeID == user.UserID).Count() == 0) {
|
|
PCRBAttendee attendee = new() {
|
|
PlanNumber = pcrb.PlanNumber,
|
|
Attendee = user,
|
|
AttendeeID = user.UserID,
|
|
Step = step
|
|
};
|
|
|
|
await pcrbService.CreateNewAttendee(attendee);
|
|
}
|
|
}
|
|
|
|
attendees = await pcrbService.GetAttendeesByPlanNumber(pcrb.PlanNumber, true);
|
|
|
|
processing = false;
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to add attendee, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task MarkAllAttended(int step) {
|
|
if (!processing) {
|
|
try {
|
|
processing = true;
|
|
|
|
List<Task> updateAttendeeTasks = new();
|
|
|
|
foreach (PCRBAttendee attendee in attendees.Where(a => a.Step == step)) {
|
|
attendee.Attended = true;
|
|
updateAttendeeTasks.Add(pcrbService.UpdateAttendee(attendee));
|
|
}
|
|
|
|
await Task.WhenAll(updateAttendeeTasks);
|
|
|
|
processing = false;
|
|
} catch (Exception ex) {
|
|
processing = false;
|
|
snackbar.Add($"Unable to mark all attended, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
}
|
|
|
|
private async Task AddApprover(int step) {
|
|
try {
|
|
DialogParameters<PCRBApproverForm> parameters = new DialogParameters<PCRBApproverForm> {
|
|
{ x => x.planNumber, pcrb.PlanNumber },
|
|
{ x => x.step, step }
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCRBApproverForm>("Add Approver", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Approver successfully added", Severity.Success);
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, false);
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to add approver, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private async Task UpdateApproval(Approval approval) {
|
|
try {
|
|
if (approval is null)
|
|
throw new ArgumentNullException("approval cannot be null");
|
|
|
|
DialogParameters<PCRBApproverForm> parameters = new DialogParameters<PCRBApproverForm> {
|
|
{ x => x.planNumber, pcrb.PlanNumber },
|
|
{ x => x.step, approval.Step },
|
|
{ x => x.approval, approval }
|
|
};
|
|
|
|
var dialog = dialogService.Show<PCRBApproverForm>("Update Approval", parameters);
|
|
|
|
var result = await dialog.Result;
|
|
|
|
if (result is not null && !result.Canceled)
|
|
snackbar.Add("Approval successfully updated", Severity.Success);
|
|
|
|
approvals = await approvalService.GetApprovalsForIssueId(pcrb.PlanNumber, true);
|
|
} catch (Exception ex) {
|
|
snackbar.Add($"Unable to update approval, because {ex.Message}", Severity.Error);
|
|
}
|
|
|
|
StateHasChanged();
|
|
await OnParametersSetAsync();
|
|
}
|
|
|
|
private string SubRoleCategoryItemToJobTitleConverter(string subRoleCategoryItem) {
|
|
if (string.IsNullOrWhiteSpace(subRoleCategoryItem)) return "";
|
|
|
|
string jobTitle = subRoleCategoryItem.Replace("Si", "");
|
|
|
|
if (!jobTitle.Contains("other", StringComparison.InvariantCultureIgnoreCase) &&
|
|
!jobTitle.Contains("qa pre approver", StringComparison.InvariantCultureIgnoreCase))
|
|
jobTitle = jobTitle + " Manager";
|
|
|
|
return jobTitle;
|
|
}
|
|
|
|
private string GetApprovalStatus(int itemStatus) {
|
|
if (itemStatus < 0) return "Denied";
|
|
if (itemStatus > 0) return "Approved";
|
|
return "Pending";
|
|
}
|
|
} |