Skip to content

Commit

Permalink
Merge Patients (#166)
Browse files Browse the repository at this point in the history
* Merge patient UI
* Database functionality and UI for both databases
* Update report templates
  • Loading branch information
markusrt authored Aug 31, 2024
1 parent a0445c1 commit 2353038
Show file tree
Hide file tree
Showing 46 changed files with 496 additions and 3 deletions.
2 changes: 2 additions & 0 deletions HaemophilusWeb/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public ActionResult Index()
},
new List<Change>
{
new Change(new DateTime(2024, 08, 10), "Update Kopfzeile Befundvorlagen", ChangeType.Feature, DatabaseType.None),
new Change(new DateTime(2024, 08, 8), "Maske zum Zusammenfügen von Patienten", ChangeType.Feature, DatabaseType.None),
new Change(new DateTime(2024, 06, 30), "Stämme: Update Regel 43", ChangeType.Feature, DatabaseType.Meningococci),
new Change(new DateTime(2024, 06, 20, 8, 30, 0), "Deutlich schnellere Exporte", ChangeType.Bug, DatabaseType.None),
new Change(new DateTime(2024, 06, 20, 8, 0, 0), "Erweiterung der Exporte um Demis ID", ChangeType.Feature, DatabaseType.None),
Expand Down
22 changes: 22 additions & 0 deletions HaemophilusWeb/Controllers/MeningoPatientSendingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ private void ValidatePatientBirthdateGreaterOrEqualReceivingDate(PatientSendingV

protected override string IsolateControllerName => "MeningoIsolate";

protected override IEnumerable<MeningoSending> SendingsByPatient(int patientId)
{
var queryResult = NotDeletedSendings()
.Include(s => s.Patient)
.Include(s => s.Isolate)
.Where(s => s.MeningoPatientId == patientId);
return queryResult;
}

protected override void MergePatients(int patientIdToKeep, int patientIdToDelete)
{
var sendingsToMigrate = SendingsByPatient(patientIdToDelete);
foreach (var sending in sendingsToMigrate)
{
sending.MeningoPatientId = patientIdToKeep;
}

var patientToDelete = PatientDbSet().Find(patientIdToDelete);
PatientDbSet().Remove(patientToDelete);
db.SaveChanges();
}

protected override IEnumerable<MeningoSending> SendingsMatchingExportQuery(FromToQuery query, ExportType exportType)
{
var queryResult = NotDeletedSendings()
Expand Down
22 changes: 22 additions & 0 deletions HaemophilusWeb/Controllers/PatientSendingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ protected override void CreateAndEditPreparationsExtensions(PatientSendingViewMo

protected override string IsolateControllerName => "Isolate";

protected override IEnumerable<Sending> SendingsByPatient(int patientId)
{
var queryResult = NotDeletedSendings()
.Include(s => s.Patient)
.Include(s => s.Isolate)
.Where(s => s.PatientId == patientId);
return queryResult;
}

protected override void MergePatients(int patientIdToKeep, int patientIdToDelete)
{
var sendingsToMigrate = SendingsByPatient(patientIdToDelete);
foreach (var sending in sendingsToMigrate)
{
sending.PatientId = patientIdToKeep;
}

var patientToDelete = PatientDbSet().Find(patientIdToDelete);
PatientDbSet().Remove(patientToDelete);
db.SaveChanges();
}

protected override IEnumerable<Sending> SendingsMatchingExportQuery(FromToQuery query, ExportType exportType)
{
var samplingLocations = exportType == ExportType.Rki || exportType == ExportType.Iris
Expand Down
67 changes: 67 additions & 0 deletions HaemophilusWeb/Controllers/PatientSendingControllerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Web.Mvc;
using DataTables.Mvc;
using FluentValidation;
using HaemophilusWeb.Migrations;
using HaemophilusWeb.Models;
using HaemophilusWeb.Tools;
using HaemophilusWeb.Utils;
Expand Down Expand Up @@ -85,6 +86,10 @@ protected IQueryable<TSending> NotDeletedSendings()
return SendingDbSet().Where(s => !s.Deleted);
}

protected abstract IEnumerable<TSending> SendingsByPatient(int patientId);

protected abstract void MergePatients(int patientIdToKeep, int patientIdToDelete);

protected abstract IEnumerable<TSending> SendingsMatchingExportQuery(FromToQuery query, ExportType additionalFilters);

protected abstract ExportDefinition<TSending> CreateRkiExportDefinition();
Expand Down Expand Up @@ -114,6 +119,13 @@ protected TSending LoadSendingFromSendingController(int? id)
return sending;
}

protected TPatient LoadPatientFromPatientController(int? id)
{
var patientResult = patientController.Edit(id) as ViewResult;
var patient = (TPatient) patientResult.Model;
return patient;
}

[HttpPost]
[Authorize(Roles = DefaultRoles.User)]
public ActionResult Edit(TViewModel patientSending)
Expand Down Expand Up @@ -290,6 +302,61 @@ public ActionResult LaboratoryExport(FromToQuery query)
return ExportToExcel(query, sendings, CreateLaboratoryExportDefinition(), "Labor");
}

[Authorize(Roles = DefaultRoles.User)]
public ActionResult MergePatient(MergePatientRequest mergeRequest)
{
if (!ModelState.IsValid)
{
return View(mergeRequest);
}

var sendingsOne = SendingsByPatient(mergeRequest.PatientOneId).ToList();
if (!sendingsOne.Any())
{
ModelState.AddModelError(nameof(MergePatientRequest.PatientOneId), "Unbekannter Patient");
}
var sendingsTwo = SendingsByPatient(mergeRequest.PatientTwoId).ToList();
if (!sendingsTwo.Any())
{
ModelState.AddModelError(nameof(MergePatientRequest.PatientTwoId), "Unbekannter Patient");
}

if (!ModelState.IsValid)
{
return View(mergeRequest);
}

var confirmation = new MergePatientConfirmation
{
PatientOne = sendingsOne.First().Patient.ToReportFormatLong(),
PatientOneId = mergeRequest.PatientOneId,
PatientOneSendings = sendingsOne.Select(s => s.ToReportFormat()).ToList(),
PatientTwo = sendingsTwo.First().Patient.ToReportFormatLong(),
PatientTwoId = mergeRequest.PatientOneId,
PatientTwoSendings = sendingsTwo.Select(s => s.ToReportFormat()).ToList(),
MainPatient = mergeRequest.MainPatient,
Confirmation = true
};

if (!mergeRequest.Confirmation)
{
return View("MergePatientConfirmation", confirmation);
}

if (mergeRequest.MainPatient == MainPatientSelector.PatientOne)
{
MergePatients(mergeRequest.PatientOneId, mergeRequest.PatientTwoId);
}
else
{
MergePatients(mergeRequest.PatientTwoId, mergeRequest.PatientOneId);
}

return View("MergePatientSuccess", confirmation);

}


[HttpPost]
[Authorize(Roles = DefaultRoles.User)]
public JsonResult DataTableAjax([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestParameters)
Expand Down
9 changes: 9 additions & 0 deletions HaemophilusWeb/HaemophilusWeb.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -600,11 +600,14 @@
<Compile Include="Validators\EucastClinicalBreakpointValidator.cs" />
<Compile Include="Validators\HealthOfficeValidator.cs" />
<Compile Include="Validators\MeningoPatientValidator.cs" />
<Compile Include="Validators\MergePatientRequestValidator.cs" />
<Compile Include="Validators\PatientValidator.cs" />
<Compile Include="Validators\MeningoSendingValidator.cs" />
<Compile Include="Validators\SendingValidator.cs" />
<Compile Include="ViewModels\EpsilometerTestReportModel.cs" />
<Compile Include="ViewModels\EpsilometerTestViewModel.cs" />
<Compile Include="ViewModels\MergePatientConfirmation.cs" />
<Compile Include="ViewModels\MergePatientRequest.cs" />
<Compile Include="ViewModels\IsolateViewModel.cs" />
<Compile Include="ViewModels\MeningoIsolateViewModel.cs" />
<Compile Include="ViewModels\PatientSendingViewModel.cs" />
Expand Down Expand Up @@ -1049,6 +1052,12 @@
<Content Include="Views\MeningoSender\Export.cshtml" />
<Content Include="Scripts\moment.min.js.map" />
<Content Include="Scripts\moment-with-locales.min.js.map" />
<Content Include="Views\MeningoPatientSending\MergePatient.cshtml" />
<Content Include="Views\MeningoPatientSending\MergePatientConfirmation.cshtml" />
<Content Include="Views\MeningoPatientSending\MergePatientSuccess.cshtml" />
<Content Include="Views\PatientSending\MergePatient.cshtml" />
<Content Include="Views\PatientSending\MergePatientConfirmation.cshtml" />
<Content Include="Views\PatientSending\MergePatientSuccess.cshtml" />
<None Include="Web.template.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.template.config</DependentUpon>
Expand Down
4 changes: 2 additions & 2 deletions HaemophilusWeb/Properties/GlobalAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:

[assembly: AssemblyVersion("3.38")]
[assembly: AssemblyFileVersion("3.38")]
[assembly: AssemblyVersion("3.39")]
[assembly: AssemblyFileVersion("3.39")]
Binary file modified HaemophilusWeb/ReportTemplates/BLNAR v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/BLNAS v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/BLPACR v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/BLPACS v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - BLNAR v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - BLNAS v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - BLPACR v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - BLPACS v10.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - Kein Wachstum v1.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - Nicht Invasiv v1.docx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Fax - Teilbefund - Serotyp v4.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Kein Wachstum v1.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Meningo/Fax - Nativmaterial v2.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Meningo/Fax - Teilbefund - v2.docx
Binary file not shown.
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Meningo/Nativmaterial v2.docx
Binary file not shown.
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Nicht Invasiv v1.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Sonstige - Ampi-S Cipro-R v3.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/Sonstige - Ampi-S Imi-R v3.docx
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/includes/Kopfzeile - Kontakt.docx
Binary file not shown.
Binary file modified HaemophilusWeb/ReportTemplates/includes/Kopfzeile - Kurz.docx
Binary file not shown.
1 change: 1 addition & 0 deletions HaemophilusWeb/Tools/ExportDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public void AddField<TMember>(Expression<Func<T, TMember>> field, string headerN
exportedFields.Add(Tuple.Create(wrappedExpression, headerName, typeof(TMember)));
}


protected void AddFieldOnPositiveTestResult<TMember>(Func<T, NativeMaterialTestResult> testResult, Func<T, TMember> field, string headerName)
{
AddField(s => testResult(s) == NativeMaterialTestResult.Positive
Expand Down
11 changes: 11 additions & 0 deletions HaemophilusWeb/Utils/ReportFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ public static string ToReportFormat(this PatientBase patient)
return $"{patient.Initials} / {patient.PostalCode}";
}

public static string ToReportFormatLong(this PatientBase patient)
{
return $"Patienten-Nr.: {patient.PatientId}, Initialen: {patient.Initials}, Geschlecht: {EnumUtils.GetEnumDescription<Gender>(patient.Gender)}, Postleitzahl: {patient.PostalCode}";
}

public static string ToReportFormat<TPatient>(this SendingBase<TPatient> sending)
{
return $"Labornummer: {sending.GetIsolate().LaboratoryNumberWithPrefix}, Labnr. Einsender: {sending.SenderLaboratoryNumber}, Eingangsdatum: {sending.ReceivingDate.ToReportFormat()}, Stammnummer: {sending.GetIsolate().StemNumberWithPrefix}";
}


public static string ToStemNumberWithPrefix(this int? stemNumber, DatabaseType databaseType = DatabaseType.None)
{
var stemNumberString = stemNumber.HasValue? stemNumber.ToString() : " -";
Expand Down
15 changes: 15 additions & 0 deletions HaemophilusWeb/Validators/MergePatientRequestValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using FluentValidation;
using HaemophilusWeb.Models;
using HaemophilusWeb.ViewModels;

namespace HaemophilusWeb.Validators
{
public class MergePatientRequestValidator : AbstractValidator<MergePatientRequest>
{
public MergePatientRequestValidator()
{
RuleFor(m => m.PatientOneId).NotEqual(m => m.PatientTwoId)
.WithMessage("Bitte geben Sie zum Zusammenfügen zwei verschiedenen Patientennummern ein");
}
}
}
33 changes: 33 additions & 0 deletions HaemophilusWeb/ViewModels/MergePatientConfirmation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using DocumentFormat.OpenXml.Office2010.ExcelAc;
using HaemophilusWeb.Models;

namespace HaemophilusWeb.ViewModels
{
public class MergePatientConfirmation : MergePatientRequest
{
[Display(Name = "Patient 1")]
public string PatientOne { get; set; }

[Display(Name = "Einsendungen Patient 1")]
public List<string> PatientOneSendings { get; set; }

[Display(Name = "Patient 2")]
public string PatientTwo { get; set; }

[Display(Name = "Einsendungen Patient 2")]
public List<string> PatientTwoSendings { get; set; }

}

public enum MainPatientSelector
{
[Description("Patient 1")]
PatientOne,
[Description("Patient 2")]
PatientTwo
}
}
22 changes: 22 additions & 0 deletions HaemophilusWeb/ViewModels/MergePatientRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.ComponentModel.DataAnnotations;
using FluentValidation.Attributes;
using HaemophilusWeb.Validators;

namespace HaemophilusWeb.ViewModels
{
[Validator(typeof (MergePatientRequestValidator))]
public class MergePatientRequest
{
[Display(Name = "Patienten-Nr. 1")]
public int PatientOneId { get; set; }

[Display(Name = "Patienten-Nr. 2")]
public int PatientTwoId { get; set; }

[Display(Name = "Zusammenfügen zu")]
public MainPatientSelector MainPatient { get; set; }

public bool Confirmation { get; set; }
}
}
27 changes: 27 additions & 0 deletions HaemophilusWeb/Views/MeningoPatientSending/MergePatient.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@using HaemophilusWeb.Views.Utils
@model HaemophilusWeb.ViewModels.MergePatientRequest

@{
ViewBag.Title = "Patienten Zusammenfügen (Meningokokken)";
}

<h3>Patientennummern</h3>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
@Html.ValidationSummary(true)

@Html.TextEditorFor(m => m.PatientOneId)
@Html.TextEditorFor(m => m.PatientTwoId)

<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" name="primary-submit" value="Zusammenfügen vorbereiten" class="btn btn-primary" />
</div>
</div>
</div>
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@using HaemophilusWeb.Views.Utils
@model HaemophilusWeb.ViewModels.MergePatientConfirmation

@{
ViewBag.Title = "Patienten Zusammenfügen (Meningokokken)";
}

<h3>Bestätigung</h3>

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
@Html.ValidationSummary(true)

@Html.HiddenFor(m => m.PatientOneId)
@Html.HiddenFor(m => m.PatientTwoId)
@Html.HiddenFor(m => m.Confirmation)

@Html.ReadonlyFor(m => m.PatientOne, smXClass: "col-sm-10")
<div class="form-group">
<div class="col-sm-2 control-label">@Html.LabelFor(m => m.PatientOneSendings)</div>
<div class="col-sm-10 form-control-static">
<ul>
@foreach (var sending in Model.PatientOneSendings)
{
<li>@sending</li>
}
</ul>
</div>
</div>
<hr />
@Html.ReadonlyFor(m => m.PatientTwo, smXClass: "col-sm-10")
<div class="form-group">
<div class="col-sm-2 control-label">@Html.LabelFor(m => m.PatientTwoSendings)</div>
<div class="col-sm-10 form-control-static">
<ul>
@foreach (var sending in Model.PatientTwoSendings)
{
<li>@sending</li>
}
</ul>
</div>
</div>
<hr />
@Html.EnumRadioEditorFor(m => m.MainPatient)
<hr />
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" name="primary-submit" value="Zusammenfügen und doppelten Patienten löschen" class="btn btn-danger" />
@Html.ActionLink("Abbrechen", "MergePatient", "MeningoPatientSending", null, new { @class = "btn btn-secondary" })
</div>
</div>
</div>
}

Loading

0 comments on commit 2353038

Please sign in to comment.