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 TestSfaOnlyProcessorsCalled()
        {
            var requiredPayment = new RequiredPayment();
            var employerCoInvestedPaymentProcessorMock = new Mock <IEmployerCoInvestedPaymentProcessor>(MockBehavior.Strict);
            var sfaCoInvestedPaymentProcessorMock      = new Mock <ISfaCoInvestedPaymentProcessor>(MockBehavior.Strict);

            var payment1 = new EmployerCoInvestedPayment {
                AmountDue = 0
            };
            var payment2 = new SfaCoInvestedPayment {
                AmountDue = 100
            };

            employerCoInvestedPaymentProcessorMock.Setup(p => p.Process(requiredPayment)).Returns(payment1).Verifiable();
            sfaCoInvestedPaymentProcessorMock.Setup(p => p.Process(requiredPayment)).Returns(payment2).Verifiable();

            ICoInvestedPaymentProcessor processor = new CoInvestedPaymentProcessor(employerCoInvestedPaymentProcessorMock.Object, sfaCoInvestedPaymentProcessorMock.Object);
            var actualPayments = processor.Process(requiredPayment);

            actualPayments.Should().HaveCount(1);
            actualPayments[0].Should().BeSameAs(payment2);

            employerCoInvestedPaymentProcessorMock.Verify();
            sfaCoInvestedPaymentProcessorMock.Verify();
        }
        public void TestLevyAndCoInvestedCall()
        {
            // arrange
            var levyPayment = new LevyPayment {
                AmountDue = 45
            };
            var coInvestedPayment = new EmployerCoInvestedPayment {
                AmountDue = 55
            };
            var requiredPayment = new RequiredPayment {
                AmountDue = 100
            };

            levyPaymentProcessorMock.Setup(p => p.Process(requiredPayment)).Returns(new[] { levyPayment }).Verifiable();
            coInvestedPaymentProcessorMock.Setup(p => p.Process(It.Is <RequiredPayment>(rp => rp.AmountDue == 55))).Returns(new[] { coInvestedPayment }).Verifiable();

            // act
            var actualPayments = processor.Process(requiredPayment);

            // assert
            actualPayments.Should().NotBeNull();
            actualPayments.Should().HaveCount(2);
            actualPayments[0].Should().BeSameAs(levyPayment);
            actualPayments[1].Should().BeSameAs(coInvestedPayment);
        }
        public void GetFundedPaymentsShouldCallAllPaymentProcessors()
        {
            // Arrange
            var message = new CalculatedRequiredCoInvestedAmount();
            var requiredCoInvestedPayment = new RequiredCoInvestedPayment();
            var fundingSourcePayment      = new EmployerCoInvestedPayment();

            var sfaPaymentProcessor      = new Mock <ICoInvestedPaymentProcessorOld>(MockBehavior.Strict);
            var employerPaymentProcessor = new Mock <ICoInvestedPaymentProcessorOld>(MockBehavior.Strict);

            var sfaPaymentEvent = new SfaCoInvestedFundingSourcePaymentEvent();

            var mapper = new Mock <ICoInvestedFundingSourcePaymentEventMapper>(MockBehavior.Strict);

            mapper.Setup(o => o.MapToRequiredCoInvestedPayment(message)).Returns(requiredCoInvestedPayment);
            mapper.Setup(o => o.MapToCoInvestedPaymentEvent(message, fundingSourcePayment)).Returns(sfaPaymentEvent);

            sfaPaymentProcessor
            .Setup(o => o.Process(requiredCoInvestedPayment)).Returns(fundingSourcePayment)
            .Verifiable();

            employerPaymentProcessor
            .Setup(o => o.Process(requiredCoInvestedPayment)).Returns(fundingSourcePayment)
            .Verifiable();

            var paymentProcessors = new List <ICoInvestedPaymentProcessorOld>
            {
                sfaPaymentProcessor.Object,
                employerPaymentProcessor.Object
            };

            // Act
            var handler = new CoInvestedFundingSourceService(paymentProcessors, mapper.Object);

            handler.GetFundedPayments(message);

            //Assert
            sfaPaymentProcessor.Verify();
            employerPaymentProcessor.Verify();
        }
        public void ShouldMapToValidEmployerCoInvestedFundingSourcePaymentEvent()
        {
            //Arrange
            var coInvestedPayment = new EmployerCoInvestedPayment
            {
                AmountDue = 100.00m,
                Type      = FundingSourceType.CoInvestedEmployer
            };

            var expectedPayment = new EmployerCoInvestedFundingSourcePaymentEvent
            {
                EventId = Guid.NewGuid(),
                RequiredPaymentEventId = requiredCoInvestedAmount.EventId,
                AmountDue    = 100.00m,
                ContractType = ContractType.Act2,
                SfaContributionPercentage = requiredCoInvestedAmount.SfaContributionPercentage,
                CollectionPeriod          = requiredCoInvestedAmount.CollectionPeriod,
                DeliveryPeriod            = requiredCoInvestedAmount.DeliveryPeriod,
                EventTime                  = requiredCoInvestedAmount.EventTime,
                JobId                      = requiredCoInvestedAmount.JobId,
                Learner                    = requiredCoInvestedAmount.Learner,
                TransactionType            = (TransactionType)requiredCoInvestedAmount.OnProgrammeEarningType,
                LearningAim                = requiredCoInvestedAmount.LearningAim,
                PriceEpisodeIdentifier     = requiredCoInvestedAmount.PriceEpisodeIdentifier,
                Ukprn                      = requiredCoInvestedAmount.Ukprn,
                FundingSourceType          = FundingSourceType.CoInvestedEmployer,
                AccountId                  = 1000000,
                ApprenticeshipEmployerType = requiredCoInvestedAmount.ApprenticeshipEmployerType,
            };



            var actualEmployerCoInvestedPayment = coInvestedFundingMapper.MapToCoInvestedPaymentEvent(requiredCoInvestedAmount, coInvestedPayment);

            expectedPayment.EventId   = actualEmployerCoInvestedPayment.EventId;
            expectedPayment.EventTime = actualEmployerCoInvestedPayment.EventTime;
            actualEmployerCoInvestedPayment.Should().BeEquivalentTo(expectedPayment);
        }
        public async Task ShouldProcessPaymentIfMonthEndProcessed()
        {
            // arrange
            var keys = new List <string> {
                "1"
            };
            var unableToFundEvent = new ProcessUnableToFundTransferFundingSourcePayment
            {
                EventId   = Guid.NewGuid(),
                Learner   = new Learner(),
                AccountId = 666,
                AmountDue = 100
            };

            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 };

            levyBalanceServiceMock.Setup(s => s.Initialise(balance, transferAllowance))
            .Verifiable();

            processorMock.Setup(p => p.Process(It.IsAny <RequiredPayment>()))
            .Returns(() => allPayments)
            .Verifiable();

            monthEndCacheMock.Setup(c => c.TryGet(It.Is <string>(key => key.Equals(CacheKeys.MonthEndCacheKey)), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new ConditionalValue <bool>(true, true))
            .Verifiable();

            levyAccountCacheMock.Setup(c => c.TryGet(CacheKeys.LevyBalanceKey, It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => new ConditionalValue <LevyAccountModel>(true, new LevyAccountModel {
                AccountId = 666, Balance = balance, TransferAllowance = transferAllowance
            }))
            .Verifiable();

            levyAccountCacheMock.Setup(c => c.AddOrReplace(CacheKeys.LevyBalanceKey, It.Is <LevyAccountModel>(model => model.AccountId == 666), It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask)
            .Verifiable();

            // act
            var fundingSourcePayments = await service.ProcessReceiverTransferPayment(unableToFundEvent);

            // assert
            fundingSourcePayments.Should().HaveCount(3);
            fundingSourcePayments[0].Should().BeOfType <LevyFundingSourcePaymentEvent>();
            fundingSourcePayments[1].Should().BeOfType <EmployerCoInvestedFundingSourcePaymentEvent>();
            fundingSourcePayments[2].Should().BeOfType <SfaCoInvestedFundingSourcePaymentEvent>();

            fundingSourcePayments[0].AmountDue.Should().Be(55);
            fundingSourcePayments[1].AmountDue.Should().Be(44);
            fundingSourcePayments[2].AmountDue.Should().Be(33);
        }
        public async Task ProcessesTransferPayments()
        {
            // 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 = 2,
                TransferSenderAccountId = 666
            };

            var balance           = 100m;
            var transferAllowance = 50;
            var transferPayment   = new TransferPayment {
                AmountDue = 55, Type = FundingSourceType.Transfer
            };
            var employerCoInvestedPayment = new EmployerCoInvestedPayment {
                AmountDue = 44, Type = FundingSourceType.CoInvestedEmployer
            };
            var sfaCoInvestedPayment = new SfaCoInvestedPayment {
                AmountDue = 33, Type = FundingSourceType.CoInvestedSfa
            };
            var allPayments = new FundingSourcePayment[] { transferPayment, 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);

            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);

            processorMock.Verify(p => p.Process(It.Is <RequiredPayment>(rp => rp.IsTransfer)), Times.Once);

            // assert
            fundingSourcePayments.Should().HaveCount(3);
            fundingSourcePayments[0].Should().BeOfType <TransferFundingSourcePaymentEvent>();
            fundingSourcePayments[1].Should().BeOfType <EmployerCoInvestedFundingSourcePaymentEvent>();
            fundingSourcePayments[2].Should().BeOfType <SfaCoInvestedFundingSourcePaymentEvent>();

            fundingSourcePayments[0].AmountDue.Should().Be(55);
            fundingSourcePayments[1].AmountDue.Should().Be(44);
            fundingSourcePayments[2].AmountDue.Should().Be(33);
        }