public void Maps_Required_Fields_From_Identified_Learner() { var requiredPayment = new CalculatedRequiredLevyAmount(); mapper.Map(identifiedLearningAim, requiredPayment); requiredPayment.ShouldBeMappedTo(identifiedLearningAim); }
public async Task ShouldRemovePreviousSuccessfulProviderJobSubmission() { var keys = new List <string> { "1", "2" }; var successfulUkprn = 23456; var requiredPaymentEvent1 = new CalculatedRequiredLevyAmount { EventId = Guid.NewGuid(), AmountDue = 100, SfaContributionPercentage = 11, OnProgrammeEarningType = OnProgrammeEarningType.Completion, Learner = new Learner(), CollectionPeriod = new CollectionPeriod { AcademicYear = 1920, Period = 1 }, Ukprn = successfulUkprn, AccountId = 1, JobId = 1, IlrSubmissionDateTime = DateTime.Now.AddMinutes(-1) }; var requiredPaymentEvent2 = new CalculatedRequiredLevyAmount { EventId = Guid.NewGuid(), AmountDue = 100, SfaContributionPercentage = 11, OnProgrammeEarningType = OnProgrammeEarningType.Completion, Learner = new Learner(), CollectionPeriod = new CollectionPeriod { AcademicYear = 1920, Period = 1 }, Ukprn = successfulUkprn, AccountId = 1, JobId = 2, IlrSubmissionDateTime = DateTime.Now }; generateSortedPaymentKeysMock .Setup(x => x.GeyKeys()) .ReturnsAsync(keys) .Verifiable(); eventCacheMock.Setup(c => c.TryGet("1", CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <CalculatedRequiredLevyAmount>(true, requiredPaymentEvent1)) .Verifiable(); eventCacheMock.Setup(c => c.TryGet("2", CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <CalculatedRequiredLevyAmount>(true, requiredPaymentEvent2)) .Verifiable(); eventCacheMock.Setup(c => c.Clear("1", CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); // act await service.RemovePreviousSubmissions(requiredPaymentEvent2.JobId, requiredPaymentEvent2.CollectionPeriod.Period, requiredPaymentEvent2.CollectionPeriod.AcademicYear, requiredPaymentEvent2.IlrSubmissionDateTime, requiredPaymentEvent2.Ukprn); // assert }
public async Task TestStoresRefundPayments() { // arrange long expectedUln = 100; long expectedUkprn = 100; var requiredPaymentEvent = new CalculatedRequiredLevyAmount { Ukprn = expectedUkprn, EventId = Guid.NewGuid(), Priority = 1, Learner = new Learner { Uln = expectedUln }, AccountId = 1, AmountDue = -500 }; eventCacheMock.Setup(c => c.AddOrReplace(requiredPaymentEvent.EventId.ToString(), requiredPaymentEvent, CancellationToken.None)).Returns(Task.CompletedTask) .Verifiable(); refundSortKeysCacheMock .Setup(c => c.TryGet(CacheKeys.RefundPaymentsKeyListKey, CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <List <string> >(false, null)).Verifiable(); refundSortKeysCacheMock .Setup(c => c.AddOrReplace(CacheKeys.RefundPaymentsKeyListKey, It.Is <List <string> >(list => list.Count == 1), CancellationToken.None)) .Returns(Task.CompletedTask).Verifiable(); // act await service.AddRequiredPayment(requiredPaymentEvent); // assert in teardown }
public void TestEarningPeriodMap() { var earningPeriod = new EarningPeriod { ApprenticeshipId = 101, ApprenticeshipPriceEpisodeId = 102, Period = 1, AccountId = 103, Priority = 104, SfaContributionPercentage = 1m, PriceEpisodeIdentifier = "123-01", Amount = 1000000, AgreedOnDate = DateTime.Today }; var requiredPayment = new CalculatedRequiredLevyAmount { SfaContributionPercentage = .9m, OnProgrammeEarningType = OnProgrammeEarningType.Balancing }; // act mapper.Map(earningPeriod, requiredPayment); var act1RequiredPayment = requiredPayment; Assert.AreEqual(earningPeriod.Period, act1RequiredPayment.DeliveryPeriod); Assert.AreEqual(earningPeriod.ApprenticeshipId, act1RequiredPayment.ApprenticeshipId); Assert.AreEqual(earningPeriod.ApprenticeshipPriceEpisodeId, act1RequiredPayment.ApprenticeshipPriceEpisodeId); Assert.AreEqual(earningPeriod.AgreedOnDate, act1RequiredPayment.AgreedOnDate); Assert.AreEqual(earningPeriod.Priority, act1RequiredPayment.Priority); Assert.AreEqual(earningPeriod.SfaContributionPercentage, act1RequiredPayment.SfaContributionPercentage); Assert.AreEqual(OnProgrammeEarningType.Balancing, act1RequiredPayment.OnProgrammeEarningType); }
public async Task ShouldSetMonthEndPaymentsProcessedFlag() { // arrange var keys = new List <string> { "1" }; var requiredPaymentEvent = new CalculatedRequiredLevyAmount { EventId = Guid.NewGuid(), AmountDue = 100, SfaContributionPercentage = 11, OnProgrammeEarningType = OnProgrammeEarningType.Completion, Learner = new Learner(), }; var balance = 100m; var transferAllowance = 50; var levyPayment = new LevyPayment { AmountDue = 55, Type = FundingSourceType.Levy }; var employerCoInvestedPayment = new EmployerCoInvestedPayment { AmountDue = 44, Type = FundingSourceType.CoInvestedEmployer }; var sfaCoInvestedPayment = new SfaCoInvestedPayment { AmountDue = 33, Type = FundingSourceType.CoInvestedSfa }; var allPayments = new FundingSourcePayment[] { levyPayment, employerCoInvestedPayment, sfaCoInvestedPayment }; generateSortedPaymentKeysMock .Setup(x => x.GeyKeys()) .ReturnsAsync(keys) .Verifiable(); eventCacheMock.Setup(c => c.TryGet("1", CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <CalculatedRequiredLevyAmount>(true, requiredPaymentEvent)) .Verifiable(); levyAccountRepositoryMock.Setup(r => r.GetLevyAccount(666, CancellationToken.None)) .ReturnsAsync(() => new LevyAccountModel { Balance = balance, TransferAllowance = transferAllowance }) .Verifiable(); levyBalanceServiceMock.Setup(s => s.Initialise(balance, transferAllowance)).Verifiable(); processorMock.Setup(p => p.Process(It.IsAny <RequiredPayment>())).Returns(() => allPayments).Verifiable(); eventCacheMock.Setup(c => c.Clear(It.IsAny <string>(), It.IsAny <CancellationToken>())).Returns(Task.CompletedTask); refundSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RefundPaymentsKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); transferPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.SenderTransferKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); requiredPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RequiredPaymentKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); // act await service.HandleMonthEnd(666, 1); // assert monthEndCacheMock.Verify(x => x.AddOrReplace(It.Is <string>(key => key.Equals(CacheKeys.MonthEndCacheKey)), It.Is <bool>(value => value), It.IsAny <CancellationToken>())); }
public void Maps_Required_Fields_From_Historic_Payment() { var requiredPayment = new CalculatedRequiredLevyAmount(); mapper.Map(historicPayment, requiredPayment); requiredPayment.ShouldBeMappedTo(historicPayment); }
public static long CalculateFundingAccountId(this CalculatedRequiredLevyAmount levyTransaction, bool isReceiverTransferPayment) { if (isReceiverTransferPayment) { return(levyTransaction.AccountId.GetValueOrDefault()); } return(levyTransaction.IsTransfer() ? levyTransaction.TransferSenderAccountId.GetValueOrDefault() : levyTransaction.AccountId.GetValueOrDefault()); }
public static bool IsTransfer(this CalculatedRequiredLevyAmount message) { if (!message.AccountId.HasValue) { throw new InvalidOperationException($"The account id of the levy message is invalid."); } return(message.TransferSenderAccountId.HasValue && message.TransferSenderAccountId != 0 && message.AccountId != message.TransferSenderAccountId); }
public long GetDestinationAccountId(CalculatedRequiredLevyAmount message) { if (!message.AccountId.HasValue) { throw new InvalidOperationException($"The account id of the levy message is invalid."); } return(message.IsTransfer() ? message.TransferSenderAccountId.Value : message.AccountId.Value); }
public void MapperDoesNotChangeEventId() { var payment = new ApprenticeshipContractType1EarningEvent(); var requiredPayment = new CalculatedRequiredLevyAmount(); var expected = requiredPayment.EventId; mapper.Map(payment, requiredPayment); requiredPayment.EventId.Should().Be(expected); }
private async Task AddRefundPaymentToCache(CalculatedRequiredLevyAmount paymentEvent) { var keysValue = await refundSortKeysCache.TryGet(CacheKeys.RefundPaymentsKeyListKey).ConfigureAwait(false); var refundKeysList = keysValue.HasValue ? keysValue.Value : new List <string>(); refundKeysList.Add(paymentEvent.EventId.ToString()); await requiredPaymentsCache.AddOrReplace(paymentEvent.EventId.ToString(), paymentEvent).ConfigureAwait(false); await refundSortKeysCache.AddOrReplace(CacheKeys.RefundPaymentsKeyListKey, refundKeysList).ConfigureAwait(false); }
public PeriodisedRequiredPaymentEvent Create(EarningType earningType, int transactionType) { PeriodisedRequiredPaymentEvent paymentEvent = null; switch (earningType) { case EarningType.CoInvested: if (IsValidPaymentType <OnProgrammeEarningType>(transactionType)) { paymentEvent = new CalculatedRequiredCoInvestedAmount { OnProgrammeEarningType = (OnProgrammeEarningType)transactionType, }; } break; case EarningType.Incentive: if (IsValidPaymentType <IncentivePaymentType>(transactionType)) { paymentEvent = new CalculatedRequiredIncentiveAmount { Type = (IncentivePaymentType)transactionType, }; } break; case EarningType.Levy: if (IsValidPaymentType <OnProgrammeEarningType>(transactionType)) { paymentEvent = new CalculatedRequiredLevyAmount { OnProgrammeEarningType = (OnProgrammeEarningType)transactionType, }; } break; default: throw new InvalidOperationException( $"Unknown earning type found: {earningType:G}. Cannot create the PeriodisedRequiredPaymentEvent."); } if (paymentEvent == null) { logger.LogError( $"Invalid EarningType and TransactionType combination: EarningType: {earningType:G}, TransactionType: {transactionType}"); } return(paymentEvent); }
public void Process_BuildsFundingSourceEvents_Correctly() { var amount = new CalculatedRequiredLevyAmount { AccountId = eventEmployerAccountId, AmountDue = amountDue, AgreementId = "Agreement Two", SfaContributionPercentage = sfaContributionPercentage, TransferSenderAccountId = transferSenderEmployerAccountId }; fundingSourcePayments = new List <FundingSourcePayment> { new EmployerCoInvestedPayment { AmountDue = 540, Type = FundingSourceType.CoInvestedSfa }, new LevyPayment { AmountDue = 700, Type = FundingSourceType.Levy }, new TransferPayment { AmountDue = 900, Type = FundingSourceType.Transfer } }; processor.Setup(x => x.Process(It.IsAny <RequiredPayment>())) .Returns(fundingSourcePayments); mapper.Setup(x => x.Map <FundingSourcePaymentEvent>(It.IsAny <EmployerCoInvestedPayment>())).Returns(new EmployerCoInvestedFundingSourcePaymentEvent()); mapper.Setup(x => x.Map <FundingSourcePaymentEvent>(It.IsAny <LevyPayment>())).Returns(new LevyFundingSourcePaymentEvent()); mapper.Setup(x => x.Map <FundingSourcePaymentEvent>(It.IsAny <TransferPayment>())).Returns(new TransferFundingSourcePaymentEvent()); var results = service.BuildFundingSourcePaymentsForRequiredPayment(amount, transferSenderEmployerAccountId, jobId); processor.Verify(x => x.Process(It.Is <RequiredPayment>(rp => rp.SfaContributionPercentage == sfaContributionPercentage && rp.AmountDue == amountDue && rp.IsTransfer )), Times.Once); mapper.VerifyAll(); mapper.Verify(x => x.Map(It.IsAny <CalculatedRequiredLevyAmount>(), It.IsAny <FundingSourcePaymentEvent>()), Times.Exactly(3)); results.Count.Should().Be(3); results.Should().Contain(x => x.GetType() == typeof(LevyFundingSourcePaymentEvent)); results.Should().Contain(x => x.GetType() == typeof(EmployerCoInvestedFundingSourcePaymentEvent)); results.Should().Contain(x => x.GetType() == typeof(TransferFundingSourcePaymentEvent)); results.ForEach(x => x.JobId.Should().Be(jobId)); }
private static void AssertCalculatedRequiredLevyAmountEvent(CalculatedRequiredLevyAmount listOfCalculatedRequiredLevyAmounts, PaymentModel historicalPayment, IdentifiedRemovedLearningAim message) { listOfCalculatedRequiredLevyAmounts.AgreementId.Should().Be(historicalPayment.AgreementId); listOfCalculatedRequiredLevyAmounts.AgreedOnDate.Should().Be(null); listOfCalculatedRequiredLevyAmounts.AccountId.Should().Be(historicalPayment.AccountId); listOfCalculatedRequiredLevyAmounts.ActualEndDate.Should().Be(historicalPayment.ActualEndDate); listOfCalculatedRequiredLevyAmounts.AmountDue.Should().Be(-100); listOfCalculatedRequiredLevyAmounts.ApprenticeshipEmployerType.Should().Be(historicalPayment.ApprenticeshipEmployerType); listOfCalculatedRequiredLevyAmounts.ApprenticeshipId.Should().Be(historicalPayment.ApprenticeshipId); listOfCalculatedRequiredLevyAmounts.ApprenticeshipPriceEpisodeId.Should().Be(historicalPayment.ApprenticeshipPriceEpisodeId); listOfCalculatedRequiredLevyAmounts.CollectionPeriod.Period.Should().Be(message.CollectionPeriod.Period); listOfCalculatedRequiredLevyAmounts.CollectionPeriod.AcademicYear.Should().Be(message.CollectionPeriod.AcademicYear); listOfCalculatedRequiredLevyAmounts.CompletionAmount.Should().Be(historicalPayment.CompletionAmount); listOfCalculatedRequiredLevyAmounts.CompletionStatus.Should().Be(historicalPayment.CompletionStatus); listOfCalculatedRequiredLevyAmounts.ContractType.Should().Be(historicalPayment.ContractType); listOfCalculatedRequiredLevyAmounts.DeliveryPeriod.Should().Be(historicalPayment.DeliveryPeriod); listOfCalculatedRequiredLevyAmounts.EarningEventId.Should().Be(Guid.Empty); listOfCalculatedRequiredLevyAmounts.EventTime.Should().BeCloseTo(DateTimeOffset.UtcNow, 100); listOfCalculatedRequiredLevyAmounts.IlrFileName.Should().Be(null); listOfCalculatedRequiredLevyAmounts.IlrSubmissionDateTime.Should().Be(message.IlrSubmissionDateTime); listOfCalculatedRequiredLevyAmounts.InstalmentAmount.Should().Be(historicalPayment.InstalmentAmount); listOfCalculatedRequiredLevyAmounts.JobId.Should().Be(message.JobId); listOfCalculatedRequiredLevyAmounts.Learner.ReferenceNumber.Should().Be(historicalPayment.LearnerReferenceNumber); listOfCalculatedRequiredLevyAmounts.Learner.Uln.Should().Be(historicalPayment.LearnerUln); listOfCalculatedRequiredLevyAmounts.LearningAim.FrameworkCode.Should().Be(historicalPayment.LearningAimFrameworkCode); listOfCalculatedRequiredLevyAmounts.LearningAim.FundingLineType.Should().Be(historicalPayment.LearningAimFundingLineType); listOfCalculatedRequiredLevyAmounts.LearningAim.PathwayCode.Should().Be(historicalPayment.LearningAimPathwayCode); listOfCalculatedRequiredLevyAmounts.LearningAim.ProgrammeType.Should().Be(historicalPayment.LearningAimProgrammeType); listOfCalculatedRequiredLevyAmounts.LearningAim.Reference.Should().Be(historicalPayment.LearningAimReference); listOfCalculatedRequiredLevyAmounts.LearningAim.SequenceNumber.Should().Be(0); listOfCalculatedRequiredLevyAmounts.LearningAim.StandardCode.Should().Be(historicalPayment.LearningAimStandardCode); listOfCalculatedRequiredLevyAmounts.LearningAim.StartDate.Should().Be(historicalPayment.StartDate); listOfCalculatedRequiredLevyAmounts.LearningStartDate.Should().Be(historicalPayment.LearningStartDate); listOfCalculatedRequiredLevyAmounts.NumberOfInstalments.Should().Be(historicalPayment.NumberOfInstalments); listOfCalculatedRequiredLevyAmounts.OnProgrammeEarningType.Should().Be((OnProgrammeEarningType)historicalPayment.TransactionType); listOfCalculatedRequiredLevyAmounts.PlannedEndDate.Should().Be(historicalPayment.PlannedEndDate); listOfCalculatedRequiredLevyAmounts.PriceEpisodeIdentifier.Should().Be(historicalPayment.PriceEpisodeIdentifier); listOfCalculatedRequiredLevyAmounts.Priority.Should().Be(0); listOfCalculatedRequiredLevyAmounts.ReportingAimFundingLineType.Should().Be(historicalPayment.ReportingAimFundingLineType); listOfCalculatedRequiredLevyAmounts.SfaContributionPercentage.Should().Be(historicalPayment.SfaContributionPercentage); listOfCalculatedRequiredLevyAmounts.StartDate.Should().Be(historicalPayment.StartDate); listOfCalculatedRequiredLevyAmounts.TransactionType.Should().Be(historicalPayment.TransactionType); listOfCalculatedRequiredLevyAmounts.TransferSenderAccountId.Should().Be(historicalPayment.TransferSenderAccountId); listOfCalculatedRequiredLevyAmounts.Ukprn.Should().Be(historicalPayment.Ukprn); }
public async Task AddRequiredPayment(CalculatedRequiredLevyAmount paymentEvent) { if (paymentEvent.AmountDue < 0) { await AddRefundPaymentToCache(paymentEvent); return; } if (paymentEvent.IsTransfer()) { await AddTransferPaymentToCache(paymentEvent); return; } await AddRequiredPaymentToCache(paymentEvent); }
private async Task AddRequiredPaymentToCache(CalculatedRequiredLevyAmount paymentEvent) { var keysValue = await requiredPaymentSortKeysCache.TryGet(CacheKeys.RequiredPaymentKeyListKey).ConfigureAwait(false); var requiredPaymentKeysList = keysValue.HasValue ? keysValue.Value : new List <RequiredPaymentSortKeyModel>(); var newRequiredPaymentSortKey = new RequiredPaymentSortKeyModel { Id = paymentEvent.EventId.ToString(), Uln = paymentEvent.Learner.Uln, Ukprn = paymentEvent.Ukprn, AgreedOnDate = paymentEvent.AgreedOnDate ?? DateTime.MinValue }; requiredPaymentKeysList.Add(newRequiredPaymentSortKey); await requiredPaymentsCache.AddOrReplace(newRequiredPaymentSortKey.Id, paymentEvent).ConfigureAwait(false); await requiredPaymentSortKeysCache.AddOrReplace(CacheKeys.RequiredPaymentKeyListKey, requiredPaymentKeysList).ConfigureAwait(false); }
public async Task HandleRequiredPayment(CalculatedRequiredLevyAmount message) { try { using (var operation = telemetry.StartOperation("LevyFundedService.HandleRequiredPayment", message.EventId.ToString())) { var stopwatch = Stopwatch.StartNew(); paymentLogger.LogVerbose($"Handling RequiredPayment for {Id}, Job: {message.JobId}, UKPRN: {message.Ukprn}, Account: {message.AccountId}"); await fundingSourceService.AddRequiredPayment(message).ConfigureAwait(false); paymentLogger.LogInfo($"Finished handling required payment for {Id}, Job: {message.JobId}, UKPRN: {message.Ukprn}, Account: {message.AccountId}"); telemetry.TrackDuration("LevyFundedService.HandleRequiredPayment", stopwatch, message); telemetry.StopOperation(operation); } } catch (Exception e) { paymentLogger.LogError($"Error handling required levy payment. Error:{e.Message}", e); throw; } }
public async Task TestStoresTransferPayment() { // arrange long expectedUln = 100; var requiredPaymentEvent = new CalculatedRequiredLevyAmount { Ukprn = 100, EventId = Guid.NewGuid(), Priority = 1, Learner = new Learner { Uln = expectedUln }, AccountId = 1, TransferSenderAccountId = 9 }; eventCacheMock.Setup(c => c.AddOrReplace(requiredPaymentEvent.EventId.ToString(), requiredPaymentEvent, CancellationToken.None)) .Returns(Task.CompletedTask) .Verifiable(); transferPaymentSortKeysCacheMock .Setup(c => c.TryGet(CacheKeys.SenderTransferKeyListKey, CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <List <TransferPaymentSortKeyModel> >(false, null)).Verifiable(); transferPaymentSortKeysCacheMock .Setup(c => c.AddOrReplace(CacheKeys.SenderTransferKeyListKey, It.Is <List <TransferPaymentSortKeyModel> >(list => list.Count == 1 && list[0].Uln == expectedUln), CancellationToken.None)) .Returns(Task.CompletedTask).Verifiable(); // act await service.AddRequiredPayment(requiredPaymentEvent); // assert in teardown }
public void Setup() { requiredPaymentEvent = new CalculatedRequiredLevyAmount { AmountDue = 1000.00m, CollectionPeriod = CollectionPeriodFactory.CreateFromAcademicYearAndPeriod(1819, 1), DeliveryPeriod = 1, EventTime = DateTime.UtcNow, JobId = 1, Learner = new Learner { ReferenceNumber = "001", Uln = 1234567890 }, OnProgrammeEarningType = OnProgrammeEarningType.Learning, LearningAim = new LearningAim { FrameworkCode = 403 }, PriceEpisodeIdentifier = "1819-P01", SfaContributionPercentage = 0.9m, Ukprn = 10000, AgreementId = "11", Priority = 13, EventId = Guid.NewGuid(), AccountId = 1000000, IlrSubmissionDateTime = DateTime.Today, EarningEventId = Guid.NewGuid(), ContractType = ContractType.Act1, ApprenticeshipEmployerType = ApprenticeshipEmployerType.Levy, ApprenticeshipId = 12, }; mapperConfiguration = AutoMapperConfigurationFactory.CreateMappingConfig(); autoMapper = mapperConfiguration.CreateMapper(); }
public void TestPayableEarningEventMap() { // arrange var payableEarning = CreatePayableEarning(); PeriodisedRequiredPaymentEvent requiredPayment = new CalculatedRequiredLevyAmount { SfaContributionPercentage = .9m, OnProgrammeEarningType = OnProgrammeEarningType.Completion }; // act mapper.Map(payableEarning, requiredPayment); // assert AssertCommonProperties(requiredPayment, payableEarning); var act1RequiredPayment = (CalculatedRequiredLevyAmount)requiredPayment; Assert.AreEqual(payableEarning.AgreementId, act1RequiredPayment.AgreementId); Assert.AreEqual(.9m, act1RequiredPayment.SfaContributionPercentage); Assert.AreEqual(OnProgrammeEarningType.Completion, act1RequiredPayment.OnProgrammeEarningType); Assert.AreEqual(payableEarning.EarningEventId, act1RequiredPayment.EarningEventId); Assert.AreNotEqual(payableEarning.EventId, act1RequiredPayment.EarningEventId); }
public void SetUp() { ukprn = 3383742; accountId = 78934234; message = new ProcessUnableToFundTransferFundingSourcePayment { AccountId = accountId, Ukprn = ukprn }; calculatedRequiredLevyAmount = new CalculatedRequiredLevyAmount { Ukprn = ukprn }; levyAccountModel = new LevyAccountModel { AccountId = accountId, Balance = 3000, TransferAllowance = 2000 }; mappedLevyAccountModel = new LevyAccountModel { AccountId = accountId, Balance = 3000, TransferAllowance = 2000 }; fundingSourcePaymentEvents = new List <FundingSourcePaymentEvent> { new LevyFundingSourcePaymentEvent { AccountId = accountId, Ukprn = ukprn, AmountDue = 1000 } }; paymentLogger = new Mock <IPaymentLogger>(); mapper = new Mock <IMapper>(); monthEndCache = new Mock <IDataCache <bool> >(); levyAccountCache = new Mock <IDataCache <LevyAccountModel> >(); levyBalanceService = new Mock <ILevyBalanceService>(); fundingSourcePaymentEventBuilder = new Mock <IFundingSourcePaymentEventBuilder>(); levyTransactionBatchStorageService = new Mock <ILevyTransactionBatchStorageService>(); mapper.Setup(x => x.Map <CalculatedRequiredLevyAmount>(message)) .Returns(calculatedRequiredLevyAmount); mapper.Setup(x => x.Map <LevyAccountModel>(levyAccountModel)) .Returns(mappedLevyAccountModel); levyAccountCache.Setup(x => x.TryGet(CacheKeys.LevyBalanceKey, It.IsAny <CancellationToken>())) .ReturnsAsync(new ConditionalValue <LevyAccountModel>(true, levyAccountModel)); fundingSourcePaymentEventBuilder.Setup(x => x.BuildFundingSourcePaymentsForRequiredPayment( It.IsAny <CalculatedRequiredLevyAmount>(), accountId, It.IsAny <long>())) .Returns(fundingSourcePaymentEvents); service = new TransferFundingSourceEventGenerationService( paymentLogger.Object, mapper.Object, monthEndCache.Object, levyAccountCache.Object, levyBalanceService.Object, fundingSourcePaymentEventBuilder.Object, levyTransactionBatchStorageService.Object ); }
public async Task ProcessesUnableToFundTransferPayments() { // arrange var keys = new List <string> { "1" }; var requiredPaymentEvent = new CalculatedRequiredLevyAmount { EventId = Guid.NewGuid(), AmountDue = 100, SfaContributionPercentage = 11, OnProgrammeEarningType = OnProgrammeEarningType.Completion, Learner = new Learner(), AccountId = 666, TransferSenderAccountId = 2 }; var balance = 100m; var transferAllowance = 50; var transferPayment = new TransferPayment { AmountDue = 55, Type = FundingSourceType.Transfer }; var unableToFundTransferPayment = new UnableToFundTransferPayment { AmountDue = 44, Type = FundingSourceType.Transfer }; var allPayments = new FundingSourcePayment[] { transferPayment, unableToFundTransferPayment }; generateSortedPaymentKeysMock .Setup(x => x.GeyKeys()) .ReturnsAsync(keys) .Verifiable(); eventCacheMock.Setup(c => c.TryGet("1", CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <CalculatedRequiredLevyAmount>(true, requiredPaymentEvent)) .Verifiable(); levyAccountRepositoryMock.Setup(r => r.GetLevyAccount(666, CancellationToken.None)) .ReturnsAsync(() => new LevyAccountModel { Balance = balance, TransferAllowance = transferAllowance }) .Verifiable(); levyBalanceServiceMock.Setup(s => s.Initialise(balance, transferAllowance)).Verifiable(); processorMock.Setup(p => p.Process(It.IsAny <RequiredPayment>())).Returns(() => allPayments).Verifiable(); eventCacheMock.Setup(c => c.Clear("1", CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); refundSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RefundPaymentsKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); transferPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.SenderTransferKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); requiredPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RequiredPaymentKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); // act var fundingSourcePayments = await service.HandleMonthEnd(666, 1); // assert fundingSourcePayments.Should().HaveCount(2); fundingSourcePayments[0].Should().BeOfType <TransferFundingSourcePaymentEvent>(); fundingSourcePayments[1].Should().BeOfType <ProcessUnableToFundTransferFundingSourcePayment>(); fundingSourcePayments[0].AmountDue.Should().Be(55); fundingSourcePayments[1].AmountDue.Should().Be(44); }
public async Task TestMonthEndPaymentProcessing() { // arrange var keys = new List <string> { "1", "99", "4", "9" }; var expectedKeys = new Queue <string>(new[] { "1", "99", "4", "9" }); var expectedKeys2 = new Queue <string>(new[] { "1", "99", "4", "9" }); var requiredPaymentEvent = new CalculatedRequiredLevyAmount { EventId = Guid.NewGuid(), AmountDue = 100, SfaContributionPercentage = 11, OnProgrammeEarningType = OnProgrammeEarningType.Completion, Priority = 4, Learner = new Learner() }; var value = new ConditionalValue <CalculatedRequiredLevyAmount>(true, requiredPaymentEvent); var requiredPayments = new Queue <ConditionalValue <CalculatedRequiredLevyAmount> >(new[] { value, value, value, value }); var fundingSourcePayment = new LevyPayment { AmountDue = 55, Type = FundingSourceType.CoInvestedEmployer }; var balance = 100m; var transferAllowance = 50; generateSortedPaymentKeysMock .Setup(x => x.GeyKeys()) .ReturnsAsync(keys) .Verifiable(); eventCacheMock.Setup(c => c.TryGet(It.IsAny <string>(), CancellationToken.None)) .ReturnsAsync(requiredPayments.Dequeue()) .Callback <string, CancellationToken>((k, c) => Assert.AreEqual(expectedKeys.Dequeue(), k)) .Verifiable(); levyAccountRepositoryMock.Setup(r => r.GetLevyAccount(666, CancellationToken.None)) .ReturnsAsync(() => new LevyAccountModel { AccountId = 666, Balance = balance, TransferAllowance = transferAllowance }) .Verifiable(); levyBalanceServiceMock.Setup(s => s.Initialise(balance, transferAllowance)).Verifiable(); processorMock.Setup(p => p.Process(It.IsAny <RequiredPayment>())) .Returns(() => new[] { fundingSourcePayment }) .Verifiable(); eventCacheMock.Setup(c => c.Clear(It.IsAny <string>(), CancellationToken.None)) .Returns(Task.CompletedTask) .Callback <string, CancellationToken>((k, c) => Assert.AreEqual(expectedKeys2.Dequeue(), k)) .Verifiable(); refundSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RefundPaymentsKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); transferPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.SenderTransferKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); requiredPaymentSortKeysCacheMock.Setup(c => c.Clear(CacheKeys.RequiredPaymentKeyListKey, CancellationToken.None)).Returns(Task.CompletedTask).Verifiable(); levyAccountCacheMock.Setup(c => c.AddOrReplace(CacheKeys.LevyBalanceKey, It.Is <LevyAccountModel>(model => model.AccountId == 666), It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask) .Verifiable(); // act await service.HandleMonthEnd(666, 1); // assert Assert.AreEqual(0, expectedKeys.Count); Assert.AreEqual(0, expectedKeys2.Count); }
public async Task TestRegisterSubsequentRequiredPayment() { // arrange var eventId = Guid.NewGuid(); long expectedUln = 100; long expectedUkprn = 100; var keys = new List <RequiredPaymentSortKeyModel> { new RequiredPaymentSortKeyModel { Ukprn = expectedUkprn, Uln = 1, Id = Guid.NewGuid().ToString(), AgreedOnDate = DateTime.Today }, new RequiredPaymentSortKeyModel { Ukprn = expectedUkprn, Uln = 2, Id = Guid.NewGuid().ToString(), AgreedOnDate = DateTime.Today } }; var requiredPaymentEvent = new CalculatedRequiredLevyAmount { Ukprn = expectedUkprn, StartDate = DateTime.Today, EventId = eventId, Priority = 4, Learner = new Learner { Uln = expectedUln }, AccountId = 1, }; eventCacheMock.Setup(c => c.AddOrReplace(requiredPaymentEvent.EventId.ToString(), requiredPaymentEvent, CancellationToken.None)) .Returns(Task.CompletedTask) .Verifiable(); requiredPaymentSortKeysCacheMock .Setup(c => c.TryGet(CacheKeys.RequiredPaymentKeyListKey, CancellationToken.None)) .ReturnsAsync(() => new ConditionalValue <List <RequiredPaymentSortKeyModel> >(true, keys)) .Verifiable(); requiredPaymentSortKeysCacheMock .Setup(c => c.AddOrReplace(CacheKeys.RequiredPaymentKeyListKey, It.Is <List <RequiredPaymentSortKeyModel> >(list => list.Count == 3 && list[2].Uln == expectedUln && list[2].Ukprn == expectedUkprn), CancellationToken.None)) .Returns(Task.CompletedTask) .Verifiable(); // act await service.AddRequiredPayment(requiredPaymentEvent); // assert }
public List <FundingSourcePaymentEvent> BuildFundingSourcePaymentsForRequiredPayment(CalculatedRequiredLevyAmount requiredPaymentEvent, long employerAccountId, long jobId) { var fundingSourceEvents = new List <FundingSourcePaymentEvent>(); var requiredPayment = new RequiredPayment { SfaContributionPercentage = requiredPaymentEvent.SfaContributionPercentage, AmountDue = requiredPaymentEvent.AmountDue, IsTransfer = employerAccountId != requiredPaymentEvent.AccountId && requiredPaymentEvent.TransferSenderAccountId.HasValue && requiredPaymentEvent.TransferSenderAccountId == employerAccountId }; var fundingSourcePayments = processor.Process(requiredPayment); foreach (var fundingSourcePayment in fundingSourcePayments) { var fundingSourceEvent = mapper.Map <FundingSourcePaymentEvent>(fundingSourcePayment); mapper.Map(requiredPaymentEvent, fundingSourceEvent); fundingSourceEvent.JobId = jobId; fundingSourceEvents.Add(fundingSourceEvent); } return(fundingSourceEvents); }
public void Setup() { var requiredPaymentEventEventId = Guid.NewGuid(); var earningEventId = Guid.NewGuid(); var utcNow = DateTime.UtcNow; unableToFundTransferFundingSourcePayment = new ProcessUnableToFundTransferFundingSourcePayment { EventId = requiredPaymentEventEventId, EarningEventId = earningEventId, EventTime = utcNow, RequiredPaymentEventId = requiredPaymentEventEventId, AmountDue = 1000.00m, CollectionPeriod = CollectionPeriodFactory.CreateFromAcademicYearAndPeriod(1819, 1), DeliveryPeriod = 1, JobId = 1, Learner = new Learner { ReferenceNumber = "001", Uln = 1234567890 }, LearningAim = new LearningAim { FrameworkCode = 403 }, PriceEpisodeIdentifier = "1819-P01", SfaContributionPercentage = 0.9m, Ukprn = 10000, AccountId = 1000000, IlrSubmissionDateTime = DateTime.Today, ContractType = ContractType.Act1, ApprenticeshipEmployerType = ApprenticeshipEmployerType.Levy, ApprenticeshipId = 12, CompletionAmount = 10, CompletionStatus = 1, InstalmentAmount = 10, StartDate = utcNow, TransactionType = TransactionType.Balancing, ActualEndDate = utcNow, FundingSourceType = FundingSourceType.Levy, IlrFileName = "Test", LearningStartDate = utcNow, NumberOfInstalments = 1, PlannedEndDate = utcNow, ApprenticeshipPriceEpisodeId = 1, TransferSenderAccountId = 10, ReportingAimFundingLineType = "Test" }; expectedEvent = new CalculatedRequiredLevyAmount { EventId = requiredPaymentEventEventId, EarningEventId = earningEventId, EventTime = utcNow, AmountDue = 1000.00m, CollectionPeriod = CollectionPeriodFactory.CreateFromAcademicYearAndPeriod(1819, 1), DeliveryPeriod = 1, JobId = 1, Learner = new Learner { ReferenceNumber = "001", Uln = 1234567890 }, LearningAim = new LearningAim { FrameworkCode = 403 }, PriceEpisodeIdentifier = "1819-P01", SfaContributionPercentage = 0.9m, Ukprn = 10000, AccountId = 1000000, IlrSubmissionDateTime = DateTime.Today, ContractType = ContractType.Act1, ApprenticeshipEmployerType = ApprenticeshipEmployerType.Levy, ApprenticeshipId = 12, CompletionAmount = 10, CompletionStatus = 1, InstalmentAmount = 10, StartDate = utcNow, ActualEndDate = utcNow, IlrFileName = "Test", LearningStartDate = utcNow, NumberOfInstalments = 1, PlannedEndDate = utcNow, ApprenticeshipPriceEpisodeId = 1, OnProgrammeEarningType = OnProgrammeEarningType.Balancing, TransferSenderAccountId = 10, ReportingAimFundingLineType = "Test" }; mapperConfiguration = AutoMapperConfigurationFactory.CreateMappingConfig(); autoMapper = mapperConfiguration.CreateMapper(); }
private async Task AddRequiredPayment(CalculatedRequiredLevyAmount calculatedRequiredLevyAmount) { await levyTransactionBatchStorageService.StoreLevyTransactions(new List <CalculatedRequiredLevyAmount> { calculatedRequiredLevyAmount }, CancellationToken.None, true); }
public static bool IsRefund(this CalculatedRequiredLevyAmount calculatedRequiredLevyAmount) { return(calculatedRequiredLevyAmount.AmountDue < 0); }