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