diff --git a/application/CohortManager/src/Functions/CaasIntegration/RetrieveMeshFile/RetrieveMeshFile.csproj b/application/CohortManager/src/Functions/CaasIntegration/RetrieveMeshFile/RetrieveMeshFile.csproj index c7da6e5da8..546d66720d 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/RetrieveMeshFile/RetrieveMeshFile.csproj +++ b/application/CohortManager/src/Functions/CaasIntegration/RetrieveMeshFile/RetrieveMeshFile.csproj @@ -26,6 +26,9 @@ PreserveNewest + + + PreserveNewest PreserveNewest diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CallDurableDemographicFunc.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CallDurableDemographicFunc.cs index cad696d519..8a79bf9ad2 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CallDurableDemographicFunc.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CallDurableDemographicFunc.cs @@ -51,7 +51,7 @@ public CallDurableDemographicFunc(IHttpClientFunction httpClientFunction, ILogge /// This method handles posting data, logging, and checking the status of the durable function. /// Implements retry logic for status checking. /// - public async Task PostDemographicDataAsync(List participants, string DemographicFunctionURI, string fileName) + public async Task PostDemographicDataAsync(List participants, string DemographicFunctionURI, string fileName, List parquetValuesForRetry) { var batchSize = participants.Count; var responseContent = ""; @@ -92,7 +92,9 @@ public async Task PostDemographicDataAsync(List pa _logger.LogError("Check limit reached or demographic function failed for a batch of size: {BatchSize} {FinalStatus}", batchSize, finalStatus); await _copyFailedBatchToBlob.writeBatchToBlob( JsonSerializer.Serialize(participants), - new InvalidOperationException("there was an error while adding batch of participants to the demographic table") + new InvalidOperationException("there was an error while adding batch of participants to the demographic table"), + parquetValuesForRetry, + fileName ); return false; @@ -106,7 +108,9 @@ await _copyFailedBatchToBlob.writeBatchToBlob( await _copyFailedBatchToBlob.writeBatchToBlob( JsonSerializer.Serialize(participants), - new InvalidOperationException("there was an error while adding batch of participants to the demographic table") + new InvalidOperationException("there was an error while adding batch of participants to the demographic table"), + parquetValuesForRetry, + fileName ); return false; diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CopyFailedBatchToBlob.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CopyFailedBatchToBlob.cs index fd020ecd83..88f3785823 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CopyFailedBatchToBlob.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/CopyFailedBatchToBlob.cs @@ -1,11 +1,14 @@ namespace NHS.Screening.ReceiveCaasFile; -using System.Text; +using System; +using System.Collections.Generic; using System.Text.Json; +using Azure.Storage.Blobs; using Common; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Model; +using Parquet.Serialization; public class CopyFailedBatchToBlob : ICopyFailedBatchToBlob { @@ -15,32 +18,131 @@ public class CopyFailedBatchToBlob : ICopyFailedBatchToBlob private readonly ReceiveCaasFileConfig _config; - public CopyFailedBatchToBlob(ILogger logger, IBlobStorageHelper blobStorageHelper, IExceptionHandler handleException, IOptions config) + private readonly IFailedBatchDict _failedBatchDict; + + public CopyFailedBatchToBlob(ILogger logger, IBlobStorageHelper blobStorageHelper, IExceptionHandler handleException, IOptions config, IFailedBatchDict failedBatchDict) { _config = config.Value; _logger = logger; _blobStorageHelper = blobStorageHelper; _handleException = handleException; + _failedBatchDict = failedBatchDict; } - public async Task writeBatchToBlob(string jsonFromBatch, InvalidOperationException invalidOperationException) + public async Task writeBatchToBlob(string jsonFromBatch, InvalidOperationException invalidOperationException, List parquetValuesForRetry, string fileName = "") { using (var stream = GenerateStreamFromString(jsonFromBatch)) { - var blobFile = new BlobFile(stream, $"failedBatch-{Guid.NewGuid()}.json"); - var copied = await _blobStorageHelper.UploadFileToBlobStorage(_config.caasfolder_STORAGE, "failed-batch", blobFile); - - if (copied) + if (!string.IsNullOrEmpty(fileName)) { - _logger.LogInformation("adding failed batch to blob was successful"); - await _handleException.CreateSystemExceptionLog(invalidOperationException, new Participant(), "file name unknown but batch was copied to FailedBatch blob store"); - return true; + if (_failedBatchDict.ShouldRetryFile(fileName)) + { + var fileRetryCount = _failedBatchDict.GetRetryCount(fileName); + upsertRetryValue(fileName, fileRetryCount); + var pathOfFileToRetry = await convertBatchToParquet(parquetValuesForRetry, fileName); + if (!string.IsNullOrEmpty(pathOfFileToRetry)) + { + await RetryFailedBatch(pathOfFileToRetry, fileName); + } + } + else + { + var filePath = FileDirectoryPath(fileName); + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } } + + fileName = $"failedBatch-{Guid.NewGuid()}.json"; + await AddItemToBlob(stream, fileName); + + await _handleException.CreateSystemExceptionLog(invalidOperationException, new Participant(), "file name unknown but batch was copied to FailedBatch blob store"); _logger.LogInformation("adding failed batch to blob was unsuccessful"); - return false; + return true; + } + } + + private void upsertRetryValue(string filename, int fileRetryCount) + { + fileRetryCount = fileRetryCount + 1; + if (!_failedBatchDict.HasFileFailedBefore(filename)) + { + + _failedBatchDict.AddFailedBatchDataToDict(filename, fileRetryCount); + } + else + { + _failedBatchDict.UpdateFileFailureCount(filename, fileRetryCount); + } + } + + private async Task convertBatchToParquet(List parquetValuesForRetry, string fileName) + { + try + { + var parquetData = parquetValuesForRetry + .Select(ParticipantsParquetMap.ToParticipantParquet) + .ToList(); + + var filePath = FileDirectoryPath(fileName); + await ParquetSerializer.SerializeAsync(parquetData, filePath); + + return filePath; + } + catch (Exception ex) + { + _logger.LogError(ex, "There was a problem when converting a failed batch to parquet for retry {error}", ex.Message); + return ""; + } + + } + + private async Task RetryFailedBatch(string localFilePath, string fileName) + { + + var copied = false; + using (FileStream fileStream = File.OpenRead(localFilePath)) + { + var blobFile = new BlobFile(fileStream, fileName); + copied = await _blobStorageHelper.UploadFileToBlobStorage(_config.caasfolder_STORAGE, "inbound", blobFile, true); + } + + if (copied) + { + _logger.LogInformation("Adding failed batch to blob was successful"); + return true; + } + _logger.LogError("Adding failed batch to blob was unsuccessful"); + return false; + } + + + private async Task AddItemToBlob(Stream stream, string fileName) + { + var blobFile = new BlobFile(stream, fileName); + var copied = await _blobStorageHelper.UploadFileToBlobStorage(_config.caasfolder_STORAGE, "failed-batch", blobFile); + + if (copied) + { + _logger.LogInformation("Adding failed batch to blob was successful"); + return true; } + return false; } + private string FileDirectoryPath(string fileName) + { + var currentDirectory = Directory.GetCurrentDirectory(); + var filePath = Path.Combine(currentDirectory, fileName); + + filePath = filePath.Replace("bin/output/", ""); + + return filePath; + } + + private static Stream GenerateStreamFromString(string s) { var stream = new MemoryStream(); diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/FailedBatchDict.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/FailedBatchDict.cs new file mode 100644 index 0000000000..995d2031d9 --- /dev/null +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/FailedBatchDict.cs @@ -0,0 +1,62 @@ +using Common; +using Microsoft.Azure.Functions.Worker; + +public class FailedBatchDict : IFailedBatchDict +{ + private Dictionary RetryDictionary; + + private static readonly int RetryCount = 3; + public FailedBatchDict() + { + RetryDictionary = new Dictionary(); + } + + public void AddFailedBatchDataToDict(string FileName, int retryCount) + { + RetryDictionary.Add(FileName, retryCount); + } + + public int GetRetryCount(string fileName) + { + if (RetryDictionary.TryGetValue(fileName, out int fileRetryCount)) + { + return fileRetryCount; + } + return 0; + } + + public bool HasFileFailedBefore(string fileName) + { + return RetryDictionary.ContainsKey(fileName); + } + + public void UpdateFileFailureCount(string fileName, int failureCount) + { + RetryDictionary[fileName] = failureCount; + } + + + public bool ShouldRetryFile(string filename) + { + if (RetryDictionary.Count < 1) + { + return true; + } + + if (RetryDictionary.TryGetValue(filename, out int fileRetryCount)) + { + if (fileRetryCount < RetryCount) + { + return true; + } + RetryDictionary.Remove(filename); + return false; + } + + return true; + } + + + + +} \ No newline at end of file diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICallDurableDemographicFunc.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICallDurableDemographicFunc.cs index 161a5ee2fa..c5e8248db0 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICallDurableDemographicFunc.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICallDurableDemographicFunc.cs @@ -4,6 +4,6 @@ namespace NHS.Screening.ReceiveCaasFile; public interface ICallDurableDemographicFunc { - Task PostDemographicDataAsync(List participants, string DemographicFunctionURI, string fileName); + Task PostDemographicDataAsync(List participants, string DemographicFunctionURI, string fileName, List values); } diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICopyFailedBatchToBlob.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICopyFailedBatchToBlob.cs index 698ad06630..f09f3fc4c4 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICopyFailedBatchToBlob.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ICopyFailedBatchToBlob.cs @@ -1,6 +1,8 @@ namespace NHS.Screening.ReceiveCaasFile; +using Model; + public interface ICopyFailedBatchToBlob { - Task writeBatchToBlob(string jsonFromBatch, InvalidOperationException invalidOperationException); + Task writeBatchToBlob(string jsonFromBatch, InvalidOperationException invalidOperationException, List parquetValuesForRetry, string fileName = ""); } diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/IFailedBatchDict.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/IFailedBatchDict.cs new file mode 100644 index 0000000000..896a073ed9 --- /dev/null +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/IFailedBatchDict.cs @@ -0,0 +1,8 @@ +public interface IFailedBatchDict +{ + void AddFailedBatchDataToDict(string FileName, int retryCount); + bool ShouldRetryFile(string filename); + int GetRetryCount(string fileName); + bool HasFileFailedBefore(string fileName); + void UpdateFileFailureCount(string fileName, int failureCount); +} \ No newline at end of file diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ProcessCaasFile.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ProcessCaasFile.cs index 3d46356549..df189cd340 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ProcessCaasFile.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/ProcessFileClasses/ProcessCaasFile.cs @@ -64,30 +64,35 @@ IOptions receiveCaasFileConfig public async Task ProcessRecords(List values, ParallelOptions options, ScreeningLkp screeningService, string name) { var currentBatch = new Batch(); + await Parallel.ForEachAsync(values, options, async (rec, cancellationToken) => { var participant = _receiveCaasFileHelper.MapParticipant(rec, screeningService.ScreeningId.ToString(), screeningService.ScreeningName, name); if (participant == null) { + values.Remove(rec); await _exceptionHandler.CreateSystemExceptionLogFromNhsNumber(new Exception($"Could not map participant in file {name}"), rec.NhsNumber.ToString(), name, screeningService.ScreeningName, ""); return; } if (!ValidationHelper.ValidateNHSNumber(participant.NhsNumber)) { + values.Remove(rec); await _exceptionHandler.CreateSystemExceptionLog(new Exception($"Invalid NHS Number was passed in for participant {participant} and file {name}"), participant, name, nameof(ExceptionCategory.CaaS)); return; // skip current participant } if (!_validateDates.ValidateAllDates(participant)) { + values.Remove(rec); await _exceptionHandler.CreateSystemExceptionLog(new Exception($"Invalid effective date found in participant data {participant} and file name {name}"), participant, name); return; // Skip current participant } if (!_recordsProcessTracker.RecordAlreadyProcessed(participant.RecordType, participant.NhsNumber)) { + values.Remove(rec); await _exceptionHandler.CreateSystemExceptionLog(new Exception($"Duplicate Participant was in the file"), participant, name); return; // Skip current participant } @@ -95,7 +100,7 @@ await Parallel.ForEachAsync(values, options, async (rec, cancellationToken) => await AddRecordToBatch(participant, currentBatch, name); }); - if (await _callDurableDemographicFunc.PostDemographicDataAsync(currentBatch.DemographicData.ToList(), DemographicURI, name)) + if (await _callDurableDemographicFunc.PostDemographicDataAsync(currentBatch.DemographicData.ToList(), DemographicURI, name, values)) { await AddBatchToQueue(currentBatch, name); } diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/Program.cs b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/Program.cs index db7f262421..5c333009d9 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/Program.cs +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/Program.cs @@ -35,8 +35,9 @@ services.AddScoped(); services.AddScoped(); services.AddScoped(); //Do not change the lifetime of this. - services.AddTransient(); - services.AddTransient(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddScoped(); // Register health checks services.AddBlobStorageHealthCheck("receiveCaasFile"); diff --git a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/receiveCaasFile.csproj b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/receiveCaasFile.csproj index 2d3df00af5..e69e3d51d1 100644 --- a/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/receiveCaasFile.csproj +++ b/application/CohortManager/src/Functions/CaasIntegration/receiveCaasFile/receiveCaasFile.csproj @@ -15,6 +15,7 @@ + diff --git a/application/CohortManager/src/Functions/DemographicServices/DemographicDurableFunction/DurableDemographicFunction.cs b/application/CohortManager/src/Functions/DemographicServices/DemographicDurableFunction/DurableDemographicFunction.cs index 1f014cd20e..1ae374e5a2 100644 --- a/application/CohortManager/src/Functions/DemographicServices/DemographicDurableFunction/DurableDemographicFunction.cs +++ b/application/CohortManager/src/Functions/DemographicServices/DemographicDurableFunction/DurableDemographicFunction.cs @@ -37,60 +37,42 @@ public DurableDemographicFunction(IDataServiceClient dat public async Task RunOrchestrator( [OrchestrationTrigger] TaskOrchestrationContext context) { - var orchestrationTimeout = TimeSpan.FromHours(2.5); - var expirationTime = context.CurrentUtcDateTime.Add(orchestrationTimeout); - using (var cts = new CancellationTokenSource(orchestrationTimeout)) + try { - try - { - var demographicJsonData = context.GetInput(); - - if (string.IsNullOrEmpty(demographicJsonData)) - { - throw new InvalidDataException("demographicJsonData was null or empty in Orchestration function"); - } - - var retryOptions = TaskOptions.FromRetryPolicy(new RetryPolicy( - maxNumberOfAttempts: 1, // this means the function will not retry and therefore add duplicates - firstRetryInterval: TimeSpan.FromSeconds(100)) - ); - - // Add timeout-aware logic - var task = context.CallActivityAsync( - nameof(InsertDemographicData), - demographicJsonData, - options: retryOptions - ); - - // Monitor for timeout - var timeoutTask = context.CreateTimer(expirationTime, cts.Token); - var completedTask = await Task.WhenAny(task, timeoutTask); - - if (completedTask == timeoutTask) - { - _logger.LogWarning("Orchestration timed out."); - throw new TimeoutException("Orchestration function exceeded its timeout."); - } - - cts.Cancel(); - var recordsInserted = await task; - - if (!recordsInserted) - { - throw new InvalidOperationException("Demographic records were not added to the database in the orchestration function"); - } - return true; + var demographicJsonData = context.GetInput(); + if (string.IsNullOrEmpty(demographicJsonData)) + { + throw new InvalidDataException("demographicJsonData was null or empty in Orchestration function"); } - catch (Exception ex) + + var retryOptions = TaskOptions.FromRetryPolicy(new RetryPolicy( + maxNumberOfAttempts: 1, // this means the function will not retry and therefore add duplicates + firstRetryInterval: TimeSpan.FromSeconds(100)) + ); + + var recordsInserted = await context.CallActivityAsync( + nameof(InsertDemographicData), + demographicJsonData, + options: retryOptions + ); + + if (!recordsInserted) { - _logger.LogError(ex, "Orchestration failed with exception. {exception}", ex.Message); - throw; + throw new InvalidOperationException("Demographic records were not added to the database in the orchestration function"); } + return true; + + } + catch (Exception ex) + { + _logger.LogError(ex, "Orchestration failed with exception. {exception}", ex.Message); + throw; } } + /// /// Inserts demographic data into the data store. /// @@ -103,7 +85,7 @@ public async Task InsertDemographicData([ActivityTrigger] string demograph try { var participantData = JsonSerializer.Deserialize>(demographicJsonData); - return await _participantDemographic.AddRange(participantData); + return await _participantDemographic.AddRange(participantData!); } catch (Exception ex) { diff --git a/application/CohortManager/src/Functions/Shared/Model/Mapping/PartcipantsMapToParquet.cs b/application/CohortManager/src/Functions/Shared/Model/Mapping/PartcipantsMapToParquet.cs new file mode 100644 index 0000000000..755a3c0f74 --- /dev/null +++ b/application/CohortManager/src/Functions/Shared/Model/Mapping/PartcipantsMapToParquet.cs @@ -0,0 +1,43 @@ +namespace Model; + +public struct ParticipantsParquet +{ + public string? record_type { get; set; } + public long? change_time_stamp { get; set; } + public long? serial_change_number { get; set; } + public long? nhs_number { get; set; } + public long? superseded_by_nhs_number { get; set; } + public string? primary_care_provider { get; set; } + public string? primary_care_effective_from_date { get; set; } + public string? current_posting { get; set; } + public string? current_posting_effective_from_date { get; set; } + public string? name_prefix { get; set; } + public string? given_name { get; set; } + public string? other_given_name { get; set; } + public string? family_name { get; set; } + public string? previous_family_name { get; set; } + public string? date_of_birth { get; set; } + public long? gender { get; set; } + public string? address_line_1 { get; set; } + public string? address_line_2 { get; set; } + public string? address_line_3 { get; set; } + public string? address_line_4 { get; set; } + public string? address_line_5 { get; set; } + public string? postcode { get; set; } + public string? paf_key { get; set; } + public string? address_effective_from_date { get; set; } + public string? reason_for_removal { get; set; } + public string? reason_for_removal_effective_from_date { get; set; } + public string? date_of_death { get; set; } + public int? death_status { get; set; } + public string? home_telephone_number { get; set; } + public string? home_telephone_effective_from_date { get; set; } + public string? mobile_telephone_number { get; set; } + public string? mobile_telephone_effective_from_date { get; set; } + public string? email_address { get; set; } + public string? email_address_effective_from_date { get; set; } + public string? preferred_language { get; set; } + public bool? is_interpreter_required { get; set; } + public bool? invalid_flag { get; set; } + public bool? eligibility { get; set; } +} \ No newline at end of file diff --git a/application/CohortManager/src/Functions/Shared/Model/Mapping/ParticipantsParquetMap.cs b/application/CohortManager/src/Functions/Shared/Model/Mapping/ParticipantsParquetMap.cs index a2dde28a94..1a80279ec8 100644 --- a/application/CohortManager/src/Functions/Shared/Model/Mapping/ParticipantsParquetMap.cs +++ b/application/CohortManager/src/Functions/Shared/Model/Mapping/ParticipantsParquetMap.cs @@ -1,5 +1,9 @@ namespace Model; + using ParquetSharp.RowOriented; +using Parquet.Serialization.Attributes; +using System.ComponentModel.DataAnnotations.Schema; +using System.Security.Cryptography; public struct ParticipantsParquetMap { @@ -116,4 +120,49 @@ public struct ParticipantsParquetMap [MapToColumn("eligibility")] public bool? EligibilityFlag { get; set; } + + public static ParticipantsParquet ToParticipantParquet(ParticipantsParquetMap participantsParquetMap) + { + return new ParticipantsParquet() + { + record_type = participantsParquetMap.RecordType, + change_time_stamp = participantsParquetMap.ChangeTimeStamp, + serial_change_number = participantsParquetMap.SerialChangeNumber, + nhs_number = participantsParquetMap.NhsNumber, + superseded_by_nhs_number = participantsParquetMap.SupersededByNhsNumber, + primary_care_provider = participantsParquetMap.PrimaryCareProvider, + primary_care_effective_from_date = participantsParquetMap.PrimaryCareEffectiveFromDate, + current_posting = participantsParquetMap.CurrentPosting, + current_posting_effective_from_date = participantsParquetMap.CurrentPostingEffectiveFromDate, + name_prefix = participantsParquetMap.NamePrefix, + given_name = participantsParquetMap.FirstName, + other_given_name = participantsParquetMap.OtherGivenNames, + family_name = participantsParquetMap.SurnamePrefix, + previous_family_name = participantsParquetMap.PreviousSurnamePrefix, + date_of_birth = participantsParquetMap.DateOfBirth, + gender = participantsParquetMap.Gender, + address_line_1 = participantsParquetMap.AddressLine1, + address_line_2 = participantsParquetMap.AddressLine2, + address_line_3 = participantsParquetMap.AddressLine3, + address_line_4 = participantsParquetMap.AddressLine4, + address_line_5 = participantsParquetMap.AddressLine5, + postcode = participantsParquetMap.Postcode, + paf_key = participantsParquetMap.PafKey, + address_effective_from_date = participantsParquetMap.UsualAddressEffectiveFromDate, + reason_for_removal = participantsParquetMap.ReasonForRemoval, + reason_for_removal_effective_from_date = participantsParquetMap.ReasonForRemovalEffectiveFromDate, + date_of_death = participantsParquetMap.DateOfDeath, + death_status = participantsParquetMap.DeathStatus, + home_telephone_number = participantsParquetMap.TelephoneNumber, + home_telephone_effective_from_date = participantsParquetMap.TelephoneNumberEffectiveFromDate, + mobile_telephone_number = participantsParquetMap.MobileNumber, + mobile_telephone_effective_from_date = participantsParquetMap.MobileNumberEffectiveFromDate, + email_address = participantsParquetMap.EmailAddress, + email_address_effective_from_date = participantsParquetMap.EmailAddressEffectiveFromDate, + preferred_language = participantsParquetMap.PreferredLanguage, + is_interpreter_required = participantsParquetMap.IsInterpreterRequired, + invalid_flag = participantsParquetMap.InvalidFlag, + eligibility = participantsParquetMap.EligibilityFlag + }; + } } diff --git a/application/CohortManager/src/Functions/Shared/Model/Model.csproj b/application/CohortManager/src/Functions/Shared/Model/Model.csproj index 1671fb51d5..dfbb87c457 100644 --- a/application/CohortManager/src/Functions/Shared/Model/Model.csproj +++ b/application/CohortManager/src/Functions/Shared/Model/Model.csproj @@ -8,6 +8,7 @@ +