/// <summary>
        /// 更新申请单工作流
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="dbOrders"></param>
        /// <param name="order"></param>
        /// <param name="process"></param>
        /// <param name="currentUser"></param>
        private void UpdateOrderProcess(MissionskyOAEntities dbContext, IEnumerable <Order> dbOrders, OrderModel order,
                                        WorkflowProcessModel process, UserModel currentUser)
        {
            //流程结束 && 批量申请,向流程申请人发推送消息
            if (process.IsCompletedApproved() && order.IsBatchApply)
            {
                this._orderService.AddNotification(dbContext, order, currentUser.Id, process); //默认发送到申请人
            }


            dbOrders.ToList().ForEach(entity =>
            {
                entity.WorkflowId = process.FlowId;
                entity.Status     = (int)process.NextStatus;

                if (process.IsCompletedApproved()) //申请通过 || 过[行政审阅]到[财务审阅]
                {
                    this._orderService.AddNotification(dbContext, order, currentUser.Id, process, entity.UserId);
                }
                else //需要下一步审批
                {
                    if (process.NextApprover == null)
                    {
                        Log.Error("流程下一步审批人异常。");
                        throw new InvalidOperationException("流程下一步审批人异常。");
                    }

                    entity.NextStep  = process.NextStep.Id;
                    entity.NextAudit = process.NextApprover.Id;

                    this._orderService.AddNotification(dbContext, order, currentUser.Id, process,
                                                       process.NextApprover.Id);
                }
            });
        }
        /// <summary>
        /// 流程撤销
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="order">申请单</param>
        /// <param name="owner">申请人</param>
        /// <param name="operation">流程操作</param>
        /// <returns>下一个审批步骤</returns>
        public WorkflowProcessModel Revoke(MissionskyOAEntities dbContext, OrderModel order, UserModel owner, OperateOrderModel operation)
        {
            if (order == null)
            {
                Log.Error("参数无效。");
                throw new InvalidOperationException("参数无效。");
            }

            // 流程审批
            WorkflowProcessModel process = _workflowProcessService.Process(dbContext, order, owner, operation);

            return(process);
        }
        /// <summary>
        /// 添加流程处理记录
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="curUser"></param>
        /// <param name="operation"></param>
        public void AddWorkflowProcess(MissionskyOAEntities dbContext, UserModel curUser,
                                       OperateOrderModel operation)
        {
            var process = new WorkflowProcessModel()
            {
                OrderNo       = operation.OrderNo,
                FlowId        = 0,
                StepId        = 0,
                Operator      = curUser.Id,
                OperationDesc = string.Format("{0}取消了申请单。", curUser.EnglishName),
                Operation     = operation.Operation,
                CreatedTime   = DateTime.Now
            };

            dbContext.WorkflowProcesses.Add(process.ToEntity());
        }
        public static WorkflowProcessModel ToModel(this WorkflowProcess entity)
        {
            var model = new WorkflowProcessModel()
            {
                Id            = entity.Id,
                OrderNo       = entity.OrderNo,
                FlowId        = entity.FlowId,
                StepId        = entity.StepId,
                Operator      = entity.Operator,
                Operation     = (WorkflowOperation)entity.Operation,
                OperationDesc = entity.OperationDesc,
                CreatedTime   = entity.CreatedTime
            };

            return(model);
        }
        public static WorkflowProcess ToEntity(this WorkflowProcessModel model)
        {
            var entity = new WorkflowProcess()
            {
                Id            = model.Id,
                OrderNo       = model.OrderNo,
                FlowId        = model.FlowId,
                StepId        = model.StepId,
                Operator      = model.Operator,
                Operation     = model.Operation == WorkflowOperation.None ? (int)WorkflowOperation.Apply : (int)model.Operation,
                OperationDesc = model.OperationDesc,
                CreatedTime   = model.CreatedTime
            };

            return(entity);
        }
        /// <summary>
        /// 工作流处理消息推送
        /// </summary>
        /// <param name="dbContext"></param>
        /// <param name="order">申请单</param>
        /// <param name="operaterId">消息推送人Id</param>
        /// <param name="process">流程处理</param>
        /// <param name="receiverId">消息接收人Id</param>
        /// <remarks>receiverId = 0: 表示默认发送到代申请人</remarks>
        public void AddNotification(MissionskyOAEntities dbContext, OrderModel order, int operaterId,
                                    WorkflowProcessModel process, int receiverId = 0)
        {
            #region 1. 获取用户信息

            //代理申请人
            var agentUser = dbContext.Users.FirstOrDefault(it => it.Id == order.ApplyUserId);
            if (agentUser == null)
            {
                Log.Error(string.Format("找不到代申请人, Id: {0}", order.ApplyUserId));
                throw new KeyNotFoundException("找不到代申请人。");
            }

            //消息接收人
            var receiver = dbContext.Users.FirstOrDefault(it => it.Id == receiverId);
            receiver = receiver ?? agentUser;

            //消息推送人
            var operater = (operaterId == receiverId
                ? receiver
                : dbContext.Users.FirstOrDefault(it => it.Id == operaterId));

            if (operater == null)
            {
                Log.Error(string.Format("找不到流程操作人, Id: {0}", receiverId));
                throw new KeyNotFoundException("找不到流程操作人。");
            }
            #endregion

            #region 2. 验证申请单

            if (order == null || order.OrderDets == null || order.OrderDets.Count < 1)
            {
                Log.Error("无效的流程申请单。");
                throw new InvalidOperationException("无效的流程申请单。");
            }

            var detail = order.OrderDets.FirstOrDefault();
            if (detail == null || !detail.IOHours.HasValue)
            {
                Log.Error("无效的流程申请单详细。");
                throw new InvalidOperationException("无效的流程申请单详细。");
            }

            // 委托人
            var recipient = dbContext.Users.FirstOrDefault(it => it.Id == detail.Recipient);

            var checkType = order.OrderType;
            if (checkType == OrderType.DaysOff)
            {
                checkType = OrderType.Overtime;
            }

            #endregion

            #region 3. 批量申请,向代申请推送消息

            var model = new NotificationModel()
            {
                Target        = receiver.Email,
                CreatedUserId = operater.Id,
                //MessageType = NotificationType.PushMessage,
                MessageType   = NotificationType.Email,
                BusinessType  = BusinessType.Approving,
                Title         = "Missionsky OA Notification",
                MessagePrams  = "申请单流程处理",
                Scope         = NotificationScope.User,
                CreatedTime   = DateTime.Now,
                TargetUserIds = new List <int> {
                    receiver.Id
                }
            };

            //流程拒绝时,推送拒绝消息
            if (process.Operation == WorkflowOperation.Rejecte)
            {
                model.MessageContent = string.Format("您的{0}单被拒绝。", order.IsOvertime() ? "加班" : "请假");
            }
            //审批流程结束,或者到财务审批时(需要更新用户假期信息)
            else if (process.Operation == WorkflowOperation.Approve &&
                     (process.NextStep == null || process.NextStep.IsFinanceReviewing()))
            {
                if (receiverId == 0) //默认发送到代申请人
                {
                    model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                }
                else if (receiver.Id == receiverId) //发送到请假或加班实际申请人
                {
                    //假期汇总信息
                    var summary =
                        dbContext.AttendanceSummaries.FirstOrDefault(
                            it =>
                            it.UserId == receiverId && it.Type == (int)checkType && it.Year == DateTime.Now.Year);

                    if (summary == null)
                    {
                        Log.Error("未找用户假期或加班信息。");
                        throw new KeyNotFoundException("未找用户假期或加班信息。");
                    }

                    //计算剩余天数
                    var days       = Math.Round(detail.IOHours.Value / 8, 1); //申请天数
                    var remainDays = summary.RemainValue.HasValue
                        ? Math.Round(summary.RemainValue.Value / 8, 1) + days
                        : 0.0;                                    //剩余天数

                    days = Math.Abs(days);                        //取绝对值

                    if (order.OrderType == OrderType.AnnualLeave) //年假
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的年假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的年假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else if (order.OrderType == OrderType.DaysOff) //调休
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的调休假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的调休假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else if (order.OrderType == OrderType.Overtime) //加班
                    {
                        model.MessageContent = order.RefOrderId.HasValue
                            ? string.Format("{0}, 您的调休假被扣除{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays)
                            : string.Format("{0}, 您的调休假增加{1}天,剩余{2}天。", receiver.EnglishName, days, remainDays);
                    }
                    else //其它假期
                    {
                        model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                    }
                }
                else
                {
                    Log.Error("推送消息接收人不匹配。");
                    throw new KeyNotFoundException("推送消息接收人不匹配。");
                }
            }
            //申请或审批时,发送到下一步审批人
            else
            {
                if (receiverId == 0) //默认发送到代申请人
                {
                    model.MessageContent = string.Format("请您及时审批{0}的{1}单, 时间从{2} {3}到{4} {5}, 总时长为{6}, {7}。",
                                                         agentUser.EnglishName,
                                                         order.IsOvertime() ? "加班" : "请假",
                                                         detail.StartDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.StartTime),
                                                         detail.EndDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.EndTime),
                                                         Math.Abs((sbyte)detail.IOHours),
                                                         recipient == null ? "没有工作交接人。" : "把工作交接给了" + recipient.EnglishName
                                                         );

                    model.MessageContent = string.Format("您的{0}单已批准。", order.IsOvertime() ? "加班" : "请假");
                }
                else if (receiver.Id == receiverId) //发送到请假或加班实际申请人
                {
                    model.MessageContent = string.Format("请您及时审批{0}的{1}单,时间从{2} {3}到{4} {5}, 总时长为{6}, {7}。",
                                                         agentUser.EnglishName,
                                                         order.IsOvertime() ? "加班" : "请假",
                                                         detail.StartDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.StartTime),
                                                         detail.EndDate.ToString("yyyy-MM-dd"),
                                                         OrderExtentions.FormatTimeSpan(detail.EndTime),
                                                         Math.Abs((sbyte)detail.IOHours),
                                                         recipient == null ? "没有工作交接人。" : "把工作交接给了" + recipient.EnglishName
                                                         );
                }
                else
                {
                    Log.Error("推送消息接收人不匹配。");
                    throw new KeyNotFoundException("推送消息接收人不匹配。");
                }
            }

            this._notificationService.Add(model, Global.IsProduction); //消息推送

            #endregion
        }
        /// <summary>
        /// 拒绝请假加班申请(撤销)单
        /// </summary>
        /// <param name="model">申请单</param>
        /// <param name="approver">审批人</param>
        /// <returns>是否拒绝成功</returns>
        public bool Rejecte(OperateOrderModel model, UserModel approver)
        {
            if (model == null || model.OrderNo < 1 || approver == null)
            {
                Log.Error("无效的参数。");
                throw new InvalidOperationException("无效的参数。");
            }

            if (string.IsNullOrEmpty(model.Opinion))
            {
                Log.Error("拒拒理由为空。");
                throw new InvalidOperationException("拒拒理由为空。");
            }

            using (var dbContext = new MissionskyOAEntities())
            {
                #region 申请单详细
                //申请单详细
                var orderEntities = dbContext.Orders.Where(it => it.OrderNo == model.OrderNo);

                #region 验证申请是否有效
                var validateEntity = orderEntities.FirstOrDefault();

                //流程及步骤是否有效
                if (validateEntity == null || validateEntity.WorkflowId < 1 || validateEntity.NextStep < 1)
                {
                    Log.Error("申请单流程无效。");
                    throw new InvalidOperationException("申请单流程无效.");
                }

                var validateOrder = validateEntity.ToModel();

                //申请单为撤销单
                var isRevokedOrder = validateOrder.IsRevokedOrder();

                //领导审批中
                var isApproveStatus = validateOrder.IsApproveStatus();

                //行政财务审批中
                var isReviewStatus = validateOrder.IsReviewStatus();

                //申请状态不是审批状态
                if (!isApproveStatus && !isReviewStatus)
                {
                    Log.Error("申请单状态无效。");
                    throw new InvalidOperationException("申请单状态无效.");
                }

                //用户不是申请当前的审批人
                if (approver.Id != validateEntity.NextAudit)
                {
                    Log.Error("当前用户不能审批申请。");
                    throw new InvalidOperationException("当前用户不能审批申请.");
                }

                //申请人详细
                var applicant = dbContext.Users.FirstOrDefault(it => it.Id == validateEntity.ApplyUserId);
                if (applicant == null)
                {
                    Log.Error("无效的申请人。");
                    throw new KeyNotFoundException("无效的申请人。");
                }
                #endregion

                var hasSentToAapplicant = false;  //已经向申请人发送过拒绝申请的推送消息
                var operation           = new OperateOrderModel()
                {
                    Operation = WorkflowOperation.Rejecte, Opinion = model.Opinion
                };
                WorkflowProcessModel process = _workflowProcessService.Process(dbContext, validateOrder, approver, operation); //拒绝申请

                orderEntities.ToList().ForEach(o =>
                {
                    if (isRevokedOrder && !isApproveStatus) //拒绝撤销申请单,则更新原始申请单为通过状态
                    {
                        var oldOrder = dbContext.Orders.FirstOrDefault(it => it.Id == o.RefOrderId.Value);

                        if (oldOrder != null)
                        {
                            oldOrder.Status = (int)OrderStatus.Approved;
                        }
                    }

                    //更新申请单状态[拒绝]
                    o.Status    = (int)OrderStatus.Rejected;
                    o.NextAudit = null; //不再需要审批
                    o.NextStep  = null; //

                    //更新假期
                    //_askLeaveService.RecoverOrder(o.ToModel());

                    hasSentToAapplicant = (hasSentToAapplicant || o.UserId == applicant.Id);
                    AddNotification(dbContext, validateOrder, approver.Id, process, o.Id); //向用户推送拒绝消息
                });

                if (!hasSentToAapplicant)
                {
                    AddNotification(dbContext, validateOrder, approver.Id, process, applicant.Id); //向申请人推送拒绝消息
                }
                #endregion

                #region 添加审计信息
                //审计信息
                var message = new AuditMessageModel()
                {
                    Type        = AuditMessageType.None,
                    Status      = AuditMessageStatus.Unread,
                    CreatedTime = DateTime.Now,
                    Message     = "你拒绝{0}的{1}申请"
                };

                //同意加班申请/撤销消息
                if (validateOrder.IsOvertime())
                {
                    message.Type    = AuditMessageType.Recject_OT_Application_Message;
                    message.Message = string.Format(message.Message, applicant.EnglishName,
                                                    (validateOrder.IsRevokedOrder() ? "加班撤销" : "加班"));
                }

                //同意请假申请/撤销消息
                if (validateOrder.IsAskLeave())
                {
                    message.Type    = AuditMessageType.Recject_Leave_Application_Message;
                    message.Message = string.Format(message.Message, applicant.EnglishName,
                                                    (validateOrder.IsRevokedOrder() ? "请假撤销" : "请假"));
                }

                dbContext.AuditMessages.Add(message.ToEntity());
                #endregion

                //更新数据库
                dbContext.SaveChanges();

                return(true);
            }
        }
        /// <summary>
        /// 流程处理
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        /// <param name="order">申请单</param>
        /// <param name="operation">流程操作</param>
        /// <param name="curUser">当前用户</param>
        /// <returns>流程处理对象</returns>
        /// <remarks>
        /// 流程逻辑:
        /// 1, 提交申请时,查找申请人的直接领导,
        /// 2, 如果申请人的直接领导可以审批通过,则转到行政审批
        /// 3, 如果申请人的直接领导没有权限审批, 则转到审批人的直接领导,重复2的验证
        /// 4, 如果申请人无直接领导,则转到行政审批
        /// </remarks>
        public WorkflowProcessModel Process(MissionskyOAEntities dbContext, OrderModel order, UserModel curUser, OperateOrderModel operation)
        {
            try
            {
                #region 1, 验证申请单数据及状态
                if (order == null || order.OrderDets == null || order.OrderDets.Count < 1)
                {
                    Log.Error("申请单数据无效。");
                    throw new InvalidOperationException("申请单数据无效。");
                }

                if (!order.IsApproveStatus() && !order.IsReviewStatus()) //无效的[审批或审阅]状态
                {
                    Log.Error("申请单状态无效。");
                    throw new KeyNotFoundException("申请单状态无效。");
                }

                if (operation.Operation == WorkflowOperation.Approve &&
                    (order.WorkflowId == null || order.WorkflowId.Value < 1 || order.NextStep == null ||
                     order.NextStep.Value < 1 || order.NextAudit == null || order.NextAudit.Value < 1))
                {
                    Log.Error("申请单流程无效。");
                    throw new KeyNotFoundException("申请单流程无效。");
                }

                var detail = order.OrderDets.FirstOrDefault(); //申请单详细

                if (detail == null || !detail.IOHours.HasValue)
                {
                    throw new KeyNotFoundException("申请单详细数据无效。");
                }
                #endregion

                //流程处理
                var workflow     = GetWorkflow(dbContext, order, curUser, operation);      //2, 选择流程
                var nextStep     = GotoNextStep(order, curUser, workflow, operation);      //3, 选择流程下一步
                var nextApprover = GotoNextApprover(dbContext, nextStep);                  //4, 转到流程下一步审批人
                var nextStatus   = SwitchStatus(order, nextStep, operation);               //5, 转换申请单流程状态

                UpdateAttendanceSummary(dbContext, order, workflow, nextStep, nextStatus); //6, 更新假期表

                var process = new WorkflowProcessModel()
                {
                    OrderNo       = order.OrderNo,
                    FlowId        = workflow.Id,
                    StepId        = operation.Operation == WorkflowOperation.Apply || !order.NextStep.HasValue? 0 : order.NextStep.Value,
                    NextStep      = nextStep,
                    NextApprover  = nextApprover,
                    NextStatus    = nextStatus,
                    Operator      = curUser.Id,
                    OperationDesc =
                        operation.Operation == WorkflowOperation.Apply ? detail.Description : operation.Opinion,
                    Operation =
                        operation.Operation == WorkflowOperation.Apply
                            ? WorkflowOperation.Apply
                            : operation.Operation,
                    CreatedTime = DateTime.Now
                };

                dbContext.WorkflowProcesses.Add(process.ToEntity());

                return(process);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <summary>
        /// 销请假单或者加班单
        /// </summary>
        /// <returns>取消</returns>
        public bool RevokeOrder(int orderNo, RevokeOrderModel model, UserModel applicant)
        {
            using (var dbContext = new MissionskyOAEntities())
            {
                #region 申请单信息

                var revokeOrder = new OrderModel()
                {
                    Status       = OrderStatus.Apply,
                    ApplyUserId  = applicant.Id,
                    IsBatchApply = (model.UserIds.Count() > 1),
                    CreatedTime  = DateTime.Now
                };

                var orderDet = new OrderDetModel()
                {
                    StartDate    = model.StartDate,
                    EndDate      = model.EndDate,
                    StartTime    = model.StartDate.TimeOfDay,
                    EndTime      = model.EndDate.TimeOfDay,
                    IOHours      = model.IOHours,
                    Description  = model.RevokeReason,
                    InformLeader = model.InformLeader,
                    WorkTransfer = model.WorkTransfer,
                    Recipient    = model.Recipient
                };

                revokeOrder.OrderNo    = _orderService.GenerateOrderNo(dbContext);             //生成申请单号
                revokeOrder.OrderUsers = _userService.GetOrderUsers(dbContext, model.UserIds); //相关申请单用户
                revokeOrder.OrderDets  = new List <OrderDetModel>()
                {
                    orderDet
                };

                //验证申请单
                Order oldEntity = null;
                revokeOrder.OrderUsers.ToList().ForEach(ou =>
                {
                    //申请单是否存在
                    oldEntity = dbContext.Orders.FirstOrDefault(o => o.UserId == ou.Id && o.OrderNo == orderNo);
                    if (oldEntity == null)
                    {
                        Log.Error("此订单不存在。");
                        throw new KeyNotFoundException("此订单不存在。");
                    }

                    ou.OrderId = oldEntity.Id; //撤销单Id

                    //是否已经撤销过
                    var revokedEntity =
                        dbContext.Orders.FirstOrDefault(o => o.RefOrderId.HasValue && o.RefOrderId == ou.OrderId);
                    if (revokedEntity != null && !revokedEntity.ToModel().CanRevokeOrder())
                    {
                        Log.Error("已经撤销一次,不能再撤销。");
                        throw new InvalidOperationException("已经撤销一次,不能再撤销。");
                    }
                });

                revokeOrder.OrderType = (OrderType)oldEntity.OrderType;  //申请单类型

                var oldDetailEntity = dbContext.OrderDets.FirstOrDefault(it => it.OrderId == oldEntity.Id);
                if (oldDetailEntity != null && oldDetailEntity.IOHours.HasValue)
                {
                    if (Math.Abs(oldDetailEntity.IOHours.Value) < Math.Abs(model.IOHours))
                    {
                        Log.Error("撤销时长不正确。");
                        throw new InvalidOperationException("撤销时长不正确。");
                    }
                }

                //验证申请单是否有效,并转换IOHours正负值
                ValidOrder(revokeOrder, WorkflowOperation.Revoke);

                #endregion

                //添加初始审批信息
                AddAuditMessages(dbContext, revokeOrder, applicant);

                //对于同意的请假单或者加班单,自动填写新的撤销请假单
                if (oldEntity.Status == (int)OrderStatus.Approved)
                {
                    //添加申请单到数据库
                    var dbOrders = AddOrderToDb(dbContext, revokeOrder, WorkflowOperation.Revoke);

                    //流程申请
                    WorkflowProcessModel process = _orderService.Apply(dbContext, revokeOrder);
                    if (process == null)
                    {
                        Log.Error("找不到流程。");
                        throw new InvalidOperationException("找不到流程。");
                    }

                    //更新申请单工作流
                    UpdateOrderProcess(dbContext, dbOrders, revokeOrder, process, applicant);

                    try
                    {
                        dbContext.SaveChanges();
                    }
                    catch (DbEntityValidationException dbEx)
                    {
                        LogDatabaseError(dbEx);
                        throw dbEx;
                    }

                    return(true);
                }
                else
                {
                    Log.Error("流程处理异常。");
                    throw new InvalidOperationException("流程处理异常。");
                }
            }
        }
        /// <summary>
        /// 添加请假信息
        ///
        /// 处理请假申请单逻辑
        ///
        /// </summary>
        /// <param name="model">申请单详细: 对应APP中的申请单详细</param>
        /// <param name="applicant">流程申请人Id</param>
        /// <returns>请假单信息</returns>
        public OrderModel AddOrder(ApplyOrderModel model, UserModel applicant)
        {
            /*
             *
             *
             *
             * **/

            #region 申请单详细

            // 1、新建申请单变量
            var order = new OrderModel()
            {
                OrderType    = model.OrderType,
                Status       = OrderStatus.Apply,
                ApplyUserId  = applicant.Id,
                IsBatchApply = (model.UserIds.Count() > 1),
                CreatedTime  = DateTime.Now,
            };

            // 2、新建申请单详情
            var orderDet = new OrderDetModel()
            {
                StartDate    = model.StartDate,
                EndDate      = model.EndDate,
                StartTime    = model.StartDate.TimeOfDay,
                EndTime      = model.EndDate.TimeOfDay,
                Description  = model.Description,
                InformLeader = model.InformLeader ?? false,
                WorkTransfer = model.WorkTransfer ?? false,
                Recipient    = model.Recipient ?? 0,
                IOHours      = model.IOHours
            };

            // 3、将申请单详情变量 放入到 申请单变量中
            order.OrderDets = new List <OrderDetModel>()
            {
                orderDet
            };
            #endregion

            // 4、逻辑处理
            using (var dbContext = new MissionskyOAEntities())
            {
                // 1、生成申请单号 、申请单用户
                // OrderNo --> int
                order.OrderNo = _orderService.GenerateOrderNo(dbContext); //生成申请单号

                /*
                 * OrderUsers -->  IList<OrderUserModel>
                 * model.UserIds --> 定义为 int[], 表示可以或者可能有多个申请用户
                 *
                 * **/
                order.OrderUsers = _userService.GetOrderUsers(dbContext, model.UserIds);


                // 2、验证申请单是否有效,并转换IOHours正负值
                ValidOrder(order, WorkflowOperation.Apply);


                // 3、添加初始审批信息
                AddAuditMessages(dbContext, order, applicant);

                // 4、添加申请单到数据库
                var dbOrders = AddOrderToDb(dbContext, order, WorkflowOperation.Apply);

                // 5、流程申请
                WorkflowProcessModel process = _orderService.Apply(dbContext, order);
                if (process == null)
                {
                    Log.Error("找不到流程。");
                    throw new InvalidOperationException("找不到流程。");
                }

                // 6、更新申请单工作流
                UpdateOrderProcess(dbContext, dbOrders, order, process, applicant);

                // 7、发送工作交接通知
                if (model.WorkTransfer.HasValue && model.WorkTransfer.Value && model.Recipient.HasValue && model.OrderType != OrderType.Overtime)
                {
                    _orderService.AddNotification(dbContext, order);
                }

                // 8、更新申请单其它信息
                dbContext.SaveChanges();

                // 9、
                return(order);
            }
        }
 /// <summary>
 /// 流程需要继续审批
 /// </summary>
 /// <param name="process"></param>
 /// <returns></returns>
 public static bool NeedContinueApprove(this WorkflowProcessModel process)
 {
     return(process.NextStep != null && process.NextApprover != null);
 }
 /// <summary>
 /// 流程审批结束
 /// </summary>
 /// <param name="process"></param>
 /// <returns></returns>
 public static bool IsCompletedApproved(this WorkflowProcessModel process)
 {
     return(process.NextStep == null || process.NextStep.IsFinanceReviewing());
 }