} // SuspendCustomer private void EscalateCustomer(NL_Decisions newDecision) { this.decisionToApply.Customer.DateEscalated = this.now; this.decisionToApply.Customer.EscalationReason = this.decisionModel.reason; if (!SaveDecision <ManuallyEscalate>()) { return; } FireToBackground( new Escalated(this.decisionModel.customerID), e => Warning = "Failed to send 'escalated' email: " + e.Message ); newDecision.DecisionNameID = (int)DecisionActions.Escalate; AddDecision nlAddDecision = new AddDecision(newDecision, this.decisionToApply.CashRequest.ID, null); nlAddDecision.Context.CustomerID = this.decisionModel.customerID; nlAddDecision.Context.UserID = this.decisionModel.underwriterID; try { nlAddDecision.Execute(); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error("Failed to add NL_decision. Err: {0}", ex.Message); } UpdateSalesForceOpportunity(OpportunityStage.s20); } // EscalateCustomer
public AddDecision(NL_Decisions decision, long? oldCashRequestID, IEnumerable<NL_DecisionRejectReasons> decisionRejectReasons) { this.decision = decision; this.oldCashRequestID = oldCashRequestID; this.decisionRejectReasons = (List<NL_DecisionRejectReasons>)decisionRejectReasons; this.strategyArgs = new object[] { decision, oldCashRequestID, decisionRejectReasons }; }//constructor
} // EscalateCustomer private bool RejectCustomer(NL_Decisions newDecision) { this.decisionToApply.Customer.DateRejected = this.now; this.decisionToApply.Customer.RejectedReason = this.decisionModel.reason; this.decisionToApply.Customer.NumRejects = 1 + this.currentState.NumOfPrevRejections; this.decisionToApply.CashRequest.RejectionReasons.Clear(); List <NL_DecisionRejectReasons> nlRejectReasonsList = new List <NL_DecisionRejectReasons>(); if (this.decisionModel.rejectionReasons != null && this.decisionModel.rejectionReasons.Any()) { this.decisionToApply.CashRequest.RejectionReasons.AddRange(this.decisionModel.rejectionReasons); nlRejectReasonsList = this.decisionModel.rejectionReasons.Select(x => new NL_DecisionRejectReasons { RejectReasonID = x }).ToList(); } if (!SaveDecision <ManuallyReject>()) { return(false); } bool bSendToCustomer = !(this.currentState.FilledByBroker && (this.currentState.NumOfPrevApprovals == 0)); if (!this.currentState.EmailSendingBanned) { FireToBackground( new RejectUser(this.decisionModel.customerID, bSendToCustomer), e => Warning = "Failed to send 'reject user' email: " + e.Message ); } // if newDecision.DecisionNameID = (int)DecisionActions.Reject; AddDecision nlAddDecision = new AddDecision(newDecision, this.decisionToApply.CashRequest.ID, nlRejectReasonsList); nlAddDecision.Context.CustomerID = this.decisionModel.customerID; nlAddDecision.Context.UserID = this.decisionModel.underwriterID; try { nlAddDecision.Execute(); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error("Failed to add NL_decision. Err: {0}", ex.Message); } UpdateSalesForceOpportunity(null, model => { model.CloseDate = this.now; model.DealCloseType = OpportunityDealCloseReason.Lost.ToString(); model.DealLostReason = this.decisionModel.reason; }); return(true); } // RejectCustomer
} // AddCashRequest public NLLongActionResult AddDecision(int userID, int customerID, NL_Decisions decision, long?oldCashRequest, IEnumerable <NL_DecisionRejectReasons> decisionRejectReasons) { AddDecision s = new AddDecision(decision, oldCashRequest, decisionRejectReasons); s.Context.UserID = userID; s.Context.CustomerID = customerID; var amd = ExecuteSync(out s, customerID, userID, decision, oldCashRequest, decisionRejectReasons); return(new NLLongActionResult { MetaData = amd, Value = s.DecisionID, Error = s.Error }); } // AddDecision
} // ApproveCustomer private void PendingInvestor(NL_Decisions newDecision) { Log.Info("Investor not found for customer {0} cr {1}, mark as pending investor", this.decisionToApply.Customer.ID, this.decisionToApply.CashRequest.ID); this.decisionToApply.Customer.CreditResult = CreditResultStatus.PendingInvestor.ToString(); this.decisionToApply.CashRequest.UnderwriterDecision = CreditResultStatus.PendingInvestor.ToString(); SaveDecision <ManuallySuspend>(); var notifyRiskPendingInvestorCustomer = new NotifyRiskPendingInvestorOffer( this.decisionToApply.Customer.ID, this.currentState.OfferedCreditLine, this.currentState.OfferValidUntil ); notifyRiskPendingInvestorCustomer.Execute(); //TODO newDecision PendingInvestor status }
} // ReturnCustomerToWaitingForDecision private bool SuspendCustomer(NL_Decisions newDecision) { this.decisionToApply.Customer.IsWaitingForSignature = this.decisionModel.signature == 1; this.decisionToApply.Customer.ManagerApprovedSum = this.currentState.OfferedCreditLine; if (!SaveDecision <ManuallySuspend>()) { return(false); } newDecision.DecisionNameID = (int)DecisionActions.Pending; AddDecision nlAddDecision = new AddDecision(newDecision, this.decisionToApply.CashRequest.ID, null); nlAddDecision.Context.CustomerID = this.decisionModel.customerID; nlAddDecision.Context.UserID = this.decisionModel.underwriterID; nlAddDecision.Execute(); UpdateSalesForceOpportunity((this.decisionModel.signature == 1) ? OpportunityStage.s75 : OpportunityStage.s50); return(true); } // SuspendCustomer
} // CanChangeDecision private void ReturnCustomerToWaitingForDecision(NL_Decisions newDecision) { if (!SaveDecision <ManuallyUnsuspend>()) { return; } newDecision.DecisionNameID = (int)DecisionActions.Waiting; AddDecision nlAddDecision = new AddDecision(newDecision, this.decisionToApply.CashRequest.ID, null); nlAddDecision.Context.CustomerID = this.decisionModel.customerID; nlAddDecision.Context.UserID = this.decisionModel.underwriterID; try { nlAddDecision.Execute(); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error("Failed to add NL_decision. Err: {0}", ex.Message); } UpdateSalesForceOpportunity(OpportunityStage.s40); } // ReturnCustomerToWaitingForDecision
/// <exception cref="ArgumentOutOfRangeException">Condition. </exception> public override void Execute() { Log.Debug("Applying manual decision by model: {0}.", this.decisionModel.Stringify()); switch (CanChangeDecision()) { case ChangeDecisionOption.Available: Log.Debug("Decision can be applied to model.attemptID = {0}.", this.decisionModel.attemptID); break; case ChangeDecisionOption.BlockedByConcurrency: case ChangeDecisionOption.BlockedNoCashRequest: case ChangeDecisionOption.BlockedByFinalDecision: case ChangeDecisionOption.BlockedByMainStrategy: case ChangeDecisionOption.BlockedByApprovedAmount: case ChangeDecisionOption.BlockedByMaxLoanAmount: Log.Info("Decision cannot be applied to model {0}: '{1}'.", this.decisionModel.Stringify(), Error); return; case ChangeDecisionOption.BlockedByError: Log.Alert("Decision cannot be applied to model {0}: '{1}'.", this.decisionModel.Stringify(), Error); return; default: throw new ArgumentOutOfRangeException(); } // switch this.decisionToApply = new DecisionToApply( this.decisionModel.underwriterID, this.decisionModel.customerID, this.decisionModel.cashRequestID, this.currentState.CashRequestTimestamp ); this.decisionToApply.Customer.CreditResult = this.decisionModel.status.ToString(); this.decisionToApply.Customer.UnderwriterName = this.currentState.UnderwriterID == this.decisionModel.underwriterID ? this.currentState.UnderwriterName : null; this.decisionToApply.CashRequest.UnderwriterDecisionDate = this.now; this.decisionToApply.CashRequest.UnderwriterDecision = this.decisionModel.status.ToString(); this.decisionToApply.CashRequest.UnderwriterComment = this.decisionModel.reason; var newDecision = new NL_Decisions { UserID = this.decisionModel.underwriterID, DecisionTime = this.now, Notes = this.decisionModel.reason, }; if (this.decisionModel.status != CreditResultStatus.ApprovedPending) { this.decisionToApply.Customer.IsWaitingForSignature = false; } SilentAutomation.Callers?silentAutomationCaller = null; bool notifyAlibaba = false; switch (this.decisionModel.status) { case CreditResultStatus.Approved: if (ApproveCustomer(newDecision)) { if (this.currentState.LastWizardStep) { silentAutomationCaller = SilentAutomation.Callers.ManuallyApproved; } notifyAlibaba = this.currentState.IsAlibaba; } // if break; case CreditResultStatus.Rejected: if (RejectCustomer(newDecision)) { silentAutomationCaller = SilentAutomation.Callers.ManuallyRejected; notifyAlibaba = this.currentState.IsAlibaba; } // if break; case CreditResultStatus.Escalated: EscalateCustomer(newDecision); break; case CreditResultStatus.ApprovedPending: if (SuspendCustomer(newDecision)) { silentAutomationCaller = SilentAutomation.Callers.ManuallySuspended; } break; case CreditResultStatus.WaitingForDecision: ReturnCustomerToWaitingForDecision(newDecision); break; } // switch if (notifyAlibaba) { FireToBackground(new DataSharing(this.decisionModel.customerID, AlibabaBusinessType.APPLICATION_REVIEW)); } if (silentAutomationCaller.HasValue) { FireToBackground( new SilentAutomation(this.decisionModel.customerID) .SetTag(silentAutomationCaller.Value) .PreventMainStrategy() ); } // if Log.Debug("Done applying manual decision by model: {0}.", this.decisionModel.Stringify()); } // Execute
} // RejectCustomer private bool ApproveCustomer(NL_Decisions newDecision) { LinkOfferToInvestor linkOfferToInvestor = new LinkOfferToInvestor(this.decisionToApply.Customer.ID, this.decisionToApply.CashRequest.ID, this.decisionModel.ForceInvestor, this.decisionModel.InvestorID, this.decisionModel.underwriterID); linkOfferToInvestor.Execute(); Log.Info("ApproveCustomer Decision {0} for Customer {1} cr {2} OP {3} FoundInvestor {4}", this.decisionToApply.CashRequest.UnderwriterDecision, this.decisionToApply.Customer.ID, this.decisionToApply.CashRequest.ID, linkOfferToInvestor.IsForOpenPlatform, linkOfferToInvestor.FoundInvestor); if (linkOfferToInvestor.IsForOpenPlatform && !linkOfferToInvestor.FoundInvestor) { PendingInvestor(newDecision); return(false); } this.decisionToApply.Customer.DateApproved = this.now; this.decisionToApply.Customer.ApprovedReason = this.decisionModel.reason; this.decisionToApply.Customer.CreditSum = this.currentState.OfferedCreditLine; this.decisionToApply.Customer.ManagerApprovedSum = this.currentState.OfferedCreditLine; this.decisionToApply.Customer.NumApproves = 1 + this.currentState.NumOfPrevApprovals; this.decisionToApply.Customer.IsLoanTypeSelectionAllowed = this.currentState.IsLoanTypeSelectionAllowed; this.decisionToApply.CashRequest.ManagerApprovedSum = (int)this.currentState.OfferedCreditLine; if (!SaveDecision <ManuallyApprove>()) { return(false); } bool bSendBrokerForceResetCustomerPassword = this.currentState.FilledByBroker && (this.currentState.NumOfPrevApprovals == 0); bool bSendApprovedUser = !this.currentState.EmailSendingBanned; int validForHours = (int)(this.currentState.OfferValidUntil - this.currentState.OfferStart).TotalHours; if (bSendBrokerForceResetCustomerPassword && bSendApprovedUser) { FireToBackground( new ApprovedUser( this.decisionModel.customerID, this.currentState.OfferedCreditLine, validForHours, this.currentState.NumOfPrevApprovals == 0 ) { SendToCustomer = false, }, e => Warning = "Failed to force reset customer password and send 'approved user' email: " + e.Message ); } else if (bSendApprovedUser) { FireToBackground( new ApprovedUser( this.decisionModel.customerID, this.currentState.OfferedCreditLine, validForHours, this.currentState.NumOfPrevApprovals == 0 ), e => Warning = "Failed to send 'approved user' email: " + e.Message ); } else if (bSendBrokerForceResetCustomerPassword) { FireToBackground(new BrokerForceResetCustomerPassword(this.decisionModel.customerID)); } newDecision.DecisionNameID = (int)DecisionActions.Approve; AddDecision nlAddDecision = new AddDecision(newDecision, this.decisionToApply.CashRequest.ID, null); nlAddDecision.Context.CustomerID = this.decisionModel.customerID; nlAddDecision.Context.UserID = this.decisionModel.underwriterID; try { try { nlAddDecision.Execute(); Log.Debug("nl AddDecision {0}, Error: {1}", nlAddDecision.DecisionID, nlAddDecision.Error); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error("Failed to add NL_decision. Err: {0}", ex.Message); } NL_Offers nlOffer = new NL_Offers() { DecisionID = nlAddDecision.DecisionID, CreatedTime = this.currentState.CreationDate, Amount = this.currentState.OfferedCreditLine, BrokerSetupFeePercent = this.currentState.BrokerSetupFeePercent, //IsAmountSelectionAllowed = this.currentState. SendEmailNotification = !this.currentState.EmailSendingBanned, StartTime = this.currentState.OfferStart, EndTime = this.currentState.OfferValidUntil, IsLoanTypeSelectionAllowed = this.currentState.IsLoanTypeSelectionAllowed == 1, Notes = this.decisionToApply.CashRequest.UnderwriterComment + " old cr " + this.decisionToApply.CashRequest.ID, MonthlyInterestRate = this.currentState.InterestRate, LoanSourceID = this.currentState.LoanSourceID, DiscountPlanID = this.currentState.DiscountPlanID, LoanTypeID = this.currentState.LoanTypeID, RepaymentIntervalTypeID = (int)RepaymentIntervalTypes.Month, RepaymentCount = this.currentState.RepaymentPeriod, // ApprovedRepaymentPeriod??? IsRepaymentPeriodSelectionAllowed = this.currentState.IsCustomerRepaymentPeriodSelectionAllowed }; Log.Debug("Adding nl offer: {0}", nlOffer); NL_OfferFees setupFee = new NL_OfferFees() { LoanFeeTypeID = (int)NLFeeTypes.SetupFee, Percent = this.currentState.ManualSetupFeePercent, OneTimePartPercent = 1, DistributedPartPercent = 0 }; if (this.currentState.SpreadSetupFee) { setupFee.LoanFeeTypeID = (int)NLFeeTypes.ServicingFee; setupFee.OneTimePartPercent = 0; setupFee.DistributedPartPercent = 1; } NL_OfferFees[] ofeerFees = { setupFee }; AddOffer sAddOffer = new AddOffer(nlOffer, ofeerFees); sAddOffer.Context.CustomerID = this.decisionToApply.Customer.ID; sAddOffer.Context.UserID = this.decisionModel.underwriterID; try { sAddOffer.Execute(); Log.Debug("nl offer added: {0}, Error: {1}", sAddOffer.OfferID, sAddOffer.Error); // ReSharper disable once CatchAllClause } catch (Exception ex) { Log.Error("Failed to AddOffer. Err: {0}", ex.Message); } // ReSharper disable once CatchAllClause } catch (Exception nlException) { Log.Error("Failed to run NL offer/decision Err: {0}", nlException.Message); } UpdateSalesForceOpportunity(OpportunityStage.s90, model => { model.ApprovedAmount = (int)this.currentState.OfferedCreditLine; model.ExpectedEndDate = this.currentState.OfferValidUntil; }); return(true); } // ApproveCustomer