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);
        }
Example #2
0
        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 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 FundingSourcePayment Process(RequiredPayment message)
        {
            Validate(message);

            var fundingSourcePayment = CreatePayment(message);

            return(fundingSourcePayment);
        }
Example #5
0
        private CalculatedRequiredIncentiveAmount BuildIncentiveRequiredPaymentEvent(RequiredPayment requiredPayment)
        {
            var paymentEvent = new CalculatedRequiredIncentiveAmount();

            MapCommon(requiredPayment, paymentEvent);
            paymentEvent.Type         = (IncentivePaymentType)requiredPayment.Type;
            paymentEvent.ContractType = (ContractType)ContractType;
            return(paymentEvent);
        }
        private void Validate(RequiredPayment message)
        {
            var validationResults = validator.Validate(message);

            if (validationResults.Any())
            {
                throw new FundingSourceRequiredPaymentValidationException(JsonConvert.SerializeObject(validationResults));
            }
        }
Example #7
0
 private static void AddRefundCommitmentDetails(RequiredPayment requiredPayment, PeriodisedRequiredPaymentEvent requiredPaymentEvent)
 {
     if (requiredPayment.Amount < 0)
     {
         requiredPaymentEvent.ApprenticeshipId             = requiredPayment.ApprenticeshipId;
         requiredPaymentEvent.ApprenticeshipPriceEpisodeId = requiredPayment.ApprenticeshipPriceEpisodeId;
         requiredPaymentEvent.ApprenticeshipEmployerType   = requiredPayment.ApprenticeshipEmployerType;
     }
 }
        public IReadOnlyList <FundingSourcePayment> Process(RequiredPayment requiredPayment)
        {
            var transferAmount = levyBalanceService.TryFundTransfer(requiredPayment.AmountDue).AsRounded();

            return(transferAmount == 0
                ? new FundingSourcePayment[0]
                : new[] { new TransferPayment {
                              Type = FundingSourceType.Transfer, AmountDue = transferAmount
                          }, });
        }
Example #9
0
        protected override FundingSourcePayment CreatePayment(RequiredPayment requiredPayment)
        {
            var amountToPay = requiredPayment.SfaContributionPercentage * requiredPayment.AmountDue;

            return(new SfaCoInvestedPayment
            {
                AmountDue = amountToPay.AsRounded(),
                Type = FundingSourceType.CoInvestedSfa,
            });
        }
Example #10
0
        public IReadOnlyList <FundingSourcePayment> Process(RequiredPayment requiredPayment)
        {
            var results = new List <FundingSourcePayment>
            {
                employerCoInvestedPaymentProcessor.Process(requiredPayment),
                sfaCoInvestedPaymentProcessor.Process(requiredPayment),
            }
            .Where(x => x.AmountDue != 0);

            return(results.ToArray());
        }
Example #11
0
        public void AccountIdIsCorrect(Type requiredPaymentEventType)
        {
            var requiredPaymentEvent = Activator.CreateInstance(requiredPaymentEventType) as PeriodisedRequiredPaymentEvent;
            var requiredPayment      = new RequiredPayment
            {
                AccountId = 1,
                TransferSenderAccountId = 2
            };

            mapper.Map(requiredPayment, requiredPaymentEvent);
            requiredPaymentEvent.AccountId.Should().Be(requiredPayment.AccountId);
        }
Example #12
0
 private void MapCommon(RequiredPayment requiredPayment, PeriodisedRequiredPaymentEvent paymentEvent)
 {
     paymentEvent.Learner                = TestSession.Learner.ToLearner();
     paymentEvent.Ukprn                  = TestSession.Ukprn;
     paymentEvent.AmountDue              = requiredPayment.Amount;
     paymentEvent.JobId                  = TestSession.JobId;
     paymentEvent.EventTime              = DateTimeOffset.UtcNow;
     paymentEvent.CollectionPeriod       = CollectionPeriodFactory.CreateFromAcademicYearAndPeriod(AcademicYear, CollectionPeriod);
     paymentEvent.DeliveryPeriod         = requiredPayment.DeliveryPeriod;
     paymentEvent.IlrSubmissionDateTime  = TestSession.IlrSubmissionTime;
     paymentEvent.LearningAim            = TestSession.Learner.Course.ToLearningAim();
     paymentEvent.PriceEpisodeIdentifier = requiredPayment.PriceEpisodeIdentifier;
 }
        public void PriceEpisodeIdentifierIsCorrect(Type requiredPaymentEventType)
        {
            var requiredPaymentEvent           = Activator.CreateInstance(requiredPaymentEventType) as PeriodisedRequiredPaymentEvent;
            var expectedPriceEpisodeIdentifier = "peid";

            var requiredPayment = new RequiredPayment
            {
                PriceEpisodeIdentifier = expectedPriceEpisodeIdentifier,
            };

            var actual = mapper.Map(requiredPayment, requiredPaymentEvent);

            actual.PriceEpisodeIdentifier.Should().Be(expectedPriceEpisodeIdentifier);
        }
        public void AmountIsCorrect(Type requiredPaymentEventType)
        {
            var requiredPaymentEvent = Activator.CreateInstance(requiredPaymentEventType) as PeriodisedRequiredPaymentEvent;
            var expectedAmount       = 100;

            var requiredPayment = new RequiredPayment
            {
                Amount = expectedAmount,
            };

            var actual = mapper.Map(requiredPayment, requiredPaymentEvent);

            actual.AmountDue.Should().Be(expectedAmount);
        }
        public void SfaPercentageIsCorrect(Type requiredPaymentEventType)
        {
            var requiredPaymentEvent  = Activator.CreateInstance(requiredPaymentEventType) as CalculatedRequiredOnProgrammeAmount;
            var expectedSfaPercentage = 100;

            var requiredPayment = new RequiredPayment
            {
                SfaContributionPercentage = expectedSfaPercentage,
            };

            var actual = mapper.Map(requiredPayment, requiredPaymentEvent);

            actual.SfaContributionPercentage.Should().Be(expectedSfaPercentage);
        }
Example #16
0
        public IEnumerable <RequiredCoInvestedPaymentValidationResult> Validate(RequiredPayment requiredPayment)
        {
            var results = new List <RequiredCoInvestedPaymentValidationResult>();

            if (requiredPayment.SfaContributionPercentage <= 0)
            {
                results.Add(new RequiredCoInvestedPaymentValidationResult
                {
                    Rule = RequiredPaymentEventValidationRules.ZeroSfaContributionPercentage
                });
            }

            return(results);
        }
        public void Should_Return_Unable_To_Pay_Transfer_If_No_Transfer_Allowance()
        {
            var requiredPayment = new RequiredPayment {
                AmountDue = 50, IsTransfer = true, SfaContributionPercentage = .95M
            };

            mocker.GetMock <ITransferPaymentProcessor>()
            .Setup(x => x.Process(requiredPayment))
            .Returns(new FundingSourcePayment[0]);
            var paymentProcessor = mocker.Resolve <PaymentProcessor>();
            var payments         = paymentProcessor.Process(requiredPayment);

            payments.Count.Should().Be(1);
            payments.All(p => p.Type == FundingSourceType.Transfer && p is UnableToFundTransferPayment && p.AmountDue == 50).Should().BeTrue();
        }
        public void TestProcessPaymentWithOneSfaContribution() // Small employer earnings have SFA contribution of 1
        {
            // arrange
            var requiredPayment = new RequiredPayment
            {
                SfaContributionPercentage = 1m,
                AmountDue = 100
            };

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

            // assert
            payments.Should().HaveCount(0);
        }
        public void Should_Return_Refund_Transfer_Payment()
        {
            var requiredPayment = new RequiredPayment {
                AmountDue = -50, IsTransfer = true, SfaContributionPercentage = .95M
            };

            mocker.GetMock <ITransferPaymentProcessor>()
            .Setup(x => x.Process(requiredPayment))
            .Returns(new[] { new TransferPayment {
                                 AmountDue = -50, Type = FundingSourceType.Transfer
                             } });
            var paymentProcessor = mocker.Resolve <PaymentProcessor>();
            var payments         = paymentProcessor.Process(requiredPayment);

            payments.Count.Should().Be(1);
            payments.Count(p => p.Type == FundingSourceType.Transfer && p is TransferPayment && p.AmountDue == -50).Should().Be(1);
        }
        public void Should_Return_Transfer_And_Unable_To_Pay_Transfer_If_Not_Enough_Allowance_To_Cover_Whole_Transfer_Amount()
        {
            var requiredPayment = new RequiredPayment {
                AmountDue = 50, IsTransfer = true, SfaContributionPercentage = .95M
            };

            mocker.GetMock <ITransferPaymentProcessor>()
            .Setup(x => x.Process(requiredPayment))
            .Returns(new[] { new TransferPayment {
                                 AmountDue = 40, Type = FundingSourceType.Transfer
                             } });
            var paymentProcessor = mocker.Resolve <PaymentProcessor>();
            var payments         = paymentProcessor.Process(requiredPayment);

            payments.Count(p => p.Type == FundingSourceType.Transfer && p is TransferPayment && p.AmountDue == 40).Should().Be(1);
            payments.Count(p => p.Type == FundingSourceType.Transfer && p is UnableToFundTransferPayment && p.AmountDue == 10).Should().Be(1);
        }
        public void TestProcessPaymentWithZeroLevyBalance()
        {
            // arrange
            var requiredPayment = new RequiredPayment
            {
                SfaContributionPercentage = .9m,
                AmountDue = 100
            };

            levyBalanceServiceMock.Setup(s => s.TryFund(100)).Returns(0).Verifiable();

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

            // assert
            payments.Should().BeEmpty();
        }
Example #22
0
        private PeriodisedRequiredPaymentEvent CreateRequiredPaymentEvent(RequiredPayment requiredPayment)
        {
            PeriodisedRequiredPaymentEvent paymentEvent;

            switch (requiredPayment.Type)
            {
            case TransactionType.Learning:
            case TransactionType.Completion:
            case TransactionType.Balancing:
                paymentEvent = BuildApprenticeshipContractTypeRequiredPaymentEvent(requiredPayment);
                break;

            default:
                paymentEvent = BuildIncentiveRequiredPaymentEvent(requiredPayment);
                break;
            }
            return(paymentEvent);
        }
        public void TestProcessRefundPayment()
        {
            // arrange
            var requiredPayment = new RequiredPayment
            {
                SfaContributionPercentage = .9m,
                AmountDue = -600
            };

            levyBalanceServiceMock.Setup(s => s.TryFund(-600)).Returns(-600).Verifiable();

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

            // assert
            payments.Should().NotBeEmpty();
            payments[0].AmountDue.Should().Be(-600);
        }
        public void TestProcessPaymentNoSfaContribution()
        {
            // arrange
            var requiredPayment = new RequiredPayment
            {
                SfaContributionPercentage = 0m,
                AmountDue = 100
            };

            levyBalanceServiceMock.Setup(s => s.TryFund(100)).Returns(100).Verifiable();

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

            // assert
            payments.Should().HaveCount(1);
            payments[0].AmountDue.Should().Be(100);
            payments[0].Type.Should().Be(FundingSourceType.Levy);
        }
        public void Should_Use_TransferProcessor_For_Transfer_Payments()
        {
            var requiredPayment = new RequiredPayment {
                AmountDue = 50, IsTransfer = true, SfaContributionPercentage = .95M
            };

            mocker.GetMock <ITransferPaymentProcessor>()
            .Setup(x => x.Process(requiredPayment))
            .Returns(new[] { new TransferPayment {
                                 AmountDue = 50, Type = FundingSourceType.Transfer
                             } });
            var paymentProcessor = mocker.Resolve <PaymentProcessor>();
            var payments         = paymentProcessor.Process(requiredPayment);

            payments.Count.Should().Be(1);
            payments.All(p => p.Type == FundingSourceType.Transfer && p is TransferPayment).Should().BeTrue();
            mocker.GetMock <ILevyPaymentProcessor>()
            .Verify(x => x.Process(It.IsAny <RequiredPayment>()), Times.Never);
        }
        public void TestLevyOnlyCall()
        {
            // arrange
            var levyPayment = new LevyPayment {
                AmountDue = 100
            };
            var requiredPayment = new RequiredPayment {
                AmountDue = 100
            };

            levyPaymentProcessorMock.Setup(p => p.Process(It.IsAny <RequiredPayment>())).Returns(new[] { levyPayment }).Verifiable();

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

            // assert
            actualPayments.Should().NotBeNull();
            actualPayments.Should().HaveCount(1);
            actualPayments[0].Should().BeSameAs(levyPayment);
        }
Example #27
0
        public IReadOnlyList <FundingSourcePayment> Process(RequiredPayment requiredPayment)
        {
            if (requiredPayment.SfaContributionPercentage == 1)
            {
                return(new FundingSourcePayment[0]);
            }

            var amountDue = levyBalanceService.TryFund(requiredPayment.AmountDue).AsRounded();

            if (amountDue == 0)
            {
                return(new FundingSourcePayment[0]);
            }

            return(new[]
            {
                new LevyPayment
                {
                    AmountDue = amountDue,
                    Type = FundingSourceType.Levy
                }
            });
        }
Example #28
0
        public IReadOnlyList <FundingSourcePayment> Process(RequiredPayment requiredPayment)
        {
            var fundingSourcePayments = new List <FundingSourcePayment>();

            if (requiredPayment.IsTransfer)
            {
                fundingSourcePayments.AddRange(transferPaymentProcessor.Process(requiredPayment));
                var remainingTransferAmount = requiredPayment.AmountDue - fundingSourcePayments.Sum(transfer => transfer.AmountDue);
                if (remainingTransferAmount > 0)
                {
                    fundingSourcePayments.Add(new UnableToFundTransferPayment
                    {
                        AmountDue = remainingTransferAmount,
                        Type      = FundingSourceType.Transfer
                    });
                }
                return(fundingSourcePayments);
            }

            fundingSourcePayments.AddRange(levyPaymentProcessor.Process(requiredPayment));

            var amountDue = requiredPayment.AmountDue - fundingSourcePayments.Select(p => p.AmountDue).Sum();

            if (amountDue != 0m)
            {
                var partFundedRequiredPayment = new RequiredPayment
                {
                    AmountDue = amountDue,
                    SfaContributionPercentage = requiredPayment.SfaContributionPercentage
                };

                fundingSourcePayments.AddRange(coInvestedPaymentProcessor.Process(partFundedRequiredPayment));
            }

            return(fundingSourcePayments);
        }
 protected abstract FundingSourcePayment CreatePayment(RequiredPayment message);
Example #30
0
        private CalculatedRequiredOnProgrammeAmount BuildApprenticeshipContractTypeRequiredPaymentEvent(RequiredPayment requiredPayment)
        {
            var paymentEvent = ContractType == ContractType.Act1
                ? (CalculatedRequiredOnProgrammeAmount) new CalculatedRequiredLevyAmount()
                : new CalculatedRequiredCoInvestedAmount();

            MapCommon(requiredPayment, paymentEvent);
            paymentEvent.OnProgrammeEarningType    = (OnProgrammeEarningType)requiredPayment.Type;
            paymentEvent.ContractType              = (ContractType)ContractType;
            paymentEvent.SfaContributionPercentage = SfaContributionPercentage;
            return(paymentEvent);
        }