public ActionResult GetAmortizationByAsset(string projectGuid, string paymentDate, int assetId)
        {
            return(ActionUtils.Json(() =>
            {
                var project = new ProjectLogicModel(CurrentUserName, projectGuid);
                var dataset = project.DealSchedule.GetByPaymentDay(DateUtils.ParseDigitDate(paymentDate)).Dataset;
                var asset = dataset.Assets.Single(x => x.AssetId == assetId);

                if (asset.AmortizationType == AmortizationType.UserDefined)
                {
                    var records = dataset.AmortizationSchedule.SelectByAsset(assetId);
                    var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, records);
                    viewModel.AsOfDateBegin = dataset.DatasetSchedule.AsOfDateBegin;
                    viewModel.AsOfDateEnd = dataset.DatasetSchedule.AsOfDateEnd;
                    return ActionUtils.Success(viewModel);
                }
                else if (IsEqualPmtOrEqualPrin(asset.AmortizationType))
                {
                    if (IsEqualPmtOrEqualPrin(asset.SecurityData.PaymentMethod))
                    {
                        //当期的偿付类型是EqualPmt/EqualPrin
                        //返回值为系统根据EqualPmt/EqualPrin测算出的本金
                        var basicAnalyticsData = NancyUtils.GetBasicAnalyticsData(project.Instance.ProjectId, null, dataset.Instance.AsOfDate);
                        var assetCashflow = basicAnalyticsData.BasicAssetCashflow.BasicAssetCashflowItems.SelectByAsset(assetId);

                        var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, assetCashflow);
                        return ActionUtils.Success(viewModel);
                    }
                    else
                    {
                        //已经发生了提前偿付,后几期的偿付类型是EqualPmt/EqualPrin
                        //返回值为提前偿付+系统根据EqualPmt/EqualPrin测算出的本金
                        var records = dataset.AmortizationSchedule.SelectByAsset(assetId);
                        var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, records);

                        var nextDatasetBasicAnalyticsData = NancyUtils.GetBasicAnalyticsData(project.Instance.ProjectId, null, dataset.DatasetSchedule.Next.AsOfDateBegin);
                        var nextAssetCashflowItems = nextDatasetBasicAnalyticsData.BasicAssetCashflow.BasicAssetCashflowItems
                                                     .SelectByAsset(assetId).Where(x => x.PaymentDate > dataset.DatasetSchedule.PaymentDate);

                        viewModel.AddRange(nextAssetCashflowItems);
                        return ActionUtils.Success(viewModel);
                    }
                }
                else if (asset.AmortizationType == AmortizationType.SingleAmortization)
                {
                    var records = dataset.AmortizationSchedule.SelectByAsset(assetId);
                    var sumPrepayMoney = records.Sum(x => x.ReductionAmount);
                    var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, records);
                    viewModel.Add(assetId, asset.SecurityData.PrincipalBalance - sumPrepayMoney, project.DealSchedule.LegalMaturity);
                    return ActionUtils.Success(viewModel);
                }

                return ActionUtils.Failure("无法识别的偿付类型,projectGuid=["
                                           + projectGuid + "] + paymentDate=[" + paymentDate + "] + assetId=[" + assetId + "]");
            }));
        }
        public ActionResult CalculatePrepayAmortizationByAsset(string projectGuid, string paymentDate, int assetId,
                                                               string prepayDate, double money, string distributionType)
        {
            return(ActionUtils.Json(() =>
            {
                CommUtils.Assert(money >= 0, "提前偿付金额不能为负数");
                var type = CommUtils.ParseEnum <PrepayDistrubutionType>(distributionType);
                CommUtils.Assert(type != PrepayDistrubutionType.Custom, "自定义模式下,无法预计算提前偿付数据。");

                var project = new ProjectLogicModel(CurrentUserName, projectGuid);
                var dataset = project.DealSchedule.GetByPaymentDay(DateUtils.ParseDigitDate(paymentDate)).Dataset;
                var asset = dataset.Assets.Single(x => x.AssetId == assetId);

                CommUtils.Assert(DateUtils.ParseDigitDate(prepayDate) >= dataset.DatasetSchedule.AsOfDateBegin &&
                                 DateUtils.ParseDigitDate(prepayDate) <= dataset.DatasetSchedule.AsOfDateEnd,
                                 "提前偿付日期必须在当期时间范围(" + dataset.DatasetSchedule.AsOfDateBegin.ToShortDateString()
                                 + "~" + dataset.DatasetSchedule.AsOfDateEnd.ToShortDateString() + ")内");

                if (asset.AmortizationType == AmortizationType.UserDefined)
                {
                    var amortization = dataset.AmortizationSchedule;
                    amortization.AddPrepayment(assetId, DateUtils.ParseDigitDate(prepayDate), money, type);
                    var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, amortization.SelectByAsset(assetId));
                    return ActionUtils.Success(viewModel);
                }

                //处理等额本金、等额本息、一次偿付类的提前偿付,需要下期模型存在
                if (dataset.Next == null)
                {
                    //下期模型不存在,自动生成下一期模型
                    CommUtils.AssertNotNull(dataset.DatasetSchedule.Next, "找不到下期模型封包日,提前偿付测算失败");

                    CreateDataset(project.Instance, dataset.DatasetSchedule.Next.AsOfDateBegin.ToString("yyyyMMdd"));

                    var assetModifier = new AssetModifier(CurrentUserName);
                    assetModifier.Load(project.Instance.ProjectId, dataset.DatasetSchedule.AsOfDateBegin);
                    assetModifier.GenerateNextDataset(project.Instance.ProjectId);
                }
                CommUtils.AssertNotNull(dataset.Next, "无法找到下期模型数据,提前偿付测算失败");

                if (IsEqualPmtOrEqualPrin(asset.AmortizationType))
                {
                    var curDatasetBasicAnalyticsData = NancyUtils.GetBasicAnalyticsData(project.Instance.ProjectId, null, dataset.DatasetSchedule.AsOfDateBegin);

                    double curDatasetPrincipal = 0;
                    if (IsEqualPmtOrEqualPrin(asset.SecurityData.PaymentMethod))
                    {
                        //当期未发生过提前偿付,当期偿付金额是Nancy测算金额
                        curDatasetPrincipal = curDatasetBasicAnalyticsData.BasicAssetCashflow.BasicAssetCashflowItems
                                              .Single(x => x.AssetId == assetId && x.PaymentDate == dataset.DatasetSchedule.PaymentDate).Principal;
                    }
                    else
                    {
                        var nextDatasetAsset = dataset.Next.Assets.Single(x => x.AssetId == assetId);
                        CommUtils.Assert(IsEqualPmtOrEqualPrin(nextDatasetAsset.AmortizationType),
                                         "第[" + dataset.Next.DatasetSchedule.PaymentDate.ToString("yyyyMMdd") + "]期偿付类型错误,提前偿付测算失败");

                        //当期发生过提前偿付,当期偿付金额是AmortizationSchedule中金额
                        var curAmortizationRecord = dataset.AmortizationSchedule.Single(x => x.ReductionDate == dataset.DatasetSchedule.PaymentDate);
                        //当期未发生本次提前偿付的偿付本金
                        curDatasetPrincipal = (double)curAmortizationRecord.ReductionAmount;
                    }

                    var sumFutureDatasetPrincipal = curDatasetBasicAnalyticsData.BasicAssetCashflow.BasicAssetCashflowItems
                                                    .SelectByAsset(assetId)
                                                    .Where(x => x.PaymentDate > dataset.DatasetSchedule.PaymentDate)
                                                    .Sum(x => x.Principal);

                    var records = new List <AmortizationScheduleRecord>();
                    //当期的新的本金偿付值是 根据等额本金/等额本息计算出的本金值 加上提前偿付金额
                    records.Add(new AmortizationScheduleRecord()
                    {
                        AssetId = assetId,
                        ReductionAmount = curDatasetPrincipal + money,
                        ReductionDate = dataset.DatasetSchedule.PaymentDate
                    });

                    var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, records);

                    //更新下期的本金期末余额(减去提前偿付金额),重新根据等额本金/等额本息计算本金
                    dataset.Next.CollateralCsv.UpdateCellValue(assetId, "PrincipalBalance", (sumFutureDatasetPrincipal - money).ToString());
                    dataset.Next.CollateralCsv.Save();

                    var nextDatasetBasicAnalyticsData = NancyUtils.GetBasicAnalyticsData(project.Instance.ProjectId, null, dataset.DatasetSchedule.Next.AsOfDateBegin);
                    var nextAssetCashflowItems = nextDatasetBasicAnalyticsData.BasicAssetCashflow.BasicAssetCashflowItems
                                                 .SelectByAsset(assetId).Where(x => x.PaymentDate > dataset.DatasetSchedule.PaymentDate);

                    viewModel.AddRange(nextAssetCashflowItems);

                    //恢复下期的本金期末余额
                    dataset.Next.CollateralCsv.UpdateCellValue(assetId, "PrincipalBalance", sumFutureDatasetPrincipal.ToString());
                    dataset.Next.CollateralCsv.Save();

                    return ActionUtils.Success(viewModel);
                }
                else if (asset.AmortizationType == AmortizationType.SingleAmortization)
                {
                    var nextDatasetAsset = dataset.Next.Assets.Single(x => x.AssetId == assetId);
                    CommUtils.AssertEquals(nextDatasetAsset.SecurityData.PaymentMethod, ZEnums.EPaymentMethod.UNDEFINEDENUM,
                                           "无法识别的偿付类型,提前偿付测算失败。");

                    var nextAmortizationRecords = dataset.Next.AmortizationSchedule.SelectByAsset(assetId);
                    CommUtils.AssertEquals(nextAmortizationRecords.Count, 0,
                                           "第[" + dataset.Next.DatasetSchedule.PaymentDate.ToString("yyyyMMdd") + "]期已发生提前偿付, 提前偿付测算失败");

                    var records = dataset.AmortizationSchedule.SelectByAsset(assetId);
                    var viewModel = new PrepayRecordListViewModel(dataset.DatasetSchedule, records);
                    viewModel.Add(assetId, money, DateUtils.ParseDigitDate(prepayDate));

                    var sumPrepayAmount = records.Sum(x => x.ReductionAmount);
                    CommUtils.Assert(sumPrepayAmount <= asset.SecurityData.PrincipalBalance,
                                     "提前偿付金额[" + sumPrepayAmount + "]大于剩余未偿付金额[" + asset.SecurityData.PrincipalBalance + "]");

                    viewModel.Add(assetId, asset.SecurityData.PrincipalBalance - sumPrepayAmount, asset.SecurityData.MaturityDate);
                    return ActionUtils.Success(viewModel);
                }

                return ActionUtils.Success("无法识别的偿付类型,projectGuid=["
                                           + projectGuid + "] + paymentDate=[" + paymentDate + "] + assetId=[" + assetId + "]");
            }));
        }