public async Task Build_Period_For_Apprenticeship_And_PriceEpisode(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLockEvent,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            List <ApprenticeshipModel> apprenticeships)
        {
            CommonTestSetup(repository, dataLockEvent, periods, apprenticeships, dataLockFailures);

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLockEvent
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (dataLockEvent.PriceEpisodes[0].Identifier, PriceEpisodeStatus.New)
            },
                new List <PriceEpisodeStatusChange>(), dataLockEvent.CollectionPeriod.AcademicYear);

            result.First().Periods.Should().ContainEquivalentOf(new
            {
                DataLockEventId      = result.First().DataLock.DataLockEventId,
                IsPayable            = false,
                TransactionTypesFlag = 1
            });
        }
        public async Task Builds_an_event_with_errors(
            DataLockErrorCode errorCode,
            string description,
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLock,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            ApprenticeshipModel apprenticeships)
        {
            CommonTestSetup(repository, dataLock, periods, new List <ApprenticeshipModel> {
                apprenticeships
            }, dataLockFailures);
            var priceEpisode = dataLock.PriceEpisodes[0];

            periods[0].DataLockFailures[0].DataLockError = errorCode;

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLock
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (priceEpisode.Identifier, PriceEpisodeStatus.New)
            },
                new List <PriceEpisodeStatusChange>(), dataLock.CollectionPeriod.AcademicYear);

            result.Should().NotBeEmpty();
            result[0].Errors.Should().ContainEquivalentOf(new
            {
                DataLockEventId   = result[0].DataLock.DataLockEventId,
                ErrorCode         = errorCode.ToString(),
                SystemDescription = description,
            });
        }
 private CurrentPriceEpisode CreateCurrentPriceEpisodeFor(EarningFailedDataLockMatching earning)
 {
     return(new CurrentPriceEpisode
     {
         JobId = earning.JobId,
         Ukprn = earning.Ukprn,
         Uln = earning.Learner.Uln,
         PriceEpisodeIdentifier = earning.PriceEpisodes.First().Identifier,
         AgreedPrice = earning.PriceEpisodes.First().AgreedPrice + 1,
         MessageType = typeof(List <PriceEpisodeStatusChange>).AssemblyQualifiedName,
         Message = "[]"
     });
 }
        public async Task Build_PriceEpisode_Removed_Event(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLockEvent,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            List <ApprenticeshipModel> apprenticeships)
        {
            CommonTestSetup(repository, dataLockEvent, periods, apprenticeships, dataLockFailures);
            var episodeStatusChange = new List <PriceEpisodeStatusChange>
            {
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[0].Identifier,
                        Status       = PriceEpisodeStatus.New,
                        UKPRN        = dataLockEvent.Ukprn,
                        ULN          = dataLockEvent.Learner.Uln,
                        AcademicYear = "1920"
                    }
                }
            };

            dataLockEvent.CollectionPeriod.AcademicYear = 1920;

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLockEvent
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (dataLockEvent.PriceEpisodes[0].Identifier, PriceEpisodeStatus.Removed)
            },
                episodeStatusChange, dataLockEvent.CollectionPeriod.AcademicYear);

            result.Should().ContainEquivalentOf(new
            {
                DataLock = new
                {
                    PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[0].Identifier,
                    Status = PriceEpisodeStatus.Removed,
                    UKPRN  = dataLockEvent.Ukprn,
                    ULN    = dataLockEvent.Learner.Uln
                },
            });
        }
        public async Task Build_PriceEpisode_Should_not_have_remove_event_twice(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLockEvent,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            List <ApprenticeshipModel> apprenticeships)
        {
            CommonTestSetup(repository, dataLockEvent, periods, apprenticeships, dataLockFailures);

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLockEvent
            },
                new List <(string identifier, PriceEpisodeStatus status)>(),
                new List <PriceEpisodeStatusChange>(), dataLockEvent.CollectionPeriod.AcademicYear);

            result.Should().BeEmpty();
        }
        public async Task StoreValidOnprogNonPayableDataLockEvents(
            IReceivedDataLockEventStore receivedDataLockEventStore,
            EarningFailedDataLockMatching nonPayableEarningEvent,
            List <EarningPeriod> periods,
            ApprenticeshipModel apprenticeship,
            List <DataLockFailure> dataLockFailures,
            ManageReceivedDataLockEvent manageReceivedDataLockEvent)
        {
            CommonTestSetup(nonPayableEarningEvent, periods, apprenticeship, dataLockFailures);
            await manageReceivedDataLockEvent.ProcessDataLockEvent(nonPayableEarningEvent);

            var result = (await receivedDataLockEventStore
                          .GetDataLocks(nonPayableEarningEvent.JobId, nonPayableEarningEvent.Ukprn)).ToList();

            result.Should().NotBeNull();
            result.Should().HaveCount(1);
            result[0].MessageType.Should().Be(nonPayableEarningEvent.GetType().AssemblyQualifiedName);
            result[0].Message.Should().Be(nonPayableEarningEvent.ToJson());
        }
        public async Task OnprogNonPayableDataLockEventWithNoApprenticeshipIdShouldNotBeStored(
            IReceivedDataLockEventStore receivedDataLockEventStore,
            EarningFailedDataLockMatching nonPayableEarningEvent,
            EarningPeriod period,
            ApprenticeshipModel apprenticeship,
            List <DataLockFailure> dataLockFailures,
            ManageReceivedDataLockEvent manageReceivedDataLockEvent)
        {
            period.ApprenticeshipId = default(long?);
            period.AccountId        = default(long?);
            period.DataLockFailures = new List <DataLockFailure>
            {
                new DataLockFailure
                {
                    DataLockError = DataLockErrorCode.DLOCK_01
                }
            };

            nonPayableEarningEvent.OnProgrammeEarnings = new List <OnProgrammeEarning>
            {
                new OnProgrammeEarning
                {
                    Periods = (new List <EarningPeriod>
                    {
                        period
                    }).AsReadOnly(),
                    Type       = OnProgrammeEarningType.Learning,
                    CensusDate = DateTime.UtcNow
                }
            };

            await manageReceivedDataLockEvent.ProcessDataLockEvent(nonPayableEarningEvent);

            var result = (await receivedDataLockEventStore
                          .GetDataLocks(nonPayableEarningEvent.JobId, nonPayableEarningEvent.Ukprn)).ToList();

            result.Should().BeEmpty();
        }
        public async Task Built_event_should_have_distinct_errors(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLock,
            EarningPeriod period,
            ApprenticeshipModel apprenticeships)
        {
            var periods = new List <EarningPeriod> {
                period
            };

            var dLockFailures = new List <DataLockFailure>
            {
                new DataLockFailure
                {
                    ApprenticeshipId = apprenticeships.Id,
                    DataLockError    = DataLockErrorCode.DLOCK_03,
                    ApprenticeshipPriceEpisodeIds = new List <long> {
                        apprenticeships.ApprenticeshipPriceEpisodes[0].Id
                    }
                },
                new DataLockFailure
                {
                    ApprenticeshipId = apprenticeships.Id,
                    DataLockError    = DataLockErrorCode.DLOCK_07,
                    ApprenticeshipPriceEpisodeIds = apprenticeships.ApprenticeshipPriceEpisodes.Select(x => x.Id).ToList(),
                },
                new DataLockFailure
                {
                    ApprenticeshipId = apprenticeships.Id,
                    DataLockError    = DataLockErrorCode.DLOCK_06,
                    ApprenticeshipPriceEpisodeIds = apprenticeships.ApprenticeshipPriceEpisodes.Select(x => x.Id).ToList(),
                },
            };

            dataLock.OnProgrammeEarnings = new List <OnProgrammeEarning>
            {
                new OnProgrammeEarning
                {
                    Type = OnProgrammeEarningType.Learning,
                },
                new OnProgrammeEarning
                {
                    Type = OnProgrammeEarningType.Completion,
                }
            };

            CommonTestSetup(repository, dataLock, periods, new List <ApprenticeshipModel> {
                apprenticeships
            }, dLockFailures);


            var priceEpisode = dataLock.PriceEpisodes[0];

            dataLock.OnProgrammeEarnings[1].Periods = periods.AsReadOnly();


            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLock
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (priceEpisode.Identifier, PriceEpisodeStatus.New)
            },
                new List <PriceEpisodeStatusChange>(), dataLock.CollectionPeriod.AcademicYear);

            result.Should().NotBeEmpty();
            result[0].Errors.Should().HaveCount(3);
            result[0].Errors.Should().BeEquivalentTo(new List <LegacyDataLockEventError>
            {
                new LegacyDataLockEventError
                {
                    DataLockEventId = result[0].DataLock.DataLockEventId,
                    ErrorCode       = DataLockErrorCode.DLOCK_03.ToString(),
                },
                new LegacyDataLockEventError
                {
                    DataLockEventId = result[0].DataLock.DataLockEventId,
                    ErrorCode       = DataLockErrorCode.DLOCK_07.ToString(),
                },
                new LegacyDataLockEventError
                {
                    DataLockEventId = result[0].DataLock.DataLockEventId,
                    ErrorCode       = DataLockErrorCode.DLOCK_06.ToString(),
                },
            }, options => options.Excluding(o => o.SystemDescription));
        }
        public async Task Build_Should_Generate_Update_Event_For_Previous_AcademicYear_PriceEpisode(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLockEvent1920,
            EarningFailedDataLockMatching dataLockEvent2021,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            List <ApprenticeshipModel> apprenticeships)
        {
            CommonTestSetup(repository, dataLockEvent1920, periods, apprenticeships, dataLockFailures);
            CommonTestSetup(repository, dataLockEvent2021, periods, apprenticeships, dataLockFailures);

            apprenticeships.RemoveRange(1, 2);

            var episodeStatusChange = new List <PriceEpisodeStatusChange>
            {
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent1920.PriceEpisodes[0].Identifier,
                        Status       = PriceEpisodeStatus.New,
                        UKPRN        = dataLockEvent1920.Ukprn,
                        ULN          = dataLockEvent1920.Learner.Uln,
                        AcademicYear = "1920"
                    }
                },
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent1920.PriceEpisodes[1].Identifier,
                        Status       = PriceEpisodeStatus.Updated,
                        UKPRN        = dataLockEvent1920.Ukprn,
                        ULN          = dataLockEvent1920.Learner.Uln,
                        AcademicYear = "1920"
                    }
                },
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent2021.PriceEpisodes[0].Identifier,
                        Status       = PriceEpisodeStatus.Updated,
                        UKPRN        = dataLockEvent2021.Ukprn,
                        ULN          = dataLockEvent2021.Learner.Uln,
                        AcademicYear = "2021"
                    }
                }
            };

            dataLockEvent1920.CollectionPeriod.AcademicYear = 1920;
            dataLockEvent2021.CollectionPeriod.AcademicYear = 2021;

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLockEvent1920, dataLockEvent2021
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (dataLockEvent1920.PriceEpisodes[0].Identifier, PriceEpisodeStatus.Removed),
                (dataLockEvent1920.PriceEpisodes[1].Identifier, PriceEpisodeStatus.Removed),
                (dataLockEvent2021.PriceEpisodes[0].Identifier, PriceEpisodeStatus.Removed)
            },
                episodeStatusChange, dataLockEvent2021.CollectionPeriod.AcademicYear);

            result.Count.Should().Be(3);
            result.Select(s => s.DataLock).Any(x =>
                                               x.PriceEpisodeIdentifier == dataLockEvent1920.PriceEpisodes[0].Identifier &&
                                               x.Status == PriceEpisodeStatus.Updated &&
                                               x.UKPRN == dataLockEvent1920.Ukprn &&
                                               x.ULN == dataLockEvent1920.Learner.Uln &&
                                               x.AcademicYear == "1920"
                                               ).Should().BeTrue();

            result.Select(s => s.DataLock).Any(x =>
                                               x.PriceEpisodeIdentifier == dataLockEvent1920.PriceEpisodes[1].Identifier &&
                                               x.Status == PriceEpisodeStatus.Updated &&
                                               x.UKPRN == dataLockEvent1920.Ukprn &&
                                               x.ULN == dataLockEvent1920.Learner.Uln &&
                                               x.AcademicYear == "1920"
                                               ).Should().BeTrue();

            result.Select(s => s.DataLock).Any(x =>
                                               x.PriceEpisodeIdentifier == dataLockEvent2021.PriceEpisodes[0].Identifier &&
                                               x.Status == PriceEpisodeStatus.Removed &&
                                               x.UKPRN == dataLockEvent2021.Ukprn &&
                                               x.ULN == dataLockEvent2021.Learner.Uln &&
                                               x.AcademicYear == "2021"
                                               ).Should().BeTrue();
        }
        public async Task Build_Should_Not_Generate_Remove_Event_For_Previous_AcademicYear_PriceEpisode(
            [Frozen] Mock <IApprenticeshipRepository> repository,
            PriceEpisodeStatusChangeBuilder sut,
            EarningFailedDataLockMatching dataLockEvent,
            List <EarningPeriod> periods,
            List <DataLockFailure> dataLockFailures,
            List <ApprenticeshipModel> apprenticeships)
        {
            CommonTestSetup(repository, dataLockEvent, periods, apprenticeships, dataLockFailures);
            var episodeStatusChange = new List <PriceEpisodeStatusChange>
            {
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[0].Identifier,
                        Status       = PriceEpisodeStatus.New,
                        UKPRN        = dataLockEvent.Ukprn,
                        ULN          = dataLockEvent.Learner.Uln,
                        AcademicYear = "1920"
                    }
                },
                new PriceEpisodeStatusChange
                {
                    DataLock = new LegacyDataLockEvent
                    {
                        PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[1].Identifier,
                        Status       = PriceEpisodeStatus.New,
                        UKPRN        = dataLockEvent.Ukprn,
                        ULN          = dataLockEvent.Learner.Uln,
                        AcademicYear = "2021"
                    }
                }
            };

            dataLockEvent.CollectionPeriod.AcademicYear = 2021;

            var result = await sut.Build(
                new List <DataLockEvent> {
                dataLockEvent
            },
                new List <(string identifier, PriceEpisodeStatus status)>
            {
                (dataLockEvent.PriceEpisodes[0].Identifier, PriceEpisodeStatus.Removed),
                (dataLockEvent.PriceEpisodes[1].Identifier, PriceEpisodeStatus.Removed)
            },
                episodeStatusChange, dataLockEvent.CollectionPeriod.AcademicYear);

            result.Count.Should().Be(2);
            result.Select(s => s.DataLock).Should().BeEquivalentTo(new
            {
                PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[0].Identifier,
                Status       = PriceEpisodeStatus.Updated,
                UKPRN        = dataLockEvent.Ukprn,
                ULN          = dataLockEvent.Learner.Uln,
                AcademicYear = "1920"
            }, new
            {
                PriceEpisodeIdentifier = dataLockEvent.PriceEpisodes[1].Identifier,
                Status       = PriceEpisodeStatus.Removed,
                UKPRN        = dataLockEvent.Ukprn,
                ULN          = dataLockEvent.Learner.Uln,
                AcademicYear = "2021"
            });
        }
        public async Task TestDataLockStatusChangedToPassedWithNonPayablePeriods()
        {
            // arrange
            var dataLockEvent = new EarningFailedDataLockMatching()
            {
                Ukprn   = 1,
                Learner = new Learner {
                    ReferenceNumber = "2", Uln = 3
                },
                LearningAim = new LearningAim
                {
                    FrameworkCode   = 4, StandardCode = 5, Reference = "6", PathwayCode = 7, ProgrammeType = 8,
                    FundingLineType = "9"
                },
                CollectionYear   = 1819,
                CollectionPeriod = new CollectionPeriod {
                    AcademicYear = 7, Period = 8
                },
                OnProgrammeEarnings = new List <OnProgrammeEarning>
                {
                    new OnProgrammeEarning
                    {
                        Type    = OnProgrammeEarningType.Learning,
                        Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod>
                        {
                            new EarningPeriod {
                                Period = 1, Amount = 0m, DataLockFailures = null
                            },
                            new EarningPeriod
                            {
                                Period = 2, Amount = 0m, ApprenticeshipId = null, ApprenticeshipPriceEpisodeId = null,
                                PriceEpisodeIdentifier = string.Empty, DataLockFailures = null
                            },
                            new EarningPeriod
                            {
                                Period = 3,
                                Amount = 1m,
                                PriceEpisodeIdentifier       = "pe-1",
                                ApprenticeshipId             = 5,
                                ApprenticeshipPriceEpisodeId = 12
                            }
                        })
                    }
                },
                IncentiveEarnings = new List <IncentiveEarning>()
                {
                    new IncentiveEarning
                    {
                        Type    = IncentiveEarningType.Balancing16To18FrameworkUplift,
                        Periods = new ReadOnlyCollection <EarningPeriod>(new List <EarningPeriod>
                        {
                            new EarningPeriod {
                                Period = 1, Amount = 0m, DataLockFailures = null
                            },
                            new EarningPeriod
                            {
                                Period = 2, Amount = 0m, PriceEpisodeIdentifier = " ", ApprenticeshipId = null,
                                ApprenticeshipPriceEpisodeId = null
                            },
                            new EarningPeriod
                            {
                                Period = 3, Amount = 0m, PriceEpisodeIdentifier = string.Empty, ApprenticeshipId = null,
                                ApprenticeshipPriceEpisodeId = null
                            }
                        })
                    }
                }
            };

            var dbFailures = new List <DataLockFailureEntity>
            {
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Learning, DeliveryPeriod = 1, EarningPeriod = new EarningPeriod()
                },
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Learning, DeliveryPeriod = 2, EarningPeriod = new EarningPeriod()
                },
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Learning, DeliveryPeriod = 3, EarningPeriod = new EarningPeriod()
                },
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Balancing16To18FrameworkUplift, DeliveryPeriod = 1, EarningPeriod = new EarningPeriod()
                },
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Balancing16To18FrameworkUplift, DeliveryPeriod = 2, EarningPeriod = new EarningPeriod()
                },
                new DataLockFailureEntity {
                    Id = 100, TransactionType = TransactionType.Balancing16To18FrameworkUplift, DeliveryPeriod = 3, EarningPeriod = new EarningPeriod()
                },
            };

            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 == 1), It.Is <List <DataLockFailureEntity> >(newF => newF.Count == 0), It.IsAny <Guid>(), It.IsAny <Guid>())).Returns(Task.CompletedTask).Verifiable();
            dataLockStatusServiceMock.Setup(s => s.GetStatusChange(null, dataLockEvent.OnProgrammeEarnings[0].Periods[0].DataLockFailures)).Returns(DataLockStatusChange.ChangedToPassed).Verifiable();

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

            // assert
            statusChangedEvents.Should().NotBeNull();
            statusChangedEvents.Should().HaveCount(1);
            statusChangedEvents[0].Should().BeOfType <DataLockStatusChangedToPassed>();
            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(3);
        }