using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using LCU.API.Internal.Operations.IncentiveApi.Services; using LCU.Library.Internal.IncentiveApiModels.Entities; using LCU.Library.Internal.IncentiveApiModels.Enums; using LCU.Library.Internal.CoreApiWrapperModel.CoreModels.Transaction; using Moq; using NUnit.Framework; using LCU.API.Internal.Operations.IncentiveApi.Services.AutoDecision; using LCU.Library.Internal.IncentiveApiModels.Common; using LCU.API.Internal.Operations.IncentiveApi.Exceptions; using LCU.Library.Internal.IncentiveApiModels.Requests; namespace Application.UnitTests.Services.AutoDecision { public class ActivityDecisionServiceTest { private ActivityDecisionService _activityDecisionService; private IActivityService _activityService; private IActivityDetailService _activityDetailService; private DebtProtectionAccessoryService _debtProtectionAccessoryService; private IDnaService _dnaService; [SetUp] public void Setup() { var strategies = new List() { new ManualDecisionStrategy(), new ReferralDecisionStrategy(), new NewCheckingDecisionStrategy(), new CardSaleDecisionStrategy(), new MortgageSaleDecisionStrategy(), new VehicleDecisionStrategy(), new DebtProtectionEligibleLoanDecisionStrategy() }; _activityService = Mock.Of(); _activityDetailService = Mock.Of(); _debtProtectionAccessoryService = new DebtProtectionAccessoryService(_activityService, _activityDetailService); _dnaService = Mock.Of(); _activityDecisionService = new ActivityDecisionService(strategies, _activityService, _activityDetailService, _debtProtectionAccessoryService, _dnaService); } [Test] public async Task Decision_Basic_Accept() { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Other, Product = Product.CheckCard, Accepted = DateTime.Today, Detail = new ActivityDetail() { AccountStatus = "ACT" } }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreNotEqual(activity.State, decision.State); Assert.AreEqual(ActivityState.Accepted, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [Test] public async Task Decision_ByState_Basic() { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Other, Product = Product.CheckCard, Accepted = DateTime.Today, Detail = new ActivityDetail() { AccountStatus = "ACT" }, State = ActivityState.Created }; var pagedResult = new PagedResult() { Total = 1, Items = new List() { activity } }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.IsAny())) .ReturnsAsync(pagedResult); Mock.Get(_activityService).Setup(x => x.ApplyStateChange(It.IsAny(),true)) .Verifiable(); var changes = await _activityDecisionService.DecisionActivityByState(ActivityState.Created); Assert.NotNull(changes); Assert.IsNotEmpty(changes); var decision = changes.FirstOrDefault(); Assert.NotNull(decision); Assert.AreNotEqual(activity.State, decision.State); Assert.AreEqual(ActivityState.Accepted, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); Mock.Get(_activityService).Verify(x => x.ListByFilterAsync(It.IsAny()), Times.Once); Mock.Get(_activityService).Verify(x => x.ApplyStateChange(It.IsAny(),true), Times.Once); } [Test] public async Task Decision_ManualReview_Basic() { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Other, Product = Product.CheckCard, Accepted = DateTime.Today, Detail = new ActivityDetail() { AccountStatus = "ACT" }, State = ActivityState.Created }; var pagedResult = new PagedResult() { Total = 1, Items = new List() { activity } }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.IsAny())) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_activityDetailService) .Setup(x => x.TryUpdateActivityAccountDetails(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); Mock.Get(_activityService).Setup(x => x.ApplyStateChange(It.IsAny(),true)) .Verifiable(); var changes = await _activityDecisionService.UpdateAndDecideManualReviewActivities(); Assert.NotNull(changes); Assert.IsNotEmpty(changes); var decision = changes.FirstOrDefault(); Assert.NotNull(decision); Assert.AreNotEqual(activity.State, decision.State); Assert.AreEqual(ActivityState.Accepted, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); Mock.Get(_activityService).Verify(); Mock.Get(_activityDetailService).Verify(); Mock.Get(_activityService).Verify(x => x.ListByFilterAsync(It.IsAny()), Times.Once); Mock.Get(_activityService).Verify(x => x.ApplyStateChange(It.IsAny(),true), Times.Once); } [TestCase(Product.LIC, ActivityType.Sale)] [TestCase(Product.DirectDeposit, ActivityType.Sale)] [TestCase(Product.CreditCardBalanceTransfer, ActivityType.Sale)] public async Task Decision_Basic_NoDecision(Product product, ActivityType type) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = type, Product = product, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreNotEqual(activity.State, decision.State); Assert.AreEqual(ActivityState.ManualReview, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase("APPR", ActivityState.ManualReview)] [TestCase("ACT", ActivityState.Accepted)] [TestCase("CLS", ActivityState.Rejected)] [TestCase("YeeHaw", ActivityState.ManualReview)] [TestCase(null, ActivityState.Rejected)] public async Task Decision_Mortgage(string status, ActivityState state) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, Detail = new ActivityDetail() { AccountStatus = status }, Product = Product.Mortgage, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase(Product.ATMCard, ActivityState.PendingReferral, "60")] [TestCase(Product.CheckCard, ActivityState.PendingReferral, "60")] [TestCase(Product.NewChecking, ActivityState.PendingReferral, "60")] [TestCase(Product.Mortgage, ActivityState.PendingReferral, "60")] [TestCase(Product.FirstMortgageReferral, ActivityState.PendingReferral, "120")] [TestCase(Product.DirectDeposit, ActivityState.PendingReferral, "60")] [TestCase(Product.CreditCardBalanceTransfer, ActivityState.PendingReferral, "60")] [TestCase(Product.LIC, ActivityState.ManualReview, "Not In Final Station")] public async Task Decision_Referrals(Product product, ActivityState expectedState, string expectedExpirationDays) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Referral, Product = product, Accepted = DateTime.Today, Detail = new ActivityDetail() }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(expectedState, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); Assert.IsTrue(decision.Note.Contains(expectedExpirationDays)); } [TestCase(null, ActivityState.ManualReview)] [TestCase("NotRealStation", ActivityState.ManualReview)] [TestCase("LIC Referral-Qualified", ActivityState.Accepted)] [TestCase("LIC Referral- Not Qualified", ActivityState.Rejected)] public async Task Decision_LIC_Referrals(String stationName, ActivityState expectedState) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Referral, Product = Product.LIC, Accepted = DateTime.Today, Detail = new ActivityDetail() { StationName = stationName } }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(expectedState, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase(Product.GAPInsurance)] [TestCase(Product.MechanicalBreakdownProtection)] [TestCase(Product.DebtProtectionEligibleLoan)] [TestCase(Product.Vehicle)] [TestCase(Product.CreditCard)] public void Decision_Referrals_Throws(Product product) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Referral, Product = product, Accepted = DateTime.Today }; Assert.ThrowsAsync(async () => await _activityDecisionService.TryDecisionActivity(activity)); } [TestCase(Product.ATMCard, "ACT", ActivityState.Accepted)] [TestCase(Product.CheckCard, "ACT", ActivityState.Accepted)] [TestCase(Product.ATMCard, "APPR", ActivityState.Accepted)] [TestCase(Product.CheckCard, "APPR", ActivityState.Accepted)] [TestCase(Product.ATMCard, "ORIG", ActivityState.Accepted)] [TestCase(Product.CheckCard, "ORIG", ActivityState.Accepted)] [TestCase(Product.ATMCard, "CLS", ActivityState.Accepted)] [TestCase(Product.CheckCard, "CLS", ActivityState.Accepted)] public async Task Decision_Cards(Product product, string status, ActivityState state) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Other, Detail = new ActivityDetail() { AccountStatus = status }, Product = product, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase("ACT", ActivityState.Accepted)] [TestCase("APPR", ActivityState.ManualReview)] [TestCase("ORIG", ActivityState.ManualReview)] [TestCase("CLS", ActivityState.Rejected)] [TestCase(null, ActivityState.Rejected)] public async Task Decision_NewChecking(string status, ActivityState state) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, Detail = new ActivityDetail() { AccountStatus = status }, Product = Product.NewChecking, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase("ACT", ActivityState.Accepted)] [TestCase("APPR", ActivityState.ManualReview)] [TestCase("ORIG", ActivityState.ManualReview)] [TestCase("CLS", ActivityState.Rejected)] [TestCase(null, ActivityState.Rejected)] public async Task Decision_NewDigitalBankingChecking(string status, ActivityState state) { var activity = new Activity() { DepartmentId = 43, EmployeeId = "DigitalBankingAppUserEmployeeId", Type = ActivityType.Sale, Detail = new ActivityDetail() { AccountStatus = status }, Product = Product.NewChecking, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase("ACT", ActivityState.Accepted)] [TestCase("APPR", ActivityState.ManualReview)] [TestCase("CLS", ActivityState.Rejected)] [TestCase("ORIG", ActivityState.ManualReview)] [TestCase(null, ActivityState.Rejected)] public async Task Decision_Vehicle(string status, ActivityState state) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, Detail = new ActivityDetail() { AccountStatus = status }, Product = Product.Vehicle, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [TestCase("ACT", ActivityState.Accepted)] [TestCase("APPR", ActivityState.ManualReview)] [TestCase("CLS", ActivityState.Rejected)] [TestCase("ORIG", ActivityState.ManualReview)] [TestCase(null, ActivityState.Rejected)] public async Task Decision_DPEligibleLoan(string status, ActivityState state) { var activity = new Activity() { DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, Detail = new ActivityDetail() { AccountStatus = status }, Product = Product.DebtProtectionEligibleLoan, Accepted = DateTime.Today }; var decision = await _activityDecisionService.TryDecisionActivity(activity); Assert.NotNull(activity); Assert.AreEqual(state, decision.State); Assert.AreEqual(activity.Id, decision.ActivityId); } [Test] public async Task UpdateAndDecideDirectDepositPendingReferralActivities_OK() { var activity = new Activity { Id = 123, DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Referral, Detail = new ActivityDetail { AccountNumber = "12345" }, Created = DateTime.Parse("2021/11/23 10:00:00"), Product = Product.DebtProtectionEligibleLoan, Accepted = DateTime.Today }; var pagedResult = new PagedResult { Items = new[] { activity } }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.PendingReferral) && x.Product.Contains(Product.DirectDeposit)))) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_dnaService).Setup(x => x.GetTransactionHistory(It.Is(x => x.Equals("12345")), It.Is(x => x.Equals(DateTime.Parse("2021/11/23 10:00:00"))), It.IsAny(), It.Is>(x => x.Contains("XDEP")))) .ReturnsAsync(new List { new TransactionHistory { Id = "1" } }).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDirectDepositPendingReferralActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService).Verify(); Assert.NotNull(decision); var firstDecision = decision.First(); Assert.AreEqual(ActivityState.Accepted, firstDecision.State); Assert.AreEqual(123, firstDecision.ActivityId); } [Test] public async Task UpdateAndDecideDirectDepositPendingReferralActivities_NullReturned_RejectActivity() { var activity = new Activity { Id = 123, DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Referral, Detail = new ActivityDetail { AccountNumber = "12345" }, Created = DateTime.Parse("2021/11/23 10:00:00"), Product = Product.DebtProtectionEligibleLoan, Accepted = DateTime.Today }; var pagedResult = new PagedResult { Items = new[] { activity } }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.PendingReferral) && x.Product.Contains(Product.DirectDeposit)))) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_dnaService).Setup(x => x.GetTransactionHistory(It.Is(x => x.Equals("12345")), It.Is(x => x.Equals(DateTime.Parse("2021/11/23 10:00:00"))), It.IsAny(), It.Is>(x => x.Contains("XDEP")))) .ReturnsAsync((List)null).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDirectDepositPendingReferralActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService).Verify(); Assert.NotNull(decision); var firstDecision = decision.First(); Assert.AreEqual(ActivityState.Rejected, firstDecision.State); Assert.AreEqual(123, firstDecision.ActivityId); } [Test] public async Task UpdateAndDecideDirectDepositPendingReferralActivities_None_NoActivitiesReturned() { var pagedResult = new PagedResult(); Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.PendingReferral) && x.Product.Contains(Product.DirectDeposit)))) .ReturnsAsync(pagedResult).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDirectDepositPendingReferralActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService).Verify(x => x.GetTransactionHistory(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Never); Assert.IsEmpty(decision); } [Test] public async Task UpdateAndDecideDirectDepositPendingReferralActivities_Empty_NoActivitiesReturned() { var pagedResult = new PagedResult { Items = new Activity[] { } }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.PendingReferral) && x.Product.Contains(Product.DirectDeposit)))) .ReturnsAsync(pagedResult).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDirectDepositPendingReferralActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService).Verify(x => x.GetTransactionHistory(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Never); Assert.IsEmpty(decision); } [Test] public async Task UpdateAndDecideDpEligibleLoanActivities_NoPagedResults_Ok() { var activity = new Activity { Id = 123, DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, MatchingDpAccessoryActivityId = 0, Detail = new ActivityDetail { AccountNumber = "12345", DebtProtectionAddDate = DateTime.UtcNow, IsDebtProtectionEligible = true, IsGapInsuranceEligible = true }, Created = DateTime.Parse("2021/11/23 10:00:00"), Product = Product.Vehicle, Accepted = DateTime.Today }; var pagedResult = new PagedResult { Items = null, Total = 0 }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.Accepted) && x.Product.Contains(Product.Vehicle)))) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateActivityAccountDetails(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateDpEligibleLoanDetail(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDpEligibleLoanActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService) .Verify(x => x.GetTransactionHistory(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Never); Assert.IsEmpty(decision); } [Test] public async Task UpdateAndDecideDpEligibleLoanActivities_GapInsuranceWasEligible_DebtProtectionAdded() { var activity = new Activity { Id = 123, DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, MatchingDpAccessoryActivityId = 0, Detail = new ActivityDetail { AccountNumber = "12345", DebtProtectionAddDate = DateTime.UtcNow, IsDebtProtectionEligible = true, IsGapInsuranceEligible = true }, Created = DateTime.Parse("2021/11/23 10:00:00"), Product = Product.Vehicle, Accepted = DateTime.Today }; var pagedResult = new PagedResult { Items = new[] { activity }, Total = 1 }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.Accepted) && x.Product.Contains(Product.Vehicle)))) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateActivityAccountDetails(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateDpEligibleLoanDetail(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDpEligibleLoanActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService) .Verify(x => x.GetTransactionHistory(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Never); Assert.NotNull(decision); } [Test] public async Task UpdateAndDecideDpEligibleLoanActivities_GapInsuranceWasNotEligible_DebtProtectionAdded() { var activity = new Activity { Id = 123, DepartmentId = 56, EmployeeId = "11771", Type = ActivityType.Sale, MatchingDpAccessoryActivityId = 0, Detail = new ActivityDetail { AccountNumber = "12345", DebtProtectionAddDate = DateTime.UtcNow, IsDebtProtectionEligible = true, IsGapInsuranceEligible = false }, Created = DateTime.Parse("2021/11/23 10:00:00"), Product = Product.Vehicle, Accepted = DateTime.Today }; var pagedResult = new PagedResult { Items = new[] { activity }, Total = 1 }; Mock.Get(_activityService).Setup(x => x.ListByFilterAsync(It.Is(x => x.Limit.Equals(1000) && x.State.Contains(ActivityState.Accepted) && x.Product.Contains(Product.Vehicle)))) .ReturnsAsync(pagedResult).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateActivityAccountDetails(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); Mock.Get(_activityDetailService).Setup(x => x.TryUpdateDpEligibleLoanDetail(It.IsAny>())) .ReturnsAsync(new List() { activity }).Verifiable(); var decision = await _activityDecisionService.UpdateAndDecideDpEligibleLoanActivities(); Mock.Get(_activityService).Verify(); Mock.Get(_dnaService).Verify(x => x.GetTransactionHistory(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()), Times.Never); Assert.NotNull(decision); } } }