private string FindPriceEpisodeIdentifier(decimal value, Earning earning, FM36Learner fm36Learner, TransactionType transactionType)
        {
            // null for 0 values
            if (value == 0)
            {
                return(null);
            }

            // it could be specified in earnings table
            if (earning.PriceEpisodeIdentifier != null)
            {
                return(earning.PriceEpisodeIdentifier);
            }

            // find first price episode with non-zero value for a period
            var period = earning.DeliveryCalendarPeriod;

            earning.PriceEpisodeIdentifier = fm36Learner.PriceEpisodes
                                             .SingleOrDefault(pe => pe.PriceEpisodePeriodisedValues
                                                              .Any(pepv => pepv.GetValue(period).GetValueOrDefault(0) != 0 &&
                                                                   pepv.AttributeName == transactionType.ToAttributeName()))?
                                             .PriceEpisodeIdentifier;

            return(earning.PriceEpisodeIdentifier);
        }
        public void SetUp()
        {
            mocker                 = AutoMock.GetStrict();
            validatorMock          = mocker.Mock <ILearnerValidator>();
            actBuilder             = mocker.Mock <IApprenticeshipContractTypeEarningsEventBuilder>();
            functionalSkillBuilder = mocker.Mock <IFunctionalSkillEarningsEventBuilder>();
            validatorMock          = mocker.Mock <ILearnerValidator>();
            configurationHelper    = mocker.Mock <IConfigurationHelper>();

            configurationHelper
            .Setup(x => x.HasSetting("Settings", "DoNotGenerateACT1TransactionType4To16Payments"))
            .Returns(true);

            configurationHelper
            .Setup(x => x.GetSetting("Settings", "DoNotGenerateACT1TransactionType4To16Payments"))
            .Returns("false");

            configurationHelper
            .Setup(x => x.HasSetting("Settings", "DoNotGenerateACT2Payments"))
            .Returns(true);

            configurationHelper
            .Setup(x => x.GetSetting("Settings", "DoNotGenerateACT2Payments"))
            .Returns("false");

            validatorMock.Setup(x => x.Validate(It.IsAny <FM36Learner>())).Returns(new ValidationResult(new List <ValidationRuleResult>()));
            learner = new FM36Learner();
        }
Exemplo n.º 3
0
        public void ValidationPassesIfThereAreMultiplePriceEpisodes()
        {
            var learner = new FM36Learner
            {
                PriceEpisodes = new List <PriceEpisode>
                {
                    new PriceEpisode
                    {
                        PriceEpisodeIdentifier = "pe-1",
                        PriceEpisodeValues     = new PriceEpisodeValues
                        {
                            EpisodeStartDate           = DateTime.Today.AddMonths(-2),
                            PriceEpisodePlannedEndDate = DateTime.Today,
                            PriceEpisodeActualEndDate  = DateTime.Today.AddDays(-36)
                        }
                    },
                    new PriceEpisode
                    {
                        PriceEpisodeIdentifier = "pe-2",
                        PriceEpisodeValues     = new PriceEpisodeValues
                        {
                            EpisodeStartDate           = DateTime.Today.AddDays(-35),
                            PriceEpisodePlannedEndDate = DateTime.Today,
                        }
                    }
                }
            };

            var rule   = new OverlappingPriceEpisodeValidationRule();
            var result = rule.IsValid(learner);

            Assert.IsFalse(result.Failed);
        }
Exemplo n.º 4
0
        public void Validation_Fails_If_There_Are_Overlapping_Price_Episodes()
        {
            var learner = new FM36Learner
            {
                PriceEpisodes = new List <PriceEpisode>
                {
                    new PriceEpisode
                    {
                        PriceEpisodeIdentifier = "pe-1",
                        PriceEpisodeValues     = new PriceEpisodeValues
                        {
                            EpisodeStartDate           = DateTime.Today.AddMonths(-2),
                            PriceEpisodePlannedEndDate = DateTime.Today.AddDays(-30),
                            PriceEpisodeActualEndDate  = DateTime.Today.AddDays(-30)
                        }
                    },
                    new PriceEpisode
                    {
                        PriceEpisodeIdentifier = "pe-2",
                        PriceEpisodeValues     = new PriceEpisodeValues
                        {
                            EpisodeStartDate           = DateTime.Today.AddDays(-35),
                            PriceEpisodePlannedEndDate = DateTime.Today,
                        }
                    }
                }
            };

            var rule   = new OverlappingPriceEpisodeValidationRule();
            var result = rule.IsValid(learner);

            Assert.IsTrue(result.Failed, result.FailureReason);
        }
Exemplo n.º 5
0
 public AppsMonthlyPaymentModel BuildModel(ILearner learner, FM36Learner learnerData)
 {
     return(new AppsMonthlyPaymentModel()
     {
         LearnerReferenceNumber = learner.LearnRefNumber,
         UniqueLearnerNumber = learner.ULN
     });
 }
Exemplo n.º 6
0
 public AEC_Learner BuildLearner(FM36Learner fm36Learner, int ukprn, string learnRefNumber)
 {
     return(new AEC_Learner
     {
         UKPRN = ukprn,
         LearnRefNumber = learnRefNumber,
         ULN = fm36Learner.ULN
     });
 }
Exemplo n.º 7
0
        public void TestAct1EarningIsDetected()
        {
            // arrange
            var fm36Learner = new FM36Learner
            {
                PriceEpisodes = new List <PriceEpisode>()
                {
                    new PriceEpisode
                    {
                        PriceEpisodeIdentifier = "1",
                        PriceEpisodeValues     = new PriceEpisodeValues
                        {
                            PriceEpisodeContractType = "Non-Levy Contract",
                            EpisodeStartDate         = new DateTime(2018, 8, 6),
                            PriceEpisodeAimSeqNumber = 4
                        },
                        PriceEpisodePeriodisedValues = new List <PriceEpisodePeriodisedValues>()
                    }
                },
                LearningDeliveries = new List <LearningDelivery>
                {
                    new LearningDelivery
                    {
                        AimSeqNumber           = 4,
                        LearningDeliveryValues = new LearningDeliveryValues
                        {
                            LearnAimRef = "ld1"
                        }
                    }
                }
            };

            var processLearnerCommand = new ProcessLearnerCommand
            {
                Learner               = fm36Learner,
                CollectionYear        = 1819,
                Ukprn                 = 12345,
                JobId                 = 69,
                CollectionPeriod      = 1,
                IlrSubmissionDateTime = DateTime.UtcNow,
                SubmissionDate        = DateTime.UtcNow
            };

            var learningAim = new IntermediateLearningAim(processLearnerCommand, fm36Learner.PriceEpisodes, fm36Learner.LearningDeliveries);

            // act
            var earningEvent = mapper.Map <IntermediateLearningAim, ApprenticeshipContractType1EarningEvent>(learningAim);

            // assert
            earningEvent.PriceEpisodes.Single().Identifier.Should().Be("1");
        }
Exemplo n.º 8
0
 private static ProcessLearnerCommand Build(FM36Learner learner, long jobId, DateTime ilrSubmissionDateTime, short academicYear, int collectionPeriod, long ukprn, string fileName)
 {
     return(new ProcessLearnerCommand
     {
         JobId = jobId,
         Learner = learner,
         RequestTime = DateTimeOffset.UtcNow,
         IlrSubmissionDateTime = ilrSubmissionDateTime,
         IlrFileName = fileName,
         CollectionYear = academicYear,
         CollectionPeriod = collectionPeriod,
         Ukprn = ukprn
     });
 }
        public void Condense()
        {
            var learnerOne   = new FM36Learner();
            var learnerTwo   = new FM36Learner();
            var learnerThree = new FM36Learner();
            var learnerFour  = new FM36Learner();
            var learnerFive  = new FM36Learner();
            var learnerSix   = new FM36Learner();

            var globalOne = new FM36Global()
            {
                Learners = new List <FM36Learner>()
                {
                    learnerOne,
                    learnerTwo,
                },
            };

            var globalTwo = new FM36Global()
            {
                Learners = new List <FM36Learner>
                {
                    learnerThree,
                    learnerFour,
                },
            };

            var globalThree = new FM36Global()
            {
                Learners = new List <FM36Learner>
                {
                    learnerFive,
                    learnerSix,
                },
            };

            var fundingOutputs = new List <FM36Global>()
            {
                globalOne,
                globalTwo,
                globalThree,
            };

            var fundingOutput = NewService().Condense(fundingOutputs);

            fundingOutput.Should().Be(globalOne);
            fundingOutput.Learners.Should().HaveCount(6);
            fundingOutput.Learners.Should().Contain(new[] { learnerOne, learnerTwo, learnerThree, learnerFour, learnerFive, learnerSix });
        }
Exemplo n.º 10
0
 public ValidationRuleResult IsValid(FM36Learner learner)
 {
     foreach (var priceEpisode in learner.PriceEpisodes)
     {
         var overlappingPriceEpisode = learner.PriceEpisodes
                                       .Where(pe => pe != priceEpisode)
                                       .FirstOrDefault(pe =>
                                                       (priceEpisode.PriceEpisodeValues.PriceEpisodeActualEndDate ?? priceEpisode.PriceEpisodeValues.PriceEpisodePlannedEndDate) > pe.PriceEpisodeValues?.EpisodeStartDate &&
                                                       priceEpisode.PriceEpisodeValues.EpisodeStartDate < (pe.PriceEpisodeValues.PriceEpisodeActualEndDate ?? pe.PriceEpisodeValues?.PriceEpisodePlannedEndDate));
         if (overlappingPriceEpisode != null)
         {
             return(ValidationRuleResult.Failure($"Found overlapping price episodes.  Price Episode {priceEpisode.PriceEpisodeIdentifier} overlapped with price episode {overlappingPriceEpisode.PriceEpisodeIdentifier}."));
         }
     }
     return(ValidationRuleResult.Ok());
 }
 protected IntermediateLearningAim(
     FM36Learner learner,
     LearningDelivery aim,
     IEnumerable <PriceEpisode> priceEpisodes,
     long ukprn,
     short collectionYear,
     int collectionPeriod,
     DateTime ilrSubmissionDateTime,
     string ilrFileName,
     long jobId)
 {
     Aim     = aim;
     Learner = learner;
     PriceEpisodes.AddRange(FilterPriceEpisodes(priceEpisodes, collectionYear));
     Ukprn                 = ukprn;
     AcademicYear          = collectionYear;
     CollectionPeriod      = collectionPeriod;
     IlrSubmissionDateTime = ilrSubmissionDateTime;
     IlrFileName           = ilrFileName;
     JobId                 = jobId;
 }
        protected FM36Learner CreateFM36Learner(TestSession session, Learner testLearner, DateTime startDate)
        {
            var learner = new FM36Learner {
                LearnRefNumber = testLearner.LearnRefNumber, ULN = testLearner.Uln
            };
            var priceEpisode = new ESFA.DC.ILR.FundingService.FM36.FundingOutput.Model.Output.PriceEpisode
            {
                PriceEpisodeIdentifier = "pe-1",
                PriceEpisodeValues     = new PriceEpisodeValues
                {
                    EpisodeStartDate              = startDate,
                    EpisodeEffectiveTNPStartDate  = startDate,
                    PriceEpisodeCompletionElement = 3000,
                    PriceEpisodeCompleted         = false,
                    PriceEpisodeTotalTNPPrice     = 15000,
                    TNP1 = 9000,
                    TNP2 = 6000,
                    PriceEpisodeInstalmentValue    = 1000,
                    PriceEpisodePlannedInstalments = 12,
                    PriceEpisodeActualInstalments  = null,
                    PriceEpisodeBalancePayment     = 0,
                    PriceEpisodeFundLineType       = testLearner.Course.FundingLineType,
                    PriceEpisodeBalanceValue       = 0,
                    PriceEpisodeCompletionPayment  = 3000,
                    PriceEpisodeContractType       = testLearner.IsLevyLearner ? "Levy Contract" : "Non-Levy Contract",
                    PriceEpisodeOnProgPayment      = 1000,
                    PriceEpisodePlannedEndDate     = startDate.AddMonths(12),
                    PriceEpisodeAimSeqNumber       = 1,
                    PriceEpisodeCumulativePMRs     = int.MaxValue
                },
                PriceEpisodePeriodisedValues = new List <PriceEpisodePeriodisedValues>()
            };

            var learningValues = new PriceEpisodePeriodisedValues
            {
                AttributeName = "PriceEpisodeOnProgPayment",
            };

            Enumerable.Range(1, 12).ToList().ForEach(i => SetPeriodValue(i, learningValues, 1000));
            var completionEarnings = new PriceEpisodePeriodisedValues
            {
                AttributeName = "PriceEpisodeCompletionPayment",
            };

            SetPeriodValue(12, completionEarnings, 3000);
            var balancingEarnings = new PriceEpisodePeriodisedValues
            {
                AttributeName = "PriceEpisodeBalancePayment",
            };

            var sfaContributionValues = new PriceEpisodePeriodisedValues
            {
                AttributeName = "PriceEpisodeSFAContribPct"
            };

            Enumerable.Range(1, 12).ToList().ForEach(i => SetPeriodValue(i, sfaContributionValues, .9M));

            learner.PriceEpisodes = new List <PriceEpisode>(new[] { priceEpisode });
            priceEpisode.PriceEpisodePeriodisedValues.Add(learningValues);
            priceEpisode.PriceEpisodePeriodisedValues.Add(completionEarnings);
            priceEpisode.PriceEpisodePeriodisedValues.Add(balancingEarnings);
            priceEpisode.PriceEpisodePeriodisedValues.Add(sfaContributionValues);

            learner.LearningDeliveries = new List <LearningDelivery>(new[]
            {
                new LearningDelivery
                {
                    AimSeqNumber           = 1,
                    LearningDeliveryValues = new LearningDeliveryValues
                    {
                        LearnStartDate = startDate,
                        LearnDelInitialFundLineType = testLearner.Course.FundingLineType,
                        PwayCode    = testLearner.Course.PathwayCode,
                        FworkCode   = testLearner.Course.FrameworkCode,
                        ProgType    = testLearner.Course.ProgrammeType,
                        StdCode     = testLearner.Course.StandardCode,
                        LearnAimRef = testLearner.Course.LearnAimRef,
                    }
                }
            });
            return(learner);
        }
 private List <EarningPeriod> GetEarningPeriods(List <Earning> aimEarningSpecs, Aim aimSpec, ApprenticeshipContractTypeEarningsEvent onProgEarning, TransactionType tt, FM36Learner fm36Learner)
 {
     return(aimEarningSpecs
            .Select(e => new EarningPeriod
     {
         Amount = PriceEpisodeContractTypeMatchesAim(aimSpec.PriceEpisodes, e.PriceEpisodeIdentifier, onProgEarning) ? e.Values[tt] : 0M,
         Period = e.DeliveryCalendarPeriod,
         PriceEpisodeIdentifier = FindPriceEpisodeIdentifier(e.Values[tt], e, fm36Learner, tt)
     })
            .Where(p => p.Period <= collectionPeriod.Period)
            .OrderBy(p => p.Period)
            .ToList());
 }
        private List <FunctionalSkillEarningsEvent> CreateFunctionalSkillEarningEvents(List <TransactionType> functionalSkillEarnings,
                                                                                       List <Earning> aimEarningSpecs, FM36Learner fm36Learner, Learner learner, LearningAim learningAim, Aim aimSpec)
        {
            var contractTypes = EnumHelper.GetContractTypes(currentIlr, currentPriceEpisodes);

            var events = new List <FunctionalSkillEarningsEvent>();

            contractTypes?.ForEach(c =>
            {
                switch (c)
                {
                case ContractType.Act1:
                    events.Add(new Act1FunctionalSkillEarningsEvent
                    {
                        CollectionPeriod = collectionPeriod,
                        Ukprn            = provider.Ukprn,
                        Earnings         = functionalSkillEarnings.Select(tt => new FunctionalSkillEarning
                        {
                            Type    = (FunctionalSkillType)(int)tt,
                            Periods = aimEarningSpecs.Select(e => new EarningPeriod
                            {
                                Amount = e.Values[tt],
                                Period = e.DeliveryCalendarPeriod,
                                PriceEpisodeIdentifier = FindPriceEpisodeIdentifier(e.Values[tt], e, fm36Learner, tt)
                            }).ToList().AsReadOnly()
                        }).ToList().AsReadOnly(),
                        JobId       = provider.JobId,
                        Learner     = learner,
                        LearningAim = learningAim
                    });
                    break;

                case ContractType.Act2:
                    events.Add(new Act2FunctionalSkillEarningsEvent
                    {
                        CollectionPeriod = collectionPeriod,
                        Ukprn            = provider.Ukprn,
                        Earnings         = functionalSkillEarnings.Select(tt => new FunctionalSkillEarning
                        {
                            Type    = (FunctionalSkillType)(int)tt,
                            Periods = aimEarningSpecs.Select(e => new EarningPeriod
                            {
                                Amount = e.Values[tt],
                                Period = e.DeliveryCalendarPeriod,
                                PriceEpisodeIdentifier = FindPriceEpisodeIdentifier(e.Values[tt], e, fm36Learner, tt)
                            }).ToList().AsReadOnly()
                        }).ToList().AsReadOnly(),
                        JobId       = provider.JobId,
                        Learner     = learner,
                        LearningAim = learningAim
                    });
                    break;

                default:
                    throw new InvalidOperationException(
                        "Cannot create the EarningEventMatcher invalid contract type ");
                }
            });


            events.ForEach(x => x.LearningAim.FundingLineType = aimSpec.FundingLineType);

            return(events);
        }
        public IEnumerable <AppsIndicativeEarningsReportModel> Build(IReportServiceContext reportServiceContext, IReportServiceDependentData reportServiceDependentData)
        {
            var message  = reportServiceDependentData.Get <IMessage>();
            var fm36Data = reportServiceDependentData.Get <FM36Global>();
            var appsIndicativeEarningsModels = new List <AppsIndicativeEarningsReportModel>();
            var referenceData = reportServiceDependentData.Get <ReferenceDataRoot>();
            IDictionary <string, LARSLearningDelivery> larsLearningDeliveries = BuildLarsLearningDeliveryDictionary(referenceData);
            IDictionary <int, LARSStandard>            larsStandards          = BuildLarsStandardDictionary(referenceData);
            IDictionary <string, FM36Learner>          fm36Learners           = BuildFm36LearnerDeliveryDictionary(fm36Data);

            foreach (var learner in message?.Learners?.Where(l => l != null) ?? Enumerable.Empty <ILearner>())
            {
                FM36Learner fm36Learner = fm36Learners.GetValueOrDefault(learner.LearnRefNumber);

                foreach (var learningDelivery in learner.LearningDeliveries ?? Enumerable.Empty <ILearningDelivery>())
                {
                    if (learningDelivery.FundModel != FundModelConstants.FM36)
                    {
                        continue;
                    }

                    LARSLearningDelivery larsDelivery         = larsLearningDeliveries.GetValueOrDefault(learningDelivery.LearnAimRef);
                    LearningDelivery     fm36LearningDelivery = fm36Learner?.LearningDeliveries?.FirstOrDefault(x => x.AimSeqNumber == learningDelivery.AimSeqNumber);
                    string larsStandard = null;

                    if (learningDelivery.StdCodeNullable != null)
                    {
                        larsStandard = larsStandards.GetValueOrDefault(learningDelivery.StdCodeNullable.Value)?.NotionalEndLevel ?? "NA";
                    }

                    if (fm36Learner?.PriceEpisodes.Any() ?? false)
                    {
                        List <PriceEpisode> episodesInRange = fm36Learner.PriceEpisodes
                                                              .Where(p => p.PriceEpisodeValues.EpisodeStartDate >= ReportingConstants.BeginningOfYear &&
                                                                     p.PriceEpisodeValues.EpisodeStartDate <= ReportingConstants.EndOfYear &&
                                                                     learningDelivery.AimSeqNumber == p.PriceEpisodeValues.PriceEpisodeAimSeqNumber)
                                                              .ToList();

                        if (episodesInRange.Any())
                        {
                            DateTime earliestEpisodeDate = episodesInRange.Select(x => x.PriceEpisodeValues.EpisodeStartDate ?? DateTime.MaxValue).Min();

                            foreach (PriceEpisode episodeAttribute in episodesInRange)
                            {
                                appsIndicativeEarningsModels.Add(BuildLineModel(learner,
                                                                                learningDelivery,
                                                                                fm36LearningDelivery,
                                                                                episodeAttribute,
                                                                                larsDelivery,
                                                                                larsStandard,
                                                                                episodeAttribute.PriceEpisodeValues.EpisodeStartDate == earliestEpisodeDate,
                                                                                true));
                            }
                            continue;
                        }
                    }

                    appsIndicativeEarningsModels.Add(BuildLineModel(learner,
                                                                    learningDelivery,
                                                                    fm36LearningDelivery,
                                                                    null,
                                                                    larsDelivery,
                                                                    larsStandard,
                                                                    false,
                                                                    false));
                }
            }

            return(appsIndicativeEarningsModels
                   .OrderBy(x => x.LearnRefNumber)
                   .ThenByDescending(x => x.AimSeqNumber)
                   .ThenByDescending(x => x.PriceEpisodeStartDate));
        }
Exemplo n.º 16
0
        private async Task GenerateRowsAsync(IMessage ilrFile, FM36Global fm36Data, List <string> validLearners, List <AppsIndicativeEarningsModel> appsIndicativeEarningsModels, CancellationToken cancellationToken)
        {
            ILearner[] learners     = ilrFile.Learners.Where(x => validLearners.Contains(x.LearnRefNumber)).ToArray();
            string[]   learnAimRefs = learners.SelectMany(x => x.LearningDeliveries).Select(x => x.LearnAimRef).Distinct().ToArray();
            Dictionary <string, LarsLearningDelivery> larsLearningDeliveries = await _larsProviderService.GetLearningDeliveriesAsync(learnAimRefs, cancellationToken);

            foreach (ILearner learner in learners)
            {
                FM36Learner fm36Learner = fm36Data?.Learners?.SingleOrDefault(x => string.Equals(x.LearnRefNumber, learner.LearnRefNumber, StringComparison.OrdinalIgnoreCase));

                foreach (ILearningDelivery learningDelivery in learner.LearningDeliveries)
                {
                    if (learningDelivery.FundModel != 36)
                    {
                        continue;
                    }

                    string larsStandard = null;
                    if (learningDelivery.StdCodeNullable != null)
                    {
                        larsStandard = await _larsProviderService.GetStandardAsync(
                            learningDelivery.StdCodeNullable.Value,
                            cancellationToken);
                    }

                    LarsLearningDelivery larsDelivery = larsLearningDeliveries.SingleOrDefault(x => string.Equals(x.Key, learningDelivery.LearnAimRef, StringComparison.OrdinalIgnoreCase)).Value;

                    LearningDelivery fm36LearningDelivery = fm36Learner?.LearningDeliveries
                                                            ?.SingleOrDefault(x => x.AimSeqNumber == learningDelivery.AimSeqNumber);

                    if (fm36Learner?.PriceEpisodes.Any() ?? false)
                    {
                        List <PriceEpisode> episodesInRange = fm36Learner.PriceEpisodes
                                                              .Where(p => p.PriceEpisodeValues.EpisodeStartDate >= Constants.BeginningOfYear &&
                                                                     p.PriceEpisodeValues.EpisodeStartDate <= Constants.EndOfYear &&
                                                                     learningDelivery.AimSeqNumber == p.PriceEpisodeValues.PriceEpisodeAimSeqNumber).ToList();

                        if (episodesInRange.Any())
                        {
                            DateTime earliestEpisodeDate = episodesInRange.Select(x => x.PriceEpisodeValues.EpisodeStartDate ?? DateTime.MaxValue).Min();

                            bool earliestEpisode = false;
                            foreach (PriceEpisode episodeAttribute in episodesInRange)
                            {
                                if (episodeAttribute.PriceEpisodeValues.EpisodeStartDate == earliestEpisodeDate)
                                {
                                    earliestEpisode = true;
                                }

                                appsIndicativeEarningsModels.Add(
                                    _modelBuilder.BuildModel(
                                        learner,
                                        learningDelivery,
                                        fm36LearningDelivery,
                                        episodeAttribute,
                                        larsDelivery,
                                        larsStandard,
                                        earliestEpisode,
                                        true));

                                earliestEpisode = false;
                            }

                            continue;
                        }
                    }

                    appsIndicativeEarningsModels.Add(
                        _modelBuilder.BuildModel(
                            learner,
                            learningDelivery,
                            fm36LearningDelivery,
                            null,
                            larsDelivery,
                            larsStandard,
                            false,
                            false));
                }
            }

            appsIndicativeEarningsModels.Sort(AppsIndicativeEarningsModelComparer);
        }
 public ValidationResult Validate(FM36Learner learner)
 {
     return(new ValidationResult(LearnerRules
                                 .Select(rule => rule.IsValid(learner))
                                 .ToList()));
 }
        public async Task <FM36Global> GetFM36Data(IReportServiceContext reportServiceContext, CancellationToken cancellationToken)
        {
            await _getDataLock.WaitAsync(cancellationToken);

            try
            {
                if (_loadedDataAlready)
                {
                    return(_fundingOutputs);
                }

                cancellationToken.ThrowIfCancellationRequested();

                _loadedDataAlready = true;

                int ukPrn = reportServiceContext.Ukprn;
                if (string.Equals(reportServiceContext.CollectionName, "ILR1819", StringComparison.OrdinalIgnoreCase))
                {
                    string fm36Filename = reportServiceContext.FundingFM36OutputKey;
                    string fm36         = await _storage.GetAsync(fm36Filename, cancellationToken);

                    if (string.IsNullOrEmpty(fm36))
                    {
                        _fundingOutputs = null;
                        return(_fundingOutputs);
                    }

                    // await _blob.SaveAsync($"{jobContextMessage.KeyValuePairs[JobContextMessageKey.UkPrn]}_{jobContextMessage.JobId.ToString()}_Fm36.json", fm36, cancellationToken);
                    _fundingOutputs = _jsonSerializationService.Deserialize <FM36Global>(fm36);
                }
                else
                {
                    FM36Global fm36Global = new FM36Global();
                    using (var ilrContext = _ilrRulebaseContextFactory())
                    {
                        var fm36GlobalDb = await ilrContext.AEC_globals.FirstOrDefaultAsync(x => x.UKPRN == ukPrn, cancellationToken);

                        //AEC_LearningDelivery[] res = await ilrContext.AEC_LearningDelivery_Period.Where(x => x.UKPRN == ukPrn).Select(x => x.AEC_LearningDelivery)
                        //    .Include(x => x.AEC_LearningDelivery_PeriodisedValues).ToArrayAsync(cancellationToken);

                        AEC_LearningDelivery[] res = await ilrContext.AEC_LearningDeliveries.Where(x => x.UKPRN == ukPrn)
                                                     .Include(x => x.AEC_LearningDelivery_PeriodisedValues).ToArrayAsync(cancellationToken);

                        IGrouping <string, AEC_LearningDelivery>[] learners = res.GroupBy(x => x.LearnRefNumber).ToArray();

                        fm36Global.Learners = new List <FM36Learner>();

                        foreach (IGrouping <string, AEC_LearningDelivery> albLearningDeliveries in learners)
                        {
                            var learningDeliveryDto = new List <ILR.FundingService.FM36.FundingOutput.Model.Output.LearningDelivery>();
                            foreach (var ld in albLearningDeliveries)
                            {
                                var ldPeriodisedValues = ld.AEC_LearningDelivery_PeriodisedValues.Select(ldpv => new LearningDeliveryPeriodisedValues()
                                {
                                    AttributeName = ldpv.AttributeName,
                                    Period1       = ldpv.Period_1,
                                    Period2       = ldpv.Period_2,
                                    Period3       = ldpv.Period_3,
                                    Period4       = ldpv.Period_4,
                                    Period5       = ldpv.Period_5,
                                    Period6       = ldpv.Period_6,
                                    Period7       = ldpv.Period_7,
                                    Period8       = ldpv.Period_8,
                                    Period9       = ldpv.Period_9,
                                    Period10      = ldpv.Period_10,
                                    Period11      = ldpv.Period_11,
                                    Period12      = ldpv.Period_12
                                }).ToList();

                                learningDeliveryDto.Add(new LearningDelivery()
                                {
                                    AimSeqNumber = ld.AimSeqNumber,
                                    LearningDeliveryPeriodisedValues = ldPeriodisedValues,
                                    LearningDeliveryValues           = new LearningDeliveryValues()
                                    {
                                        LearnDelInitialFundLineType = ld.LearnDelInitialFundLineType // todo : rest of the properties
                                    }
                                });
                            }

                            FM36Learner learner = new FM36Learner()
                            {
                                LearnRefNumber     = albLearningDeliveries.Key,
                                LearningDeliveries = learningDeliveryDto
                            };

                            fm36Global.Learners.Add(learner);
                        }

                        if (fm36GlobalDb != null)
                        {
                            fm36Global.LARSVersion     = fm36GlobalDb.LARSVersion;
                            fm36Global.RulebaseVersion = fm36GlobalDb.RulebaseVersion;
                            fm36Global.UKPRN           = fm36GlobalDb.UKPRN;
                        }
                    }

                    _fundingOutputs = fm36Global;
                }
            }
            finally
            {
                _getDataLock.Release();
            }

            return(_fundingOutputs);
        }