/// <summary> /// Assigns an Episode to the given patient /// </summary> /// <param name="patientId">The Id of the Patient to assign the episode to</param> /// <param name="condition">The condition the episode is for</param> /// <param name="externalEpisodeId">The external Episode Id</param> /// <returns>The episode assigned</returns> public Episode AssignEpisode(string patientId, string condition, string externalEpisodeId) { try { SecuritySession.Current.VerifyAccess(Actions.ASSIGN_EPISODE, patientId); Patient p = new UserManager(this.manager).FindPatient(patientId); if (p == null) { throw this.manager.MessageHandler.GetError(ErrorCodes.USER_UNKNOWN); } Episode e = this.manager.EpisodeAccessHandler.AssignEpisode(p, condition, externalEpisodeId); QuestionnaireUserResponseGroup g = this.manager.QuestionnaireAccessHandler.GetLastQuestionnaireResponsesForPatient(p.Id, BusinessLogic.Properties.Settings.Default.CurrentConditionQuestionnaire, null); if (g == null) { this.manager.QuestionnaireAccessHandler.CreateQuestionnaireUserResponseGroup(p.Id, BusinessLogic.Properties.Settings.Default.CurrentConditionQuestionnaire, null, null); } Logger.Audit(new Audit(Model.Security.Actions.ASSIGN_EPISODE, AuditEventType.ADD, typeof(Patient), "Id", patientId)); return(e); } catch (Exception ex) { Logger.Audit(new Audit(Model.Security.Actions.ASSIGN_EPISODE, AuditEventType.ADD, typeof(Patient), "Id", patientId, false, ex.Message)); throw ex; } }
/// <summary> /// Gets the data for an anoymous Pro request /// </summary> /// <param name="patientId">The Id of the patient to get the Questionnaire For</param> /// <param name="questionnaireName">The name of the questionnaire to load</param> /// <param name="episodeId">The Id of the episode to load the questionnaire for</param> /// <param name="platform">The platform to load the format for</param> /// <returns>The Questionnaire requested</returns> public OperationResultAsUserQuestionnaire GetQuestionnaireForPatient(string patientId, string questionnaireName, int?episodeId, Platform platform) { if (WcfUserSessionSecurity.Current.User == null) { return(new OperationResultAsUserQuestionnaire(this.handler.MessageManager.GetError(ErrorCodes.USER_SESSION_EXPIRED), null, null, null)); } PCHI.Model.Questionnaire.Questionnaire q = null; Format f = null; QuestionnaireUserResponseGroup g = null; try { this.handler.UserEpisodeManager.GetQuestionnaireForPatient(patientId, questionnaireName, episodeId, platform, ref q, ref f, ref g); OperationResultAsUserQuestionnaire result; if (q != null && f != null && g != null) { result = new OperationResultAsUserQuestionnaire(null, q, f, g); } else { result = new OperationResultAsUserQuestionnaire(this.handler.MessageManager.GetError(ErrorCodes.DATA_LOAD_ERROR), q, f, g); } return(result); } catch (Exception ex) { return(new OperationResultAsUserQuestionnaire(ex, q, f, g)); } }
/// <summary> /// Initializes a new instance of the <see cref="OperationResultAsUserQuestionnaire"/> class /// </summary> /// <param name="ex">Any exception that has occurred. If no exception has occurred set to null and Succeeded is marked as True. If the exception is not null, succeeded is marked as false and the Errorcode and ErrorMessages are filled in</param> /// <param name="questionnaire">Holds the questionnaire</param> /// <param name="format">Holds the format</param> /// <param name="group">Any response Groups</param> public OperationResultAsUserQuestionnaire(Exception ex, PCHI.Model.Questionnaire.Questionnaire questionnaire, Format format, QuestionnaireUserResponseGroup group) : base(ex) { this.Questionnaire = questionnaire; this.Format = format; this.QuestionnaireUserResponseGroup = group; }
/// <summary> /// Gets the data for an anoymous Pro request /// </summary> /// <param name="anonymous">The encrypted string providing anonymous access</param> /// <param name="platform">The platform to load the format for</param> /// <returns>The Questionnaire requested</returns> public InterfaceContracts.Model.OperationResultAsUserQuestionnaire GetQuestionnaireAnonymous(string anonymous, Platform platform) { PCHI.Model.Questionnaire.Questionnaire q = null; Format f = null; QuestionnaireUserResponseGroup g = null; try { this.handler.UserEpisodeManager.GetQuestionnaireAnonymous(anonymous, platform, ref q, ref f, ref g); OperationResultAsUserQuestionnaire result; if (q != null && f != null && g != null) { result = new OperationResultAsUserQuestionnaire(null, q, f, g); } else { result = new OperationResultAsUserQuestionnaire(this.handler.MessageManager.GetError(ErrorCodes.DATA_LOAD_ERROR), q, f, g); } return(result); } catch (Exception ex) { return(new OperationResultAsUserQuestionnaire(ex, q, f, g)); } }
/// <summary> /// Calculates the scores for all domains belonging to the questionnaire includes and saves them to the database. Any existing domains are overwritten. /// This is ONLY done for PROs /// </summary> /// <param name="group">The group to calculate the scores for</param> public void CalculateResponseScores(QuestionnaireUserResponseGroup group) { if (group.Questionnaire.GetType() == typeof(ProInstrument)) { ProDomainResultSet proDomainResultSet = this.ProcessGroup(group); this.manager.QuestionnaireAccessHandler.SaveProDomainResult(proDomainResultSet); } }
/// <summary> /// Creates a User Response Group for the given user and Questionnaire Name /// </summary> /// <param name="patientId">The id of the Patient</param> /// <param name="questionnaireName">The name of the questionnaire</param> /// <param name="formatName">the name of the format to create the response group for. If null the default format name of the questionnaire is used</param> /// <param name="sqd">The optional scheduled questionniare date that the user responsegroup must belong to</param> /// <returns>The newly created QuestionnaireUserResponseGroup</returns> public QuestionnaireUserResponseGroup CreateQuestionnaireUserResponseGroup(string patientId, string questionnaireName, string formatName, ScheduledQuestionnaireDate sqd) { QuestionnaireUserResponseGroup group = new QuestionnaireUserResponseGroup(); group.Patient = this.context.Patients.Where(u => u.Id == patientId).Single(); group.Questionnaire = this.context.Questionnaires.Where(q => q.Name == questionnaireName).OrderByDescending(q => q.Id).First(); group.QuestionnaireFormatName = formatName == null ? group.Questionnaire.DefaultFormatName : formatName; group.DatetimeCreated = DateTime.Now; group.Status = QuestionnaireUserResponseGroupStatus.New; group.ScheduledQuestionnaireDate = sqd == null ? null : this.context.ScheduledQuestionnaireDates.Where(s => s.Id == sqd.Id).Single(); this.context.QuestionnaireUserResponseGroups.Add(group); this.context.SaveChanges(); new NotificationHandler(this.context).CreateNotification(NotificationType.NewQuestionnaire, group.Id); return(group); }
/// <summary> /// Processes a QuestionnaireUserResponseGroup and calculates the domain results for it. /// The domain must be loaded in the the questionnaire (PRO) of the group /// </summary> /// <param name="group">The group to get the result for</param> /// <returns>A ProDomainResultSet containing the list of calculated PRO Domain Results</returns> private ProDomainResultSet ProcessGroup(QuestionnaireUserResponseGroup group) { ProDomainResultSet gr = new ProDomainResultSet(); gr.GroupId = group.Id; foreach (ProDomain domain in ((ProInstrument)group.Questionnaire).Domains) { ProDomainResult result = new ProDomainResult(); result.DomainId = domain.Id; result.Score = DomainScoreEngine.DomainScoreEngine.CalculateResult(group.Responses.ToList(), domain.ScoreFormula); gr.Results.Add(result); } return(gr); }
/// <summary> /// Finds the current completed QuestionUserResponseGroup for the given user and questionnaireName. /// </summary> /// <param name="userId">The user Id to get the response group for</param> /// <param name="questionnaireName">The name of the questionnaire to get the response group for</param> /// <param name="date">The date by which to get the response group.</param> /// <returns>If Date has not been specified, the last one is always returend. If the date has been specified, the first QuestionnaireUserResponseGroup that was completed after the given date is returned.</returns> public QuestionnaireUserResponseGroup GetCurrentQuestionnaireResponsesForUser(string userId, string questionnaireName, DateTime?date) { var q = this.context.QuestionnaireUserResponseGroups.Where(u => u.Patient.Id == userId && u.Questionnaire.Name == questionnaireName && u.Status == QuestionnaireUserResponseGroupStatus.Completed).Include(u => u.Responses.Select(r => r.Item)).Include(u => u.Responses.Select(r => r.Option.Group.Item.Section.Questionnaire)).Include(r => r.ScheduledQuestionnaireDate.AssignedQuestionnaire.Episode).Include(r => r.Questionnaire); if (date.HasValue) { q = q.Where(e => e.DateTimeCompleted > date.Value); } else { q = q.Where(e => e.DateTimeCompleted == this.context.QuestionnaireUserResponseGroups.Where(e2 => e2.Patient.Id == userId && e2.Questionnaire.Name == questionnaireName).Max(e2 => e2.DateTimeCompleted).Value); } QuestionnaireUserResponseGroup group = q.OrderBy(u => u.DateTimeCompleted).FirstOrDefault(); return(group); }
/// <summary> /// Gets the Last answers given for the user to this Questionnaire provided the QuestionnaireUserResponseGroup is not marked as Completed /// </summary> /// <param name="userEntityId">The Id of the PCHI User Entity to get the responses for</param> /// <param name="questionnaireName">The questionnaire Id to get the responses for</param> /// <param name="episodeId">The optional Id of the episode to look for. If specified, it will look ONLY for response groups belonging to this Episode.</param> /// <param name="excludeCompleted">If true (default) and the last ResponseGroup is completed Null is returned. If false, the last response group is returned instead</param> /// <returns>A QuestionnaireUserResponseGroup containing all responses given for that group</returns> public QuestionnaireUserResponseGroup GetLastQuestionnaireResponsesForPatient(string userEntityId, string questionnaireName, int?episodeId, bool excludeCompleted = true) { var q = this.context.QuestionnaireUserResponseGroups.Where(u => u.Patient.Id == userEntityId && u.Questionnaire.Name == questionnaireName).Include(u => u.Patient).Include(u => u.Responses.Select(r => r.Item)).Include(u => u.Responses.Select(r => r.Option.Group.Item.Section.Questionnaire)).Include(r => r.ScheduledQuestionnaireDate.AssignedQuestionnaire.Episode).Include(r => r.Questionnaire); if (episodeId != null && episodeId.Value > 0) { q = q.Where(e => e.ScheduledQuestionnaireDate.AssignedQuestionnaire.Episode.Id == episodeId.Value); } else { q = q.Where(e => e.ScheduledQuestionnaireDate == null); } QuestionnaireUserResponseGroup group = q.OrderByDescending(u => u.Id).FirstOrDefault(); if (group == null || (excludeCompleted && group.Completed)) { return(null); } return(group); }
/// <summary> /// Gets the last completed first visit questionnaire /// </summary> /// <param name="patientId" >The ID of the Patient to get the result for</param> /// <param name="episodeId">The optional Id of the episode to get the result for, if null or 0 the last filled in is retreived. If not null or greater then 0 the first completed current condition questionnaire is returned AFTER the episode was created</param> /// <returns>The completed questionnaire with format and answers</returns> public OperationResultAsUserQuestionnaire GetCompletedCurrentConditionQuestionnaire(string patientId, int?episodeId) { PCHI.Model.Questionnaire.Questionnaire q = null; QuestionnaireUserResponseGroup g = null; try { this.handler.UserEpisodeManager.GetCompletedCurrentConditionQuestionnaire(patientId, episodeId, ref q, ref g); OperationResultAsUserQuestionnaire result; if (q != null && g != null) { result = new OperationResultAsUserQuestionnaire(null, q, null, g); } else { result = new OperationResultAsUserQuestionnaire(this.handler.MessageManager.GetError(ErrorCodes.DATA_LOAD_ERROR), q, null, g); } return(result); } catch (Exception ex) { return(new OperationResultAsUserQuestionnaire(ex, q, null, g)); } }
/// <summary> /// Copies over the Patient Tags to the QuestionnaireUserResponseGroup Tags /// </summary> /// <param name="group">The QuestionnaireUserResponseGroup to copy the tags to</param> public void AssignQuestionnaireUserResponseGroupTags(QuestionnaireUserResponseGroup group) { List <PatientTag> tags = this.manager.UserAccessHandler.GetPatientTags(group.Patient.Id); var groupTags = tags.Where(t => t.TagName != "Age").Select(t => new QuestionnaireUserResponseGroupTag() { QuestionnaireUserResponseGroup = group, TagName = t.TagName, TextValue = t.TextValue }).ToList(); if (group.Patient.DateOfBirth.HasValue) { DateTime now = DateTime.Today; int age = now.Year - group.Patient.DateOfBirth.Value.Year; if (group.Patient.DateOfBirth > now.AddYears(-age)) { age--; } groupTags.Add(new QuestionnaireUserResponseGroupTag() { QuestionnaireUserResponseGroup = group, TagName = "Age", TextValue = age.ToString() }); } this.manager.QuestionnaireAccessHandler.AddOrUpdateQuestionnaireUserResponseGroupTags(groupTags); }
/// <summary> /// Runs the notification checker and sends outstanding notifications and reminders /// </summary> public static void SendNotifications() { AccessHandlerManager ahm = new AccessHandlerManager(); List <Notification> notifications = ahm.NotificationHandler.GetNotifications(); Dictionary <string, NotificationData> notificationData = new Dictionary <string, NotificationData>(); foreach (Notification n in notifications) { switch (n.NotificationType) { case NotificationType.RegistrationComplete: Task <User> t = ahm.UserAccessHandler.FindByIdAsync(n.NotificationObjectId); t.Wait(); User user = t.Result; NotifcationManager.AssignNotification(user, n.NotificationType, notificationData); n.NotificationSendTime = DateTime.Now; n.NotificationCompleted = true; ahm.NotificationHandler.UpdateNotification(n); break; case NotificationType.NewQuestionnaire: QuestionnaireUserResponseGroup group = ahm.QuestionnaireAccessHandler.GetSmallQuestionnaireUserResponseGroupById(int.Parse(n.NotificationObjectId)); Patient patient = ahm.UserAccessHandler.FindPatient(group.Patient.Id); if (group != null && !group.Completed && group.Patient.ProxyUserPatientMap.Any(m => m.User.EmailConfirmed) && (n.NotificationSendTime == null || n.NotificationSendTime < DateTime.Now.AddHours(-4))) { NotifcationManager.AssignNotification(patient, n.NotificationType, notificationData); n.NotificationSendTime = DateTime.Now; n.NotificationCompleted = true; ahm.NotificationHandler.UpdateNotification(n); } else { n.NotificationCompleted = true; ahm.NotificationHandler.UpdateNotification(n); } break; } } TextParser parser = new TextParser(ahm); foreach (string email in notificationData.Keys) { NotificationData data = notificationData[email]; StringBuilder textBuilder = new StringBuilder(); StringBuilder htmlBuilder = new StringBuilder(); ReplaceableObjectKeys objectKey = data.NotificationTarget.GetType() == typeof(User) ? ReplaceableObjectKeys.User : ReplaceableObjectKeys.Patient; TextDefinition start = parser.ParseMessage("NotificationStart", new Dictionary <ReplaceableObjectKeys, object>() { { objectKey, data.NotificationTarget } }); TextDefinition end = parser.ParseMessage("NotificationEnd", new Dictionary <ReplaceableObjectKeys, object>() { { objectKey, data.NotificationTarget } }); textBuilder.Append(start.Text); htmlBuilder.Append(start.Html); foreach (NotificationType t in data.Notifications) { TextDefinition td; td = parser.ParseMessage(t.ToString(), new Dictionary <ReplaceableObjectKeys, object>() { { objectKey, data.NotificationTarget } }); textBuilder.Append(td.Text); htmlBuilder.Append(td.Html); /* * switch (t) * { * case NotificationType.RegistrationComplete: * //textBuilder.AppendLine(Text) * td = parser.ParseMessage(NotificationType.RegistrationComplete.ToString(), null); * textBuilder.Append(td.Text); * htmlBuilder.Append(td.Html); * break; * case NotificationType.NewQuestionnaire: * td = parser.ParseMessage(NotificationType.RegistrationComplete.ToString(), null); * textBuilder.Append(td.Text); * htmlBuilder.Append(td.Html); * break; * }*/ } textBuilder.Append(end.Text); htmlBuilder.Append(end.Html); SmtpMailClient.SendMail(email, "Replay Notification", textBuilder.ToString(), htmlBuilder.ToString()); } }
/// <summary> /// Saves the given <see cref="QuestionnaireResponse"/> to the database /// Existing answers are overwritten /// </summary> /// <param name="questionnaireId">The Id of the questionnaire to save the response for</param> /// <param name="groupId">The Id of the group for which to save the responses</param> /// <param name="questionnaireCompleted">Indicates whether or user has filled in all responses and the Questionnaire is now completed</param> /// <param name="responses">A list of <see cref="QuestionnaireResponse"/> to save</param> /// <param name="status">The optional status to set the QuestionnaireUserResponse group to. If not given the status will be adjusted based upon the QuestionnaireCompleted flag and if there are any responses</param> /// <exception cref="ArgumentException">Thrown when either the questionniare or group has not been found</exception> public void SaveQuestionnaireResponse(int questionnaireId, int groupId, bool questionnaireCompleted, List <QuestionnaireResponse> responses, QuestionnaireUserResponseGroupStatus?status = null) { Questionnaire questionnaire = this.context.Questionnaires.Where(q => q.Id == questionnaireId).SingleOrDefault(); QuestionnaireUserResponseGroup group = this.context.QuestionnaireUserResponseGroups.Where(u => u.Questionnaire.Name == questionnaire.Name && u.Id == groupId).Include(u => u.Questionnaire).Include(u => u.Patient).SingleOrDefault(); if (group == null) { throw new ArgumentException("No group has been found for the given User and Questionnaire"); } if (questionnaire == null) { throw new ArgumentException("Questionniare doesn't exist"); } if (!group.StartTime.HasValue) { group.StartTime = DateTime.Now; } if (questionnaireCompleted) { group.Completed = true; group.Status = QuestionnaireUserResponseGroupStatus.Completed; group.DateTimeCompleted = DateTime.Now; } else if (responses.Count > 0) { group.Status = QuestionnaireUserResponseGroupStatus.InProgress; } if (status.HasValue) { group.Status = status.Value; } if (responses.Count > 0) { List <QuestionnaireResponse> existingResponses = this.context.QuestionnaireResponses.Where(r => r.QuestionnaireUserResponseGroup.Id == groupId).Include(r => r.Item).ToList(); if (group.Questionnaire.Id != questionnaireId) { // delete all existing answers as we have a new questionnaire Id group.Questionnaire = this.context.Questionnaires.Where(q => q.Id == questionnaireId).Single(); } // Get all option groups that multi-select enabled List <int> multiSelectGroupsIds = this.context.QuestionnaireItemOptionGroups.Where(g => g.Item.Section.Questionnaire.Id == questionnaireId && g.ResponseType == QuestionnaireResponseType.MultiSelect).Select(g => g.Id).ToList(); // Load all the relevant options to increase performance this.context.QuestionnaireItemOptions.Where(o => o.Group.Item.Section.Questionnaire.Id == questionnaireId).Load(); foreach (QuestionnaireResponse response in responses) { // QuestionnaireItem item = this.context.QuestionnaireElements.OfType<QuestionnaireItem>().Where(q => q.Id == response.Item.Id).Include(i => i.OptionGroups.Select(g => g.Options)).Single(); QuestionnaireItemOptionGroup optionGroup = response.Option == null ? null : this.context.QuestionnaireItemOptions.Where(o => o.Id == response.Option.Id).Select(o => o.Group).Single(); if (multiSelectGroupsIds.Contains(optionGroup.Id)) { response.QuestionnaireUserResponseGroup = group; response.Item = response.Item == null ? null : this.context.QuestionnaireElements.OfType <QuestionnaireItem>().Where(el => el.Id == response.Item.Id).SingleOrDefault(); response.Option = response.Option == null ? null : this.context.QuestionnaireItemOptions.Where(o => o.Id == response.Option.Id).SingleOrDefault(); if (response.Item == null && response.Option == null) { throw new ArgumentNullException("Both Item and Option are null in the QuestionnaireResponse and this is not allowed"); } this.context.QuestionnaireResponses.Add(response); } else { QuestionnaireResponse existing = existingResponses.Where(r => r.Item.Id == response.Item.Id && r.Id == optionGroup.Id).SingleOrDefault(); if (existing != null) { existing.Option = response.Option == null ? null : this.context.QuestionnaireItemOptions.Where(o => o.Id == response.Option.Id).SingleOrDefault(); existing.ResponseValue = response.ResponseValue; existing.ResponseText = response.ResponseText; this.context.Entry(existing).State = EntityState.Modified; } else { response.QuestionnaireUserResponseGroup = group; response.Item = response.Item == null ? null : this.context.QuestionnaireElements.OfType <QuestionnaireItem>().Where(el => el.Id == response.Item.Id).SingleOrDefault(); response.Option = response.Option == null ? null : this.context.QuestionnaireItemOptions.Where(o => o.Id == response.Option.Id).SingleOrDefault(); if (response.Item == null && response.Option == null) { throw new ArgumentNullException("Both Item and Option are null in the QuestionnaireResponse and this is not allowed"); } this.context.QuestionnaireResponses.Add(response); } } } existingResponses.Where(r => this.context.Entry(r).State == EntityState.Unchanged).ToList().ForEach(o => this.context.Entry(o).State = EntityState.Deleted); } try { this.context.SaveChanges(); } catch (DbEntityValidationException e) { string errorResult = string.Empty; foreach (var eve in e.EntityValidationErrors) { errorResult += "Entity of type \" " + eve.Entry.Entity.GetType().Name + "\" in state \"" + eve.Entry.State + "\" has the following validation errors: \n"; foreach (var ve in eve.ValidationErrors) { errorResult += "- Property: \"" + ve.PropertyName + "\", Error: \"" + ve.ErrorMessage + "\" \n"; } } throw new DbEntityValidationException(errorResult, e); } }
/// <summary> /// Gets the questionnare, format and response group to fill in for the questionnaire /// </summary> /// <param name="patientId">The Id of the Patient to get the questionnaire for</param> /// <param name="questionnaireName">The name of the questionnaire to load</param> /// <param name="episodeId">The Id of the episode to load the questionnaire for</param> /// <param name="platform">The platform for which to load the format</param> /// <param name="q">The resulting questionnaire </param> /// <param name="f">The resulting format</param> /// <param name="g">The resulting Response group</param> /// <exception cref="PCHIError">Thrown when no response group has been assigned to the user for the questionnaire or when the questionnaire has already been completed</exception> public void GetQuestionnaireForPatient(string patientId, string questionnaireName, int?episodeId, Platform platform, ref Questionnaire q, ref Format f, ref QuestionnaireUserResponseGroup g) { try { SecuritySession.Current.VerifyAccess(Actions.GET_QUESTIONNAIRE_FOR_PATIENT, patientId, episodeId); g = this.manager.QuestionnaireAccessHandler.GetLastQuestionnaireResponsesForPatient(patientId, questionnaireName, episodeId); if (g == null) { throw this.manager.MessageHandler.GetError(ErrorCodes.QUESTIONNAIRE_NOT_ASSIGNED); } q = this.manager.QuestionnaireAccessHandler.GetFullQuestionnaireByName(questionnaireName); f = this.manager.QuestionnaireFormatAccessHandler.GetFullFormatByName(g.QuestionnaireFormatName, platform); q.CurrentInstance = this.manager.QuestionnaireAccessHandler.GetAllQuestionnaireResponsesForPatient <Questionnaire>(patientId, questionnaireName).Count > 0 ? Instance.Followup : Instance.Baseline; Instance currentInstance = q.CurrentInstance; UserTypes audience = UserTypes.Patient; Utilities.Utilities.Filter(ref q, currentInstance, platform, audience); /* * q.IntroductionMessages = q.IntroductionMessages.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * q.Descriptions = q.Descriptions.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * foreach (QuestionnaireSection s in q.Sections) * { * s.Instructions = s.Instructions.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * foreach (QuestionnaireElement e in s.Elements) * { * e.TextVersions = e.TextVersions.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * if (e.GetType() == typeof(QuestionnaireItem)) * { * QuestionnaireItem item = (QuestionnaireItem)e; * item.Instructions = item.Instructions.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * foreach (QuestionnaireItemOptionGroup group in item.OptionGroups) * { * group.TextVersions = group.TextVersions.Where(i => i.SupportsInstance(currentInstance) && i.SupportsPlatform(platform) && i.SupportsAudience(audience)).ToList(); * } * } * } * }*/ TextParser p = new TextParser(this.manager); p.UpdateQuestionnaireTexts(q, new Dictionary <Model.Messages.ReplaceableObjectKeys, object>() { { ReplaceableObjectKeys.Patient, g.Patient }, }); Logger.Audit(new Audit(Model.Security.Actions.GET_QUESTIONNAIRE_FOR_PATIENT, AuditEventType.READ, g)); } catch (Exception ex) { Logger.Audit(new Audit(Model.Security.Actions.GET_QUESTIONNAIRE_FOR_PATIENT, AuditEventType.READ, typeof(Patient), "Id", patientId, false, ex.Message)); throw ex; } }
/// <summary> /// Gets the questionnare, format and response group to fill in for the anonymous questionnaire /// </summary> /// <param name="anonymous">The anonymous idenfitier string</param> /// <param name="platform">The platform to load everything for</param> /// <param name="q">The resulting questionnaire </param> /// <param name="f">The resulting format</param> /// <param name="g">The resulting Response group</param> /// <exception cref="ArgumentException">Thrown when no response group has been assigned to the user for the questionnaire and format encoded in the anonymous string</exception> /// <exception cref="AccessViolationException">Thrown when the user has already answers 1 or more questions on this questionnaire for the given response group</exception> public void GetQuestionnaireAnonymous(string anonymous, Platform platform, ref Questionnaire q, ref Format f, ref QuestionnaireUserResponseGroup g) { try { string patientId = null; string questionnaireName = null; string formatName = null; int? episodeId = null; this.DecryptAnonymous(anonymous, ref patientId, ref questionnaireName, ref formatName, ref episodeId); Logger.Audit(new Audit(Model.Security.Actions.GET_QUESTIONNAIRE_ANONYMOUS, AuditEventType.READ, typeof(Patient), "Id", patientId)); this.GetQuestionnaireForPatient(patientId, questionnaireName, episodeId, platform, ref q, ref f, ref g); if (g.Responses.Count > 0) { throw this.manager.MessageHandler.GetError(ErrorCodes.ANONYMOUS_QUESTIONNAIRE_CANNOT_BE_CONTINUED_ANONYMOUSLY); } } catch (Exception ex) { Logger.Audit(new Audit(Model.Security.Actions.GET_QUESTIONNAIRE_ANONYMOUS, AuditEventType.READ, null, null, anonymous, false, ex.Message)); throw ex; } }
/// <summary> /// Creates or updates a patient. /// If a user with the given Username doesn't exist it will be created, if it does exist, the patient will be added to that user /// </summary> /// <param name="externalId">The external ID of the patient</param> /// <param name="userName">The username of the user</param> /// <param name="email">The email</param> /// <param name="title">the title of the patient</param> /// <param name="firstName">The first name</param> /// <param name="lastName">The last name</param> /// <param name="dateOfBirth">The date of birth</param> /// <param name="mobilePhone">The patients mobile phone</param> /// <returns>The created or updated Patient</returns> public Patient CreateOrUpdatePatient(string externalId, string userName, string email, string title, string firstName, string lastName, DateTime dateOfBirth, string mobilePhone) { try { SecuritySession.Current.VerifyAccess(Actions.CREATE_OR_UPDATE_PATIENT); if (userName.Length > 450) { throw this.manager.MessageHandler.GetError(ErrorCodes.USERNAME_LENGTH_EXCEEDED); } if (userName.Contains("\\") || userName.Contains("/")) { throw this.manager.MessageHandler.GetError(ErrorCodes.USERNAME_CONTAINS_ILLEGAL_CHARACTERS); } } catch (Exception ex) { Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, typeof(Patient), "Email", email, false, ex.Message)); throw ex; } IdentityResult result = new IdentityResult(null); User existing = this.Users.Where(u => u.UserName == userName).SingleOrDefault(); User user = null; if (existing == null) { try { result = UserManagerExtensions.Create(this, new User() { UserName = userName, Email = email, PhoneNumber = mobilePhone, Title = title, FirstName = firstName, LastName = lastName }); if (result.Succeeded) { user = this.Users.Where(u => u.UserName == userName).SingleOrDefault(); } else { throw new PCHIError(ErrorCodes.GENERAL_IDENTITY_RESULT_ERROR, result.Errors.Aggregate((s1, s2) => { return(s1 + "\n" + s2); })); } Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, user)); } catch (Exception ex) { Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, typeof(User), "UserName", userName, false, ex.Message)); throw ex; } } else { user = existing; } Patient patient = null; Patient newPatient = null; if (user != null) { patient = !string.IsNullOrWhiteSpace(externalId) ? this.manager.UserAccessHandler.GetPatientByExternalId(externalId) : null; try { if (patient != null) { Patient p = patient; p.Title = title; p.FirstName = firstName; p.LastName = lastName; p.ProxyUserPatientMap.Add(new ProxyUserPatientMap(user, p)); p.DateOfBirth = dateOfBirth; p.Email = email; p.PhoneNumber = mobilePhone; p.ExternalId = externalId; this.manager.UserAccessHandler.Update(p); Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.MODIFIED, p)); } else { Patient p = new Patient(); p.Title = title; p.FirstName = firstName; p.LastName = lastName; p.ProxyUserPatientMap.Add(new ProxyUserPatientMap(user, p)); p.DateOfBirth = dateOfBirth; p.Email = email; p.PhoneNumber = mobilePhone; p.ExternalId = externalId; this.manager.UserAccessHandler.Add(p); newPatient = p; Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, p)); } this.AddToRole(user.Id, "PatientProxy"); } catch (Exception ex) { Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, typeof(Patient), "Email", email, false, ex.Message)); throw ex; } } // Only send the registration mail if the user is created (i.e. existing is null) if (existing == null && user != null) { UserSecurityCode confirmationToken = null; do { confirmationToken = UserSecurityCode.CreateSecurityCode(user, "Registration"); } while (this.FindUserForRegistrationToken(confirmationToken.Code) != null); user.RegistrationConfirmationToken = confirmationToken.EncryptedCode; UserManagerExtensions.Update(this, user); // string confirmationToken = HttpUtility.UrlEncode(MachineKeyEncryption.Encrypt(user.UserName)); TextParser parser = new TextParser(this.manager); TextDefinition td = parser.ParseMessage("RegistrationEmail", new Dictionary <Model.Messages.ReplaceableObjectKeys, object>() { { ReplaceableObjectKeys.Patient, newPatient }, { ReplaceableObjectKeys.Code, confirmationToken.Code } }); SmtpMailClient.SendMail(user.Email, "OPSMC RePLAY Registration", td.Text, td.Html); } if (newPatient != null) { try { QuestionnaireUserResponseGroup group = this.manager.QuestionnaireAccessHandler.CreateQuestionnaireUserResponseGroup(newPatient.Id, BusinessLogic.Properties.Settings.Default.NewRegistrationQuestionnaire, null, null); Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, group)); } catch (Exception ex) { Logger.Audit(new Audit(Actions.CREATE_OR_UPDATE_PATIENT, AuditEventType.ADD, typeof(QuestionnaireUserResponseGroup), "Id", null, false, ex.Message)); throw ex; } } return(newPatient == null ? patient : newPatient); }
/// <summary> /// Extracts the data from the responses given and saves them to the Patient Tags /// </summary> /// <param name="group">The Questionnaire User Response group to get the data from</param> public void ExtractQuestionnaireData(QuestionnaireUserResponseGroup group) { List <QuestionnaireDataExtraction> extractionData = this.manager.QuestionnaireAccessHandler.GetDataExtrationDefinitions(group.Questionnaire.Name); List <PatientTag> patientTags = new List <PatientTag>(); foreach (QuestionnaireDataExtraction data in extractionData) { var responses = group.Responses.Where(r => r.Item.ActionId == data.ItemActionId).ToList(); if (responses.Count > 0) { List <string> values = new List <string>(); if (!string.IsNullOrWhiteSpace(data.OptionGroupActionId)) { string value = string.Empty; foreach (var response in responses) { if (response.ResponseValue.HasValue) { values.Add(response.ResponseValue.Value.ToString()); } if (response.ResponseText != null) { values.Add(response.ResponseText); } } } else { if (!string.IsNullOrWhiteSpace(data.OptionActionId)) { var subResponses = responses.Where(o => o.Option.Group.ActionId == data.OptionGroupActionId).ToList(); foreach (var response in subResponses) { if (response.ResponseValue.HasValue) { values.Add(response.ResponseValue.Value.ToString()); } if (response.ResponseText != null) { values.Add(response.ResponseText); } } } else { var response = responses.Where(o => o.Option.Group.ActionId == data.OptionGroupActionId && o.Option.ActionId == data.OptionActionId).SingleOrDefault(); if (response != null) { if (response.ResponseValue.HasValue) { values.Add(response.ResponseValue.Value.ToString()); } if (response.ResponseText != null) { values.Add(response.ResponseText); } } } } if (values.Count > 0) { PatientTag t = new PatientTag(); t.Patient = group.Patient; t.TagName = data.TagName; t.TextValue = values.Aggregate((s1, s2) => { return(s1 + "|" + s2); }); patientTags.Add(t); } } } if (group.Patient.DateOfBirth.HasValue) { DateTime now = DateTime.Today; int age = now.Year - group.Patient.DateOfBirth.Value.Year; if (group.Patient.DateOfBirth > now.AddYears(-age)) { age--; } patientTags.Add(new PatientTag() { Patient = group.Patient, TagName = "Age", TextValue = age.ToString() }); } this.manager.UserAccessHandler.AddOrUpdatePatientTags(patientTags); }
/// <summary> /// Gets the appropriate completed CompletedCurrentCondition questionnaire /// </summary> /// <param name="patientId">The id of the patient to get the questionnaire for</param> /// <param name="episodeId">The optional id of the episode to get the questionnaire for. If not specified, the last one found is returned instead</param> /// <param name="q">The questionnaire instance to fill</param> /// <param name="g">The responsegroup to fill</param> public void GetCompletedCurrentConditionQuestionnaire(string patientId, int?episodeId, ref Questionnaire q, ref QuestionnaireUserResponseGroup g) { try { SecuritySession.Current.VerifyAccess(Actions.GET_COMPLETED_CURRENT_CONDITION_QUESTIONNAIRE, patientId: patientId, episodeId: episodeId); DateTime?date = null; if (episodeId != null && episodeId.Value > 0) { Episode e = this.manager.EpisodeAccessHandler.GetEpisodeById(episodeId.Value); date = e.DateCreated; } g = this.manager.QuestionnaireAccessHandler.GetCurrentQuestionnaireResponsesForUser(patientId, BusinessLogic.Properties.Settings.Default.CurrentConditionQuestionnaire, date); if (g == null) { throw this.manager.MessageHandler.GetError(ErrorCodes.QUESTIONNAIRE_NOT_ASSIGNED); } q = this.manager.QuestionnaireAccessHandler.GetFullQuestionnaireByName(BusinessLogic.Properties.Settings.Default.CurrentConditionQuestionnaire); q.CurrentInstance = this.manager.QuestionnaireAccessHandler.GetAllQuestionnaireResponsesForPatient <Questionnaire>(patientId, BusinessLogic.Properties.Settings.Default.CurrentConditionQuestionnaire).Count > 0 ? Instance.Followup : Instance.Baseline; Logger.Audit(new Audit(Model.Security.Actions.GET_COMPLETED_CURRENT_CONDITION_QUESTIONNAIRE, AuditEventType.READ, typeof(Patient), "Id", patientId)); } catch (Exception ex) { Logger.Audit(new Audit(Model.Security.Actions.GET_COMPLETED_CURRENT_CONDITION_QUESTIONNAIRE, AuditEventType.READ, typeof(Patient), "Id", patientId, false, ex.Message)); throw ex; } }