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