Files
Fab2ApprovalSystem
App_Start
Content
Controllers
AccountController.cs
AdminController.cs
AuditController.cs
ChangeControlController.cs
CorrectiveActionController.cs
ECNController.cs
HomeController.cs
LotDispositionController.cs
LotTravelerController.cs
MRBController.cs
ManagerController.cs
PartsRequestController.cs
ReportsController.cs
TrainingController.cs
WebAPIController.cs
WorkflowController.cs
DMO
EmailTemplates
FTPBatch
JobSchedules
Jobs
Lib
Misc
Models
PdfGenerator
Properties
Scripts
Utilities
ViewModels
Views
fonts
Fab2ApprovalSystem.csproj
Global.asax
Global.asax.cs
Project_Readme.html
README.md
Startup.cs
Test.html
Web.Debug.config
Web.Release.config
Web.config
favicon.ico
package.json
Kendo
SQL
references
.editorconfig
.gitignore
Fab2ApprovalSystem-Development.yml
Fab2ApprovalSystem.sln
Fab2ApprovalSystem.yml
README.md
azure-pipelines.yml
mesa-fab-approval/Fab2ApprovalSystem/Controllers/PartsRequestController.cs
Jonathan Ouellette 580e90f6a2 initial add
2022-09-27 14:10:30 -07:00

754 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Fab2ApprovalSystem.Models;
using Fab2ApprovalSystem.DMO;
using Fab2ApprovalSystem.Misc;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
namespace Fab2ApprovalSystem.Controllers
{
[Authorize]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
[SessionExpireFilter]
public class PartsRequestController : Controller
{
PartsRequestDMO prDMO = new PartsRequestDMO();
UserAccountDMO userDMO = new UserAccountDMO();
WorkflowDMO wfDMO = new WorkflowDMO();
const int WorkflowNumber = 1;
public PartsRequestController()
{
ViewBag.ShowReAssignApprovers = false;
}
protected ActionResult HandleValidationError(string msg)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
return Json(new { result = "Invalid", detail = msg });
}
protected ActionResult HandleAPIException(int issueID, Exception ex, string additionalKeys = "")
{
HandleException(issueID, ex, additionalKeys);
Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
return Json(new { result = "Error", issueID = issueID, detail = ex.Message });
}
protected void HandleException(int issueID, Exception ex, string additionalKeys = "")
{
var st = new System.Diagnostics.StackTrace();
var sf = st.GetFrame(1);
String controller = sf.GetMethod().DeclaringType.Name.Replace("Controller", "");
String method = sf.GetMethod().Name;
string detailedException = String.Format(
"Exception for issue # {0}\r\n" +
"Controller: {1}, Method: {2}, User: {3}, Keys: {4}\r\n" +
"=====\r\n",
issueID,
controller,
method,
User?.Identity?.Name,
additionalKeys);
Exception x = ex;
while (x != null)
{
detailedException += x.ToString();
detailedException += "\r\n=====\r\n";
x = x.InnerException;
}
Functions.WriteEvent(detailedException, System.Diagnostics.EventLogEntryType.Error);
EventLogDMO.Add(new WinEventLog()
{
IssueID = issueID,
UserID = @User.Identity.Name,
DocumentType = controller,
OperationType = "Error",
Comments = detailedException
});
}
// GET: PartsRequest
public ActionResult Index()
{
return View();
}
public ActionResult Edit(int issueID)
{
var pr = new PartsRequest();
try
{
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
else if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
else if (pr.CurrentStep >= 1)
{
return RedirectToAction("EditApproval", new { issueID = issueID });
}
else
{
if (pr.OriginatorID != (int)Session[GlobalVars.SESSION_USERID])
{
if (Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]) == false)
{
return RedirectToAction("ReadOnly", new { issueID = issueID });
}
}
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
[HttpPost]
public ActionResult Edit(PartsRequest pr)
{
try
{
var pr_srv = prDMO.Get(pr.PRNumber);
if (pr_srv == null)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
}
if (pr_srv.CurrentStep < 0)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document is deleted");
}
if (pr_srv.CurrentStep >= 1)
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Parts Request is not editable");
}
prDMO.Update(pr);
return Content("");
}
catch (Exception e)
{
return HandleAPIException(pr.PRNumber, e);
}
}
public ActionResult EditApproval(int issueID)
{
var pr = new PartsRequest();
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
var wfStep = wfDMO.GetWorkflowStep((int)GlobalVars.DocumentType.PartsRequest, WorkflowNumber, pr.CurrentStep);
var userList = MiscDMO.GetPendingApproversListByDocument(issueID, Convert.ToByte(pr.CurrentStep), (int)GlobalVars.DocumentType.PartsRequest);
ViewBag.IsApprover = (userList.Count(u => u.UserID == myUserID) > 0);
if (ViewBag.IsApprover == false)
{
if (pr.OriginatorID != myUserID)
{
if (Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]) == false)
{
return RedirectToAction("ReadOnly", new { issueID = issueID });
}
}
}
ViewBag.IsAdmin = Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]);
ViewBag.IsOriginator = (pr.OriginatorID == myUserID);
ViewBag.AllowReject = (wfStep != null ? (wfStep.AllowReject.HasValue && wfStep.AllowReject.Value) : false);
ViewBag.ShowReAssignApprovers = ViewBag.IsAdmin || ViewBag.IsOriginator;
ViewBag.ShowAddApprovers = ViewBag.IsAdmin || ViewBag.IsApprover || ViewBag.IsOriginator;
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
public ActionResult ReadOnly(int issueID)
{
var pr = new PartsRequest();
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
pr = prDMO.Get(issueID);
if (pr == null)
{
ViewBag.ErrorDescription = "Document does not exist";
return View("Error");
}
if (pr.CurrentStep < 0)
{
ViewBag.ErrorDescription = "Document is deleted";
return View("Error");
}
ViewBag.IsAdmin = Convert.ToBoolean(Session[GlobalVars.IS_ADMIN]);
ViewBag.IsOriginator = (pr.OriginatorID == myUserID);
ViewBag.UserList = userDMO.GetAllUsers();
return View(pr);
}
catch (Exception e)
{
HandleException(issueID, e);
return View("Error");
}
}
public ActionResult Create()
{
var pr = new PartsRequest();
try
{
pr.OriginatorID = (int)Session[GlobalVars.SESSION_USERID];
if (!CanCreatePartsRequest(pr.OriginatorID) && Convert.ToBoolean(Session[GlobalVars.CAN_CREATE_PARTS_REQUEST]) == false)
throw new Exception("User does not have permission to create Parts Request");
prDMO.Insert(pr);
return RedirectToAction("Edit", new { issueID = pr.PRNumber });
}
catch (Exception e)
{
return HandleAPIException(pr.PRNumber, e);
}
}
public static bool CanCreatePartsRequest(int userID)
{
var adminDMO = new AdminDMO();
var role = adminDMO.GetSubRoles().Where(r => string.Equals(r.RoleName, "Parts Request", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (role != null)
{
var subrole = role.SubRoles.FirstOrDefault(sr => string.Equals(sr.SubRoleCategoryItem, "Originator", StringComparison.OrdinalIgnoreCase));
if (subrole != null)
{
var users = adminDMO.GetAllUsersBySubRole(subrole.SubRoleID);
if (users.Count(u => u.UserID == userID) > 0)
{
return true;
}
}
}
return false;
}
public ActionResult Attachment_Read([DataSourceRequest]DataSourceRequest request, int prNumber)
{
try
{
return Json(prDMO.GetAttachments(prNumber).ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return HandleAPIException(prNumber, ex);
}
}
[HttpPost]
public ActionResult AttachSave(IEnumerable<HttpPostedFileBase> files, int prNumber)
{
// The Name of the Upload component is "files"
if (files != null)
{
foreach (var file in files)
{
// Some browsers send file names with full path.
// We are only interested in the file name.
var fileName = System.IO.Path.GetFileName(file.FileName);
string prFolderPath = Functions.GetAttachmentFolder() + "PartsRequest\\" + prNumber.ToString();
var di = new System.IO.DirectoryInfo(prFolderPath);
if (!di.Exists)
di.Create();
var physicalPath = System.IO.Path.Combine(prFolderPath, fileName);
file.SaveAs(physicalPath);
var attach = new PartsRequestAttachment()
{
PRNumber = prNumber,
FileName = fileName,
UserID = (int)Session[GlobalVars.SESSION_USERID],
};
prDMO.InsertAttachment(attach);
}
}
return Content("");
}
public FileResult DownloadFile(string attachmentID, string prNumber)
{
string fileName = prDMO.GetFileName(attachmentID);
string folderPath = Functions.GetAttachmentFolder() + "PartsRequest\\" + prNumber.ToString();
var sDocument = System.IO.Path.Combine(folderPath, fileName);
var FDir_AppData = Functions.GetAttachmentFolder();
if (!sDocument.StartsWith(FDir_AppData))
{
// Ensure that we are serving file only inside the Fab2ApprovalAttachments folder
// and block requests outside like "../web.config"
throw new HttpException(403, "Forbidden");
}
if (!System.IO.File.Exists(sDocument))
return null;
return File(sDocument, System.Net.Mime.MediaTypeNames.Application.Octet, fileName);
}
[HttpPost]
public ActionResult DeleteAttachment(int attachmentID, string fileName, int prNumber)
{
try
{
if (ModelState.IsValid)
{
prDMO.DeleteAttachment(attachmentID);
var physicalPath = System.IO.Path.Combine(Functions.GetAttachmentFolder() + @"PartsRequest\" + prNumber.ToString(), fileName);
if (System.IO.File.Exists(physicalPath))
{
System.IO.File.Delete(physicalPath);
}
}
return Content("");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e, "AttachmentID=" + attachmentID.ToString());
}
}
[HttpPost]
public ActionResult Submit(int prNumber)
{
try
{
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
var pr = prDMO.Get(prNumber);
if (pr == null)
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
if (String.IsNullOrWhiteSpace(pr.Title))
return HandleValidationError("Title is required");
if (pr.RequestorID <= 0)
return HandleValidationError("Requestor is required");
if (pr.TechLeadID <= 0)
return HandleValidationError("Tech Lead is required");
prDMO.Submit(prNumber, myUserID);
var approvers = MiscDMO.GetApprovalsByDocument(prNumber, (int)GlobalVars.DocumentType.PartsRequest);
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == 1 && a.UserID == myUserID) > 0)
{
// Auto-Approve if the user is an approver for workflow step 1
var c = Approve(prNumber, 1, "Auto-Approve");
if (c != null && c is ContentResult)
{
var result = ((ContentResult)c).Content;
if (!String.Equals(result, "OK"))
throw new Exception(result);
}
if (c != null && c is JsonResult)
return c;
}
else
{
// Do step 1 notification
NotifyApprovers(prNumber, 1);
}
if (Request.IsAjaxRequest())
{
return Content("Redirect");
}
else
{
return Content("Invalid");
}
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
public ActionResult GetApproversList([DataSourceRequest]DataSourceRequest request, int issueID, byte step)
{
try
{
return Json(MiscDMO.GetApproversListByDocument(issueID, step, (int)GlobalVars.DocumentType.PartsRequest).ToDataSourceResult(request));
}
catch (Exception e)
{
return HandleAPIException(issueID, e, "Step=" + step.ToString());
}
}
public ActionResult GetAllUsersList()
{
try
{
UserAccountDMO userDMO = new UserAccountDMO();
IEnumerable<LoginModel> userlist = userDMO.GetAllUsers();
return Json(userlist, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
return HandleAPIException(0, e);
}
}
[HttpPost]
public ActionResult ReAssignApproval(int issueID, int fromUserID, int userIDs, byte step)
{
try
{
String email = wfDMO.ReAssignApproval(
issueID, fromUserID, userIDs, step, (int)GlobalVars.DocumentType.PartsRequest);
NotifyReAssignment(issueID, email);
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(issueID, e);
}
}
[HttpPost]
public ActionResult Approve(int prNumber, byte currentStep, string comments)
{
try
{
bool lastStep = false;
bool lastApproverInCurrentStep = false;
int myUserID = (int)Session[GlobalVars.SESSION_USERID];
var pr = prDMO.Get(prNumber);
if (pr == null)
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, "Document does not exist");
while (true)
{
lastApproverInCurrentStep = wfDMO.Approve(
prNumber, currentStep, comments, out lastStep,
(int)Session[GlobalVars.SESSION_USERID],
(int)GlobalVars.DocumentType.PartsRequest,
WorkflowNumber);
if (!lastApproverInCurrentStep) break;
if (lastStep)
{
NotifyCompletion(prNumber);
break;
}
currentStep++;
var approvers = MiscDMO.GetApprovalsByDocument(prNumber, (int)GlobalVars.DocumentType.PartsRequest);
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == currentStep) == 0)
return Content("No approvers found for next step, contact support!");
// only continue with approving if the next step has me as an approver also
if (approvers.Count(a => a.Step.HasValue && a.Step.Value == currentStep && a.UserID == myUserID) == 0)
{
NotifyApprovers(prNumber, currentStep);
break;
}
}
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
protected void SendEmailNotification(String subject, int prNumber, string toEmail, string emailTemplate)
{
string senderName = "Parts Request";
EmailNotification en = new EmailNotification(subject, System.Configuration.ConfigurationManager.AppSettings["EmailTemplatesPath"]);
string[] emailparams = new string[5];
emailparams[0] = prNumber.ToString();
emailparams[1] = prNumber.ToString();
emailparams[2] = GlobalVars.hostURL;
emailparams[3] = "Parts Request";
emailparams[4] = Session[GlobalVars.SESSION_USERNAME].ToString();
String userEmail = toEmail;
en.SendNotificationEmail(emailTemplate, GlobalVars.SENDER_EMAIL, senderName, userEmail, null, subject, emailparams);
}
protected void NotifyReAssignment(int prNumber, string email)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
SendEmailNotification(
subject: String.Format("Parts Request Re-Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRReAssigned.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "ReAssigned Approver: " + email
});
}
protected void NotifyCompletion(int prNumber)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
var u = userDMO.GetUserByID(pr.RequestorID);
if ((u != null) && (!String.IsNullOrWhiteSpace(u.Email)))
{
SendEmailNotification(
subject: String.Format("Parts Request Completion notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: u.Email,
emailTemplate: "PRCompleted.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Completed: " + u.Email
});
}
}
public void NotifyRejection(int prNumber)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
var u = userDMO.GetUserByID(pr.OriginatorID);
if ((u != null) && (!String.IsNullOrWhiteSpace(u.Email)))
{
SendEmailNotification(
subject: String.Format("Parts Request Rejection notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: u.Email,
emailTemplate: "PRReject.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Rejected: " + u.Email
});
}
}
protected void NotifyApprovers(int prNumber, byte step)
{
try
{
string emailSentList = "";
var pr = prDMO.Get(prNumber);
if (pr == null)
throw new Exception("Invalid pr#");
List<string> emailList = MiscDMO.GetApproverEmailListByDocument(
prNumber, step, (int)GlobalVars.DocumentType.PartsRequest).Distinct().ToList();
foreach (string email in emailList)
{
try
{
SendEmailNotification(
subject: String.Format("Parts Request Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRAssigned.txt");
}
catch (Exception ex)
{
HandleException(prNumber, ex, "email=" + email);
}
emailSentList += email + ",";
}
try
{
EventLogDMO.Add(new WinEventLog() {
IssueID = prNumber, UserID = @User.Identity.Name, DocumentType = "PR", OperationType = "Email",
Comments = "Approvers for Step " + step.ToString() + ":" + emailSentList });
}
catch { }
}
catch (Exception e)
{
HandleException(prNumber, e, "Step=" + step.ToString());
}
}
[HttpPost]
public ActionResult Reject(int prNumber, byte currentStep, string comments)
{
try
{
if (Session[GlobalVars.SESSION_USERID] != null)
{
wfDMO.Reject(prNumber, currentStep, comments, (int)Session[GlobalVars.SESSION_USERID], (int)GlobalVars.DocumentType.PartsRequest);
NotifyRejection(prNumber);
}
else
{
Response.Redirect("~/Account/Login");
}
return Content("OK");
}
catch (Exception e)
{
return HandleAPIException(prNumber, e);
}
}
public ActionResult ApprovalLogHistory_Read([DataSourceRequest] DataSourceRequest request, int prNumber)
{
return Json(prDMO.GetApprovalLogHistory(prNumber).ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
protected void NotifyAssignment(int prNumber, string email)
{
var pr = prDMO.Get(prNumber);
if (pr == null)
return;
SendEmailNotification(
subject: String.Format("Parts Request Assignment notice for # {0} - {1}", pr.PRNumber, pr.Title),
prNumber: prNumber,
toEmail: email,
emailTemplate: "PRAssigned.txt");
EventLogDMO.Add(new WinEventLog()
{
IssueID = prNumber,
UserID = @User.Identity.Name,
DocumentType = "PR",
OperationType = "Email",
Comments = "Assigned Approver: " + email
});
}
[HttpPost]
public void AddAdditionalApproval(int issueID, byte step, string userIDs)
{
var emailArray = "";
try
{
emailArray = wfDMO.AddAdditionalApproval(issueID, userIDs, step, (int)GlobalVars.DocumentType.PartsRequest);
}
catch (Exception e)
{
HandleAPIException(issueID, e);
}
string emailSentList = "";
string[] emaiList = emailArray.Split(new char[] { '~' });
foreach (string email in emaiList)
{
if (email.Length > 0)
{
NotifyAssignment(issueID, email);
emailSentList += email + ",";
}
}
try
{
EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = @User.Identity.Name, DocumentType = "PR",
OperationType = "Email", Comments = "Additional Approver: " + emailSentList });
}
catch { }
}
}
}