private ErrorMessageDTO CalculateAction(CalculateOperatorBonus bpObj)
        {
            ErrorMessageDTO errorDot = new ErrorMessageDTO();

            // 1、 bpObj.Type 为0计算采购业务员奖金,为1计算包装业务员奖金;
            //2、bpObj.OperatorsList为空或者bpObj.OperatorsList.Count为0计算指定会计期间内的所有业务员,反之计算指定业务员奖金
            //操作事件区分,0计算,1补算,2取消计算
            if (bpObj.CalculateType == 0)
            {
                #region 计算奖金功能
                //计算奖金
                #region 计算前校验
                //1、所选会计期间状态必须为“未计算”,
                foreach (BonusCalculateRecordBE.BonusCalculateRecordDTO dto in bpObj.BonusCalcuteList)
                {
                    //勾选的会计期间必须是当前月度前的会计期间并且期间状态是“未计算”的;
                    if (dto.PeriodStatus == EnumBE.PeriodStatusEnum.Calculate || dto.PeriodStatus == EnumBE.PeriodStatusEnum.RepairCalculate)
                    {
                        throw new Exception("会计期间" + dto.SOBAccountingPeriod.DisplayName + "已计算奖金");
                    }
                    if (dto.SOBAccountingPeriod != null && dto.SOBAccountingPeriod.DisplayName != "")
                    {
                        if (Convert.ToDateTime(dto.SOBAccountingPeriod.DisplayName) >= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM")))
                        {
                            throw new Exception("会计期间" + dto.SOBAccountingPeriod.DisplayName + "必须是当前月度前的会计期间");
                        }
                    }
                }
                //2、勾选的会计期间前一个会计期间必须已完成计算,
                //找到最小的会计期间,判断它的前一个会计期间是否已计算
                var minPeriodNumber = bpObj.BonusCalcuteList.Min <BonusCalculateRecordDTO>(p => p.SOBAccountingPeriod.Number);
                if ((Convert.ToInt32(minPeriodNumber) - 10) > 0) //前一个会计期间不为XXXX-01(即本年度第一个会计期间)
                {
                    //勾选的最小会计期间前一个会计期间必须已完成计算,
                    BonusCalculateRecordBE.BonusCalculateRecord record = BonusCalculateRecordBE.BonusCalculateRecord.Finder.Find("SourceType=" + bpObj.Type + " and SOBAccountingPeriod.Year=" + bpObj.Year + " and SOBAccountingPeriod.Number=" + (Convert.ToInt32(minPeriodNumber) - 10) + "");
                    //BonusCalculateRecordBE.BonusCalculateRecord.EntityList recoudList = BonusCalculateRecordBE.BonusCalculateRecord.Finder.FindAll("1=1");
                    if (record == null || record.PeriodStatus == EnumBE.PeriodStatusEnum.NoCalculate)
                    {
                        throw new Exception("勾选的最小会计期间前一个会计期间必须已完成计算");
                    }
                }
                //3、如果勾选多个,则必须是连续性的会计期间,中间不允许出现未计算的或者没有勾选的;
                //先排序,再判断是否连续会计期间
                IEnumerable <BonusCalculateRecordDTO> recordDTO = from calDTO in bpObj.BonusCalcuteList orderby calDTO.SOBAccountingPeriod.Number descending select calDTO;
                int number = 0;//判断是否连续的标志
                foreach (BonusCalculateRecordDTO bonusDTO in recordDTO)
                {
                    if (number != 0)
                    {
                        if (number != bonusDTO.SOBAccountingPeriod.Number)
                        {
                            throw new Exception("请勾选连续的会计期间进行计算");
                        }
                    }
                    number = bonusDTO.SOBAccountingPeriod.Number;
                }
                #endregion 校验结束
                #region 校验通过,计算奖金
                //奖金计算时,不区分组织,即统计发生在勾选的会计期间范围内的已审核的付款通知单,
                //并且付款通知单来源采购订单的业务员类型为产品采购的(组织间的抛单业务除外),
                //根据业务员进行分组,计算业务员奖金,

                #region 获取预置参数
                decimal bonusCoefficient         = 0;                                                                 //奖金系数
                decimal degradationCoefficient   = 0;                                                                 //降价系数
                decimal packaingBonusCoefficient = 0;                                                                 //包装奖金系数
                int     deliveryExpectDay        = 0;                                                                 //交货基准交期
                GetSysteParma(bonusCoefficient, degradationCoefficient, packaingBonusCoefficient, deliveryExpectDay); //获取预置参数值
                #endregion

                #region 查询付款通知单
                //获得会计期间的最大、最小时间
                if (recordDTO == null || recordDTO.Count <BonusCalculateRecordDTO>() == 0)
                {
                    throw new Exception("请选择计算的会计期间");
                }
                //会计期间的最小时间
                string startTime = DateTime.Parse(recordDTO.First <BonusCalculateRecordDTO>().SOBAccountingPeriod.DisplayName).ToString("yyyy-MM-01 00:00:00");
                //string endTime = DateTime.Parse(recordDTO.Last<BonusCalculateRecordDTO>().SOBAccountingPeriod.DisplayName).ToString("yyyy-MM-
                //会计期间的最大时间
                int      year     = DateTime.Parse(recordDTO.Last <BonusCalculateRecordDTO>().SOBAccountingPeriod.DisplayName).Year;
                int      month    = DateTime.Parse(recordDTO.Last <BonusCalculateRecordDTO>().SOBAccountingPeriod.DisplayName).Month;
                int      days     = DateTime.DaysInMonth(year, month);
                DateTime datetime = new DateTime(year, month, 1);
                string   endTime  = datetime.AddDays(days - 1).ToString("yyyy-MM-dd 23:59:59");
                //获取付款通知单数据集
                DataTable tablePayment = GetPaymentData(bpObj, DateTime.Parse(startTime), DateTime.Parse(endTime));
                #endregion
                string docNo = "";
                #region 生成业务员奖金
                if (bpObj.Type == 0)//生成采购业务员奖金
                {
                    docNo = CreateProductOperatorBonus(bpObj, tablePayment, bonusCoefficient, degradationCoefficient, deliveryExpectDay);
                }
                else //生成包装业务员奖金
                {
                    docNo = CreatePackagingOperatorBonus(bpObj, tablePayment, packaingBonusCoefficient);
                }
                #endregion

                #region 生成奖金计算记录
                using (ISession session = Session.Open())
                {
                    BonusCalculateRecord bonusRecord = null;
                    foreach (BonusCalculateRecordDTO bonusDTO in bpObj.BonusCalcuteList)
                    {
                        bonusRecord = BonusCalculateRecord.Create();
                        if (bpObj.Type == 0)
                        {
                            bonusRecord.SourceType = EnumBE.BonusOperatorsTypeEnum.ProductOperators;
                        }
                        else
                        {
                            bonusRecord.SourceType = EnumBE.BonusOperatorsTypeEnum.PackagingOperators;
                        }
                        bonusRecord.SOBAccountingPeriodKey = bonusDTO.SOBAccountingPeriod.Key;
                        bonusRecord.Oprator       = UFIDA.U9.Base.Context.LoginUser;
                        bonusRecord.OprateTime    = DateTime.Now;
                        bonusRecord.PeriodStatus  = EnumBE.PeriodStatusEnum.Calculate;
                        bonusRecord.Org           = UFIDA.U9.Base.Context.LoginOrg;
                        bonusRecord.OperatorBonus = docNo;
                    }
                    session.Commit();
                }
                #endregion

                if (docNo != "")
                {
                    //生成成功,发送消息
                    List <long> recever = new System.Collections.Generic.List <long>();
                    recever.Add(Convert.ToInt64(UFIDA.U9.Base.Context.LoginUserID));
                    UFIDA.U9.Cust.GS.FI.FIBP.PubBP.SendMessageExtend.SendMessage("计算业务员奖金完成,生成单号" + docNo, "业务员奖金计算完成通知", recever, UFIDA.U9.BS.Notification.PriorityEnum.Medium);
                }
                #endregion
                #endregion 计算End
            }
            else if (bpObj.CalculateType == 1)
            {
                #region 补算
                #region 补算前校验
                //可以通过计算范围选择性的选择业务员进行奖金的补算,补算可以跨月进行,补算完后,记录补算的结果,并产生差异明细;
                foreach (BonusCalculateRecordBE.BonusCalculateRecordDTO dto in bpObj.BonusCalcuteList)
                {
                    //勾选的会计期间必须是当前月度前的会计期间并且期间状态是“未计算”的;
                    if (dto.PeriodStatus == EnumBE.PeriodStatusEnum.NoCalculate)
                    {
                        throw new Exception("会计期间" + dto.SOBAccountingPeriod.DisplayName + "未计算奖金,不能补算");
                    }
                }
                #endregion 补算前校验End
                #region 获取预置参数
                decimal bonusCoefficient         = 0;                                                                 //奖金系数
                decimal degradationCoefficient   = 0;                                                                 //降价系数
                decimal packaingBonusCoefficient = 0;                                                                 //包装奖金系数
                int     deliveryExpectDay        = 0;                                                                 //交货基准交期
                GetSysteParma(bonusCoefficient, degradationCoefficient, packaingBonusCoefficient, deliveryExpectDay); //获取预置参数值
                #endregion

                #region 补算
                //获取付款通知单数据集,因为可以跨月计算,所以根据每个会计期间查询
                DataTable tablePayment = GetPaymentData(bpObj, DateTime.Now, DateTime.Now);
                string    docNo        = "";
                #region 生成业务员奖金
                if (bpObj.Type == 0)//生成采购业务员奖金
                {
                    docNo = CreateProductOperatorBonus(bpObj, tablePayment, bonusCoefficient, degradationCoefficient, deliveryExpectDay);
                }
                else //生成包装业务员奖金
                {
                    docNo = CreatePackagingOperatorBonus(bpObj, tablePayment, packaingBonusCoefficient);
                }
                #endregion

                #region 生成奖金计算记录
                using (ISession session = Session.Open())
                {
                    BonusCalculateRecord bonusRecord = null;
                    foreach (BonusCalculateRecordDTO bonusDTO in bpObj.BonusCalcuteList)
                    {
                        bonusRecord = BonusCalculateRecord.Create();
                        if (bpObj.Type == 0)
                        {
                            bonusRecord.SourceType = EnumBE.BonusOperatorsTypeEnum.ProductOperators;
                        }
                        else
                        {
                            bonusRecord.SourceType = EnumBE.BonusOperatorsTypeEnum.PackagingOperators;
                        }
                        bonusRecord.SOBAccountingPeriodKey = bonusDTO.SOBAccountingPeriod.Key;
                        bonusRecord.Oprator             = UFIDA.U9.Base.Context.LoginUser;
                        bonusRecord.OprateTime          = DateTime.Now;
                        bonusRecord.PeriodStatus        = EnumBE.PeriodStatusEnum.RepairCalculate;//补算
                        bonusRecord.Org                 = UFIDA.U9.Base.Context.LoginOrg;
                        bonusRecord.RepairOperatorBonus = docNo;
                    }
                    session.Commit();
                }
                #endregion

                if (docNo != "")
                {
                    //生成成功,发送消息
                    List <long> recever = new System.Collections.Generic.List <long>();
                    recever.Add(Convert.ToInt64(UFIDA.U9.Base.Context.LoginUserID));
                    UFIDA.U9.Cust.GS.FI.FIBP.PubBP.SendMessageExtend.SendMessage("计算业务员奖金完成,生成单号" + docNo, "业务员奖金计算完成通知", recever, UFIDA.U9.BS.Notification.PriorityEnum.Medium);
                }
                #endregion 补算 End
                #endregion 补算
            }
            else if (bpObj.CalculateType == 2)
            {
                #region 取消计算
                //1、勾选的会计期间前后的会计期间状态必须是“未计算”的,否则提示不允许取消;
                //2、校验通过后,删除勾选的会计期间对应的业务员奖金计算结果
                #region 取消计算前校验
                foreach (BonusCalculateRecordBE.BonusCalculateRecordDTO dto in bpObj.BonusCalcuteList)
                {
                    //勾选的会计期间必须是当前月度前的会计期间并且期间状态是“未计算”的;
                    if (dto.PeriodStatus == EnumBE.PeriodStatusEnum.NoCalculate)
                    {
                        throw new Exception("会计期间" + dto.SOBAccountingPeriod.DisplayName + "未计算奖金,无需取消计算");
                    }
                }
                #endregion 取消计算前校验 end

                #region 取消计算
                using (ISession session = Session.Open())
                {
                    BonusProductDoc   bonusProduct   = null;
                    BonusPackagingDoc bonusPackaging = null;
                    foreach (BonusCalculateRecordBE.BonusCalculateRecordDTO dto in bpObj.BonusCalcuteList)
                    {
                        if (dto.ID > 0)
                        {
                            if (bpObj.Type == 0)//采购业务员奖金
                            {
                                bonusProduct = BonusProductDoc.Finder.Find("OperatorBonus='" + dto.OperatorBonus + "'");
                                if (bonusProduct != null)
                                {
                                    bonusProduct.Remove();
                                }
                            }
                            else if (bpObj.Type == 1)//包装业务员奖金
                            {
                                bonusPackaging = BonusPackagingDoc.Finder.Find("OperatorBonus='" + dto.OperatorBonus + "'");
                                if (bonusPackaging != null)
                                {
                                    bonusPackaging.Remove();
                                }
                            }
                        }
                    }
                    session.Commit();
                }
                #endregion

                #endregion
            }
            return(errorDot);
        }
        /// <summary>
        /// 创建包装业务员奖金
        /// </summary>
        /// <param name="bpObj">BP入口参数:会计期间集合</param>
        /// <param name="dsPayment">付款通知单数据集</param>
        /// <param name="bonusCoefficient">奖金系数</param>
        /// <param name="degradationCoefficient">降价系数</param>
        /// <param name="DeliveryExpectDay">基准交期</param>
        private string CreatePackagingOperatorBonus(CalculateOperatorBonus bpObj, DataTable dsPayment, decimal packaingBonusCoefficient)
        {
            if (dsPayment == null || dsPayment.Rows.Count == 0)
            {
                return("");
            }
            var groupOperators             = dsPayment.Rows.Cast <DataRow>().GroupBy(t => t["Operators_Code"].ToString());
            BonusOperatorDocType bonusType = BonusOperatorDocType.Finder.Find("BuzType=1 and IsCreatedByPush=1");

            if (bonusType == null)
            {
                throw new Exception("请设置产品包装业务员单据类型并设置为上游单据推出");
            }
            using (ISession session = Session.Open())
            {
                BonusPackagingDoc bonusProduct = BonusPackagingDoc.Create();
                bonusProduct.DocumentTypeKey = bonusType.Key; //单据类型
                bonusProduct.BusinessDate    = DateTime.Now;  //业务日期
                bonusProduct.Status          = EnumBE.FICommonStatusEnum.Opened;
                if (bpObj.BonusCalcuteList[0].SOBAccountingPeriod != null && bpObj.BonusCalcuteList[0].SOBAccountingPeriod.AccountPeriod != null)
                {
                    bonusProduct.AccountPeriodKey = bpObj.BonusCalcuteList[0].SOBAccountingPeriod.AccountPeriod.AccountingCalendarKey; //会计日历
                }
                bonusProduct.CurrencyKey = Base.Currency.Currency.Finder.Find("Code='C001'").Key;                                      //币种只会为人民币,
                bonusProduct.Oprator     = Base.Context.LoginUser;
                bonusProduct.OprateDate  = DateTime.Now;

                //设置默认行号
                GetProfileValueProxy lineNo = new GetProfileValueProxy();
                lineNo.ProfileCode = "SysLineNo";
                PVDTOData pVTDOData = lineNo.Do();
                string    row       = pVTDOData.ProfileValue;
                //根据业务员分组后的付款通知单数据
                foreach (var groupOperator in groupOperators)
                {
                    decimal sumPayment           = 0; //付款单总额,
                    decimal sumPerformance       = 0; //业绩单总额
                    decimal productBonusTotal    = 0; //新产品奖金合计
                    decimal depreciateBonusTotal = 0; //降价奖金合计
                    decimal bonusTotal           = 0; //奖金合计
                    long    operatorsKey         = Convert.ToInt64(groupOperator.First <DataRow>()["Operators"].ToString());
                    long    dept = Convert.ToInt64(groupOperator.First <DataRow>()["Department"].ToString());
                    BonusPackagingDocLine productLine = BonusPackagingDocLine.Create(bonusProduct); //业务员奖金明细行
                    productLine.DocLineNo = Convert.ToInt32(row);                                   //行号
                    if (operatorsKey > 0)
                    {
                        productLine.OperatorsKey = CBO.HR.Operator.Operators.Finder.FindByID(operatorsKey).Key;//业务员
                    }
                    if (dept > 0)
                    {
                        productLine.DepartmentKey = CBO.HR.Department.Department.Finder.FindByID(dept).Key;//部门
                    }
                    //设置默认行号
                    string subRow = pVTDOData.ProfileValue;
                    foreach (DataRow Operator in groupOperator)
                    {
                        if (Convert.ToInt32(Operator["SrcDocType"].ToString()) != EnumBE.PaySrcDocTypeEnum.Rcv.Value)
                        {
                            continue;
                        }
                        BonusPackagingDocSubLine subLine = BonusPackagingDocSubLine.Create(productLine);
                        subLine.DocLineNo     = Convert.ToInt32(subRow);
                        subLine.OperatorsKey  = CBO.HR.Operator.Operators.Finder.FindByID(operatorsKey).Key; //业务员
                        subLine.DepartmentKey = CBO.HR.Department.Department.Finder.FindByID(dept).Key;      //部门
                        decimal payment = decimal.Parse(Operator["Payment"].ToString());                     //付款单金额,转换成人民币
                        subLine.PaymentMey = payment;                                                        //付款单小类金额
                        sumPayment        += payment;
                        //获得产品系数档案
                        ProductCoefficient coefficient = ProductCoefficient.Finder.Find("ItemMaster.Code='" + Operator["Item_Code"].ToString() + "'");
                        if (coefficient == null)
                        {
                            throw new Exception("料品" + Operator["Item_Code"].ToString() + " " + Operator["Item_Name"].ToString() + "没有维护类别系数档案");
                        }
                        subLine.CategoryCoefficient = coefficient;                                                                                                         //类别系数
                        subLine.PaymentRowCount     = groupOperator.Where <DataRow>(p => p["PaymentID"].ToString() == Operator["PaymentID"].ToString()).Count <DataRow>(); //付款单行数

                        decimal customerCoefficient = 1;
                        //1、如果来源采购订单有接单客户则算取出客户的客户难易系数,否则默认1
                        if (Operator["Customer"].ToString() != "")
                        {
                            CBO.SCM.Customer.Customer customer = CBO.SCM.Customer.Customer.Finder.FindByID(Operator["Customer"].ToString());
                            if (customer != null && customer.DescFlexField.PubDescSeg24 != "")
                            {
                                customerCoefficient = decimal.Parse(customer.DescFlexField.PubDescSeg24);
                            }
                        }
                        subLine.CustomerCoefficient = customerCoefficient;      //客户难易系数
                        subLine.ItemCoefficient     = packaingBonusCoefficient; //小类奖金系数
                        //计算奖金:付款通知单行数*类别系数*客户难易系数 + 付款单小类金额*千分之4*客户难易系数
                        subLine.Bonus = subLine.PaymentRowCount * coefficient.Coefficien * customerCoefficient * +payment * packaingBonusCoefficient * customerCoefficient;
                        //subLine.ExpectMey = //预期奖金
                        subLine.PaymentDocKey = PaymentBE.Payment.Finder.FindByID(Operator["PaymentID"].ToString()).Key;
                        subLine.PaymentDocNo  = Operator["Payment_DocNo"].ToString();
                        subLine.ItemKey       = CBO.SCM.Item.ItemMaster.Finder.FindByID(Operator["Item"].ToString()).Key;
                        subLine.SrcDocLineNo  = Convert.ToInt32(Operator["SrcDocLineNo"].ToString());

                        //降价奖金
                        subRow = (int.Parse(subRow) + int.Parse(pVTDOData.ProfileValue)).ToString();//自增行号
                    }
                    productLine.SumPayment = sumPayment;

                    productLine.BonusTotal = bonusTotal;
                    row = (int.Parse(row) + int.Parse(pVTDOData.ProfileValue)).ToString();//自增行号
                }
                session.Commit();
                return(bonusProduct.DocNo);
            }
        }