private static void CommonTestSetup(Mock <IApprenticeshipRepository> repository,
                                            DataLockEvent dataLock,
                                            List <EarningPeriod> periods,
                                            List <ApprenticeshipModel> apprenticeships,
                                            List <DataLockFailure> dataLockFailures = null
                                            )
        {
            repository
            .Setup(x => x.Get(It.IsAny <List <long> >(), CancellationToken.None))
            .Returns(Task.FromResult(apprenticeships));
            dataLock.IlrFileName = "bob";

            apprenticeships[0].ApprenticeshipPriceEpisodes.ForEach(x => x.ApprenticeshipId = apprenticeships[0].Id);
            periods[0].ApprenticeshipId             = apprenticeships[0].Id;
            periods[0].ApprenticeshipPriceEpisodeId = apprenticeships[0].ApprenticeshipPriceEpisodes[0].Id;
            periods[0].DataLockFailures             = dataLock is PayableEarningEvent ? null : dataLockFailures;
            periods[0].PriceEpisodeIdentifier       = dataLock.PriceEpisodes[0].Identifier;

            dataLock.OnProgrammeEarnings[0].Type    = OnProgrammeEarningType.Learning;
            dataLock.OnProgrammeEarnings[0].Periods = periods.AsReadOnly();

            if (dataLock is EarningFailedDataLockMatching)
            {
                dataLockFailures.ForEach(x =>
                {
                    x.ApprenticeshipId = apprenticeships[0].Id;
                    x.ApprenticeshipPriceEpisodeIds = apprenticeships[0].ApprenticeshipPriceEpisodes.Select(o => o.Id).ToList();
                });
            }
        }
 private bool EventsMatch(DataLockEvent original, DataLockEvent client)
 {
     return(original.Id == client.Id &&
            original.ProcessDateTime == client.ProcessDateTime &&
            original.IlrFileName == client.IlrFileName &&
            original.Ukprn == client.Ukprn &&
            original.Uln == client.Uln &&
            original.LearnRefNumber == client.LearnRefNumber &&
            original.AimSeqNumber == client.AimSeqNumber &&
            original.PriceEpisodeIdentifier == client.PriceEpisodeIdentifier &&
            original.ApprenticeshipId == client.ApprenticeshipId &&
            original.EmployerAccountId == client.EmployerAccountId &&
            original.EventSource == client.EventSource &&
            original.HasErrors == client.HasErrors &&
            original.IlrStartDate == client.IlrStartDate &&
            original.IlrStandardCode == client.IlrStandardCode &&
            original.IlrProgrammeType == client.IlrProgrammeType &&
            original.IlrFrameworkCode == client.IlrFrameworkCode &&
            original.IlrPathwayCode == client.IlrPathwayCode &&
            original.IlrTrainingPrice == client.IlrTrainingPrice &&
            original.IlrEndpointAssessorPrice == client.IlrEndpointAssessorPrice &&
            EventErrorsMatch(original.Errors, client.Errors) &&
            EventPeriodsMatch(original.Periods, client.Periods) &&
            EventApprenticeshipsMatch(original.Apprenticeships, client.Apprenticeships));
 }
        private Dictionary <(TransactionType type, byte period), EarningPeriod> GetFailuresGroupedByTypeAndPeriod(
            DataLockEvent dataLockEvent)
        {
            var result = new Dictionary <(TransactionType type, byte period), EarningPeriod>();

            if (dataLockEvent.OnProgrammeEarnings != null && dataLockEvent.OnProgrammeEarnings.Any())
            {
                foreach (var onProgrammeEarning in dataLockEvent.OnProgrammeEarnings)
                {
                    foreach (var period in onProgrammeEarning.Periods)
                    {
                        if (period.Amount == 0 && string.IsNullOrWhiteSpace(period.PriceEpisodeIdentifier))
                        {
                            continue; // DataLocks are generated for all periods, even irrelevant, ignore until fixed
                        }
                        var key = ((TransactionType)onProgrammeEarning.Type, period.Period);
                        if (result.ContainsKey(key))
                        {
                            paymentLogger.LogWarning($"DataLockEvent trying to add duplicate key \n\n " +
                                                     $"Existing Period: {JsonConvert.SerializeObject(result[key])}\n\n" +
                                                     $"Period that failed to add: {JsonConvert.SerializeObject(period)}");
                        }
                        else
                        {
                            result.Add(key, period);
                        }
                    }
                }
            }

            if (dataLockEvent.IncentiveEarnings != null && dataLockEvent.IncentiveEarnings.Any())
            {
                foreach (var incentiveEarning in dataLockEvent.IncentiveEarnings)
                {
                    foreach (var period in incentiveEarning.Periods)
                    {
                        if (period.Amount == 0 && string.IsNullOrWhiteSpace(period.PriceEpisodeIdentifier))
                        {
                            continue; // DataLocks are generated for all periods, even irrelevant, ignore until fixed
                        }
                        var key = ((TransactionType)incentiveEarning.Type, period.Period);
                        if (result.ContainsKey(key))
                        {
                            paymentLogger.LogWarning($"DataLockEvent trying to add duplicate key \n\n " +
                                                     $"Existing Period: {JsonConvert.SerializeObject(result[key])}\n\n" +
                                                     $"Period that failed to add: {JsonConvert.SerializeObject(period)}");
                        }
                        else
                        {
                            result.Add(key, period);
                        }
                    }
                }
            }

            return(result);
        }
        public List <DataLockEventPriceEpisodeModel> Resolve(DataLockEvent source, DataLockEventModel destination, List <DataLockEventPriceEpisodeModel> destMember, ResolutionContext context)
        {
            var priceEpisodeModels = source.PriceEpisodes?
                                     .Select(priceEpisode => context.Mapper.Map <DataLockEventPriceEpisodeModel>(priceEpisode))
                                     .ToList() ?? new List <DataLockEventPriceEpisodeModel>();

            priceEpisodeModels.ForEach(model => model.DataLockEventId = source.EventId);
            return(priceEpisodeModels);
        }
        public async Task <List <DataLockStatusChanged> > ProcessPayableEarning(DataLockEvent payableEarningEvent)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                                    TransactionScopeAsyncFlowOption.Enabled))
            {
                var result          = new List <DataLockStatusChanged>();
                var changedToPassed = new DataLockStatusChangedToPassed
                {
                    TransactionTypesAndPeriods = new Dictionary <TransactionType, List <EarningPeriod> >()
                };
                var failuresToDelete = new List <long>();

                var newPassesGroupedByTypeAndPeriod = GetPassesGroupedByTypeAndPeriod(payableEarningEvent);

                var oldFailures = await dataLockFailureRepository.GetFailures(
                    payableEarningEvent.Ukprn,
                    payableEarningEvent.Learner.ReferenceNumber,
                    payableEarningEvent.LearningAim.FrameworkCode,
                    payableEarningEvent.LearningAim.PathwayCode,
                    payableEarningEvent.LearningAim.ProgrammeType,
                    payableEarningEvent.LearningAim.StandardCode,
                    payableEarningEvent.LearningAim.Reference,
                    payableEarningEvent.CollectionYear
                    ).ConfigureAwait(false);

                foreach (var oldFailure in oldFailures)
                {
                    if (newPassesGroupedByTypeAndPeriod.TryGetValue(
                            (oldFailure.TransactionType, oldFailure.DeliveryPeriod), out var newPass))
                    {
                        AddTypeAndPeriodToEvent(changedToPassed, oldFailure.TransactionType, newPass, payableEarningEvent);
                        failuresToDelete.Add(oldFailure.Id);
                    }
                }

                if (changedToPassed.TransactionTypesAndPeriods.Count > 0)
                {
                    result.Add(changedToPassed);
                }

                foreach (var dataLockStatusChanged in result)
                {
                    mapper.Map(payableEarningEvent, dataLockStatusChanged);
                }

                await dataLockFailureRepository.ReplaceFailures(failuresToDelete, new List <DataLockFailureEntity>(),
                                                                payableEarningEvent.EarningEventId, payableEarningEvent.EventId).ConfigureAwait(false);

                scope.Complete();

                paymentLogger.LogDebug(
                    $"Deleted {failuresToDelete.Count} old DL failures for UKPRN {payableEarningEvent.Ukprn} Learner Ref {payableEarningEvent.Learner.ReferenceNumber} on R{payableEarningEvent.CollectionPeriod.Period:00}");

                return(result);
            }
        }
Beispiel #6
0
        public async Task ThenTheDataLockIsSaved()
        {
            var dataLock = new DataLockEvent {
                Id = 1
            };

            await _handler.Handle(new CreateDataLockCommand { Event = dataLock });

            _dataLockRepository.Verify(x => x.SaveDataLock(dataLock), Times.Once);
        }
Beispiel #7
0
        public async Task SaveDataLock(DataLockEvent dataLock)
        {
            await WithConnection(async c =>
            {
                using (var transaction = c.BeginTransaction())
                {
                    try
                    {
                        var parameters = new DynamicParameters();
                        parameters.Add("@DataLockId", dataLock.Id, DbType.Int64);
                        parameters.Add("@ProcessDateTime", dataLock.ProcessDateTime, DbType.DateTime2);
                        parameters.Add("@IlrFileName", dataLock.IlrFileName, DbType.String);
                        parameters.Add("@UkPrn", dataLock.Ukprn, DbType.Int64);
                        parameters.Add("@Uln", dataLock.Uln, DbType.Int64);
                        parameters.Add("@LearnRefNumber", dataLock.LearnRefNumber, DbType.String);
                        parameters.Add("@AimSeqNumber", dataLock.AimSeqNumber, DbType.Int64);
                        parameters.Add("@PriceEpisodeIdentifier", dataLock.PriceEpisodeIdentifier, DbType.String);
                        parameters.Add("@ApprenticeshipId", dataLock.ApprenticeshipId, DbType.Int64);
                        parameters.Add("@EmployerAccountId", dataLock.EmployerAccountId, DbType.Int64);
                        parameters.Add("@EventSource", dataLock.EventSource, DbType.Int32);
                        parameters.Add("@Status", dataLock.Status, DbType.Int32);
                        parameters.Add("@HasErrors", dataLock.HasErrors, DbType.Boolean);
                        parameters.Add("@IlrStartDate", dataLock.IlrStartDate, DbType.Date);
                        parameters.Add("@IlrStandardCode", dataLock.IlrStandardCode, DbType.Int64);
                        parameters.Add("@IlrProgrammeType", dataLock.IlrProgrammeType, DbType.Int32);
                        parameters.Add("@IlrFrameworkCode", dataLock.IlrFrameworkCode, DbType.Int32);
                        parameters.Add("@IlrPathwayCode", dataLock.IlrPathwayCode, DbType.Int32);
                        parameters.Add("@IlrTrainingPrice", dataLock.IlrTrainingPrice, DbType.Decimal);
                        parameters.Add("@IlrEndpointAssessorPrice", dataLock.IlrEndpointAssessorPrice, DbType.Decimal);
                        parameters.Add("@IlrPriceEffectiveFromDate", dataLock.IlrPriceEffectiveFromDate, DbType.Date);
                        parameters.Add("@IlrPriceEffectiveToDate", dataLock.IlrPriceEffectiveToDate, DbType.Date);

                        var id = await c.ExecuteScalarAsync <long>(
                            sql: "[Data_Load].[SaveDataLock]",
                            param: parameters,
                            commandType: CommandType.StoredProcedure,
                            transaction: transaction);

                        if (dataLock.HasErrors)
                        {
                            await SaveDataLockErrors(c, transaction, id, dataLock.Errors);
                        }

                        transaction.Commit();
                    }
                    catch (SqlException ex)
                    {
                        transaction.Rollback();
                        throw;
                    }
                }

                return(0);
            });
        }
 private async Task SaveDataLock(DataLockEvent dataLock)
 {
     try
     {
         await _dataLockRepository.SaveDataLock(dataLock);
     }
     catch (Exception ex)
     {
         _logger.Error(ex, $"Exception thrown saving data lock");
         throw;
     }
 }
Beispiel #9
0
        public async Task ThenTheCreateEventCommandShouldBeSent()
        {
            //Arrange
            var dataLockEvent = new DataLockEvent {
                Id = 123
            };

            //Act
            await _handler.Handle(dataLockEvent);

            //Assert
            _mediator.Verify(x => x.PublishAsync(It.IsAny <CreateDataLockCommand>()), Times.Once);
            _mediator.Verify(x => x.PublishAsync(It.Is <CreateDataLockCommand>(c => c.Event == dataLockEvent)), Times.Once);
        }
Beispiel #10
0
        public async Task AndSavingADataLockFailsThenTheExceptionIsLogged()
        {
            var expectedException = new Exception();
            var failingDataLock   = new DataLockEvent();

            var command = new CreateDataLockCommand {
                Event = failingDataLock
            };

            _dataLockRepository.Setup(x => x.SaveDataLock(failingDataLock)).Throws(expectedException);

            Assert.ThrowsAsync <Exception>(() => _handler.Handle(command));

            _logger.Verify(x => x.Error(expectedException, $"Exception thrown saving data lock"));
        }
Beispiel #11
0
        public List <DataLockEventNonPayablePeriodModel> Resolve(DataLockEvent source, DataLockEventModel destination, List <DataLockEventNonPayablePeriodModel> destMember, ResolutionContext context)
        {
            var periods = destination.NonPayablePeriods ?? new List <DataLockEventNonPayablePeriodModel>();

            periods.AddRange(source.OnProgrammeEarnings?
                             .SelectMany(onProgEarning => onProgEarning.Periods, (onProgEarning, period) => new { onProgEarning, period })
                             .Select(item => new DataLockEventNonPayablePeriodModel
            {
                TransactionType                 = (TransactionType)item.onProgEarning.Type,
                DeliveryPeriod                  = item.period.Period,
                Amount                          = item.period.Amount,
                PriceEpisodeIdentifier          = item.period.PriceEpisodeIdentifier,
                SfaContributionPercentage       = item.period.SfaContributionPercentage,
                DataLockEventId                 = source.EventId,
                CensusDate                      = item.onProgEarning.CensusDate,
                LearningStartDate               = source.LearningAim.StartDate,
                DataLockEventNonPayablePeriodId = Guid.NewGuid(),
                Failures                        = item.period.DataLockFailures?.Select(failure => new DataLockEventNonPayablePeriodFailureModel
                {
                    ApprenticeshipId = failure.ApprenticeshipId,
                    DataLockFailure  = failure.DataLockError,
                }).ToList() ?? new List <DataLockEventNonPayablePeriodFailureModel>(),
            }) ?? new List <DataLockEventNonPayablePeriodModel>()
                             );

            periods.AddRange(source.IncentiveEarnings?
                             .SelectMany(incentiveEarning => incentiveEarning.Periods, (incentiveEarning, period) => new { incentiveEarning, period })
                             .Select(item => new DataLockEventNonPayablePeriodModel
            {
                TransactionType                 = (TransactionType)item.incentiveEarning.Type,
                DeliveryPeriod                  = item.period.Period,
                Amount                          = item.period.Amount,
                PriceEpisodeIdentifier          = item.period.PriceEpisodeIdentifier,
                SfaContributionPercentage       = item.period.SfaContributionPercentage,
                DataLockEventId                 = source.EventId,
                CensusDate                      = item.incentiveEarning.CensusDate,
                LearningStartDate               = source.LearningAim.StartDate,
                DataLockEventNonPayablePeriodId = Guid.NewGuid(),
                Failures                        = item.period.DataLockFailures?.Select(failure => new DataLockEventNonPayablePeriodFailureModel
                {
                    ApprenticeshipId = failure.ApprenticeshipId,
                    DataLockFailure  = failure.DataLockError
                }).ToList() ?? new List <DataLockEventNonPayablePeriodFailureModel>(),
            }) ?? new List <DataLockEventNonPayablePeriodModel>()
                             );
            periods.ForEach(period => period.Failures.ForEach(failure => failure.DataLockEventNonPayablePeriodId = period.DataLockEventNonPayablePeriodId));
            return(periods);
        }
 public DataLockStatus Map(DataLockEvent dataLockEvent)
 {
     return(new DataLockStatus
     {
         DataLockEventId = dataLockEvent.Id,
         DataLockEventDatetime = dataLockEvent.ProcessDateTime,
         PriceEpisodeIdentifier = dataLockEvent.PriceEpisodeIdentifier,
         ApprenticeshipId = dataLockEvent.ApprenticeshipId,
         IlrTrainingCourseCode = DeriveTrainingCourseCode(dataLockEvent),
         IlrTrainingType = DeriveTrainingType(dataLockEvent),
         IlrActualStartDate = dataLockEvent.IlrStartDate,
         IlrEffectiveFromDate = dataLockEvent.IlrPriceEffectiveFromDate,
         IlrPriceEffectiveToDate = dataLockEvent.IlrPriceEffectiveToDate,
         IlrTotalCost = dataLockEvent.IlrTrainingPrice + dataLockEvent.IlrEndpointAssessorPrice,
         ErrorCode = DetermineErrorCode(dataLockEvent.Errors),
         Status = dataLockEvent.Errors?.Any() ?? false ? Status.Fail : Status.Pass,
         EventStatus = (EventStatus)dataLockEvent.Status
     });
 }
        private Dictionary <(TransactionType type, byte period), EarningPeriod> GetPassesGroupedByTypeAndPeriod(
            DataLockEvent dataLockEvent)
        {
            var result = new Dictionary <(TransactionType type, byte period), EarningPeriod>();

            foreach (var onProgrammeEarning in dataLockEvent.OnProgrammeEarnings)
            {
                foreach (var period in onProgrammeEarning.Periods)
                {
                    var key = ((TransactionType)onProgrammeEarning.Type, period.Period);
                    if (!result.ContainsKey(key))
                    {
                        result.Add(key, period);
                    }
                    else
                    {
                        paymentLogger.LogWarning($"DataLockEvent trying to add duplicate key \n\n " +
                                                 $"Existing Period: {JsonConvert.SerializeObject(result[key])}\n\n" +
                                                 $"Period that failed to add: {JsonConvert.SerializeObject(period)}");
                    }
                }
            }

            foreach (var incentiveEarning in dataLockEvent.IncentiveEarnings)
            {
                foreach (var period in incentiveEarning.Periods)
                {
                    var key = ((TransactionType)incentiveEarning.Type, period.Period);
                    if (!result.ContainsKey(key))
                    {
                        result.Add(key, period);
                    }
                    else
                    {
                        paymentLogger.LogWarning($"DataLockEvent trying to add duplicate key \n\n " +
                                                 $"Existing Period: {JsonConvert.SerializeObject(result[key])}\n\n" +
                                                 $"Period that failed to add: {JsonConvert.SerializeObject(period)}");
                    }
                }
            }

            return(result);
        }
 private static DataLockFailureEntity CreateEntity(DataLockEvent dataLockEvent, TransactionType transactionType,
                                                   byte deliveryPeriod, EarningPeriod period)
 {
     return(new DataLockFailureEntity
     {
         Ukprn = dataLockEvent.Ukprn,
         CollectionPeriod = dataLockEvent.CollectionPeriod.Period,
         AcademicYear = dataLockEvent.CollectionYear,
         TransactionType = transactionType,
         DeliveryPeriod = deliveryPeriod,
         LearnerReferenceNumber = dataLockEvent.Learner.ReferenceNumber,
         LearnerUln = dataLockEvent.Learner.Uln,
         LearningAimFrameworkCode = dataLockEvent.LearningAim.FrameworkCode,
         LearningAimPathwayCode = dataLockEvent.LearningAim.PathwayCode,
         LearningAimProgrammeType = dataLockEvent.LearningAim.ProgrammeType,
         LearningAimReference = dataLockEvent.LearningAim.Reference,
         LearningAimStandardCode = dataLockEvent.LearningAim.StandardCode,
         EarningPeriod = period
     });
 }
Beispiel #15
0
        public async Task ProcessDataLockEvent(DataLockEvent dataLockEvent)
        {
            if (dataLockEvent is FunctionalSkillDataLockEvent)
            {
                return;
            }

            if (dataLockEvent is EarningFailedDataLockMatching)
            {
                var hasNoApprenticeship = dataLockEvent
                                          .OnProgrammeEarnings
                                          .SelectMany(o => o.Periods)
                                          .SelectMany(p => p.DataLockFailures)
                                          .All(d => !d.ApprenticeshipId.HasValue);

                if (hasNoApprenticeship)
                {
                    return;
                }
            }

            if (dataLockEvent is PayableEarningEvent)
            {
                var hasNoApprenticeship = dataLockEvent
                                          .OnProgrammeEarnings
                                          .SelectMany(o => o.Periods)
                                          .All(p => !p.ApprenticeshipId.HasValue);
                if (hasNoApprenticeship)
                {
                    return;
                }
            }

            await receivedDataLockEventStore.Add(new ReceivedDataLockEvent
            {
                JobId       = dataLockEvent.JobId,
                Ukprn       = dataLockEvent.Ukprn,
                Message     = dataLockEvent.ToJson(),
                MessageType = dataLockEvent.GetType().AssemblyQualifiedName
            });
        }
 private static void CommonTestSetup(DataLockEvent dataLock,
                                     List <EarningPeriod> periods,
                                     ApprenticeshipModel apprenticeship,
                                     List <DataLockFailure> dataLockFailures = null
                                     )
 {
     apprenticeship.ApprenticeshipPriceEpisodes.ForEach(x => x.ApprenticeshipId = apprenticeship.Id);
     periods[0].ApprenticeshipId             = apprenticeship.Id;
     periods[0].ApprenticeshipPriceEpisodeId = apprenticeship.ApprenticeshipPriceEpisodes[0].Id;
     periods[0].DataLockFailures             = dataLock is PayableEarningEvent ? null : dataLockFailures;
     periods[0].PriceEpisodeIdentifier       = dataLock.PriceEpisodes[0].Identifier;
     dataLock.OnProgrammeEarnings[0].Type    = OnProgrammeEarningType.Learning;
     dataLock.OnProgrammeEarnings[0].Periods = periods.AsReadOnly();
     if (dataLock is EarningFailedDataLockMatching)
     {
         dataLockFailures.ForEach(x =>
         {
             x.ApprenticeshipId = apprenticeship.Id;
             x.ApprenticeshipPriceEpisodeIds = apprenticeship.ApprenticeshipPriceEpisodes.Select(o => o.Id).ToList();
         });
     }
 }
Beispiel #17
0
        public List <DataLockEventPayablePeriodModel> Resolve(DataLockEvent source, DataLockEventModel destination, List <DataLockEventPayablePeriodModel> destMember, ResolutionContext context)
        {
            var periods = destination.PayablePeriods ?? new List <DataLockEventPayablePeriodModel>();

            periods.AddRange(source.OnProgrammeEarnings?
                             .SelectMany(onProgEarning => onProgEarning.Periods, (onProgEarning, period) => new { onProgEarning, period })
                             .Select(item => new DataLockEventPayablePeriodModel
            {
                TransactionType              = (TransactionType)item.onProgEarning.Type,
                DeliveryPeriod               = item.period.Period,
                Amount                       = item.period.Amount,
                PriceEpisodeIdentifier       = item.period.PriceEpisodeIdentifier,
                SfaContributionPercentage    = item.period.SfaContributionPercentage,
                DataLockEventId              = source.EventId,
                LearningStartDate            = source.LearningAim.StartDate,
                ApprenticeshipId             = item.period.ApprenticeshipId,
                ApprenticeshipPriceEpisodeId = item.period.ApprenticeshipPriceEpisodeId,
                ApprenticeshipEmployerType   = item.period.ApprenticeshipEmployerType,
            }) ?? new List <DataLockEventPayablePeriodModel>()
                             );

            periods.AddRange(source.IncentiveEarnings?
                             .SelectMany(incentiveEarning => incentiveEarning.Periods, (incentiveEarning, period) => new { incentiveEarning, period })
                             .Select(item => new DataLockEventPayablePeriodModel
            {
                TransactionType              = (TransactionType)item.incentiveEarning.Type,
                DeliveryPeriod               = item.period.Period,
                Amount                       = item.period.Amount,
                PriceEpisodeIdentifier       = item.period.PriceEpisodeIdentifier,
                SfaContributionPercentage    = item.period.SfaContributionPercentage,
                DataLockEventId              = source.EventId,
                LearningStartDate            = source.LearningAim.StartDate,
                ApprenticeshipId             = item.period.ApprenticeshipId,
                ApprenticeshipPriceEpisodeId = item.period.ApprenticeshipPriceEpisodeId,
                ApprenticeshipEmployerType   = item.period.ApprenticeshipEmployerType,
            }) ?? new List <DataLockEventPayablePeriodModel>()
                             );
            return(periods);
        }
Beispiel #18
0
        private async Task <(long, Guid)> AddDataLockEvent(long jobId, Guid earningEventId, byte collectionPeriod, short academicYear)
        {
            var dataLockEvent = new DataLockEvent
            {
                EventId                    = Guid.NewGuid(),
                EarningEventId             = earningEventId,
                IlrSubmissionDateTime      = DateTime.Now,
                LearnerReferenceNumber     = "1234",
                LearningAimReference       = "1",
                LearningAimFundingLineType = "2",
                Ukprn            = ukprn,
                CollectionPeriod = collectionPeriod,
                AcademicYear     = academicYear,
                JobId            = jobId,
                EventTime        = DateTimeOffset.Now
            };

            await submissionDataContext.DataLockEvents.AddAsync(dataLockEvent);

            await submissionDataContext.SaveChangesAsync();

            return(dataLockEvent.Id, dataLockEvent.EventId);
        }
Beispiel #19
0
        public void Arrange()
        {
            _eventService = new Mock <IProviderEventService>();
            _logger       = new Mock <ILog>();

            var dataLock = new DataLockEvent {
                Id = 1
            };
            var _expectedDataLocks = new PageOfResults <DataLockEvent>
            {
                PageNumber         = 1,
                TotalNumberOfPages = 1,
                Items = new DataLockEvent[1] {
                    dataLock
                }
            };


            _eventService.Setup(x => x.GetUnprocessedDataLocks()).ReturnsAsync(_expectedDataLocks);

            _collector = new DataLockEventCollector(_eventService.Object, _logger.Object, new DataConfiguration {
                DataLocksEnabled = true
            });
        }
 public DataLockEventModel Map(DataLockEvent dataLockEvent)
 {
     return(mapper.Map <DataLockEventModel>(dataLockEvent));
 }
 private TrainingType DeriveTrainingType(DataLockEvent dataLockEvent)
 {
     return(dataLockEvent.IlrProgrammeType == 25
         ? TrainingType.Standard
         : TrainingType.Framework);
 }
 private string DeriveTrainingCourseCode(DataLockEvent dataLockEvent)
 {
     return(dataLockEvent.IlrProgrammeType == 25
         ? $"{dataLockEvent.IlrStandardCode}" :
            $"{dataLockEvent.IlrFrameworkCode}-{dataLockEvent.IlrProgrammeType}-{dataLockEvent.IlrPathwayCode}");
 }
        public void Arrange()
        {
            _configuration = new PaymentsEventsApiConfiguration
            {
                ApiBaseUrl  = "some-url/",
                ClientToken = "super_secure_token"
            };

            _dataLockEvent = new DataLockEvent
            {
                Id = 1,
                ProcessDateTime          = new DateTime(2017, 2, 8, 9, 10, 11),
                IlrFileName              = "ILR-123456",
                Ukprn                    = 123456,
                Uln                      = 987654,
                LearnRefNumber           = "Lrn1",
                AimSeqNumber             = 1,
                PriceEpisodeIdentifier   = "25-27-01/05/2017",
                ApprenticeshipId         = 1,
                EmployerAccountId        = 123,
                EventSource              = EventSource.Submission,
                HasErrors                = true,
                IlrStartDate             = new DateTime(2017, 5, 1),
                IlrStandardCode          = 27,
                IlrTrainingPrice         = 12000m,
                IlrEndpointAssessorPrice = 3000m,
                Errors                   = new []
                {
                    new DataLockEventError
                    {
                        ErrorCode         = "Err15",
                        SystemDescription = "Mismatch on price."
                    }
                },
                Periods = new []
                {
                    new DataLockEventPeriod
                    {
                        ApprenticeshipVersion = "1-019",
                        Period = new NamedCalendarPeriod
                        {
                            Id    = "1617-R09",
                            Month = 4,
                            Year  = 2017
                        },
                        IsPayable       = false,
                        TransactionType = TransactionType.Learning
                    },
                    new DataLockEventPeriod
                    {
                        ApprenticeshipVersion = "1-019",
                        Period = new NamedCalendarPeriod
                        {
                            Id    = "1617-R10",
                            Month = 5,
                            Year  = 2017
                        },
                        IsPayable = false
                    }
                },
                Apprenticeships = new []
                {
                    new DataLockEventApprenticeship
                    {
                        Version         = "19",
                        StartDate       = new DateTime(2017, 5, 1),
                        StandardCode    = 27,
                        NegotiatedPrice = 17500m,
                        EffectiveDate   = new DateTime(2017, 5, 1)
                    }
                }
            };

            _httpClient = new Mock <SecureHttpClient>();
            _httpClient.Setup(c => c.GetAsync(It.IsAny <string>()))
            .Returns(Task.FromResult(JsonConvert.SerializeObject(new PageOfResults <DataLockEvent>
            {
                PageNumber         = 1,
                TotalNumberOfPages = 2,
                Items = new[]
                {
                    _dataLockEvent
                }
            })));

            _client = new Client.PaymentsEventsApiClient(_configuration, _httpClient.Object);
        }
        public void GivenTheDataLockServiceHasGeneratedTheFollowingEvents(Table table)
        {
            var dataContext = Container.Resolve <AuditDataContext>();
            var submissions = table.CreateSet <SubmissionData>();

            foreach (var submission in submissions)
            {
                var dataLockEvent = new DataLockEvent
                {
                    EventId                    = Guid.NewGuid(),
                    EarningEventId             = Guid.NewGuid(),
                    IlrSubmissionDateTime      = submission.SubmissionTime,
                    LearnerReferenceNumber     = submission.Learner,
                    LearningAimReference       = "1",
                    LearningAimFundingLineType = "2",
                    Ukprn            = TestSession.Ukprn,
                    CollectionPeriod = 1,
                    AcademicYear     = 1
                };

                if (submission.Failure)
                {
                    var nonPayablePeriod = new DataLockEventNonPayablePeriod
                    {
                        DataLockEventId = dataLockEvent.EventId,
                        DataLockEventNonPayablePeriodId = Guid.NewGuid()
                    };

                    dataContext.DataLockEventNonPayablePeriods.Add(nonPayablePeriod);

                    var nonPayableFailures = new DataLockEventNonPayablePeriodFailures
                    {
                        DataLockEventNonPayablePeriodId = nonPayablePeriod.DataLockEventNonPayablePeriodId
                    };

                    dataContext.DataLockEventNonPayablePeriodFailures.Add(nonPayableFailures);
                }
                else
                {
                    var dataLockPayablePeriod = new DataLockPayablePeriod
                    {
                        DataLockEventId = dataLockEvent.EventId
                    };

                    dataContext.DataLockPayablePeriods.Add(dataLockPayablePeriod);

                    var priceEpisode = new DataLockEventPriceEpisode
                    {
                        PriceEpisodeIdentifier = "1",
                        PlannedEndDate         = DateTime.Now,
                        DataLockEventId        = dataLockEvent.EventId,
                    };

                    dataContext.DataLockEventPriceEpisodes.Add(priceEpisode);
                }

                dataContext.DataLockEvents.Add(dataLockEvent);
            }

            dataContext.SaveChanges();
        }
        public async Task TestCreatesDataLockChangedEventWhenNewFailure(DataLockEvent failureEvent)
        {
            // arrange
            failureEvent.Ukprn   = 1;
            failureEvent.Learner = new Learner {
                ReferenceNumber = "2", Uln = 3
            };
            failureEvent.LearningAim = new LearningAim
            {
                FrameworkCode   = 4,
                StandardCode    = 5,
                Reference       = "6",
                PathwayCode     = 7,
                ProgrammeType   = 8,
                FundingLineType = "9"
            };
            failureEvent.CollectionYear   = 1819;
            failureEvent.CollectionPeriod = new CollectionPeriod {
                AcademicYear = 7, Period = 8
            };
            failureEvent.OnProgrammeEarnings = new List <OnProgrammeEarning>
            {
                new OnProgrammeEarning
                {
                    Type    = OnProgrammeEarningType.Learning,
                    Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod>
                    {
                        new EarningPeriod
                        {
                            Period           = 1, Amount = 1,
                            DataLockFailures = new List <DataLockFailure>
                            {
                                new DataLockFailure {
                                    DataLockError = DataLockErrorCode.DLOCK_03
                                }
                            }
                        },
                        new EarningPeriod {
                            Period = 2, Amount = 1
                        }
                    })
                }
            };
            failureEvent.IncentiveEarnings = new List <IncentiveEarning>();

            var dbFailures = new List <DataLockFailureEntity>();

            repositoryMock.Setup(r => r.GetFailures(1, "2", 4, 7, 8, 5, "6", 1819)).ReturnsAsync(dbFailures).Verifiable();
            repositoryMock.Setup(r => r.ReplaceFailures(It.Is <List <long> >(old => old.Count == 0), It.Is <List <DataLockFailureEntity> >(newF => newF.Count == 1), It.IsAny <Guid>(), It.IsAny <Guid>())).Returns(Task.CompletedTask).Verifiable();
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, failureEvent.OnProgrammeEarnings[0].Periods[0].DataLockFailures)).Returns(DataLockStatusChange.ChangedToFailed).Verifiable();

            // act
            var statusChangedEvents = await processor.ProcessDataLockFailure(failureEvent).ConfigureAwait(false);

            // assert
            statusChangedEvents.Should().NotBeNull();
            statusChangedEvents.Should().HaveCount(1);
            statusChangedEvents[0].Should().BeOfType <DataLockStatusChangedToFailed>();
            statusChangedEvents[0].TransactionTypesAndPeriods.Should().HaveCount(1);
            statusChangedEvents[0].TransactionTypesAndPeriods.First().Key.Should().Be(1);
            statusChangedEvents[0].TransactionTypesAndPeriods.First().Value.Should().HaveCount(1);
            statusChangedEvents[0].TransactionTypesAndPeriods.First().Value[0].Period.Should().Be(1);
        }
        public async Task TestCreatesMultipleEventsForPeriodsAndTypes(DataLockEvent failureEvent)
        {
            // arrange



            // change of dlock code
            var oldTT2P5 = new DataLockFailureEntity {
                Id = 1, DeliveryPeriod = 5, TransactionType = TransactionType.Completion, EarningPeriod = new EarningPeriod {
                    Period = 5, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_06
                        }
                    }
                }
            };
            var newTT2p5 = new EarningPeriod {
                Period = 5, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_04
                    }
                }
            };

            // no new - changed to pass
            var oldTT3p3 = new DataLockFailureEntity {
                Id = 2, DeliveryPeriod = 3, TransactionType = TransactionType.Balancing, EarningPeriod = new EarningPeriod {
                    Period = 3, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_06
                        }
                    }
                }
            };
            var newTT3p3 = new EarningPeriod {
                Period = 3, Amount = 1, ApprenticeshipId = 4, ApprenticeshipPriceEpisodeId = 4
            };

            // no change
            var oldTT2p6 = new DataLockFailureEntity {
                Id = 3, DeliveryPeriod = 6, TransactionType = TransactionType.Completion, EarningPeriod = new EarningPeriod {
                    Period = 6, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_04
                        }
                    }
                }
            };
            var newTT2p6 = new EarningPeriod {
                Period = 6, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_04
                    }
                }
            };

            // change of dlock code
            var oldTT16p5 = new DataLockFailureEntity {
                Id = 4, DeliveryPeriod = 5, TransactionType = TransactionType.CareLeaverApprenticePayment, EarningPeriod = new EarningPeriod {
                    Period = 5, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_06
                        }
                    }
                }
            };
            var newTT16p5 = new EarningPeriod {
                Period = 5, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_04
                    }
                }
            };

            // no new - change to pass
            var oldTT10p3 = new DataLockFailureEntity {
                Id = 5, DeliveryPeriod = 3, TransactionType = TransactionType.Balancing16To18FrameworkUplift, EarningPeriod = new EarningPeriod {
                    Period = 3, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_06
                        }
                    }
                }
            };
            var newTT10p3 = new EarningPeriod {
                Period = 3, Amount = 1, ApprenticeshipId = 10, ApprenticeshipPriceEpisodeId = 10, DataLockFailures = new List <DataLockFailure>()
            };

            // no change
            var oldTT16p6 = new DataLockFailureEntity {
                Id = 6, DeliveryPeriod = 6, TransactionType = TransactionType.CareLeaverApprenticePayment, EarningPeriod = new EarningPeriod {
                    Period = 6, DataLockFailures = new List <DataLockFailure> {
                        new DataLockFailure {
                            DataLockError = DataLockErrorCode.DLOCK_04
                        }
                    }
                }
            };
            var newTT16p6 = new EarningPeriod {
                Period = 6, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_04
                    }
                }
            };

            // no old - change to fail
            var newTT2p1 = new EarningPeriod {
                Period = 1, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_03
                    }
                }
            };
            var newTT2p2 = new EarningPeriod {
                Period = 2, Amount = 1
            };
            var newTT16p1 = new EarningPeriod {
                Period = 1, Amount = 1, DataLockFailures = new List <DataLockFailure> {
                    new DataLockFailure {
                        DataLockError = DataLockErrorCode.DLOCK_03
                    }
                }
            };
            var newTT16p2 = new EarningPeriod {
                Period = 2, Amount = 1
            };

            failureEvent.Ukprn   = 1;
            failureEvent.Learner = new Learner {
                ReferenceNumber = "2", Uln = 3
            };
            failureEvent.LearningAim = new LearningAim
            {
                FrameworkCode   = 4,
                StandardCode    = 5,
                Reference       = "6",
                PathwayCode     = 7,
                ProgrammeType   = 8,
                FundingLineType = "9"
            };
            failureEvent.CollectionYear   = 1819;
            failureEvent.CollectionPeriod = new CollectionPeriod {
                AcademicYear = 7, Period = 8
            };
            failureEvent.OnProgrammeEarnings = new List <OnProgrammeEarning>
            {
                new OnProgrammeEarning
                {
                    Type    = OnProgrammeEarningType.Completion,  // TT2
                    Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod>
                    {
                        // changed to fail
                        newTT2p1,
                        // no change
                        newTT2p2,
                        // change of dlock code
                        newTT2p5,
                        // no change
                        newTT2p6,
                        newTT10p3
                    })
                },
                new OnProgrammeEarning
                {
                    Type    = OnProgrammeEarningType.Balancing,
                    Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod> {
                        newTT3p3
                    })
                }
            };
            failureEvent.IncentiveEarnings = new List <IncentiveEarning>
            {
                new IncentiveEarning
                {
                    Type    = IncentiveEarningType.CareLeaverApprenticePayment,  // TT16
                    Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod>
                    {
                        // changed to fail
                        newTT16p1,
                        // no change
                        newTT16p2,
                        // change of dlock code
                        newTT16p5,
                        // no change
                        newTT16p6,
                    })
                },
                new IncentiveEarning
                {
                    Type    = IncentiveEarningType.Balancing16To18FrameworkUplift,
                    Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod> {
                        newTT10p3
                    })
                }
            };

            var oldFailures = new List <DataLockFailureEntity>
            {
                oldTT2P5,
                oldTT3p3,
                oldTT2p6,
                oldTT16p5,
                oldTT10p3,
                oldTT16p6,
            };

            repositoryMock.Setup(r => r.GetFailures(1, "2", 4, 7, 8, 5, "6", 1819)).ReturnsAsync(oldFailures).Verifiable();
            repositoryMock.Setup(r => r.ReplaceFailures(It.Is <List <long> >(old => old.Count == 4), It.Is <List <DataLockFailureEntity> >(newF => newF.Count == 4), It.IsAny <Guid>(), It.IsAny <Guid>())).Returns(Task.CompletedTask).Verifiable();
            // TT2
            // P1
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, newTT2p1.DataLockFailures)).Returns(DataLockStatusChange.ChangedToFailed).Verifiable();
            // P2
            //dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, newTT2p2.DataLockFailures)).Returns(DataLockStatusChange.NoChange).Verifiable();
            // P5
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT2P5.EarningPeriod.DataLockFailures, newTT2p5.DataLockFailures)).Returns(DataLockStatusChange.FailureChanged).Verifiable();
            // P6
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT2p6.EarningPeriod.DataLockFailures, newTT2p6.DataLockFailures)).Returns(DataLockStatusChange.NoChange).Verifiable();


            // TT3 P3
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT3p3.EarningPeriod.DataLockFailures, newTT3p3.DataLockFailures)).Returns(DataLockStatusChange.ChangedToPassed).Verifiable();

            // TT10 P3
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT10p3.EarningPeriod.DataLockFailures, newTT10p3.DataLockFailures)).Returns(DataLockStatusChange.ChangedToPassed).Verifiable();

            // TT16
            // P1
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, newTT16p1.DataLockFailures)).Returns(DataLockStatusChange.ChangedToFailed).Verifiable();
            // P2
            //dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, newTT16p2.DataLockFailures)).Returns(DataLockStatusChange.NoChange).Verifiable();
            // P5
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT16p5.EarningPeriod.DataLockFailures, newTT16p5.DataLockFailures)).Returns(DataLockStatusChange.FailureChanged).Verifiable();
            // P6
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(oldTT16p6.EarningPeriod.DataLockFailures, newTT16p6.DataLockFailures)).Returns(DataLockStatusChange.NoChange).Verifiable();

            var statusChangedEvents = await processor.ProcessDataLockFailure(failureEvent).ConfigureAwait(false);

            // assert
            statusChangedEvents.Should().NotBeNull();
            statusChangedEvents.Should().HaveCount(3);

            var changedToFail = statusChangedEvents.SingleOrDefault(e => e is DataLockStatusChangedToFailed);

            changedToFail.Should().NotBeNull();

            changedToFail.TransactionTypesAndPeriods.Should().HaveCount(2);
            changedToFail.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.Completion);
            changedToFail.TransactionTypesAndPeriods[TransactionType.Completion].Should().HaveCount(1);
            changedToFail.TransactionTypesAndPeriods[TransactionType.Completion][0].Period.Should().Be(1);

            changedToFail.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.CareLeaverApprenticePayment);
            changedToFail.TransactionTypesAndPeriods[TransactionType.CareLeaverApprenticePayment].Should().HaveCount(1);
            changedToFail.TransactionTypesAndPeriods[TransactionType.CareLeaverApprenticePayment][0].Period.Should().Be(1);


            var changedToPass = statusChangedEvents.SingleOrDefault(e => e is DataLockStatusChangedToPassed);

            changedToPass.Should().NotBeNull();

            changedToPass.TransactionTypesAndPeriods.Should().HaveCount(2);
            changedToPass.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.Balancing);
            changedToPass.TransactionTypesAndPeriods[TransactionType.Balancing].Should().HaveCount(1);
            changedToPass.TransactionTypesAndPeriods[TransactionType.Balancing][0].Period.Should().Be(3);

            changedToPass.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.Balancing16To18FrameworkUplift);
            changedToPass.TransactionTypesAndPeriods[TransactionType.Balancing16To18FrameworkUplift].Should().HaveCount(1);
            changedToPass.TransactionTypesAndPeriods[TransactionType.Balancing16To18FrameworkUplift][0].Period.Should().Be(3);

            var changedCode = statusChangedEvents.SingleOrDefault(e => e is DataLockFailureChanged);

            changedCode.Should().NotBeNull();

            changedCode.TransactionTypesAndPeriods.Should().HaveCount(2);
            changedCode.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.Completion);
            changedCode.TransactionTypesAndPeriods[TransactionType.Completion].Should().HaveCount(1);
            changedCode.TransactionTypesAndPeriods[TransactionType.Completion][0].Period.Should().Be(5);

            changedCode.TransactionTypesAndPeriods.Should().ContainKey(TransactionType.CareLeaverApprenticePayment);
            changedCode.TransactionTypesAndPeriods[TransactionType.CareLeaverApprenticePayment].Should().HaveCount(1);
            changedCode.TransactionTypesAndPeriods[TransactionType.CareLeaverApprenticePayment][0].Period.Should().Be(5);
        }
        public void Arrange()
        {
            _configuration = new Mock <IPaymentsEventsApiConfiguration>();
            _configuration.Setup(m => m.ApiBaseUrl).Returns(ExpectedApiBaseUrl);
            _configuration.Setup(m => m.ClientToken).Returns(ClientToken);
            _dataLockEvent = new DataLockEvent
            {
                Id = 1,
                ProcessDateTime          = new DateTime(2017, 2, 8, 9, 10, 11),
                IlrFileName              = "ILR-123456",
                Ukprn                    = 123456,
                Uln                      = 987654,
                LearnRefNumber           = "Lrn1",
                AimSeqNumber             = 1,
                PriceEpisodeIdentifier   = "25-27-01/05/2017",
                ApprenticeshipId         = 1,
                EmployerAccountId        = 123,
                EventSource              = EventSource.Submission,
                HasErrors                = true,
                IlrStartDate             = new DateTime(2017, 5, 1),
                IlrStandardCode          = 27,
                IlrTrainingPrice         = 12000m,
                IlrEndpointAssessorPrice = 3000m,
                Errors                   = new[]
                {
                    new DataLockEventError
                    {
                        ErrorCode         = "Err15",
                        SystemDescription = "Mismatch on price."
                    }
                },
                Periods = new[]
                {
                    new DataLockEventPeriod
                    {
                        ApprenticeshipVersion = "1-019",
                        Period = new NamedCalendarPeriod
                        {
                            Id    = "1617-R09",
                            Month = 4,
                            Year  = 2017
                        },
                        IsPayable       = false,
                        TransactionType = TransactionType.Learning
                    },
                    new DataLockEventPeriod
                    {
                        ApprenticeshipVersion = "1-019",
                        Period = new NamedCalendarPeriod
                        {
                            Id    = "1617-R10",
                            Month = 5,
                            Year  = 2017
                        },
                        IsPayable = false
                    }
                },
                Apprenticeships = new[]
                {
                    new DataLockEventApprenticeship
                    {
                        Version         = "19",
                        StartDate       = new DateTime(2017, 5, 1),
                        StandardCode    = 27,
                        NegotiatedPrice = 17500m,
                        EffectiveDate   = new DateTime(2017, 5, 1)
                    }
                }
            };

            _httpMessageHandlerMock = SetupHttpMessageHandler(JsonConvert.SerializeObject(
                                                                  new PageOfResults <DataLockEvent>
            {
                PageNumber         = 1,
                TotalNumberOfPages = 2,
                Items = new[]
                {
                    _dataLockEvent
                }
            }));

            // use real http client with mocked handler
            var httpClient = new HttpClient(_httpMessageHandlerMock.Object);

            _client = new Client.PaymentsEventsApiClient(_configuration.Object, httpClient);
        }
        private void AddTypeAndPeriodToEvent(DataLockStatusChanged statusChangedEvent, TransactionType transactionType, EarningPeriod period, DataLockEvent dataLockEvent)
        {
            if (statusChangedEvent is DataLockStatusChangedToPassed)
            {
                if (period.DataLockFailures?.Count > 0)
                {
                    paymentLogger.LogWarning($"DataLockStatusChangedToPassed has data lock failures. EarningPeriod: {JsonConvert.SerializeObject(period)}");
                    return;
                }

                if (!period.ApprenticeshipId.HasValue || !period.ApprenticeshipPriceEpisodeId.HasValue)
                {
                    paymentLogger.LogWarning($"DataLockStatusChangedToPassed has no apprenticeship ID. DataLockEvent: {JsonConvert.SerializeObject(dataLockEvent)}");
                    return;
                }
            }

            if (statusChangedEvent.TransactionTypesAndPeriods.TryGetValue(transactionType, out var periods))
            {
                periods.Add(period);
            }
            else
            {
                statusChangedEvent.TransactionTypesAndPeriods.Add(transactionType, new List <EarningPeriod> {
                    period
                });
            }
        }
        public static CurrentPriceEpisode AssociateWith(this CurrentPriceEpisode priceEpisode, DataLockEvent dlock)
        {
            priceEpisode.Uln         = dlock.Learner.Uln;
            priceEpisode.Ukprn       = dlock.Ukprn;
            priceEpisode.JobId       = dlock.JobId + 1;
            priceEpisode.MessageType = typeof(List <PriceEpisodeStatusChange>).AssemblyQualifiedName;
            priceEpisode.Message     = JsonConvert.SerializeObject(
                new List <PriceEpisodeStatusChange>
            {
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = priceEpisode.PriceEpisodeIdentifier,
                        Status       = PriceEpisodeStatus.New,
                        UKPRN        = dlock.Ukprn,
                        ULN          = dlock.Learner.Uln,
                        AcademicYear = "1920"
                    }
                }
            });

            return(priceEpisode);
        }
        public async Task <List <DataLockStatusChanged> > ProcessDataLockFailure(DataLockEvent dataLockEvent)
        {
            var result          = new List <DataLockStatusChanged>();
            var changedToFailed = new DataLockStatusChangedToFailed
            {
                TransactionTypesAndPeriods = new Dictionary <TransactionType, List <EarningPeriod> >()
            };
            var changedToPassed = new DataLockStatusChangedToPassed
            {
                TransactionTypesAndPeriods = new Dictionary <TransactionType, List <EarningPeriod> >()
            };
            var failureChanged = new DataLockFailureChanged
            {
                TransactionTypesAndPeriods = new Dictionary <TransactionType, List <EarningPeriod> >()
            };
            var failuresToDelete = new List <long>();
            var failuresToRecord = new List <DataLockFailureEntity>();

            var newFailuresGroupedByTypeAndPeriod = GetFailuresGroupedByTypeAndPeriod(dataLockEvent);

            using (var scope = TransactionScopeFactory.CreateSerialisableTransaction())
            {
                var oldFailures = await dataLockFailureRepository.GetFailures(
                    dataLockEvent.Ukprn,
                    dataLockEvent.Learner.ReferenceNumber,
                    dataLockEvent.LearningAim.FrameworkCode,
                    dataLockEvent.LearningAim.PathwayCode,
                    dataLockEvent.LearningAim.ProgrammeType,
                    dataLockEvent.LearningAim.StandardCode,
                    dataLockEvent.LearningAim.Reference,
                    dataLockEvent.CollectionYear
                    ).ConfigureAwait(false);

                var fullListOfKeys = newFailuresGroupedByTypeAndPeriod.Keys
                                     .Concat(oldFailures.Select(f => (f.TransactionType, f.DeliveryPeriod)))
                                     .Distinct()
                                     .ToList();

                foreach (var key in fullListOfKeys)
                {
                    var transactionType = key.Item1;
                    var period          = key.Item2;

                    if (!newFailuresGroupedByTypeAndPeriod.TryGetValue(key, out var newPeriod))
                    {
                        paymentLogger.LogWarning(
                            $"Earning does not have transaction type {transactionType} for period {period} which is present in DataLockFailure. UKPRN {dataLockEvent.Ukprn}, LearnRefNumber: {dataLockEvent.Learner.ReferenceNumber}");
                        continue;
                    }

                    var oldFailureEntity = oldFailures.FirstOrDefault(f =>
                                                                      f.TransactionType == transactionType && f.DeliveryPeriod == period);
                    var oldFailure = oldFailureEntity?.EarningPeriod.DataLockFailures;
                    var newFailure = newPeriod?.DataLockFailures;

                    var statusChange = dataLockStatusService.GetStatusChange(oldFailure, newFailure);

                    switch (statusChange)
                    {
                    case DataLockStatusChange.ChangedToFailed:
                        AddTypeAndPeriodToEvent(changedToFailed, transactionType, newPeriod, dataLockEvent);
                        failuresToRecord.Add(CreateEntity(dataLockEvent, transactionType, period, newPeriod));
                        break;

                    case DataLockStatusChange.ChangedToPassed:
                        AddTypeAndPeriodToEvent(changedToPassed, transactionType, newPeriod, dataLockEvent);
                        failuresToDelete.Add(oldFailureEntity.Id);
                        break;

                    case DataLockStatusChange.FailureChanged:
                        AddTypeAndPeriodToEvent(failureChanged, transactionType, newPeriod, dataLockEvent);
                        failuresToRecord.Add(CreateEntity(dataLockEvent, transactionType, period, newPeriod));
                        failuresToDelete.Add(oldFailureEntity.Id);
                        break;
                    }
                }

                if (changedToFailed.TransactionTypesAndPeriods.Count > 0)
                {
                    result.Add(changedToFailed);
                }

                if (changedToPassed.TransactionTypesAndPeriods.Count > 0)
                {
                    result.Add(changedToPassed);
                }

                if (failureChanged.TransactionTypesAndPeriods.Count > 0)
                {
                    result.Add(failureChanged);
                }

                foreach (var dataLockStatusChanged in result)
                {
                    mapper.Map(dataLockEvent, dataLockStatusChanged);
                }

                await dataLockFailureRepository.ReplaceFailures(failuresToDelete, failuresToRecord,
                                                                dataLockEvent.EarningEventId, dataLockEvent.EventId).ConfigureAwait(false);

                scope.Complete();

                paymentLogger.LogDebug(
                    $"Deleted {failuresToDelete.Count} old DL failures, created {failuresToRecord.Count} new for UKPRN {dataLockEvent.Ukprn} Learner Ref {dataLockEvent.Learner.ReferenceNumber} on R{dataLockEvent.CollectionPeriod.Period:00}");

                return(result);
            }
        }