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 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 ShouldMapToValidSfaCoInvestedFundingSourcePaymentEvent()
        {
            //Arrange
            var coInvestedPayment = new SfaCoInvestedPayment
            {
                AmountDue = 900.00m,
                Type      = FundingSourceType.CoInvestedSfa,
            };

            var expectedPayment = new SfaCoInvestedFundingSourcePaymentEvent
            {
                RequiredPaymentEventId = requiredCoInvestedAmount.EventId,
                AmountDue    = 900.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.CoInvestedSfa,
                AccountId                  = 1000000,
                ApprenticeshipEmployerType = requiredCoInvestedAmount.ApprenticeshipEmployerType,
            };

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

            expectedPayment.EventId   = actualSfaCoInvestedPayment.EventId;
            expectedPayment.EventTime = actualSfaCoInvestedPayment.EventTime;

            actualSfaCoInvestedPayment.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);
        }