Beispiel #1
0
        public async Task AddCustomAttributeAsync(CustomAttributeConfigDetail customAttribute)
        {
            var newCustomAttribute = new CustomAttributeConfiguration()
            {
                ExtendableTypeName  = customAttribute.EntityName,
                Category            = customAttribute.Category,
                AttributeKey        = customAttribute.AttributeName,
                AttributeDetail     = customAttribute.AttributeDetail,
                CustomAttributeType = customAttribute.CustomAttributeType,
                IsRequired          = customAttribute.Required,
                IsSearchable        = customAttribute.Searchable
            };

            switch (newCustomAttribute.CustomAttributeType)
            {
            case CustomAttributeType.Numeric:
                if (customAttribute.NumericMinValue.HasValue)
                {
                    newCustomAttribute.NumericMinValue = customAttribute.NumericMinValue.Value;
                }

                if (customAttribute.NumericMaxValue.HasValue)
                {
                    newCustomAttribute.NumericMaxValue = customAttribute.NumericMaxValue.Value;
                }
                break;

            case CustomAttributeType.String:
                if (customAttribute.StringMaxLength.HasValue)
                {
                    newCustomAttribute.StringMaxLength = customAttribute.StringMaxLength.Value;
                }
                break;

            case CustomAttributeType.DateTime:
                newCustomAttribute.FutureDateOnly = customAttribute.FutureDateOnly;
                newCustomAttribute.PastDateOnly   = customAttribute.PastDateOnly;
                break;

            default:
                break;
            }

            await _customAttributeConfigRepository.SaveAsync(newCustomAttribute);

            if (newCustomAttribute.CustomAttributeType == CustomAttributeType.Selection)
            {
                var newSelectionDataItem = new SelectionDataItem()
                {
                    AttributeKey = customAttribute.AttributeName,
                    Value        = "",
                    SelectionKey = "0"
                };

                await _selectionDataItemRepository.SaveAsync(newSelectionDataItem);
            }
        }
Beispiel #2
0
        public async Task <ConceptIdentifierDto> Handle(AddConceptCommand message, CancellationToken cancellationToken)
        {
            var medicationFormFromRepo = await _medicationFormRepository.GetAsync(mf => mf.Description == message.MedicationForm);

            if (medicationFormFromRepo == null)
            {
                throw new KeyNotFoundException("Unable to locate medication form");
            }

            if (_conceptRepository.Exists(c => c.ConceptName == message.ConceptName &&
                                          c.MedicationForm.Id == medicationFormFromRepo.Id &&
                                          c.Strength == message.Strength))
            {
                throw new DomainException("Concept with same name, strength and form already exists");
            }

            var newConcept = new Concept(message.ConceptName, message.Strength, medicationFormFromRepo);

            await _conceptRepository.SaveAsync(newConcept);

            _logger.LogInformation($"----- Concept {message.ConceptName} created");

            var mappedConcept = _mapper.Map <ConceptIdentifierDto>(newConcept);

            CreateLinks(mappedConcept);

            return(mappedConcept);
        }
        public async Task <AppointmentIdentifierDto> Handle(AddAppointmentCommand message, CancellationToken cancellationToken)
        {
            var patientFromRepo = await _patientRepository.GetAsync(p => p.Id == message.PatientId);

            if (patientFromRepo == null)
            {
                throw new KeyNotFoundException("Unable to locate patient");
            }

            var appointmentFromRepo = await _appointmentRepository.GetAsync(a => a.PatientId == message.PatientId && a.AppointmentDate == message.AppointmentDate && !a.Archived);

            if (appointmentFromRepo != null)
            {
                throw new DomainException("Patient already has an appointment for this date");
            }

            var newAppointment = new Appointment(message.PatientId, message.AppointmentDate, message.Reason);

            await _appointmentRepository.SaveAsync(newAppointment);

            _logger.LogInformation($"----- Appointment {newAppointment.Id} created");

            var mappedAppointment = _mapper.Map <AppointmentIdentifierDto>(newAppointment);

            CreateLinks(mappedAppointment);

            return(mappedAppointment);
        }
Beispiel #4
0
        public async Task <CohortGroupDetailDto> Handle(AddCohortGroupCommand message, CancellationToken cancellationToken)
        {
            var conditionFromRepo = await _conditionRepository.GetAsync(c => c.Description == message.ConditionName);

            if (conditionFromRepo == null)
            {
                throw new KeyNotFoundException("Unable to locate condition");
            }

            if (_cohortGroupRepository.Exists(cg => cg.CohortName == message.CohortName ||
                                              cg.CohortCode == message.CohortCode))
            {
                throw new DomainException("Cohort group with same name already exists");
            }

            var newCohortGroup = new CohortGroup(message.CohortName, message.CohortCode, conditionFromRepo, message.StartDate, message.FinishDate);

            await _cohortGroupRepository.SaveAsync(newCohortGroup);

            _logger.LogInformation($"----- Cohort group {message.CohortName} created");

            var mappedCohortGroup = _mapper.Map <CohortGroupDetailDto>(newCohortGroup);

            return(CreateLinks(mappedCohortGroup));
        }
Beispiel #5
0
        /// <summary>
        /// Add a new patient to the repository
        /// </summary>
        /// <param name="patientDetail">The details of the patient to add</param>
        public async Task <int> AddPatientAsync(PatientDetailForCreation patientDetail)
        {
            var facility = _facilityRepository.Get(f => f.FacilityName == patientDetail.CurrentFacilityName);

            if (facility == null)
            {
                throw new ArgumentException(nameof(patientDetail.CurrentFacilityName));
            }
            var patientStatus = _patientStatusRepository.Get(f => f.Description == "Active");

            var newPatient = new Patient
            {
                FirstName   = patientDetail.FirstName,
                MiddleName  = patientDetail.MiddleName,
                Surname     = patientDetail.Surname,
                DateOfBirth = patientDetail.DateOfBirth,
            };

            newPatient.ChangePatientFacility(facility);
            newPatient.SetPatientStatus(patientStatus);

            // Custom Property handling
            _typeExtensionHandler.UpdateExtendable(newPatient, patientDetail.CustomAttributes, "Admin");

            // Clinical data
            AddConditions(newPatient, patientDetail.Conditions);
            await AddLabTestsAsync(newPatient, patientDetail.LabTests);
            await AddMedicationsAsync(newPatient, patientDetail.Medications);

            AddClinicalEvents(newPatient, patientDetail.ClinicalEvents);

            // Other data
            AddAttachments(newPatient, patientDetail.Attachments);

            if (patientDetail.CohortGroupId > 0)
            {
                AddCohortEnrollment(newPatient, patientDetail);
            }

            await _patientRepository.SaveAsync(newPatient);

            // Register encounter
            if (patientDetail.EncounterTypeId > 0)
            {
                await AddEncounterAsync(newPatient, new EncounterDetail()
                {
                    EncounterDate   = patientDetail.EncounterDate,
                    EncounterTypeId = patientDetail.EncounterTypeId,
                    PatientId       = newPatient.Id,
                    PriorityId      = patientDetail.PriorityId
                });
            }

            return(newPatient.Id);
        }
        public async Task <AttachmentIdentifierDto> Handle(AddAttachmentCommand message, CancellationToken cancellationToken)
        {
            Patient patientFromRepo = null;

            if (message.PatientId.HasValue)
            {
                patientFromRepo = await _patientRepository.GetAsync(f => f.Id == message.PatientId, new string[] { "" });

                if (patientFromRepo == null)
                {
                    throw new KeyNotFoundException("Unable to locate patient");
                }
            }

            if (message.Attachment.Length == 0)
            {
                throw new DomainException("Invalid file sent for attachment");
            }

            var fileExtension          = Path.GetExtension(message.Attachment.FileName).Replace(".", "");
            var attachmentTypeFromRepo = await _attachmentTypeRepository.GetAsync(at => at.Key == fileExtension);

            if (attachmentTypeFromRepo == null)
            {
                throw new KeyNotFoundException($"Unable to locate attachment type {fileExtension}");
            }

            var fileName = ContentDispositionHeaderValue.Parse(message.Attachment.ContentDisposition).FileName.Trim();

            if (fileName.Length > 50)
            {
                throw new DomainException("Maximumum file name length of 50 characters, please rename the file before uploading");
            }

            // Create the attachment
            BinaryReader reader = new BinaryReader(message.Attachment.OpenReadStream());

            byte[] buffer = reader.ReadBytes((int)message.Attachment.Length);

            var newAttachment = new Attachment(buffer, message.Description, message.Attachment.FileName, message.Attachment.Length, attachmentTypeFromRepo, null, patientFromRepo, null);

            await _attachmentRepository.SaveAsync(newAttachment);

            _logger.LogInformation($"----- Attachment {message.Attachment.FileName} created");

            var mappedAttachment = _mapper.Map <AttachmentIdentifierDto>(newAttachment);

            return(CreateLinks(mappedAttachment));
        }
Beispiel #7
0
        public async Task CreateWorkFlowInstanceAsync(string workFlowName, Guid contextGuid, string patientIdentifier, string sourceIdentifier, string facilityIdentifier)
        {
            if (string.IsNullOrWhiteSpace(workFlowName))
            {
                throw new ArgumentException($"'{nameof(workFlowName)}' cannot be null or whitespace.", nameof(workFlowName));
            }

            if (string.IsNullOrWhiteSpace(sourceIdentifier))
            {
                throw new ArgumentException($"'{nameof(sourceIdentifier)}' cannot be null or whitespace.", nameof(sourceIdentifier));
            }

            if (string.IsNullOrWhiteSpace(facilityIdentifier))
            {
                throw new ArgumentException($"'{nameof(facilityIdentifier)}' cannot be null or whitespace.", nameof(facilityIdentifier));
            }

            // Ensure instance does not exist for this context
            var workFlow = await _workFlowRepository.GetAsync(wf => wf.Description == workFlowName, new string[] { "Activities.ExecutionStatuses" });

            if (workFlow == null)
            {
                throw new KeyNotFoundException($"{nameof(workFlowName)} Unable to locate work flow");
            }

            var userName    = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
            var currentUser = await _userRepository.GetAsync(u => u.UserName == userName);

            if (currentUser == null)
            {
                throw new KeyNotFoundException($"Unable to locate current user");
            }

            var reportInstance = await _reportInstanceRepository.GetAsync(ri => ri.ContextGuid == contextGuid);

            if (reportInstance == null)
            {
                reportInstance = new ReportInstance(workFlow, currentUser, contextGuid, patientIdentifier, sourceIdentifier, facilityIdentifier);
                await _reportInstanceRepository.SaveAsync(reportInstance);

                reportInstance.SetSystemIdentifier();

                _unitOfWork.Repository <ReportInstance>().Update(reportInstance);
                await _unitOfWork.CompleteAsync();
            }
        }
Beispiel #8
0
        /// <summary>
        /// Register patient encounter
        /// </summary>
        public async Task <int> AddEncounterAsync(Patient patient, EncounterDetail encounterDetail)
        {
            var encounterType = _encounterTypeRepository.Get(et => et.Id == encounterDetail.EncounterTypeId);

            if (encounterType == null)
            {
                throw new ArgumentException(nameof(encounterDetail.EncounterTypeId));
            }

            var priority = _priorityRepository.Get(p => p.Id == encounterDetail.PriorityId);

            if (priority == null)
            {
                throw new ArgumentException(nameof(encounterDetail.PriorityId));
            }

            var newEncounter = new Encounter(patient)
            {
                EncounterType = encounterType,
                Priority      = priority,
                EncounterDate = encounterDetail.EncounterDate,
                Notes         = encounterDetail.Notes
            };

            //newEncounter.AuditStamp(user);
            await _encounterRepository.SaveAsync(newEncounter);

            var encounterTypeWorkPlan = _encounterTypeWorkPlanRepository.Get(et => et.EncounterType.Id == encounterType.Id, new string[] { "WorkPlan.Dataset" });

            if (encounterTypeWorkPlan != null)
            {
                // Create a new instance
                var dataset = _datasetRepository.Get(d => d.Id == encounterTypeWorkPlan.WorkPlan.Dataset.Id, new string[] { "DatasetCategories.DatasetCategoryElements.DatasetElement.Field.FieldType" });
                if (dataset != null)
                {
                    var datasetInstance = dataset.CreateInstance(newEncounter.Id, "", encounterTypeWorkPlan, null, null);
                    await _datasetInstanceRepository.SaveAsync(datasetInstance);
                }
            }

            return(newEncounter.Id);
        }
        public async Task Handle(E2BSubmittedDomainEvent domainEvent, CancellationToken cancellationToken)
        {
            var config = await _configRepository.GetAsync(c => c.ConfigType == ConfigType.ReportInstanceNewAlertCount);

            var alertCount = 1;

            if (config != null)
            {
                alertCount = Convert.ToInt32(config.ConfigValue);
            }

            var summary                    = $"E2B submitted for report {domainEvent.ReportInstance.PatientIdentifier}";
            var notificationType           = NotificationType.FromName("Informational");
            var notificationClassification = NotificationClassification.FromName("E2BSubmitted");
            var contextRoute               = "/clinical/feedbacksearch";
            var newNotification            = new Notification(domainEvent.ReportInstance.CreatedBy, DateTime.Now.AddDays(alertCount), summary, "", notificationType, notificationClassification, contextRoute);

            await _notificationRepository.SaveAsync(newNotification);

            await _unitOfWork.CompleteAsync();
        }
        public async Task Handle(TaskAttendedToDomainEvent domainEvent, CancellationToken cancellationToken)
        {
            var config = await _configRepository.GetAsync(c => c.ConfigType == ConfigType.ReportInstanceNewAlertCount);

            var alertCount = 1;

            if (config != null)
            {
                alertCount = Convert.ToInt32(config.ConfigValue);
            }

            var summary                    = $"A task for a report for patient {domainEvent.Task.ReportInstance.PatientIdentifier} has been attended to";
            var notificationType           = NotificationType.FromName("Informational");
            var notificationClassification = NotificationClassification.FromName("AttendedToTask");
            var contextRoute               = $"/analytical/reporttask/{domainEvent.Task.ReportInstance.WorkFlow.WorkFlowGuid}/{domainEvent.Task.ReportInstance.Id}";
            var newNotification            = new Notification(domainEvent.Task.CreatedBy, DateTime.Now.AddDays(alertCount), summary, "", notificationType, notificationClassification, contextRoute);

            await _notificationRepository.SaveAsync(newNotification);

            await _unitOfWork.CompleteAsync();
        }
        public async Task <FacilityDetailDto> Handle(AddFacilityCommand message, CancellationToken cancellationToken)
        {
            var facilityTypeFromRepo = await _facilityTypeRepository.GetAsync(c => c.Description == message.FacilityType);

            if (facilityTypeFromRepo == null)
            {
                throw new KeyNotFoundException("Unable to locate facility type");
            }

            if (_facilityRepository.Exists(f => f.FacilityName == message.FacilityName ||
                                           f.FacilityCode == message.FacilityCode))
            {
                throw new DomainException("Facility with same name or code already exists");
            }

            OrgUnit orgUnitFromRepo = null;

            if (message.OrgUnitId.HasValue)
            {
                if (message.OrgUnitId > 0)
                {
                    orgUnitFromRepo = await _orgUnitRepository.GetAsync(message.OrgUnitId);

                    if (orgUnitFromRepo == null)
                    {
                        throw new KeyNotFoundException($"Unable to locate organisation unit {message.OrgUnitId}");
                    }
                }
            }

            var newFacility = new Facility(message.FacilityName, message.FacilityCode, facilityTypeFromRepo, message.TelNumber, message.MobileNumber, message.FaxNumber, orgUnitFromRepo);

            await _facilityRepository.SaveAsync(newFacility);

            _logger.LogInformation($"----- Facility {message.FacilityName} created");

            var mappedFacility = _mapper.Map <FacilityDetailDto>(newFacility);

            return(CreateLinks(mappedFacility));
        }
Beispiel #12
0
        public async Task <UserIdentifierDto> Handle(AddUserCommand message, CancellationToken cancellationToken)
        {
            if (_userRepository.Exists(u => u.UserName == message.UserName))
            {
                throw new DomainException("User with same user name already exists");
            }

            var identityId = await CreateIdentity(message);

            var facilities = await PrepareFacilityAccess(message.Facilities);

            var newUser = new User(message.FirstName, message.LastName, message.UserName, message.Email, identityId, facilities);

            await _userRepository.SaveAsync(newUser);

            _logger.LogInformation($"----- User {message.UserName} created");

            var mappedUser = _mapper.Map <UserIdentifierDto>(newUser);

            CreateLinks(mappedUser);
            return(mappedUser);
        }
Beispiel #13
0
        public async Task SetConfigValueAsync(ConfigType configType, string configValue)
        {
            var config = _unitOfWork.Repository <Config>().Queryable().
                         FirstOrDefault(c => c.ConfigType == configType);

            if (config == null)
            {
                config = new Config()
                {
                    // Prepare new config
                    ConfigType  = configType,
                    ConfigValue = configValue
                };
                await _configRepository.SaveAsync(config);
            }
            else
            {
                config.ConfigValue = configValue;
                _configRepository.Update(config);
            }
            await _unitOfWork.CompleteAsync();
        }
Beispiel #14
0
        public async Task Handle(TaskCommentAddedDomainEvent domainEvent, CancellationToken cancellationToken)
        {
            var config = await _configRepository.GetAsync(c => c.ConfigType == ConfigType.ReportInstanceNewAlertCount);

            var alertCount = 1;

            if (config != null)
            {
                alertCount = Convert.ToInt32(config.ConfigValue);
            }

            var summary = $"Task comment has been added for patient {domainEvent.Comment.ReportInstanceTask.ReportInstance.PatientIdentifier}";
            var detail  = domainEvent.Comment.Comment.Length > 100 ? $"{domainEvent.Comment.Comment.Substring(0, 100)} ..." : domainEvent.Comment.Comment;

            var notificationType           = NotificationType.FromName("Informational");
            var notificationClassification = NotificationClassification.FromName("NewTaskComment");

            var newNotification = new Notification(GetDestinationUser(domainEvent), DateTime.Now.AddDays(alertCount), summary, detail, notificationType, notificationClassification, GetDestinationRoute(domainEvent));

            await _notificationRepository.SaveAsync(newNotification);

            await _unitOfWork.CompleteAsync();
        }
        public async Task <bool> Handle(CreateE2BForSpontaneousCommand message, CancellationToken cancellationToken)
        {
            var reportInstanceFromRepo = await _reportInstanceRepository.GetAsync(ri => ri.WorkFlow.WorkFlowGuid == message.WorkFlowGuid &&
                                                                                  ri.Id == message.ReportInstanceId, new string[] { "CreatedBy", "WorkFlow" });

            if (reportInstanceFromRepo == null)
            {
                throw new KeyNotFoundException("Unable to locate report instance");
            }

            var spontaneousReport = await _datasetInstanceRepository.GetAsync(ds => ds.DatasetInstanceGuid == reportInstanceFromRepo.ContextGuid, new string[] { "Dataset" });

            if (spontaneousReport == null)
            {
                throw new KeyNotFoundException("Unable to locate spontaneous report");
            }

            var dataset = await GetDatasetForInstance();

            if (dataset == null)
            {
                throw new KeyNotFoundException("Unable to locate E2B dataset");
            }

            var newActivityExecutionStatusEvent = await _workFlowService.ExecuteActivityAsync(reportInstanceFromRepo.ContextGuid, "E2BINITIATED", "AUTOMATION: E2B dataset created", null, "");

            var e2bInstance = dataset.CreateInstance(newActivityExecutionStatusEvent.Id, "Spontaneous", null, spontaneousReport, null);
            await _datasetInstanceRepository.SaveAsync(e2bInstance);

            UpdateValuesUsingSource(e2bInstance, spontaneousReport, dataset);

            await _unitOfWork.CompleteAsync();

            _logger.LogInformation($"----- E2B instance created for spontaneous report {message.ReportInstanceId} created");

            return(true);
        }
Beispiel #16
0
        public async Task <IActionResult> CreateForm([FromBody] FormForCreationDto formForCreation)
        {
            if (formForCreation == null)
            {
                ModelState.AddModelError("Message", "Unable to locate payload for new form");
                return(BadRequest(ModelState));
            }

            if (formForCreation.HasAttachment == false)
            {
                ModelState.AddModelError("Message", "Unable to process form as no attachment has been submitted");
                return(BadRequest(ModelState));
            }

            // Meta form for template extraction
            var metaFormFromRepo = await _metaFormRepository.GetAsync(f => f.ActionName.ToLower().Replace(" ", "") == formForCreation.FormType.ToLower().Replace(" ", ""));

            if (metaFormFromRepo == null)
            {
                ModelState.AddModelError("Message", "Unable to locate meta form for template extraction");
                return(BadRequest(ModelState));
            }

            // Store user for audit log generation purposes
            var      userName     = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
            var      userFromRepo = _userRepository.Get(u => u.UserName == userName);
            AuditLog auditLog     = null;

            // TODO Use meta form to identify context handler (add/update encounter/patient)

            //var handler = new FormValueHandler(formForCreation.FormValues.Where(fv => fv.FormControlKey == "Object").Select(fv => fv.FormControlValue).ToList());
            _formHandler.SetForm(formForCreation);

            // Validation of the source entity
            _formHandler.ValidateSourceIdentifier();
            if (_formHandler.GetValidationErrors().Count > 0)
            {
                foreach (string message in _formHandler.GetValidationErrors())
                {
                    ModelState.AddModelError("Message", message);
                }
            }

            if (ModelState.IsValid)
            {
                _formHandler.PreparePatientAndClinicalDetail();
                if (_formHandler.GetValidationErrors().Count > 0)
                {
                    foreach (string message in _formHandler.GetValidationErrors())
                    {
                        ModelState.AddModelError("Message", message);
                    }
                }
            }

            if (ModelState.IsValid)
            {
                try
                {
                    auditLog = new AuditLog()
                    {
                        AuditType  = AuditType.SynchronisationForm,
                        User       = userFromRepo,
                        ActionDate = DateTime.Now,
                        Details    = $"Form submission successful {formForCreation.FormIdentifier}",
                        Log        = JsonConvert.SerializeObject(formForCreation, Formatting.Indented)
                    };
                    await _auditLogRepository.SaveAsync(auditLog);

                    await _formHandler.ProcessFormForCreationOrUpdateAsync();

                    await _unitOfWork.CompleteAsync();

                    return(Ok());
                }
                catch (Exception ex)
                {
                    var error = new Dictionary <string, string>
                    {
                        { "Type", ex.GetType().ToString() },
                        { "Message", ex.Message },
                        { "StackTrace", ex.StackTrace }
                    };
                    auditLog = new AuditLog()
                    {
                        AuditType  = AuditType.SynchronisationError,
                        User       = userFromRepo,
                        ActionDate = DateTime.Now,
                        Details    = $"Error on form {formForCreation.FormIdentifier}",
                        Log        = JsonConvert.SerializeObject(error, Formatting.Indented)
                    };
                    _auditLogRepository.Save(auditLog);

                    return(StatusCode(500, ex.Message + " " + ex.InnerException?.Message));
                }
            }

            var audit = new AuditLog()
            {
                AuditType  = AuditType.SynchronisationError,
                User       = userFromRepo,
                ActionDate = DateTime.Now,
                Details    = $"Form submission with model error {formForCreation.FormIdentifier}",
                Log        = JsonConvert.SerializeObject(formForCreation, Formatting.Indented)
            };
            await _auditLogRepository.SaveAsync(audit);

            return(BadRequest(ModelState));
        }
Beispiel #17
0
        /// <summary>
        /// Update an existing patient in the repository
        /// </summary>
        /// <param name="patientDetail">The details of the patient to add</param>
        public async Task UpdatePatientAsync(PatientDetailForUpdate patientDetail)
        {
            var identifier_asm    = patientDetail.CustomAttributes.SingleOrDefault(ca => ca.AttributeKey == "Medical Record Number")?.Value.ToString();
            var identifierChanged = false;

            if (String.IsNullOrWhiteSpace(identifier_asm))
            {
                throw new Exception("Unable to locate patient in repo for update");
            }

            List <CustomAttributeParameter> parameters = new List <CustomAttributeParameter>();

            parameters.Add(new CustomAttributeParameter()
            {
                AttributeKey = "Medical Record Number", AttributeValue = identifier_asm
            });

            var patientFromRepo = GetPatientUsingAttributes(parameters);

            if (patientFromRepo == null)
            {
                throw new ArgumentException(nameof(patientDetail));
            }

            if (!String.IsNullOrWhiteSpace(patientDetail.FirstName))
            {
                if (!patientFromRepo.FirstName.Equals(patientDetail.FirstName, StringComparison.OrdinalIgnoreCase))
                {
                    identifierChanged = true;
                }
                patientFromRepo.FirstName = patientDetail.FirstName;
            }

            if (!String.IsNullOrWhiteSpace(patientDetail.Surname))
            {
                if (!patientFromRepo.Surname.Equals(patientDetail.Surname, StringComparison.OrdinalIgnoreCase))
                {
                    identifierChanged = true;
                }
                patientFromRepo.Surname = patientDetail.Surname;
            }

            if (!String.IsNullOrWhiteSpace(patientDetail.MiddleName))
            {
                patientFromRepo.MiddleName = patientDetail.MiddleName;
            }

            if (patientDetail.DateOfBirth.HasValue)
            {
                if (!patientFromRepo.DateOfBirth.Equals(patientDetail.DateOfBirth))
                {
                    identifierChanged = true;
                }
                patientFromRepo.DateOfBirth = patientDetail.DateOfBirth;
            }

            // Custom Property handling
            _typeExtensionHandler.UpdateExtendable(patientFromRepo, patientDetail.CustomAttributes, "Admin");

            // Clinical data
            AddConditions(patientFromRepo, patientDetail.Conditions);
            await AddLabTestsAsync(patientFromRepo, patientDetail.LabTests);
            await AddMedicationsAsync(patientFromRepo, patientDetail.Medications);

            AddClinicalEvents(patientFromRepo, patientDetail.ClinicalEvents);

            // Other data
            AddAttachments(patientFromRepo, patientDetail.Attachments);

            _patientRepository.Update(patientFromRepo);

            // Register encounter
            if (patientDetail.EncounterTypeId > 0)
            {
                await AddEncounterAsync(patientFromRepo, new EncounterDetail()
                {
                    EncounterDate   = patientDetail.EncounterDate,
                    EncounterTypeId = patientDetail.EncounterTypeId,
                    PatientId       = patientFromRepo.Id,
                    PriorityId      = patientDetail.PriorityId
                });
            }

            if (identifierChanged)
            {
                var userName     = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
                var userFromRepo = await _userRepository.GetAsync(u => u.UserName == userName);

                var auditLog = new AuditLog()
                {
                    AuditType  = AuditType.DataValidation,
                    User       = userFromRepo,
                    ActionDate = DateTime.Now,
                    Details    = $"Identifier (name or date of birth) changed for patient {identifier_asm}"
                };
                await _auditLogRepository.SaveAsync(auditLog);
            }
        }