Ejemplo n.º 1
0
        public void TestCreateScheduleSetupFeeBrokerSetupFee()
        {
            var nlModel = new NL_Model(1);

            DecorateNL_LoanNL_LoanHistory(nlModel);
            DecorateNL_Offers(nlModel, NLFeeTypes.ServicingFee, true);

            var legacyLoanCalculator = new LegacyLoanCalculator(nlModel, DateTime.UtcNow);

            legacyLoanCalculator.CreateSchedule();

            Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(nlModel.Loan.LastHistory().Schedule.Count == 3);

            var nlLoanSchedule = nlModel.Loan.LastHistory().Schedule.FirstOrDefault(x => x.Position == 1);

            Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(nlLoanSchedule != null &&
                                                                       nlLoanSchedule.Principal == 333 &&
                                                                       nlLoanSchedule.Balance == 999 &&
                                                                       nlLoanSchedule.InterestRate == 2 &&
                                                                       nlLoanSchedule.PlannedDate == new DateTime(2015, 2, 15));

            nlLoanSchedule = nlModel.Loan.LastHistory().Schedule.FirstOrDefault(x => x.Position == 2);
            Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(nlLoanSchedule != null &&
                                                                       nlLoanSchedule.Principal == 333 &&
                                                                       nlLoanSchedule.Balance == 666 &&
                                                                       nlLoanSchedule.InterestRate == 2 &&
                                                                       nlLoanSchedule.PlannedDate == new DateTime(2015, 3, 15));

            nlLoanSchedule = nlModel.Loan.LastHistory().Schedule.FirstOrDefault(x => x.Position == 3);
            Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(nlLoanSchedule != null &&
                                                                       nlLoanSchedule.Principal == 333 &&
                                                                       nlLoanSchedule.Balance == 333 &&
                                                                       nlLoanSchedule.InterestRate == 2 &&
                                                                       nlLoanSchedule.PlannedDate == new DateTime(2015, 4, 15));
        }
Ejemplo n.º 2
0
		public void CalculatorState() {
			DateTime calcTime = DateTime.UtcNow;
			const long loanID = 10007;
			const int customerID = 59;
			GetLoanState dbState = new GetLoanState(customerID, loanID, calcTime, 357, false);
			try {
				dbState.Execute();
			} catch (NL_ExceptionInputDataInvalid nlExceptionInputDataInvalid) {
				Console.WriteLine(nlExceptionInputDataInvalid.Message);
				return;
			}
			try {
				ALoanCalculator calc = new LegacyLoanCalculator(dbState.Result, calcTime);
				calc.GetState();
				m_oLog.Debug("----------------------------------{0}", calc.WorkingModel);
			} catch (Exception exception) {
				m_oLog.Error("{0}", exception.Message);
			}

			return;

			// old loan
			LoanRepository loanRep = ObjectFactory.GetInstance<LoanRepository>();
			Loan oldLoan = loanRep.Get(dbState.Result.Loan.OldLoanID);
			// old calc
			LoanRepaymentScheduleCalculator oldCalc = new LoanRepaymentScheduleCalculator(oldLoan, calcTime, 0);
			oldCalc.GetState();

			m_oLog.Debug("++++++++++++++++++++++++++++++old loan: {0}", oldLoan);
			m_oLog.Debug("NextEarlyPayment={0}", oldCalc.NextEarlyPayment());
		}
Ejemplo n.º 3
0
        public void GetStateHistoriesEvents()
        {
            var nlModel = new NL_Model(1);

            DecorateNL_LoanNL_LoanHistory(nlModel);
            DecorateHistory(nlModel);

            var legacyLoanCalculator = new LegacyLoanCalculator(nlModel, DateTime.UtcNow);

            legacyLoanCalculator.GetState();
        }
Ejemplo n.º 4
0
        public void GetStateAcceptedRolloverEvents()
        {
            var nlModel = new NL_Model(1);

            DecorateNL_LoanNL_LoanHistory(nlModel);
            DecorateNL_Offers(nlModel, NLFeeTypes.ServicingFee);
            DecoratePayment(nlModel);

            var legacyLoanCalculator = new LegacyLoanCalculator(nlModel, DateTime.UtcNow);
            //legacyLoanCalculator.
            //legacyLoanCalculator.GetState();
        }
Ejemplo n.º 5
0
        public void CreateSchedule()
        {
            NL_Model model = new NL_Model(56)
            {
                UserID = 357,
                Loan   = new NL_Loans()
            };

            model.Loan.Histories.Add(new NL_LoanHistory()
            {
                EventTime      = new DateTime(2015, 10, 15),            //DateTime.UtcNow,
                Amount         = 1000,
                RepaymentCount = 4,
                InterestRate   = 0.0225m,
            });
            var discounts = DB.Fill <NL_DiscountPlanEntries>("NL_DiscountPlanEntriesGet", CommandSpecies.StoredProcedure, new QueryParameter("@DiscountPlanID", 2));

            foreach (NL_DiscountPlanEntries dpe in discounts)
            {
                model.Offer.DiscountPlan.Add(Decimal.Parse(dpe.InterestDiscount.ToString(CultureInfo.InvariantCulture)));
            }
            //model.Offer.DiscountPlan.ForEach(d => Log.Info("discount entry: {0}", d));
            model.Offer.OfferFees = DB.Fill <NL_OfferFees>("NL_OfferFeesGet", CommandSpecies.StoredProcedure, new QueryParameter("@OfferID", 3));
            model.Offer.OfferFees.ForEach(f => Log.Info("fee: {0}", f));

            try {
                ALoanCalculator calc = new LegacyLoanCalculator(model);
                calc.CreateSchedule();
            } catch (NoInitialDataException noInitialDataException) {
                Log.Debug(noInitialDataException);
            } catch (InvalidInitialRepaymentCountException invalidInitialRepaymentCountException) {
                Log.Debug(invalidInitialRepaymentCountException);
            } catch (InvalidInitialInterestRateException invalidInitialInterestRateException) {
                Log.Debug(invalidInitialInterestRateException);
            } catch (InvalidInitialAmountException invalidInitialAmountException) {
                Log.Debug(invalidInitialAmountException);
            } catch (Exception exception) {
                Log.Error("No calculator instance {0}", exception);
            }

            Log.Info(model.Loan);
            //model.Loan.LastHistory().Schedule.ForEach(s => Log.Info(s.ToString()));
        }
Ejemplo n.º 6
0
		public void CreateSchedule() {
			DateTime issueDate = DateTime.UtcNow; // new DateTime(2015, 12, 8, 19, 12, 00);
			NL_Model model = new NL_Model(1394) { UserID = 357, Loan = new NL_Loans() };
			model.Loan.Histories.Add(new NL_LoanHistory() { EventTime = issueDate });
			BuildLoanFromOffer strategy = new BuildLoanFromOffer(model);
			strategy.Execute();
			if (!string.IsNullOrEmpty(strategy.Error)) {
				m_oLog.Debug("error: {0}", strategy.Error);
				return;
			}
			model = strategy.Result;
			m_oLog.Debug("=================================={0}\n", model.Loan);
			try {
				ALoanCalculator calc = new LegacyLoanCalculator(model);
				calc.CreateSchedule();
				m_oLog.Debug("=================Calculator end================={0}\n", model.Loan);
			} catch (Exception exception) {
				m_oLog.Error("{0}", exception.Message);
			}
		}
Ejemplo n.º 7
0
		public void TestDateInterval() {
			const long loanID = 17;
			GetLoanState strategy = new GetLoanState(56, loanID, DateTime.UtcNow, 357);
			strategy.Execute();
			NL_Model model = strategy.Result;
			model.Loan.Payments.Clear();
			try {
				DateTime calcDate = new DateTime(2015, 10, 25);
				ALoanCalculator calc = new LegacyLoanCalculator(model);
				DateTime start = calcDate;
				DateTime end = new DateTime(2016, 02, 25);
				int days = end.Subtract(start).Days;
				m_oLog.Debug("total days: {0}", days);
				var schedule = model.Loan.LastHistory().Schedule;
				for (int i=0; i <= days; i++) {
					DateTime theDate = start.AddDays(i);
					var scheduleItem = schedule.FirstOrDefault(s => theDate.Date >= calc.PreviousScheduleDate(s.PlannedDate.Date, RepaymentIntervalTypes.Month) && theDate.Date <= s.PlannedDate.Date);
					m_oLog.Debug("theDate: {0}, {1}", theDate, scheduleItem.PlannedDate);
				}
			} catch (Exception exception) {
				m_oLog.Error("{0}", exception.Message);
			}
		}
Ejemplo n.º 8
0
		public void APR() {
			const int userID = 357;
			const int oldLoanID = 3091;
			LoanRepository loanRep = ObjectFactory.GetInstance<LoanRepository>();
			Loan oldLoan = loanRep.Get(oldLoanID);
			DateTime now = oldLoan.Date;
			NL_Model model = new NL_Model(oldLoan.Customer.Id) {
				UserID = userID,
				Loan = new NL_Loans() { OldLoanID = oldLoan.Id, Refnum = oldLoan.RefNumber }
			};
			model.Loan.Histories.Add(new NL_LoanHistory() {
				EventTime = now,
				InterestRate = oldLoan.InterestRate,
				RepaymentCount = oldLoan.Schedule.Count,
				Amount = oldLoan.LoanAmount
			});
			try {
				ALoanCalculator calc = new LegacyLoanCalculator(model);
				double apr = calc.CalculateApr();
				m_oLog.Debug("CalculationDate: {0}, apr: {1}", calc.CalculationDate, apr);
			} catch (Exception exception) {
				m_oLog.Error("{0}", exception.Message);
			}
		}
Ejemplo n.º 9
0
		/**
			- loan
			- fees
			- history
			- schedules
			- broker comissions ? - update NLLoanID
			- fund transfer
			- pacnet transaction
			- agreements
			- loan options row
			*/
		public override void Execute() {

			if (!CurrentValues.Instance.NewLoanRun) {
				NL_AddLog(LogType.Info, "NL disabled by configuration", null, null, null, null);
				return;
			}

			NL_AddLog(LogType.Info, "Strategy Start", this.strategyArgs, Error, null, null);

			try {
				if (model.CustomerID == 0) {
					Error = NL_ExceptionCustomerNotFound.DefaultMessage;
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				if (model.Loan == null) {
					Error = NL_ExceptionRequiredDataNotFound.Loan;
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				if (model.Loan.OldLoanID == null) {
					Error = NL_ExceptionRequiredDataNotFound.OldLoan;
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				var history = model.Loan.LastHistory();

				if (history == null) {
					Error = NL_ExceptionRequiredDataNotFound.LastHistory;
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				if (history.Agreements == null || history.Agreements.Count == 0) {
					Error = string.Format("Expected input data not found (NL_Model initialized by: NLAgreementItem list). Customer {0}", model.CustomerID);
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				if (string.IsNullOrEmpty(history.AgreementModel)) {
					Error = string.Format("Expected input data not found (NL_Model initialized by: AgreementModel in JSON). Customer {0}", model.CustomerID);
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				BuildLoanFromOffer dataForLoan = new BuildLoanFromOffer(model);
				try {
					dataForLoan.Execute();
					// ReSharper disable once CatchAllClause
				} catch (Exception ex) {
					Log.Alert(ex.Message);
				}

				if (!string.IsNullOrEmpty(dataForLoan.Error)) {
					Error = dataForLoan.Error;
					NL_AddLog(LogType.DataExsistense, "Strategy failed - Failed to generate Schedule/fees", this.strategyArgs, null, Error, null);
					return;
				}

				model = dataForLoan.Result;

				// prevent to create the same loan (by refnum)
				if (!string.IsNullOrEmpty(model.Loan.Refnum) && !string.IsNullOrEmpty(dataForLoan.DataForLoan.ExistsRefnums) && dataForLoan.DataForLoan.ExistsRefnums.Contains(model.Loan.Refnum)) {
					Error = NL_ExceptionLoanExists.DefaultMessage;
					NL_AddLog(LogType.Info, "Strategy End", this.strategyArgs, null, Error, null);
					return;
				}

				// setup/distributed fees

				// for now: only one-time or "spreaded" setup fees supported
				// add full fees 2.0 support later

				var offerFees = model.Offer.OfferFees;

				// don't create LoanFees if OfferFees Percent == 0 or AbsoluteAmount == 0
				var setupFee = offerFees.FirstOrDefault(f => f.LoanFeeTypeID == (int)NLFeeTypes.SetupFee && (f.Percent > 0 || f.AbsoluteAmount > 0));
				var servicingFee = offerFees.FirstOrDefault(f => f.LoanFeeTypeID == (int)NLFeeTypes.ServicingFee && (f.Percent > 0 || f.AbsoluteAmount > 0)); // equal to "setup spreaded"
				decimal? brokerFeePercent = model.Offer.BrokerSetupFeePercent;
			 
				var feeCalculator = new SetupFeeCalculator(setupFee!=null ?setupFee.Percent: servicingFee.Percent, brokerFeePercent);
				SetupFeeCalculator.AbsoluteFeeAmount ff = feeCalculator.Calculate(history.Amount);
				decimal setupFeeAmount = ff.Total;
				model.BrokerComissions = ff.Broker;

				// send ot Calculator to distribute and attach to schedule planned dates
				history.DistributedFees = servicingFee == null ? 0: setupFeeAmount;
				
				ALoanCalculator nlCalculator = new LegacyLoanCalculator(model);
				// 2. Init Schedule and Fees
				try {
					// model should contain Schedule and Fees after this invocation
					nlCalculator.CreateSchedule(); // create primary dates/p/r/f distribution of schedules (P/n) and setup/servicing fees. 7 September - fully completed schedule + fee + amounts due, without payments.
				} catch (NoInitialDataException noDataException) {
					Error = noDataException.Message;
				} catch (InvalidInitialAmountException amountException) {
					Error = amountException.Message;
				} catch (InvalidInitialInterestRateException interestRateException) {
					Error = interestRateException.Message;
				} catch (InvalidInitialRepaymentCountException paymentsException) {
					Error = paymentsException.Message;
					// ReSharper disable once CatchAllClause
				} catch (Exception ex) {
					Error = string.Format("Failed to get calculator instance/Schedule. customer {0}, err: {1}", model.CustomerID, ex.Message);
					NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, null, Error, ex.StackTrace);
					return;
				}

				//// prevent creation of same loan
				//if (!string.IsNullOrEmpty(Error)) {
				//	Log.Info("Failed to calculate Schedule. customer {0}, err: {1}", model.CustomerID, Error);
				//	NL_AddLog(LogType.Error, "Strategy " + string.Format("Failed to calculate Schedule. customer {0}, err: {1}", model.CustomerID, Error), this.strategyArgs, null, Error, null);
				//	return;
				//}

				history.OutstandingInterest = nlCalculator.Interest;

				List<NL_LoanSchedules> nlSchedule = new List<NL_LoanSchedules>();
				List<NL_LoanFees> nlFees = new List<NL_LoanFees>();
				List<NL_LoanAgreements> nlAgreements = new List<NL_LoanAgreements>();

				// get updated history filled with Schedule
				history = model.Loan.LastHistory();

				// copy to local schedules list
				history.Schedule.ForEach(s => nlSchedule.Add(s));

				if (nlSchedule.Count == 0) {
					Error += "Failed to generate Schedule/fees";
					NL_AddLog(LogType.Info, "Strategy failed", this.strategyArgs, null, Error, null);
					return;
				}

				// 3. complete NL_Loans object data
				model.Loan = dataForLoan.Result.Loan;
				model.Loan.CreationTime = nowTime;
				model.Loan.LoanStatusID = (int)NLLoanStatuses.Live;
				model.Loan.Position += 1;
				
				ConnectionWrapper pconn = DB.GetPersistent();

				try {

					pconn.BeginTransaction();

					// 4. save loan
					LoanID = DB.ExecuteScalar<long>(pconn, "NL_LoansSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter("Tbl", model.Loan));
					model.Loan.LoanID = LoanID;

					//Log.Debug("NL_LoansSave: LoanID: {0}", this.LoanID);

					// 5. fees
					// copy to local fees list
					model.Loan.Fees.ForEach(f => nlFees.Add(f));

					foreach (NL_LoanFees f in nlFees) {
						f.CreatedTime = nowTime; // from calc-r
						f.AssignedByUserID = 1; //  from calc-r
						f.LoanID = LoanID;
					}

					// setup as fee
					if (setupFee != null) {
						Log.Debug("setupFeeAmount: {0}", setupFeeAmount);
						nlFees.Add(
							new NL_LoanFees() {
								LoanID = LoanID,
								Amount = setupFeeAmount,
								AssignTime = history.EventTime,
								Notes = "setup fee one-part",
								LoanFeeTypeID = (int)NLFeeTypes.SetupFee,
								CreatedTime = nowTime,
								AssignedByUserID = 1
							});
					}

					nlFees.ForEach(f => Log.Debug("Adding fees: {0}", f));

					// insert fees
					DB.ExecuteNonQuery(pconn, "NL_LoanFeesSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter<NL_LoanFees>("Tbl", nlFees));

					model.Loan.Fees.Clear();
					model.Loan.Fees.AddRange(nlFees);

					// 7. history
					history.LoanID = LoanID;
					history.Description = "adding loan. oldID: " + model.Loan.OldLoanID;

					//Log.Debug("Adding history: {0}", history);

					history.LoanHistoryID = DB.ExecuteScalar<long>(pconn, "NL_LoanHistorySave", CommandSpecies.StoredProcedure, DB.CreateTableParameter("Tbl", history));

					//Log.Debug("NL_LoanHistorySave: LoanID: {0}, LoanHistoryID: {1}", model.Loan.LoanID, history.LoanHistoryID);

					// 8. loan agreements
					history.Agreements.ForEach(a => nlAgreements.Add(a));
					nlAgreements.ForEach(a => a.LoanHistoryID = history.LoanHistoryID);

					//nlAgreements.ForEach(a => Log.Debug("Adding agreement: {0}", a));

					DB.ExecuteNonQuery(pconn, "NL_LoanAgreementsSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter<NL_LoanAgreements>("Tbl", nlAgreements));

					// 9. schedules 
					nlSchedule.ForEach(s => s.LoanHistoryID = history.LoanHistoryID);

					//nlSchedule.ForEach(s => Log.Debug("Adding schedule: {0}", s));

					DB.ExecuteNonQuery(pconn, "NL_LoanSchedulesSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter<NL_LoanSchedules>("Tbl", nlSchedule));

					// 10. Fund Transfer 
					if (model.FundTransfer != null) {
						model.FundTransfer.LoanID = LoanID;
						model.FundTransfer.FundTransferID = DB.ExecuteScalar<long>(pconn, "NL_FundTransfersSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter("Tbl", model.FundTransfer));
						//Log.Debug("NL_FundTransfersSave: LoanID: {0}, fundTransferID: {1}", this.LoanID, model.FundTransfer.FundTransferID);
					}

					// 11. save default loan options record
					model.Loan.LoanOptions.LoanOptionsID = DB.ExecuteScalar<long>(pconn, "NL_LoanOptionsSave",
					   CommandSpecies.StoredProcedure, DB.CreateTableParameter("Tbl", new NL_LoanOptions {
						   LoanID = LoanID,
						   UserID = 1, // default system user?
						   InsertDate = nowTime,
						   IsActive = true,
						   Notes = "default options"
					   }), new QueryParameter("@LoanID", LoanID)
					 );

					pconn.Commit();

					// ReSharper disable once CatchAllClause
				} catch (Exception ex) {

					pconn.Rollback();

					LoanID = 0;
					Error = ex.Message;
					Log.Error("Failed to add new loan: {0}", Error);

					SendMail("NL: loan rolled back", history, nlFees, nlSchedule, nlAgreements);

					NL_AddLog(LogType.Error, "Strategy failed - Failed to add new loan", this.strategyArgs, Error, ex.ToString(), ex.StackTrace);
					return;
				}

				// 7. Pacnet transaction
				try {
					if (model.FundTransfer != null && (model.FundTransfer.PacnetTransactions.Count > 0 && model.FundTransfer.FundTransferID > 0)) {

						var pacnetTransaction = model.FundTransfer.LastPacnetTransactions();
						pacnetTransaction.FundTransferID = model.FundTransfer.FundTransferID;
						pacnetTransaction.PacnetTransactionID = DB.ExecuteScalar<long>("NL_PacnetTransactionsSave", CommandSpecies.StoredProcedure, DB.CreateTableParameter("Tbl", pacnetTransaction));

						//Log.Debug("NL_PacnetTransactionsSave: LoanID: {0}, pacnetTransactionID: {1}", this.LoanID, pacnetTransaction.PacnetTransactionID);
					}
					// ReSharper disable once CatchAllClause
				} catch (Exception e1) {

					Error = e1.Message;
					Log.Error("Failed to save PacnetTransaction: {0}", Error);

					// PacnetTransaction error
					SendMail("NL: Failed to save PacnetTransaction", history, nlFees, nlSchedule, nlAgreements);
				}

				// 11. if setup fee - add payment to offset it
				SetupOffsetPayment();
				
				// 6. broker commissions
				// done in controller. When old loan removed: check if this is the broker's customer, calc broker fees, insert into LoanBrokerCommission
				if (model.Offer.BrokerSetupFeePercent > 0) {
					DB.ExecuteNonQuery(string.Format("UPDATE dbo.LoanBrokerCommission SET NLLoanID = {0} WHERE LoanID = {1}", LoanID, model.Loan.OldLoanID));
				}

				// OK
				SendMail("NL: Saved successfully", history, nlFees, nlSchedule, nlAgreements);

				// copy LoanCharges Ids into OldFeeID, NL_LoanFees
				DB.ExecuteNonQuery("NL_LoanFeesOldIDUpdate", CommandSpecies.StoredProcedure);

				// temporary - should be removed/modified after "old" loan remove
				CopyRebateTransaction();

				//MigrateLoanTransaction sMigrateLoan = new MigrateLoanTransaction();
				//try {
				//	sMigrateLoan.Execute();
				//	// ReSharper disable once CatchAllClause
				//} catch (Exception mex) {
				//	Error = mex.Message;
				//	Log.Error("Failed sync migration: {0}", Error);
				//	NL_AddLog(LogType.Error, "Failed sync migration", this.strategyArgs, Error, mex.ToString(), mex.StackTrace);
				//}

				NL_AddLog(LogType.Info, "Strategy End", this.strategyArgs, LoanID, Error, null);

				// ReSharper disable once CatchAllClause
			} catch (Exception ex) {
				NL_AddLog(LogType.Error, "Strategy failed", this.strategyArgs, Error, ex.ToString(), ex.StackTrace);
			}
		}//Execute
Ejemplo n.º 10
0
		public override void Execute() {
			if (!CurrentValues.Instance.NewLoanRun) {
				NL_AddLog(LogType.Info, "NL disabled by configuration", null, null, null, null);
				return;
			}

			if (Result.CustomerID == 0) {
				Error = NL_ExceptionCustomerNotFound.DefaultMessage;
				NL_AddLog(LogType.Error, "Strategy Faild", this.strategyArgs, Result, Error, null);
				return;
			}

			if (Result.Loan.LoanID == 0) {
				Error = NL_ExceptionLoanNotFound.DefaultMessage;
				NL_AddLog(LogType.Error, "Strategy Faild", this.strategyArgs, Result, Error, null);
				return;
			}

			NL_AddLog(LogType.Info, "Strategy Start", this.strategyArgs, Result, Error, null);

			try {

				// loan
				Result.Loan = LoanDAL.GetLoan(Result.Loan.LoanID);
				
				// offer-fees
				//Result.Offer.OfferFees = DB.Fill<NL_OfferFees>("NL_OfferFeesGet", CommandSpecies.StoredProcedure, new QueryParameter("OfferID", Result.Loan.OfferID));

				// histories
				Result.Loan.Histories.Clear();
				Result.Loan.Histories.AddRange(LoanDAL.GetLoanHistories(Result.Loan.LoanID, this.StateDate).ToList());

				// schedules of each history
				foreach (NL_LoanHistory h in Result.Loan.Histories) {
					h.Schedule = DB.Fill<NL_LoanSchedules>("NL_LoanSchedulesGet", CommandSpecies.StoredProcedure,new QueryParameter("LoanID", Result.Loan.LoanID));
				}

				// loan fees
				Result.Loan.Fees.Clear();
				Result.Loan.Fees.AddRange(DB.Fill<NL_LoanFees>("NL_LoanFeesGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID)).ToList());

				// filter cnacelled/deleted fees on GetLoanDBState strategy
				// filter in Calculator according to CalculationDate
				//fees.Where(f => f.DisabledTime == null || f.DeletedByUserID ==0).ForEach(f => Result.Loan.Fees.Add(f));;

				// interest freezes
				Result.Loan.FreezeInterestIntervals.Clear();
				Result.Loan.FreezeInterestIntervals.AddRange(DB.Fill<NL_LoanInterestFreeze>("NL_LoanInterestFreezeGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID)).ToList());

				// filter cancelled (deactivated) periods
				// TODO: take in consideration stateDate
				// freezes.Where(fr => fr.DeactivationDate != null).ForEach(fr => Result.Loan.FreezeInterestIntervals.Add(fr));
				//freezes.ForEach(fr => Result.Loan.FreezeInterestIntervals.Add(fr));

				// loan options
				Result.Loan.LoanOptions = DB.FillFirst<NL_LoanOptions>("NL_LoanOptionsGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID));

				// TODO combine all payments + transactions to one SP kogda nibud'

				// payments
				Result.Loan.Payments.Clear();
				Result.Loan.Payments.AddRange(DB.Fill<NL_Payments>("NL_PaymentsGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID)));

				var ppt = DB.Fill<NL_PaypointTransactions>("NL_PaypointTransactionsGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID));
				var schp = DB.Fill<NL_LoanSchedulePayments>("NL_LoanSchedulePaymentsGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID));
				var fps = DB.Fill<NL_LoanFeePayments>("NL_LoanFeePaymentsGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID));

				foreach (NL_Payments p in Result.Loan.Payments) {
					p.SchedulePayments.Clear();
					p.SchedulePayments.AddRange(schp.Where(sp=>sp.PaymentID == p.PaymentID).ToList());
	
					p.FeePayments.Clear();
					p.FeePayments.AddRange(fps.Where(fp=>fp.PaymentID == p.PaymentID).ToList());

					p.PaypointTransactions.Clear();
					p.PaypointTransactions.AddRange(ppt.Where(pp => pp.PaymentID == p.PaymentID).ToList());
				}

				// set paid amount for each fee
				foreach (NL_LoanFees fee in Result.Loan.Fees) {
					fee.PaidAmount = fps.Where(fp => fp.LoanFeeID == fee.LoanFeeID).Sum(fp => fp.Amount);
				}

				// set paid amount for each fee
				foreach (NL_LoanHistory h in Result.Loan.Histories) {
					foreach (NL_LoanSchedules s in h.Schedule) {
						s.InterestPaid = schp.Where(sp => sp.LoanScheduleID == s.LoanScheduleID).Sum(sp => sp.InterestPaid);
						s.PrincipalPaid = schp.Where(sp => sp.LoanScheduleID == s.LoanScheduleID).Sum(sp => sp.PrincipalPaid);
					}
				}

				Result.Loan.Rollovers.Clear();
				Result.Loan.Rollovers.AddRange(DB.Fill<NL_LoanRollovers>("NL_RolloversGet", CommandSpecies.StoredProcedure, new QueryParameter("LoanID", Result.Loan.LoanID)));

				// accepted rollover
				Result.Loan.AcceptedRollovers.AddRange(Result.Loan.Rollovers.Where(r => r.IsAccepted && r.CustomerActionTime.HasValue &&r.DeletionTime==null && r.DeletedByUserID==null));

				if (!GetCalculatorState)
					return;

				// get loan state updated by calculator
				try {
					ALoanCalculator calc = new LegacyLoanCalculator(Result);
					calc.GetState();
					Result = calc.WorkingModel;
				} catch (NoInitialDataException noInitialDataException) {
					Error = noInitialDataException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (InvalidInitialInterestRateException invalidInitialInterestRateException) {
					Error = invalidInitialInterestRateException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (NoLoanHistoryException noLoanHistoryException) {
					Error = noLoanHistoryException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (InvalidInitialAmountException invalidInitialAmountException) {
					Error = invalidInitialAmountException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (OverflowException overflowException) {
					Error = overflowException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (LoanPaidOffStatusException loanPaidOffexException) {
					Error = loanPaidOffexException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (LoanWriteOffStatusException loanWriteoffexException) {
					Error = loanWriteoffexException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				} catch (LoanPendingStatusException loanPendingException) {
					Error = loanPendingException.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);

					// ReSharper disable once CatchAllClause
				} catch (Exception ex) {
					Error = ex.Message;
					NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, Result, Error, null);
				}

				NL_AddLog(LogType.Info, "Strategy End", this.strategyArgs, Result, null, null);

				// ReSharper disable once CatchAllClause
			} catch (Exception ex) {
				Error = ex.Message;
				NL_AddLog(LogType.Error, "Strategy Failed", this.strategyArgs, Error, ex.ToString(), ex.StackTrace);
				Log.Alert(ex, "Failed to load loan state.");
			} // try
		} // Execute
Ejemplo n.º 11
0
		} // CalculateTotal

		/// <exception cref="OverflowException">The number of elements in is larger than <see cref="F:System.Int32.MaxValue" />.</exception>
		/// <exception cref="NullReferenceException"><paramref /> is null. </exception>
		/// <exception cref="NoScheduleException">Condition. </exception>
		public AgreementModel NL_BuildAgreementModel(Customer customer, NL_Model nlModel) {
			// fill in loan+history with offer data
			nlModel = this.serviceClient.Instance.BuildLoanFromOffer(this.context != null ? this.context.UserId : customer.Id, nlModel.CustomerID, nlModel).Value;

			ALoanCalculator nlCalculator = null;
			// 2. get Schedule and Fees
			try {
				// init calculator
				nlCalculator = new LegacyLoanCalculator(nlModel);
				// model should contain Schedule and Fees after this invocation
				nlCalculator.CreateSchedule(); // create primary dates/p/r/f distribution of schedules (P/n) and setup/servicing fees. 7 September - fully completed schedule + fee + amounts due, without payments.
			} catch (NoInitialDataException noDataException) {
				this.log.Alert("CreateSchedule failed: {0}", noDataException.Message);
			} catch (InvalidInitialAmountException amountException) {
				this.log.Alert("CreateSchedule failed: {0}", amountException.Message);
			} catch (InvalidInitialInterestRateException interestRateException) {
				this.log.Alert("CreateSchedule failed: {0}", interestRateException.Message);
			} catch (InvalidInitialRepaymentCountException paymentsException) {
				this.log.Alert("CreateSchedule failed: {0}", paymentsException.Message);
			} catch (Exception ex) {
				this.log.Alert("Failed to create Schedule for customer {0}, err: {1}", nlModel.CustomerID, ex);
			} finally {
				if (nlCalculator == null) {
					this.log.Alert("failed to get nlCalculator for customer: {0}", nlModel.CustomerID);
				} // if
			} // try

			var history = nlModel.Loan.LastHistory();

			// no Schedule
			if (history.Schedule.Count == 0) {
				this.log.Alert("No Schedule. Customer: {0}", nlModel.CustomerID);
				return null;
			}

			var model = new AgreementModel() {
				Schedule = new List<LoanScheduleItemModel>()
			};

			// fill in AgreementModel schedules list
			foreach (NL_LoanSchedules s in history.Schedule) {
				var item = new LoanScheduleItemModel {
					Id = s.LoanScheduleID,
					AmountDue = s.AmountDue,
					Date = s.PlannedDate,
					Interest = s.Interest,
					Status = Enum.GetName(typeof(NLScheduleStatuses), s.LoanScheduleStatusID).DescriptionAttr(),
					LoanRepayment = s.Principal,
					Balance = s.Balance,
					Fees = s.Fees,
					InterestRate = s.InterestRate
				};
				item.StatusDescription = item.Status;
				model.Schedule.Add(item);
			} // for each

			model.CustomerEmail = customer.Name;
			model.FullName = customer.PersonalInfo.Fullname;
			model.TypeOfBusinessName = customer.PersonalInfo.TypeOfBusinessName;

			var businessType = customer.PersonalInfo.TypeOfBusiness;
			var company = customer.Company;
			CustomerAddress companyAddress = null;
			if (company != null) {
				switch (businessType.Reduce()) {
				case TypeOfBusinessReduced.Limited:
					model.CompanyNumber = company.ExperianRefNum ?? company.CompanyNumber;
					goto case TypeOfBusinessReduced.NonLimited;
				case TypeOfBusinessReduced.NonLimited:
					model.CompanyName = company.ExperianCompanyName ?? company.CompanyName;
					companyAddress = company.ExperianCompanyAddress.LastOrDefault() ?? company.CompanyAddress.LastOrDefault();
					break;
				} // switch
			} // if

			model.CompanyAdress = companyAddress.GetFormatted();
			model.PersonAddress = customer.AddressInfo.PersonalAddress.FirstOrDefault().GetFormatted();

			// collect all setup/servicing "spreaded" fees
			List<NL_LoanFees> loanSetupFees = nlModel.Loan.Fees.Where(f => f.LoanFeeTypeID == (int)NLFeeTypes.SetupFee || f.LoanFeeTypeID == (int)NLFeeTypes.ServicingFee).ToList();
			// get fees sum
			decimal totalFees = 0m;
			loanSetupFees.ForEach(f => totalFees += f.Amount);

			decimal totalPrincipal = model.Schedule.Sum(a => a.LoanRepayment);

			// formatted totals
			model.TotalAmount = FormattingUtils.NumericFormats(model.Schedule.Sum(a => a.AmountDue));
			model.TotalPrincipal = FormattingUtils.NumericFormats(totalPrincipal);
			model.TotalInterest = FormattingUtils.NumericFormats(model.Schedule.Sum(a => a.Interest));
			model.TotalAmoutOfCredit = model.TotalPrincipal; //FormattingUtils.NumericFormats(model.Schedule.Sum(a => a.LoanRepayment));
			model.TotalFees = FormattingUtils.NumericFormats(totalFees);

			decimal currencyRate = GetUSDCurrencyRate();
			model.TotalPrincipalUsd = "$ " + (CurrentValues.Instance.AlibabaCurrencyConversionCoefficient * currencyRate * totalPrincipal).ToString("N", CultureInfo.CreateSpecificCulture("en-gb"));

			model.CurentDate = FormattingUtils.FormatDateTimeToString(DateTime.UtcNow);
			model.CurrentDate = DateTime.UtcNow;

			model.FormattedSchedules = model.Schedule.Select((installment, i) => new FormattedSchedule {
				AmountDue = FormattingUtils.NumericFormats(installment.AmountDue),
				Principal = FormattingUtils.NumericFormats(installment.LoanRepayment),
				Interest = FormattingUtils.NumericFormats(installment.Interest),
				Fees = FormattingUtils.NumericFormats(installment.Fees),
				Date = FormattingUtils.FormatDateToString(installment.Date),
				StringNumber = FormattingUtils.ConvertingNumberToWords(i + 1),
				InterestRate = string.Format("{0:0.00}", installment.InterestRate * 100),
				Iterration = i + 1,
			}).ToList();

			// TODO update from history?
			model.InterestRate = history.InterestRate * 100;
			model.SetupFee = FormattingUtils.NumericFormats(totalFees);

			model.SetupFeeAmount = FormattingUtils.NumericFormats((int)CurrentValues.Instance.SetupFeeFixed);
			model.SetupFeePercent = CurrentValues.Instance.SetupFeePercent;

			//// FEES TODO
			////According to new logic the setup fee is always percent and min setup fee is amount SetupFeeFixed  ????
			if ((totalFees > 0) || (nlModel.Offer.BrokerSetupFeePercent.HasValue && nlModel.Offer.BrokerSetupFeePercent.Value > 0)) {
				decimal setupFeePercent = totalFees + nlModel.Offer.BrokerSetupFeePercent ?? 0M;
				model.SetupFeePercent = (setupFeePercent * 100).ToString(CultureInfo.InvariantCulture);
			} // if

			// TODO was is das?
			model.IsBrokerFee = false;
			model.IsManualSetupFee = false;

			if (nlCalculator != null)
				model.APR = nlCalculator.CalculateApr(history.EventTime);

			model.InterestRatePerDay = model.Schedule[1].InterestRate / 30; // For first month
			model.InterestRatePerDayFormatted = string.Format("{0:0.00}", model.InterestRatePerDay);
			model.InterestRatePerYearFormatted = string.Format("{0:0.00}", model.InterestRate * 12);

			model.LoanType = Enum.GetName(typeof(NLLoanTypes), nlModel.Loan.LoanTypeID);
			model.TermOnlyInterest = model.Schedule.Count(s => s.LoanRepayment == 0);
			model.TermOnlyInterestWords = FormattingUtils.ConvertToWord(model.TermOnlyInterest).ToLower();
			model.TermInterestAndPrincipal = model.Schedule.Count(s => s.LoanRepayment != 0 && s.Interest != 0);
			model.TermInterestAndPrincipalWords = FormattingUtils.ConvertToWord(model.TermInterestAndPrincipal).ToLower();
			model.isHalwayLoan = Enum.GetName(typeof(NLLoanTypes), nlModel.Loan.LoanTypeID) == NLLoanTypes.HalfWayLoanType.ToString();
			model.CountRepayment = model.Schedule.Count;
			model.Term = model.Schedule.Count;

			model.TotalPrincipalWithSetupFee = FormattingUtils.NumericFormats(totalPrincipal - totalFees);

			return model;
		} // NL_BuildAgreementModel
Ejemplo n.º 12
0
        /// <exception cref="NL_ExceptionCustomerNotFound">Condition. </exception>
        /// <exception cref="NL_ExceptionLoanNotFound">Condition. </exception>
        public override void Execute()
        {
            if (!CurrentValues.Instance.NewLoanRun)
            {
                NL_AddLog(LogType.Info, "NL disabled by configuration", null, null, null, null);
                return;
            }

            NL_AddLog(LogType.Info, "Strategy Start", this.strategyArgs, null, Error, null);

            if (CustomerID == 0)
            {
                Error = NL_ExceptionCustomerNotFound.DefaultMessage;
                NL_AddLog(LogType.Error, NL_ExceptionCustomerNotFound.DefaultMessage, this.strategyArgs, null, Error, null);
                throw new NL_ExceptionCustomerNotFound(Error);
            }

            if (LoanID == 0)
            {
                Error = NL_ExceptionLoanNotFound.DefaultMessage;
                NL_AddLog(LogType.Error, NL_ExceptionLoanNotFound.DefaultMessage, this.strategyArgs, null, Error, null);
                throw new NL_ExceptionLoanNotFound(Error);
            }

            // get raw DB state of the loan - without calc
            GetLoanState state = new GetLoanState(CustomerID, LoanID, DateTime.UtcNow, Context.UserID, false);

            state.Execute();

            // failed to load loan from DB
            if (!string.IsNullOrEmpty(state.Error))
            {
                Error = state.Error;
                NL_AddLog(LogType.Error, "Loan get state failed", this.strategyArgs, state.Error, Error, null);
                return;
            }

            this.strategyArgs = new object[] { CustomerID, LoanID, UserID };

            var stateBefore = JObject.FromObject(state.Result.Loan);

            NL_Model RecalculatedModel = new NL_Model(state.Result.CustomerID);

            RecalculatedModel.Loan = state.Result.Loan;

            // get loan state updated by calculator
            try {
                ALoanCalculator calc = new LegacyLoanCalculator(RecalculatedModel);
                calc.GetState();
            } catch (NoInitialDataException noInitialDataException) {
                Error = noInitialDataException.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);
            } catch (InvalidInitialInterestRateException invalidInitialInterestRateException) {
                Error = invalidInitialInterestRateException.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);
            } catch (NoLoanHistoryException noLoanHistoryException) {
                Error = noLoanHistoryException.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);
            } catch (InvalidInitialAmountException invalidInitialAmountException) {
                Error = invalidInitialAmountException.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);
            } catch (OverflowException overflowException) {
                Error = overflowException.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);

                // ReSharper disable once CatchAllClause
            } catch (Exception ex) {
                Error = ex.Message;
                NL_AddLog(LogType.Error, "Calculator exception", this.strategyArgs, RecalculatedModel, Error, null);
                return;
            }

            // no changes, exit
            var stateAfter = JObject.FromObject(RecalculatedModel.Loan);

            if (JToken.DeepEquals(stateBefore, stateAfter))
            {
                NL_AddLog(LogType.Info, "End - no diff btwn DB state and recalculated state", stateBefore, stateAfter, Error, null);
                return;
            }

            NL_AddLog(LogType.Info, "recalculated loan state", stateBefore, stateAfter, Error, null);

            try {
                bool loanClose             = !stateAfter["LoanStatusID"].Equals(stateBefore["LoanStatusID"]);
                SaveLoanStateToDB saveLoan = new SaveLoanStateToDB(RecalculatedModel, loanClose);
                saveLoan.Execute();
            } catch (Exception ex) {
                Error = ex.Message;
                Log.Error("Failed to save updated loan DB dbState. err: {0}", Error);

                NL_AddLog(LogType.Error, "Failed", this.strategyArgs, Error, ex.ToString(), ex.StackTrace);
            }
        }