} //CollectionDay15 private void CollectionDay1to6(CollectionDataModel model, CollectionType type) { ChangeStatus(model.CustomerID, model.LoanID, CollectionStatusNames.DaysMissed1To14, type, model); //send email Default Template1-6 SendCollectionEmail(CollectionDay1to6EmailTemplate, model, type); } //CollectionDay1to6
} // MarkLoansAsLate protected void SendCollectionEmail(string emailTemplateName, CollectionDataModel model, CollectionType type) { if (model.EmailSendingAllowed) { var variables = new Dictionary <string, string> { { "FirstName", model.FirstName }, { "RefNum", model.LoanRefNum }, { "FeeAmount", model.FeeAmount.ToString(CultureInfo.InvariantCulture) }, { "AmountCharged", model.AmountDue.ToString(CultureInfo.InvariantCulture) }, { "ScheduledAmount", model.AmountDue.ToString(CultureInfo.InvariantCulture) }, }; // model.SendNotification == bool SendToCustomer // prevent while running on new loan - duplicate update CollectionMails collectionMails = new CollectionMails(model.CustomerID, emailTemplateName, variables, model.EmailSendingAllowed); collectionMails.Execute(); AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Email.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); //AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Email, model); } else { Log.Info("Collection sending email is not allowed, email is not sent to customer {0}\n email template {1}", model.CustomerID, emailTemplateName); } } //SendCollectionEmail
public MainWindow() { InitializeComponent(); var model = new CollectionDataModel() { new DataModel() { ControlHeight = 25, LabelWidth = 120, ItemName = "blablalbl", Units = "(F)" }, new DataModel() { ControlHeight = 25, LabelWidth = 120, ItemName = "blablalbl", Units = "", SubCard = "vbsdbvsdfbvfdsb" }, new DataModel() { ControlHeight = 25, LabelWidth = 120, ItemName = "blablalbl", Units = "(F)" } }; DataContext = model; }
} //ChangeStatus private void CollectionDay0(CollectionDataModel model, CollectionType type) { //send email Default Template0 SendCollectionEmail(CollectionDay0EmailTemplate, model, type); //send sms Default SMS0 SendCollectionSms(model, type); } //CollectionDay0
} //CollectionDay60 private void CollectionDay7(CollectionDataModel model, CollectionType type) { //send email Default Template7 SendCollectionEmail(CollectionDay7EmailTemplate, model, type); //send imail DefaulttemplateComm7 for limited loan SendCollectionImail(model, type); //send sms Default SMS7 SendCollectionSms(model, type); } //CollectionDay7
} //CollectionDay13 private void CollectionDay15(CollectionDataModel model, CollectionType type) { //change status to 15-30 days missed ChangeStatus(model.CustomerID, model.LoanID, CollectionStatusNames.DaysMissed15To30, type, model); //send email Default Template14-29 SendCollectionEmail(CollectionDay15EmailTemplate, model, type); //send imail DefaulttemplateConsumer14 SendCollectionImail(model, type); } //CollectionDay15
} //CollectionDay21 private void CollectionDay31(CollectionDataModel model, CollectionType type) { ChangeStatus(model.CustomerID, model.LoanID, CollectionStatusNames.DaysMissed31To45, type, model); //send email Default Template30 SendCollectionEmail(CollectionDay31EmailTemplate, model, type); //send imail DefaulttemplateConsumer31 SendCollectionImail(model, type); //send sms Default SMS31 SendCollectionSms(model, type); } //CollectionDay31
public override void Execute() { this.now = DateTime.UtcNow; DB.ForEachRowSafe((sr, bRowsetStart) => { // mark loan/schedule status as late, record fee MarkLoanAsLate(sr); return(ActionResult.Continue); }, "GetLoansToCollect", CommandSpecies.StoredProcedure, new QueryParameter("Now", this.now)); //------NL/"old"-----Send collection mails sms imails and change status -------------------- LoadSmsTemplates(); LoadImailTemplates(); DB.ForEachRowSafe((sr, bRowsetStart) => { try { // build data model+changesStatus?+senEmail?+sentImail?+sent HandleCollectionLogic(sr); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error(ex, "Failed to handle collection for customer {0}", sr["CustomerID"]); } return(ActionResult.Continue); }, "GetLateForCollection", CommandSpecies.StoredProcedure, new QueryParameter("Now", this.now)); //-----------Change status to enabled for cured loans-------------------------------- DB.ForEachRowSafe((sr, bRowsetStart) => { var model = new CollectionDataModel { CustomerID = sr["CustomerID"], LoanID = sr["LoanID"], UpdateCustomerAllowed = true }; try { HandleCuredLoan(model.CustomerID, model.LoanID, model); } catch (Exception ex) { Log.Error(ex, "Failed to handle cured loan for customer {0}", sr["CustomerID"]); } return(ActionResult.Continue); }, "GetCuredLoansForCollection", CommandSpecies.StoredProcedure); // run NL job try { Log.Debug("====================================NEWLOAN late job started==========================="); LateLoanJob nlLateJob = new LateLoanJob(this.now); nlLateJob.Execute(); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Debug(ex.Message); NL_AddLog(LogType.Error, "Strategy failed", this.now, null, ex.Message, ex.StackTrace); } } //Execute
} //SendCollectionImail protected void SendCollectionSms(CollectionDataModel model, CollectionType type) { var smsModel = this.smsTemplates.FirstOrDefault(x => x.IsActive && x.OriginID == model.OriginID && x.Type == type.ToString()); if (smsModel == null) { Log.Info("Collection not sending sms, sms template is not found. customer {0} origin {1} type {2}", model.CustomerID, model.OriginID, type); return; } var smsTemplate = string.Format(smsModel.Template, model.FirstName); if (model.SmsSendingAllowed && !CurrentValues.Instance.SmsTestModeEnabled) { Log.Info("Collection sending sms to customer {0} phone number {1}\n content {2}", model.CustomerID, model.PhoneNumber, smsTemplate); new SendSms(model.CustomerID, 1, model.PhoneNumber, smsTemplate).Execute(); //AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Sms, model); AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Sms.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); } else if (model.SmsSendingAllowed) { Log.Info("Collection sending sms is in test mode, sms is not sent to customer {0} phone number {1}\n content {2}", model.CustomerID, model.PhoneNumber, smsTemplate); //AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Sms, model); AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Sms.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); } else { Log.Info("Collection sending sms is not allowed, sms is not sent to customer {0} phone number {1}\n content {2}", model.CustomerID, model.PhoneNumber, smsTemplate); } } //SendCollectionSms
} //Execute private void BuildCollectionDataModel(SafeReader sr) { string mobilePhone = sr["MobilePhone"]; var model = new CollectionDataModel { CustomerID = sr["CustomerID"], OriginID = sr["OriginID"], LoanRefNum = sr["LoanRefNum"], FirstName = sr["FirstName"], FullName = sr["FullName"], Email = sr["email"], PhoneNumber = string.IsNullOrEmpty(mobilePhone) ? sr["DaytimePhone"] : mobilePhone, DueDate = sr["ScheduleDate"], LoanID = sr["OldLoanID"], ScheduleID = 0, NLLoanID = sr["LoanID"], LoanHistoryID = sr["LoanHistoryID"], NLScheduleID = sr["ScheduleID"], SmsSendingAllowed = sr["SmsSendingAllowed"], EmailSendingAllowed = sr["EmailSendingAllowed"], ImailSendingAllowed = sr["MailSendingAllowed"] }; model.LateDays = (int)(now - model.DueDate).TotalDays; GetLoanState loanState = new GetLoanState(model.CustomerID, model.NLLoanID, now); loanState.Execute(); List <NL_LoanSchedules> schedules = new List <NL_LoanSchedules>(); loanState.Result.Loan.Histories.ForEach(h => schedules.AddRange(h.Schedule)); var scheduleItem = schedules.FirstOrDefault(s => s.LoanScheduleID == model.NLScheduleID); model.Interest = loanState.Result.Interest; if (scheduleItem != null) { model.FeeAmount = scheduleItem.Fees; model.AmountDue = scheduleItem.AmountDue; } nlNotificationsList.Add(model); Log.Info(model.ToString()); NL_AddLog(LogType.Info, "CollectionDataModel", now, model, null, null); }
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", now, null, null, null); try { //-----------Change status to enabled for cured loans-------------------------------- DB.ForEachRowSafe((sr, bRowsetStart) => { var model = new CollectionDataModel { CustomerID = sr["CustomerID"], LoanID = sr["OldLoanID"], LoanHistoryID = sr["LoanHistoryID"], NLLoanID = sr["LoanID"] }; if (CurrentValues.Instance.SendCollectionMailOnNewLoan == false) { model.UpdateCustomerAllowed = false; } this.loansList.Add(model); return(ActionResult.Continue); }, "NL_CuredLoansGet", CommandSpecies.StoredProcedure); foreach (var model in this.loansList) { HandleCuredLoan(model.CustomerID, model.LoanID, model); } NL_AddLog(LogType.Info, "Strategy end", now, null, null, null); // ReSharper disable once CatchAllClause } catch (Exception ex) { NL_AddLog(LogType.Error, "Strategy failed", null, ex.Message, ex.ToString(), ex.StackTrace); } } //Execute
private void NLSendNotifications(CollectionDataModel model) { // prevent for sending notification twice - for old and new loan to sane customer if (!sendNotificationForNewLoan) { model.SmsSendingAllowed = false; model.ImailSendingAllowed = false; model.EmailSendingAllowed = false; model.UpdateCustomerAllowed = false; } CollectionType collectionType = GetCollectionType(model.LateDays); CollectionStatusNames collectionStatusName = GetCollectionStatusName(collectionType); string emailTemplate = GetCollectionEmailTemplateName(collectionType); bool isSendEmail = IsSendEmail(collectionType); bool isSendSMS = IsSendSMS(collectionType); bool isSendImail = IsSendImail(collectionType); bool isChangeStatusCall = IsChangeStatusCall(collectionType); if (isChangeStatusCall) { ChangeStatus(model.CustomerID, 1, collectionStatusName, collectionType, model); } if (isSendEmail) { SendCollectionEmail(emailTemplate, model, collectionType); } if (isSendSMS) { SendCollectionSms(model, collectionType); } if (isSendImail) { SendCollectionImail(model, collectionType); } }
} //SendCollectionEmail protected void SendCollectionImail(CollectionDataModel model, CollectionType type) { if (model.ImailSendingAllowed) { try { CollectionMailModel mailModel = GetCollectionMailModel(model); switch (type) { case CollectionType.CollectionDay7: if (mailModel.IsLimited) { Log.Info("Sending imail {0} to customer {1}", model.CustomerID, type); FileMetadata personal; FileMetadata business; this.collectionIMailer.SendDefaultTemplateComm7(mailModel, out personal, out business); //int collection7LogID = AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Mail, model); int collection7LogID = AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Mail.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); SaveCollectionSnailMailMetadata(collection7LogID, personal); SaveCollectionSnailMailMetadata(collection7LogID, business); } break; case CollectionType.CollectionDay15: FileMetadata day15Metadata; if (mailModel.IsLimited) { Log.Info("Sending imail {0} to customer {1}", model.CustomerID, type); day15Metadata = this.collectionIMailer.SendDefaultNoticeComm14Borrower(mailModel); //TODO uncomment when guarantor is implemented: //collectionIMailer.SendDefaultWarningComm7Guarantor(mailModel); } else { Log.Info("Sending imail {0} to customer {1}", model.CustomerID, type); day15Metadata = this.collectionIMailer.SendDefaultTemplateConsumer14(mailModel); } //int collection15LogID = AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Mail, model); int collection15LogID = AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Mail.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); SaveCollectionSnailMailMetadata(collection15LogID, day15Metadata); break; case CollectionType.CollectionDay31: if (!mailModel.IsLimited) { Log.Info("Sending imail {0} to customer {1}", model.CustomerID, type); FileMetadata consumer = this.collectionIMailer.SendDefaultTemplateConsumer31(mailModel); //int collection31LogID = AddCollectionLog(model.CustomerID, model.LoanID, type, CollectionMethod.Mail, model); int collection31LogID = AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.Mail.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); SaveCollectionSnailMailMetadata(collection31LogID, consumer); } break; } } catch (Exception ex) { Log.Error(ex, "Sending Imail failed for customer {0}", model.CustomerID); } } else { Log.Info("Collection sending mail is not allowed, mail is not sent to customer {0}\n template {1}", model.CustomerID, type); } } //SendCollectionImail
} //GetCollectionMailModel /// <summary> /// For the first late schedule /// </summary> private void HandleCollectionLogic(SafeReader sr) { DateTime scheduleDate = sr["ScheduleDate"]; int loanId = sr["LoanID"]; string dayPhone = sr["DaytimePhone"]; string mobilePhone = sr["MobilePhone"]; int lateDays = (int)(this.now - scheduleDate).TotalDays; var model = new CollectionDataModel { CustomerID = sr["CustomerID"], OriginID = sr["OriginID"], LoanID = loanId, ScheduleID = sr["ScheduleID"], LoanRefNum = sr["LoanRefNum"], FirstName = sr["FirstName"], FullName = sr["FullName"], AmountDue = sr["AmountDue"], Interest = sr["Interest"], FeeAmount = sr["Fees"], Email = sr["email"], DueDate = scheduleDate, LateDays = lateDays, PhoneNumber = string.IsNullOrEmpty(mobilePhone) ? dayPhone : mobilePhone, SmsSendingAllowed = sr["SmsSendingAllowed"], EmailSendingAllowed = sr["EmailSendingAllowed"], ImailSendingAllowed = sr["MailSendingAllowed"], UpdateCustomerAllowed = true //SendNotification = true // always perform action(send notification/changeStatus) for "old" loan }; Log.Info(model.ToString()); if (lateDays == 0) { CollectionDay0(model, CollectionType.CollectionDay0); } if (lateDays >= 1 && lateDays <= 6) { CollectionDay1to6(model, CollectionType.CollectionDay1to6); } if (lateDays == 3) { CollectionDay3(model, CollectionType.CollectionDay3); } if (lateDays == 7) { CollectionDay7(model, CollectionType.CollectionDay7); } if (lateDays >= 8 && lateDays <= 14) { CollectionDay8to14(model, CollectionType.CollectionDay8to14); } if (lateDays == 10) { CollectionDay10(model, CollectionType.CollectionDay10); } if (lateDays == 13) { CollectionDay13(model, CollectionType.CollectionDay13); } if (lateDays == 15) { CollectionDay15(model, CollectionType.CollectionDay15); } if (lateDays == 21) { CollectionDay21(model, CollectionType.CollectionDay21); } if (lateDays == 31) { CollectionDay31(model, CollectionType.CollectionDay31); } if (lateDays == 46) { CollectionDay46(model, CollectionType.CollectionDay46); } if (lateDays == 60) { CollectionDay60(model, CollectionType.CollectionDay60); } if (lateDays == 90) { CollectionDay90(model, CollectionType.CollectionDay90); } UpdateLoanStats(loanId, lateDays, model.AmountDue); } //HandleCollectionLogic
} //CollectionDay90 private CollectionMailModel GetCollectionMailModel(CollectionDataModel model) { SafeReader sr = DB.GetFirst("GetDataForCollectionMail", CommandSpecies.StoredProcedure, new QueryParameter("CustomerID", model.CustomerID), new QueryParameter("LoanID", model.LoanID)); CollectionMailModel mailModel = new CollectionMailModel { CustomerName = model.FullName, CustomerAddress = new Address { Line1 = sr["CAddress1"], Line2 = sr["CAddress2"], Line3 = sr["CAddress3"], Line4 = sr["CAddress4"], Postcode = sr["CPostcode"], }, CompanyAddress = new Address { Line1 = sr["BAddress1"], Line2 = sr["BAddress2"], Line3 = sr["BAddress3"], Line4 = sr["BAddress4"], Postcode = sr["BPostcode"], }, GuarantorAddress = new Address { //TODO implement Line1 = sr["GAddress1"], Line2 = sr["GAddress2"], Line3 = sr["GAddress3"], Line4 = sr["GAddress4"], Postcode = sr["GPostcode"], }, GuarantorName = sr["GuarantorName"], //TODO implement IsLimited = sr["IsLimited"], CompanyName = sr["CompanyName"], Date = this.now, LoanAmount = sr["LoanAmount"], LoanRef = sr["LoanRef"], LoanDate = sr["LoanDate"], //OutstandingBalance = sr["OutstandingBalance"], OutstandingPrincipal = sr["OutstandingPrincipal"], CustomerId = model.CustomerID, OriginId = model.OriginID, MissedPayment = new MissedPaymentModel { AmountDue = sr["AmountDue"], DateDue = sr["SchedDate"], Fees = sr["Fees"], RepaidAmount = sr["RepaidAmount"], RepaidDate = sr["RepaidDate"] }, PreviousMissedPayment = new MissedPaymentModel { AmountDue = sr["PreviousAmountDue"], DateDue = sr["PreviousSchedDate"], Fees = sr["PreviousFees"], RepaidAmount = sr["PreviousRepaidAmount"], RepaidDate = sr["PreviousRepaidDate"] }, }; var loanRepository = ObjectFactory.GetInstance <LoanRepository>(); Loan loan = loanRepository.Get(model.LoanID); var payEarlyCalc = new LoanRepaymentScheduleCalculator(loan, this.now, CurrentValues.Instance.AmountToChargeFrom); var balance = payEarlyCalc.TotalEarlyPayment(); mailModel.OutstandingBalance = balance; if (model.NLLoanID > 0) { GetLoanState nlState = new GetLoanState(model.CustomerID, model.NLLoanID, this.now, 1); nlState.Execute(); mailModel.LoanRef = nlState.Result.Loan.Refnum; mailModel.OutstandingPrincipal = nlState.Result.Principal; mailModel.OutstandingBalance = nlState.Result.TotalEarlyPayment; var firtHistory = nlState.Result.Loan.FirstHistory(); if (firtHistory != null) { mailModel.LoanAmount = (int)firtHistory.Amount; mailModel.LoanDate = firtHistory.EventTime; } // TODO handle MissedPayment, PreviousMissedPayment } return(mailModel); } //GetCollectionMailModel
} //CollectionDay8to14 private void CollectionDay90(CollectionDataModel model, CollectionType type) { ChangeStatus(model.CustomerID, model.LoanID, CollectionStatusNames.DaysMissed90Plus, type, model); } //CollectionDay90
} //CollectionDay7 private void CollectionDay8to14(CollectionDataModel model, CollectionType type) { //send email Default Template8-13 SendCollectionEmail(CollectionDay8to14EmailTemplate, model, type); } //CollectionDay8to14
} //CollectionDay1to6 private void CollectionDay21(CollectionDataModel model, CollectionType type) { //send sms Default SMS21 SendCollectionSms(model, type); } //CollectionDay21
} //LoadSmsTemplates protected void HandleCuredLoan(int customerID, int loanID, CollectionDataModel model) { ChangeStatus(customerID, loanID, CollectionStatusNames.Enabled, CollectionType.Cured, model); } //HandleCuredLoan
} //CalculateFee protected void ChangeStatus(int customerID, int loanID, CollectionStatusNames status, CollectionType type, CollectionDataModel model) { Log.Info("Changing collection status to customer {0} loan {1} type {2} status {3}", customerID, loanID, type, status); // prevent while running on new loan - duplicate update if (model.UpdateCustomerAllowed) { bool wasChanged = DB.ExecuteScalar <bool>("UpdateCollectionStatus", CommandSpecies.StoredProcedure, new QueryParameter("CustomerID", customerID), new QueryParameter("CollectionStatus", (int)status), new QueryParameter("Now", this.now)); if (!wasChanged) { Log.Info("ChangeStatus to customer {0} loan {1} status {2} was not changed - customer already in this status", customerID, loanID, status); } else { var salesForce = new SalesForce.AddUpdateLeadAccount(null, customerID, false, false); salesForce.Execute(); } } //AddCollectionLog(customerID, loanID, type, CollectionMethod.ChangeStatus, model); model.CustomerID = customerID; model.LoanID = loanID; AddCollectionLog(new CollectionLog() { CustomerID = model.CustomerID, LoanID = model.LoanID, LoanHistoryID = model.LoanHistoryID, Type = type.ToString(), Method = CollectionMethod.ChangeStatus.ToString(), Comments = (model.NLLoanID > 0) ? "nlloan " + model.NLLoanID : null }); //TODO update loan collection status if want to be on loan level and not on customer level Log.Info("update loan collection status if want to be on loan level and not on customer level for customer {0}, loan {1}", customerID, loanID); } //ChangeStatus