1. Business Scenario: Users login, receive notifications, approve business, continue to flow according to the configuration process, and send the final audit back to the applicant (final approval is completed, final approval does not agree that the applicant can continue to modify the submission).
2. The process of thinking:
- User login first obtains unprocessed message records and reminds processing of pre-approval records. Configuration process master table and associated step list (flow by serial number) 2. Create pre-approval records (associated processes and steps) when submitting business approval, send messages to the reviewer of the first step, and modify the status of the business master table. Step reviewer agrees: update the approval record of the owner of the node, continue sending messages to the next one if the process details still have the next approval, create the next pre-approval record, modify the status of the business master table, and update the status of the message record of oneself and the owner of the node. Step Reviewers disagree: Stop sending the next one, send it back to the applicant, update the status of the message record and the approval record of yourself and the owner of this node Each node can be configured with multiple approvers, and the first approval node must be the same department before it can be approved (multiple department leaders can be configured, but only to the same department leaders when applications are sent) The login's approval shall be based on the pre-approval record sheet to check whether there is a record to be approved and to determine whether there is the next step. After the approval is completed, it shall continue to be sent to the next step.
3. Database design:
-------------------Process Approval Design--------------------------Create Process Tables Flow: ID,Number, process name, category, developer, date and status(Is it enabled?),Remarks SELECT * FROM [dbo].[Flow] --Create process approval list(Relevant process tables, one-to-many) FlowDetail: ID,Number, serial number, step name, reviewer's account of process master table(Multiple),Name of Judges(Multiple),state(Is it enabled?), select * from FlowDetail --Create an Approval Record Table FlowRecords:ID,Main Table Number, Process Step Number, Business Number, Reviewer Account Number, Reviewer Name, Approval Status(1 Agree, 2 disagree,3 Audit in progress),Examination and approval date, remarks, select * from FlowRecords where BusinessNum='4C4CED8E3F8D42C997E2424D83C447B8' --Create a message notification table Message :ID,Title, Content, Business Number, Receiver's Account, Receiver's Name, Sender's Account, Sender's Name, Sender's Time, Status(1 Unprocessed, 2 processed) select * from FlowMessage where BusinessNum='4C4CED8E3F8D42C997E2424D83C447B8' --Business Main Table (Increase Field Related Approval Process: Process Main Table Number, Process Details Number)
4. Code process:
/// <summary> /// Audit documents /// </summary> /// <param name="entity"></param> /// <returns></returns> public override string Audite(ReceiveOrderEntity entity) { using (TransactionScope ts = new TransactionScope()) { //1.Obtain records of your current business needs to be audited,No, it can't be audited. FlowRecordsEntity record = new FlowRecordsEntity(); record.IncludeAll(); record.Where(a => a.BusinessNum == entity.SnNum).And(a => a.ApproverUserNum == entity.UserName); var myRecord = this.FlowRecords.GetList(record).FirstOrDefault(); if (myRecord == null) return "1003"; if(myRecord.ApproverResult!=3) return "1004"; //2.Get whether there are next steps in the process FlowProvider provider = new FlowProvider(CompanyID); List<FlowDetailEntity> FlowDetails = provider .GetFlowDetail(new FlowDetailEntity {FlowSnNum = entity.FlowSnNum}).OrderBy(x => x.Seq).ToList(); FlowDetailEntity nextFlowDeail = null; int line = 0; if (FlowDetails != null && FlowDetails.Count > 0) { int count = 0; foreach (var obj in FlowDetails) { if (obj.Seq == myRecord.FlowDtlSeq) break; else count++; } //Is there a next step in the process? if (FlowDetails.Count > count && FlowDetails.Count!=count+1) { nextFlowDeail = FlowDetails[count + 1]; } } #region Disagree with process if (entity.Status == (int) EAudite.NotPass) { entity.FlowDtlSeq = myRecord.FlowDtlSeq; entity.IncludeStatus(true).IncludeReason(true).IncludeFlowDtlSeq(true) .Where(a => a.SnNum == entity.SnNum) .And(a => a.CompanyID == this.CompanyID) ; line += this.ReceiveOrder.Update(entity); //1.Update your own approval records myRecord.ApproverResult = 2; myRecord.ApproverDate = DateTime.Now; myRecord.IncludeApproverResult(true).IncludeApproverDate(true); line += this.FlowRecords.Update(myRecord); //2.Renewal of oneself(This step is for everyone)Message Recording FlowMessageEntity msg = new FlowMessageEntity(); msg.Status = 2; msg.IncludeStatus(true); msg.Where(a => a.BusinessNum == entity.SnNum).And(a => a.FlowSnNum == entity.FlowSnNum) .And(a => a.FlowDtlSeq == myRecord.FlowDtlSeq); line += this.FlowMessage.Update(msg); //3.Send only messages back to the applicant FlowMessageEntity nextMsg = new FlowMessageEntity() { SendUserNum = entity.UserName, SendUserName = entity.RealName, AcceptUserNum = entity.CusNum, AcceptUserName = entity.CusName, BusinessNum = entity.SnNum, FlowSnNum = entity.FlowSnNum, FlowDtlSeq = myRecord.FlowDtlSeq, Status = 1, SendDate = DateTime.Now, Title = "Examination and verification of the application for the acquisition of articles", Notice = "Your number is:"+entity.OrderNum+"The application for goods acquisition has been rejected!" }; nextMsg.IncludeAll(); line += this.FlowMessage.Add(nextMsg); ts.Complete(); return line > 0 ? "1000" : string.Empty; } #endregion #region Consent process else if (entity.Status == (int) EAudite.Pass) { //1.Update your own approval records myRecord.ApproverResult = 1; myRecord.ApproverDate = DateTime.Now; myRecord.IncludeApproverResult(true).IncludeApproverDate(true); line += this.FlowRecords.Update(myRecord); //2.Renewal of oneself(This step is for everyone)Message Recording FlowMessageEntity msg = new FlowMessageEntity(); msg.Status = 2; msg.IncludeStatus(true); msg.Where(a => a.BusinessNum == entity.SnNum).And(a => a.FlowSnNum == entity.FlowSnNum) .And(a => a.FlowDtlSeq == myRecord.FlowDtlSeq); line += this.FlowMessage.Update(msg); //If there is a next audit if (nextFlowDeail != null) { //1.Modify business status entity.Status = 5; //2.Get a list of approvers'accounts for the next step var users = nextFlowDeail.ApproverUserNum.Split(',') .Where(x => string.IsNullOrEmpty(x) == false).ToList(); List<AdminEntity> sendUser = new List<AdminEntity>(); users.ForEach(x => { AdminEntity model = new AdminEntity(); model.IncludeAll(); model.Where(a => a.IsDelete == (int)EIsDelete.NotDelete).And(item => item.UserName == x); var user = this.Admin.GetSingle(model); if (user != null) { sendUser.Add(user); } }); foreach (var user in sendUser) { //3.Create a pre-approval record for the next approver FlowRecordsEntity nextRecord = new FlowRecordsEntity() { ApproverUserName = user.RealName, ApproverUserNum = user.UserName, BusinessNum = entity.SnNum, FlowSnNum = entity.FlowSnNum, FlowDtlSeq = nextFlowDeail.Seq, ApproverResult = 3 }; nextRecord.IncludeAll(); line += this.FlowRecords.Add(nextRecord); //4.Send a message to the next approver FlowMessageEntity nextMsg = new FlowMessageEntity() { SendUserNum = entity.UserName, SendUserName = entity.RealName, AcceptUserNum = user.UserName, AcceptUserName = user.RealName, BusinessNum = entity.SnNum, FlowSnNum = entity.FlowSnNum, FlowDtlSeq = nextFlowDeail.Seq, Status = 1, SendDate = DateTime.Now, Title = "Examination and verification of the application for the acquisition of articles", Notice = "No.:" + entity.OrderNum + "The application for goods acquisition needs to be examined by you! ____________" }; nextMsg.IncludeAll(); line += this.FlowMessage.Add(nextMsg); } } else { //Process End entity.Status = (int) EAudite.Pass; //Send a message back to the applicant FlowMessageEntity fristMsg = new FlowMessageEntity() { SendUserNum = entity.UserName, SendUserName = entity.RealName, AcceptUserNum = entity.CusNum, AcceptUserName = entity.CusName, BusinessNum = entity.SnNum, FlowSnNum = entity.FlowSnNum, FlowDtlSeq = myRecord.FlowDtlSeq, Status = 1, SendDate = DateTime.Now, Title = "Examination and verification of the application for the acquisition of articles", Notice = "Your number is:" + entity.OrderNum + "The application for goods acquisition has been approved!" }; fristMsg.IncludeAll(); line += this.FlowMessage.Add(fristMsg); } entity.FlowDtlSeq = myRecord.FlowDtlSeq; entity.AuditeTime = DateTime.Now; entity.Include(a => new {a.Status, a.AuditUser, a.AuditeTime, a.Reason, a.Remark,a.FlowDtlSeq}); entity.Where(a => a.SnNum == entity.SnNum).And(a => a.CompanyID == this.CompanyID); line += this.ReceiveOrder.Update(entity); ts.Complete(); return line > 0 ? EnumHelper.GetEnumDesc<EReturnStatus>(EReturnStatus.Success) : string.Empty; } #endregion } return string.Empty; }