@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
PCRB @planNumber
PCRB @planNumber
@if (pcrb is not null) {
@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];
@stageName
}
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))) {
@if (!pcrbIsSubmitted && !string.IsNullOrWhiteSpace(pcrb.Title) && (userIsOriginator || userIsAdmin)) {
@if (saveInProcess) {
Processing
} else {
Save
}
}
@if (!pcrbIsSubmitted && pcrb.PlanNumber > 0 && (userIsOriginator || userIsAdmin)) {
@if (deleteInProcess) {
Processing
} else {
Delete
}
}
}
@if (!pcrbIsSubmitted && GetIncompleteFields().Count() > 0) {
IEnumerable incompleteFields = GetIncompleteFields();
StringBuilder errorBuilder = new();
errorBuilder.Append($"Incomplete fields: {incompleteFields.First()}");
for (int i = 1; i < incompleteFields.Count(); i++) {
errorBuilder.Append($", {incompleteFields.ElementAt(i)}");
}
@errorBuilder.ToString()
}
@foreach (User user in allActiveUsers.OrderBy(u => u.LastName)) {
}
@if (pcrb.PlanNumber > 0 && pcrb.CurrentStep > 0) {
@for (int i = 1; i < 4; i++) {
int current_i = i;
bool previousStageSubmitted = current_i == 1;
IEnumerable 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 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 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 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;
@($"PCR {current_i}")
@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");
}
@sb.ToString()
}
@if (actionItemsIncomplete) {
All actions must be completed before PCR3 is submitted for approval
}
@if (previousStageHasOpenGatedActionItems) {
This stage cannot be submitted for approval until previous stage's gated action items are closed
}
Supporting Documents
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageSubmitted && !currentStageSubmitted) {
@if (current_i == 1) {
Download PCRB Template
}
@if (attachmentUploadInProcess) {
Processing
} else {
Upload Document
}
}
File Name
Uploaded By
Uploaded Date
@context.FileName
@(context.UploadedBy is null ? string.Empty : context.UploadedBy.GetFullName())
@context.UploadDateTime.ToString("yyyy-MM-dd HH:mm")
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageSubmitted && !currentStageSubmitted) {
@if (deleteAttachmentInProcess) {
Deleting
} else {
Delete
}
}
@if (current_i < 3) {
Action Items
@if (!currentStageSubmitted && actionItems.Where(a => a.Step == current_i).Count() == 0) {
Add action items if applicable
}
@if (previousStageSubmitted && !currentStageSubmitted) {
New Action Item
}
@if (currentStagePendingActionItemCount > 0) {
Complete All Actions
}
Action
Responsible Person
Gating
Closed Date
@context.Name
@(context.ResponsiblePerson is null ? string.Empty : context.ResponsiblePerson.GetFullName())
@(context.Gating ? "Yes" : "No")
@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && context.ClosedByID == 0) {
Update
@if (!currentStageSubmitted) {
Delete
}
}
} else {
int openPCR3Documents = pcr3Documents.Where(d => d.CompletedByID <= 0).Count();
Affected Documents
Document Type
Document Numbers
Comments
ECN#
Closed Date
Closed By
@context.DocType
@context.DocNumbers
@context.Comment
@if (string.IsNullOrWhiteSpace(context.GetEcnNumberString())) {
context.GetEcnNumberString();
} else {
@context.GetEcnNumberString()
}
@(DateTimeUtilities.GetDateAsStringMaxDefault(context.CompletedDate))
@(context.CompletedBy is null ? string.Empty : context.CompletedBy.GetFullName())
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && !currentStageSubmitted) {
Update
}
}
Attendees
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && !currentStageSubmitted) {
Add Attendee
Save Attendance
Mark All Attended
}
Attendee Name
Attended?
@(context.Attendee is null ? string.Empty : context.Attendee.GetFullName())
Approvers
@if (!actionItemsAreComplete && current_i == 3) {
All actions must be completed before PCR3 is submitted for approval
}
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && previousStageApproved) {
@if (!currentStageSubmitted) {
Add Approver
}
@if (previousStageSubmitted && !currentStageSubmitted && currentStageAttachments.Count() > 0 &&
!affectedDocumentsIncomplete && allActionItemsComplete &&
!previousStageHasOpenGatedActionItems) {
@if (submitInProcess) {
Submitting
} else {
Submit For Approval
}
}
}
Approver Name
Job Title
Status
Assigned Date
Disposition Date
Comments
@(context.User is null ? string.Empty : context.User.GetFullName())
@SubRoleCategoryItemToJobTitleConverter(context.SubRoleCategoryItem)
@GetApprovalStatus(context.ItemStatus)
@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)
@DateTimeUtilities.GetDateAsStringMaxDefault(context.CompletedDate)
@context.Comments
@if (pcrb.ClosedDate >= DateTimeUtilities.MAX_DT && (currentStageUnsubmittedApprovalCount > 0 ||
currentStagePendingApprovalsCount > 0)) {
@if (context.ItemStatus == 0 && userIsAdmin) {
Update
}
@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) {
Approve
Deny
}
}
}
}
}
@code {
[Parameter]
public string planNumber { get; set; } = "";
private int planNumberInt = 0;
private PCRB pcrb = null;
private IEnumerable approvals = new List();
private IEnumerable attendees = new List();
private IEnumerable attachments = new List();
private IEnumerable actionItems = new List();
private IEnumerable pcr3Documents = new List();
private IEnumerable qualityApproverUserIds = new List();
private IEnumerable allActiveUsers = new List();
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 createPCR3DocumentTasks = new();
if (pcr3Documents.Count() <= 0) {
List 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 generateAttendeesTasks = new();
if (attendees.Count() == 0) {
for (int stepNo = 1; stepNo < 4; stepNo++) {
generateAttendeesTasks.Add(GenerateAttendeesForStep(stepNo));
}
}
List 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 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 UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
private void ReturnToAllPcrbs() {
cache.Set("redirectUrl", $"pcrb/all");
navigationManager.NavigateTo("pcrb/all");
}
private IEnumerable GetIncompleteFields() {
List 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> GetQualityApproverUserIds() {
List qualityApproverUserIds = new();
try {
int roleId = await approvalService.GetRoleIdForRoleName("Module Manager");
if (roleId <= 0) throw new Exception($"could not find Module Manager role ID");
IEnumerable subRoles = await approvalService.GetSubRolesForSubRoleName("MMSubRole", roleId);
foreach (SubRole subRole in subRoles) {
if (subRole.SubRoleCategoryItem.Equals("Quality", StringComparison.InvariantCultureIgnoreCase)) {
IEnumerable 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 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 subRoles = await approvalService.GetSubRolesForSubRoleName("QA_PRE_APPROVAL", roleId);
foreach (SubRole subRole in subRoles) {
IEnumerable 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 subRoleCategoryItems = new() { "Si Production", "Si Engineering", "Quality" };
foreach (SubRole subRole in subRoles) {
if (subRoleCategoryItems.Contains(subRole.SubRoleCategoryItem)) {
IEnumerable 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 attendeeTasks = new();
foreach (PCRBAttendee attendee in attendees.Where(a => a.Step == step)) {
attendeeTasks.Add(pcrbService.UpdateAttendee(attendee));
}
await Task.WhenAll(attendeeTasks);
List 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 currentStageApprovals = approvals.Where(a => a.Step == step);
IEnumerable 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 copiedApprovals = new();
List 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 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 parameters = new DialogParameters { { x => x.comments, comments } };
var dialog = dialogService.Show($"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 unassignedApprovals = approvals.Where(a => a.Step == step && a.AssignedDate <= DateTimeUtilities.MIN_DT);
if (unassignedApprovals.Count() > 0) {
List 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 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 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 parameters = new DialogParameters { { x => x.comments, comments } };
var dialog = dialogService.Show($"Denial Comments", parameters);
var result = await dialog.Result;
if (result.Canceled) throw new Exception("you must provide a comment");
comments = result.Data.ToString();
IEnumerable 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 parameters = new DialogParameters {
{ x => x.planNumber, pcrb.PlanNumber },
{ x => x.step, step }
};
var dialog = dialogService.Show("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 parameters = new DialogParameters {
{ x => x.planNumber, pcrb.PlanNumber },
{ x => x.step, step },
{ x => x.allActiveUsers, allActiveUsers }
};
var dialog = dialogService.Show("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 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 parameters = new DialogParameters {
{ x => x.planNumber, pcrb.PlanNumber },
{ x => x.step, actionItem.Step },
{ x => x.allActiveUsers, allActiveUsers },
{ x => x.actionItem, actionItem }
};
var dialog = dialogService.Show("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 parameters = new DialogParameters {
{ x => x.document, document },
};
var dialog = dialogService.Show("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 subRoles = await approvalService.GetSubRolesForSubRoleName("PCRBAttendee", roleId);
foreach (SubRole subRole in subRoles) {
IEnumerable 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 pcrAttendees, int step) {
if (!processing) {
try {
processing = true;
List 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 parameters = new DialogParameters {
{ x => x.selectedUser, user }
};
var dialog = dialogService.Show("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 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 parameters = new DialogParameters {
{ x => x.planNumber, pcrb.PlanNumber },
{ x => x.step, step }
};
var dialog = dialogService.Show("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 parameters = new DialogParameters {
{ x => x.planNumber, pcrb.PlanNumber },
{ x => x.step, approval.Step },
{ x => x.approval, approval }
};
var dialog = dialogService.Show("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";
}
}