public override MedalOutputModel CalculateMedal(MedalInputModel model) { //Log.Debug(model.ToString()); var dict = new Dictionary <Parameter, Weight> { { Parameter.BusinessScore, GetBusinessScoreWeight(model.BusinessScore, model.FirstRepaymentDatePassed, model.UseHmrc) }, { Parameter.BusinessSeniority, GetBusinessSeniorityWeight(model.BusinessSeniority, model.FirstRepaymentDatePassed, model.UseHmrc) }, { Parameter.ConsumerScore, GetConsumerScoreWeight(model.ConsumerScore, model.FirstRepaymentDatePassed, model.UseHmrc) }, { Parameter.EzbobSeniority, GetEzbobSeniorityWeight(model.EzbobSeniority, model.FirstRepaymentDatePassed) }, { Parameter.MaritalStatus, GetMaritalStatusWeight(model.MaritalStatus) }, { Parameter.NumOfOnTimeLoans, GetNumOfOnTimeLoansWeight(model.NumOfOnTimeLoans, model.FirstRepaymentDatePassed) }, { Parameter.NumOfLatePayments, GetNumOfLatePaymentsWeight(model.NumOfLatePayments, model.FirstRepaymentDatePassed) }, { Parameter.NumOfEarlyPayments, GetNumOfEarlyPaymentsWeight(model.NumOfEarlyPayments, model.FirstRepaymentDatePassed) }, { Parameter.AnnualTurnover, GetAnnualTurnoverWeight(model.AnnualTurnover, model.UseHmrc) }, { Parameter.NetWorth, GetNetWorthWeight(model.NetWorth, model.FirstRepaymentDatePassed) }, { Parameter.NumOfStores, GetNumOfStoresWeight(model.NumOfStores) }, { Parameter.PositiveFeedbacks, GetPositiveFeedbacksWeight(model.PositiveFeedbacks) } }; CalcDelta(model, dict); MedalOutputModel scoreMedal = CalcScoreMedalOffer(dict, model, MedalType.OnlineNonLimitedWithBusinessScore); return(scoreMedal); }
public override MedalOutputModel CalculateMedal(MedalInputModel model) { var dict = new Dictionary <Parameter, Weight> { { Parameter.BusinessSeniority, GetBusinessSeniorityWeight(model.BusinessSeniority, model.FirstRepaymentDatePassed, model.UseHmrc) }, { Parameter.ConsumerScore, GetConsumerScoreWeight(model.ConsumerScore, model.FirstRepaymentDatePassed, model.UseHmrc) }, { Parameter.EzbobSeniority, GetEzbobSeniorityWeight(model.EzbobSeniority, model.FirstRepaymentDatePassed) }, { Parameter.MaritalStatus, GetMaritalStatusWeight(model.MaritalStatus) }, { Parameter.NumOfOnTimeLoans, GetNumOfOnTimeLoansWeight(model.NumOfOnTimeLoans, model.FirstRepaymentDatePassed) }, { Parameter.NumOfLatePayments, GetNumOfLatePaymentsWeight(model.NumOfLatePayments, model.FirstRepaymentDatePassed) }, { Parameter.NumOfEarlyPayments, GetNumOfEarlyPaymentsWeight(model.NumOfEarlyPayments, model.FirstRepaymentDatePassed) }, { Parameter.AnnualTurnover, GetAnnualTurnoverWeight(model.AnnualTurnover, model.UseHmrc) }, { Parameter.FreeCashFlow, GetFreeCashFlowWeight(model.FreeCashFlow, model.UseHmrc, model.AnnualTurnover) }, { Parameter.NetWorth, GetNetWorthWeight(model.NetWorth, model.FirstRepaymentDatePassed) }, }; CalcDelta(model, dict); MedalOutputModel scoreMedal = CalcScoreMedalOffer(dict, model, MedalType.SoleTrader); scoreMedal.FirstRepaymentDatePassed = model.FirstRepaymentDatePassed; scoreMedal.CustomerId = model.CustomerId; scoreMedal.ValueAdded = model.ValueAdded; return(scoreMedal); }
public TurnoverCalculator(int customerID, DateTime calculationDate, AConnection db, ASafeLog log) { this.db = db; this.log = log.Safe(); this.medalChooserData = null; Model = new MedalInputModel { CustomerId = customerID, CalculationDate = calculationDate, }; HasOnline = false; MinApprovalAmount = 0; } // constructor
protected override void CalcDelta(MedalInputModel model, Dictionary <Parameter, Weight> dict) { if (model.ConsumerScore <= LowConsumerScore) { //Sum of all weights var sow = dict.Sum(x => x.Value.FinalWeight); //Sum of weights of , NetWorth, MaritalStatus var sonf = dict[Parameter.NetWorth].FinalWeight + dict[Parameter.MaritalStatus].FinalWeight; var sonfDesired = sonf - sow + 1; var ratio = sonfDesired / sonf; dict[Parameter.NetWorth].FinalWeight *= ratio; dict[Parameter.MaritalStatus].FinalWeight *= ratio; } }
protected override void CalcDelta(MedalInputModel model, Dictionary <Parameter, Weight> dict) { if (model.BusinessScore <= LowBusinessScore || model.ConsumerScore <= LowConsumerScore) { //Sum of all weights var sow = dict.Sum(x => x.Value.FinalWeight); //Sum of weights of of TangibleEquity, NetWorth, MaritalStatus, NumberOfStores, PositiveFeedbacks var sonf = dict[Parameter.NetWorth].FinalWeight + dict[Parameter.MaritalStatus].FinalWeight; var sonfDesired = sonf - sow + 1; var ratio = sonfDesired / sonf; dict[Parameter.NetWorth].FinalWeight *= ratio; dict[Parameter.MaritalStatus].FinalWeight *= ratio; } }
internal static void FilterTurnoversTo( this MedalInputModel model, Guid mpTypeID, decimal[] months, decimal[] quarters, decimal[] halves, decimal[] fulls ) { int idx = mpIndices[mpTypeID]; List <TurnoverDbRow> sourceList = model.Turnovers.Where(r => r.MpTypeID == mpTypeID).ToList(); months.Add(idx, sourceList, PartOfYear.Month); quarters.Add(idx, sourceList, PartOfYear.Quarter); halves.Add(idx, sourceList, PartOfYear.Half); fulls.Add(idx, sourceList, PartOfYear.Full); } // FilterTurnoversTo
protected override void CalcDelta(MedalInputModel model, Dictionary <Parameter, Weight> dict) { if (model.ConsumerScore <= LowConsumerScore) { //Sum of all weights var sow = dict.Sum(x => x.Value.FinalWeight); //Sum of weights of of AnnualTurnover, MaritalStatus, NumberOfStores, PositiveFeedbacks var sonf = dict[Parameter.AnnualTurnover].FinalWeight + dict[Parameter.MaritalStatus].FinalWeight + dict[Parameter.NumOfStores].FinalWeight + dict[Parameter.PositiveFeedbacks].FinalWeight; var sonfDesired = sonf - sow + 1; var ratio = sonfDesired / sonf; dict[Parameter.AnnualTurnover].FinalWeight *= ratio; dict[Parameter.MaritalStatus].FinalWeight *= ratio; dict[Parameter.NumOfStores].FinalWeight *= ratio; dict[Parameter.PositiveFeedbacks].FinalWeight *= ratio; } }
public void TestMedalCalculation() { var msc = new OfflineLImitedMedalCalculator(_db, Log); var data = new MedalInputModel { AnnualTurnover = 125000, BusinessScore = 55, MaritalStatus = MaritalStatus.Married, TangibleEquity = 0.1M, BusinessSeniority = 2, ConsumerScore = 850, EzbobSeniority = 7, FirstRepaymentDatePassed = false, FreeCashFlow = 0.42M, HasHmrc = true, NetWorth = 0.3M, NumOfEarlyPayments = 0, NumOfLatePayments = 0, NumOfOnTimeLoans = 0 }; var medal = msc.CalculateMedal(data); Assert.AreEqual(Medal.Gold, medal.Medal); }
/// <summary> /// Score is calculated by sum of all Weight*Grade for each parameter /// The normalized score is calculated by (scoreSum - minScoreSum) / (maxScoreSum - minScoreSum) /// </summary> /// <param name="dict">Weight dictionary</param> /// <param name="inputModel">Medal input model</param> /// <param name="medalType">Medal type that is calculated</param> /// <returns>Medal output model</returns> protected MedalOutputModel CalcScoreMedalOffer(Dictionary <Parameter, Weight> dict, MedalInputModel inputModel, MedalType medalType = MedalType.NoMedal) { decimal minScoreSum = 0; decimal maxScoreSum = 0; decimal scoreSum = 0; foreach (var weight in dict.Values) { weight.MinimumScore = weight.FinalWeight * weight.MinimumGrade; weight.MaximumScore = weight.FinalWeight * weight.MaximumGrade; weight.Score = weight.Grade * weight.FinalWeight; minScoreSum += weight.MinimumScore; maxScoreSum += weight.MaximumScore; scoreSum += weight.Score; } // for decimal score = (scoreSum - minScoreSum) / (maxScoreSum - minScoreSum); Medal medal = GetMedal(MedalRangesConstats.MedalRanges, score); var medalOutput = new MedalOutputModel { TurnoverType = inputModel.TurnoverType, Medal = medal, MedalType = medalType, NormalizedScore = score, Score = scoreSum, WeightsDict = dict, AnnualTurnover = inputModel.AnnualTurnover, FreeCashflow = inputModel.FreeCashFlowValue, FirstRepaymentDatePassed = inputModel.FirstRepaymentDatePassed, ValueAdded = inputModel.ValueAdded, CustomerId = inputModel.CustomerId, CalculationDate = inputModel.CalculationDate, UseHmrc = inputModel.UseHmrc, CapOfferByCustomerScoresTable = inputModel.CapOfferByCustomerScoresTable.ToFormattedString(), CapOfferByCustomerScoresValue = inputModel.CapOfferByCustomerScoresValue, ConsumerScore = inputModel.ConsumerScore, BusinessScore = inputModel.BusinessScore, }; return(medalOutput); } // CalcScoreMedalOffer
/// <summary> /// /// </summary> /// <param name="model"></param> /// <param name="dict"></param> protected abstract void CalcDelta(MedalInputModel model, Dictionary <Parameter, Weight> dict);
} // GetInputParameters public abstract MedalOutputModel CalculateMedal(MedalInputModel model);
public bool TestMedalCalculation() { var passed = true; var numChecked = 0; var numPassed = 0; var numFailed = 0; var dbHelper = new DbHelper(new SqlConnection(Log), Log); List <MedalComparisonModel> testMedalData = dbHelper.GetMedalTestData(); foreach (var medalComparisonModel in testMedalData) { IMedalCalulator calulator; switch (medalComparisonModel.MedalType) { case MedalType.Limited: calulator = new OfflineLImitedMedalCalculator(DB, Log); break; case MedalType.OnlineLimited: calulator = new OnlineLImitedMedalCalculator(DB, Log); break; case MedalType.NonLimited: calulator = new NonLimitedMedalCalculator(DB, Log); break; case MedalType.SoleTrader: calulator = new SoleTraderMedalCalculator(DB, Log); break; default: Log.Debug("Skipping medal calc for {0} NoMedal", medalComparisonModel.CustomerId); continue; } numChecked++; DateTime companyDate; DateTime regDate; DateTime calcTime = medalComparisonModel.CalculationTime; int businessSeniority; decimal ezbobSeniority; if ( !DateTime.TryParseExact(medalComparisonModel.BusinessSeniority.Value, new[] { "yyyy-MM-dd HH:mm:ss" }, null, DateTimeStyles.AdjustToUniversal, out companyDate)) { businessSeniority = 0; } else { businessSeniority = (int)(calcTime - companyDate).TotalDays / 365; } if ( !DateTime.TryParseExact(medalComparisonModel.EzbobSeniority.Value, new[] { "yyyy-MM-dd HH:mm:ss" }, null, DateTimeStyles.AdjustToUniversal, out regDate)) { ezbobSeniority = 0; } else { ezbobSeniority = (decimal)(calcTime - regDate).TotalDays / (365.0M / 12.0M); } var model = new MedalInputModel { AnnualTurnover = decimal.Parse(medalComparisonModel.AnnualTurnover.Value), TangibleEquity = decimal.Parse(medalComparisonModel.TangibleEquity.Value), BusinessScore = int.Parse(medalComparisonModel.BusinessScore.Value), FirstRepaymentDatePassed = medalComparisonModel.FirstRepaymentDatePassed, BusinessSeniority = businessSeniority, MaritalStatus = (MaritalStatus)Enum.Parse(typeof(MaritalStatus), medalComparisonModel.MaritalStatus.Value), EzbobSeniority = ezbobSeniority, NetWorth = decimal.Parse(medalComparisonModel.NetWorth.Value), NumOfEarlyPayments = int.Parse(medalComparisonModel.NumOfEarlyRepayments.Value), NumOfLatePayments = int.Parse(medalComparisonModel.NumOfLateRepayments.Value), NumOfOnTimeLoans = int.Parse(medalComparisonModel.NumOfLoans.Value), NumOfStores = int.Parse(medalComparisonModel.NumOfStores.Value), PositiveFeedbacks = int.Parse(medalComparisonModel.PositiveFeedbacks.Value), FreeCashFlow = decimal.Parse(medalComparisonModel.FreeCashFlow.Value), ConsumerScore = int.Parse(medalComparisonModel.ConsumerScore.Value), HasHmrc = medalComparisonModel.NumOfHmrcMps > 0 }; var medal = calulator.CalculateMedal(model); if (Math.Abs(medal.NormalizedScore - medalComparisonModel.TotalScoreNormalized) > 0.009M) { Log.Debug("{0}", medal); if (medal.Medal != medalComparisonModel.Medal) { passed = false; Log.Error("Medal Mismatch for customerid {0} 1st {1} 2nd {2}", medalComparisonModel.CustomerId, medalComparisonModel.Medal, medal.Medal); } numFailed++; passed = false; Log.Error("Medal Normalized Score Mismatch for customerid {0} 1st {1} 2nd {2}", medalComparisonModel.CustomerId, medalComparisonModel.TotalScoreNormalized, medal.NormalizedScore); PrintComparisonMedal(medalComparisonModel); } else { numPassed++; } } Log.Debug("Test run on {0}, passed: {1}, failed: {2}", numChecked, numPassed, numFailed); return(passed); }
} // constructor /// <summary> /// Determines which medal to calculate and calculates it. /// Which medal type to choose logic: /// https://drive.google.com/open?id=0B1Io_qu9i44SVzVqV19nbnMxRW8&authuser=0 /// </summary> /// <param name="customerId">Customer ID.</param> /// <param name="calculationDate"> /// Optional. Leave empty to calculate based on current data /// or specify date to calculate medal based on data available on that date. /// </param> /// <returns>Calculated medal model.</returns> public MedalOutputModel GetMedal(int customerId, DateTime calculationDate) { var turnoverCalc = new TurnoverCalculator(customerId, calculationDate, DB, Log); string errorMsg; var type = turnoverCalc.GetMedalType(out errorMsg); if (!string.IsNullOrWhiteSpace(errorMsg)) { return(new MedalOutputModel { MedalType = MedalType.NoMedal, Medal = Medal.NoClassification, TurnoverType = null, Error = errorMsg, CustomerId = customerId, }); } // if IMedalCalulator medalCalulator; switch (type) { case MedalType.Limited: medalCalulator = new OfflineLImitedMedalCalculator(this.DB, this.Log); break; case MedalType.NonLimited: medalCalulator = new NonLimitedMedalCalculator(this.DB, this.Log); break; case MedalType.OnlineLimited: medalCalulator = new OnlineLImitedMedalCalculator(this.DB, this.Log); break; case MedalType.SoleTrader: medalCalulator = new SoleTraderMedalCalculator(this.DB, this.Log); break; case MedalType.OnlineNonLimitedNoBusinessScore: medalCalulator = new OnlineNonLimitedNoBusinessScoreMedalCalculator(this.DB, this.Log); break; case MedalType.OnlineNonLimitedWithBusinessScore: medalCalulator = new OnlineNonLimitedWithBusinessScoreMedalCalculator(this.DB, this.Log); break; default: return(new MedalOutputModel { MedalType = type, Medal = Medal.NoClassification, TurnoverType = null, Error = "None of the medals match the criteria for medal calculation", CustomerId = customerId }); } // switch MedalInputModel data = medalCalulator.GetInputParameters(customerId, calculationDate); MedalOutputModel medal = medalCalulator.CalculateMedal(data); SetOfferedAmount( medal, turnoverCalc.MinApprovalAmount ); return(medal); } // GetMedal