working Patient record merge. Fixing IPS Export Data model for more flexibility.
This commit is contained in:
parent
182d56fb88
commit
af1c033a5c
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TwiN/deepmerge"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
|
@ -15,13 +16,33 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Context) (interface{}, interface{}, error) {
|
||||
// returns IPSBundle and IPSComposition
|
||||
func (gr *GormRepository) GetInternationalPatientSummaryExport(ctx context.Context) (*ips.InternationalPatientSummaryExportData, error) {
|
||||
exportData := &ips.InternationalPatientSummaryExportData{}
|
||||
|
||||
summaryTime := time.Now()
|
||||
timestamp := summaryTime.Format(time.RFC3339)
|
||||
|
||||
exportData.GenerationDate = summaryTime
|
||||
|
||||
//get a list of all Patients associated with this user (we'll be creating a pseudo Patient for referencing in this Bundle
|
||||
patient, err := gr.GetPatientMerged(ctx)
|
||||
if err != nil {
|
||||
//TODO: determine if we should error out here. If only manually entered records were entered, we wont have a Patient record,
|
||||
return exportData, err
|
||||
}
|
||||
exportData.Patient = patient
|
||||
|
||||
//get a list of all Sources associated with this user
|
||||
sources, err := gr.GetSources(ctx)
|
||||
if err != nil {
|
||||
return exportData, err
|
||||
}
|
||||
exportData.Sources = sources
|
||||
|
||||
narrativeEngine, err := ips.NewNarrative()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating narrative engine: %w", err)
|
||||
return exportData, fmt.Errorf("error creating narrative engine: %w", err)
|
||||
}
|
||||
|
||||
//Algorithm to create the IPS bundle
|
||||
|
@ -42,7 +63,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
//Step 1. Generate the IPS Section Lists
|
||||
summarySectionQueryResults, err := gr.getInternationalPatientSummarySectionResources(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return exportData, err
|
||||
}
|
||||
|
||||
//Step 2. Create the Composition Section
|
||||
|
@ -50,7 +71,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
for sectionType, sectionQueryResultsList := range summarySectionQueryResults {
|
||||
compositionSection, err := generateIPSCompositionSection(narrativeEngine, sectionType, sectionQueryResultsList)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return exportData, err
|
||||
}
|
||||
compositionSections = append(compositionSections, *compositionSection)
|
||||
}
|
||||
|
@ -60,6 +81,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
//TODO: Step 4. Create a Fasten Health Organization resource.
|
||||
|
||||
compositionUUID := uuid.New().String()
|
||||
patientReference := fmt.Sprintf("%s/%s", exportData.Patient.GetSourceResourceType(), exportData.Patient.GetSourceResourceID())
|
||||
|
||||
//Step 5. Create the IPS Composition
|
||||
ipsComposition := &fhir401.Composition{
|
||||
|
@ -83,7 +105,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
},
|
||||
},
|
||||
Subject: &fhir401.Reference{
|
||||
Reference: stringPtr("Patient/123"), //TODO
|
||||
Reference: stringPtr(patientReference), //TODO
|
||||
},
|
||||
Date: timestamp,
|
||||
Author: []fhir401.Reference{
|
||||
|
@ -97,7 +119,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
Mode: fhir401.CompositionAttestationModePersonal,
|
||||
Time: ×tamp,
|
||||
Party: &fhir401.Reference{
|
||||
Reference: stringPtr("Patient/123"),
|
||||
Reference: stringPtr(patientReference),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -138,7 +160,7 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
// Add the Composition to the bundle
|
||||
ipsCompositionJson, err := json.Marshal(ipsComposition)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return exportData, err
|
||||
}
|
||||
ipsBundle.Entry = append(ipsBundle.Entry, fhir401.BundleEntry{
|
||||
Resource: json.RawMessage(ipsCompositionJson),
|
||||
|
@ -156,7 +178,10 @@ func (gr *GormRepository) GetInternationalPatientSummaryBundle(ctx context.Conte
|
|||
// }
|
||||
//}
|
||||
|
||||
return ipsBundle, ipsComposition, nil
|
||||
exportData.Bundle = ipsBundle
|
||||
exportData.Composition = ipsComposition
|
||||
|
||||
return exportData, nil
|
||||
}
|
||||
|
||||
// GetInternationalPatientSummary will generate an IPS bundle, which can then be used to generate a IPS QR code, PDF or JSON bundle
|
||||
|
@ -697,11 +722,64 @@ func flattenQueryResultsToResourcesList(queryResultsList []any) []database.IFhir
|
|||
return resources
|
||||
}
|
||||
|
||||
func generateIPSSectionNarrative(sectionType pkg.IPSSections, resources []models.ResourceBase) string {
|
||||
return ""
|
||||
// When given a list of Patient database records, we need to merge them together to a Patient record that's usable by the
|
||||
func (gr *GormRepository) GetPatientMerged(ctx context.Context) (*database.FhirPatient, error) {
|
||||
currentUser, currentUserErr := gr.GetCurrentUser(ctx)
|
||||
if currentUserErr != nil {
|
||||
return nil, currentUserErr
|
||||
}
|
||||
|
||||
tableName, err := database.GetTableNameByResourceType("Patient")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var wrappedFhirPatients []database.FhirPatient
|
||||
results := gr.GormClient.WithContext(ctx).
|
||||
//Group("source_id"). //broken in Postgres.
|
||||
Where(models.OriginBase{
|
||||
UserID: currentUser.ID,
|
||||
SourceResourceType: "Patient",
|
||||
}).
|
||||
Order("sort_date DESC").
|
||||
Table(tableName).
|
||||
Find(&wrappedFhirPatients)
|
||||
|
||||
if results.Error != nil {
|
||||
return nil, results.Error
|
||||
}
|
||||
|
||||
return mergePatients(wrappedFhirPatients)
|
||||
}
|
||||
|
||||
// helper utility
|
||||
func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func mergePatients(patients []database.FhirPatient) (*database.FhirPatient, error) {
|
||||
if len(patients) == 0 {
|
||||
log.Printf("no patients to merge, ignoring")
|
||||
return nil, fmt.Errorf("no patients to merge, ignoring")
|
||||
}
|
||||
mergedPatientResource := `{}`
|
||||
for ndx, _ := range patients {
|
||||
patient := patients[ndx]
|
||||
mergedPatientResourceBytes, err := deepmerge.JSON([]byte(mergedPatientResource), []byte(patient.ResourceRaw))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mergedPatientResource = string(mergedPatientResourceBytes)
|
||||
}
|
||||
|
||||
mergedPatient := &database.FhirPatient{
|
||||
ResourceBase: models.ResourceBase{
|
||||
OriginBase: patients[len(patients)-1].OriginBase,
|
||||
},
|
||||
}
|
||||
err := mergedPatient.PopulateAndExtractSearchParameters([]byte(mergedPatientResource))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error occurred while extracting fields from merged Patient")
|
||||
}
|
||||
return mergedPatient, nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/utils/ips"
|
||||
sourcePkg "github.com/fastenhealth/fasten-sources/clients/models"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -21,7 +22,7 @@ type DatabaseRepository interface {
|
|||
|
||||
//get a count of every resource type
|
||||
GetSummary(ctx context.Context) (*models.Summary, error)
|
||||
GetInternationalPatientSummaryBundle(ctx context.Context) (interface{}, interface{}, error)
|
||||
GetInternationalPatientSummaryExport(ctx context.Context) (*ips.InternationalPatientSummaryExportData, error)
|
||||
|
||||
GetResourceByResourceTypeAndId(context.Context, string, string) (*models.ResourceBase, error)
|
||||
GetResourceBySourceId(context.Context, string, string) (*models.ResourceBase, error)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package ips
|
||||
|
||||
import (
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/models/database"
|
||||
"github.com/fastenhealth/gofhir-models/fhir401"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InternationalPatientSummaryExportData struct {
|
||||
GenerationDate time.Time
|
||||
Bundle *fhir401.Bundle
|
||||
Composition *fhir401.Composition
|
||||
|
||||
Patient *database.FhirPatient
|
||||
Sources []models.SourceCredential
|
||||
}
|
|
@ -39,7 +39,7 @@ type NarrativeTemplateData struct {
|
|||
CarePlan []database.FhirCarePlan
|
||||
Observation []database.FhirObservation
|
||||
Encounter []database.FhirEncounter
|
||||
Patient []database.FhirPatient
|
||||
Patient database.FhirPatient
|
||||
}
|
||||
|
||||
func NewNarrative() (*Narrative, error) {
|
||||
|
@ -49,12 +49,15 @@ func NewNarrative() (*Narrative, error) {
|
|||
// https://stackoverflow.com/questions/50283370/include-template-from-another-directory
|
||||
// https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-go
|
||||
tmpl, err := template.New("ips").Funcs(template.FuncMap{
|
||||
"safeHTML": func(s *string) template.HTML {
|
||||
"safeHTMLPtr": func(s *string) template.HTML {
|
||||
if s == nil {
|
||||
return template.HTML("")
|
||||
}
|
||||
return template.HTML(*s)
|
||||
},
|
||||
"safeHTML": func(s string) template.HTML {
|
||||
return template.HTML(s)
|
||||
},
|
||||
"parseStringList": func(data datatypes.JSON) []string {
|
||||
var parsed []string
|
||||
_ = json.Unmarshal(data, &parsed)
|
||||
|
@ -124,8 +127,9 @@ func (r *Narrative) RenderSection(sectionType pkg.IPSSections, resources []datab
|
|||
MedicationRequest: []database.FhirMedicationRequest{},
|
||||
MedicationStatement: []database.FhirMedicationStatement{},
|
||||
Observation: []database.FhirObservation{},
|
||||
Patient: []database.FhirPatient{},
|
||||
Procedure: []database.FhirProcedure{},
|
||||
|
||||
Patient: database.FhirPatient{},
|
||||
}
|
||||
|
||||
//loop though the resources, cast them to the correct type, and then store them in the correct array
|
||||
|
@ -156,8 +160,6 @@ func (r *Narrative) RenderSection(sectionType pkg.IPSSections, resources []datab
|
|||
templateData.MedicationStatement = append(templateData.MedicationStatement, *resource.(*database.FhirMedicationStatement))
|
||||
case "Observation":
|
||||
templateData.Observation = append(templateData.Observation, *resource.(*database.FhirObservation))
|
||||
case "Patient":
|
||||
templateData.Patient = append(templateData.Patient, *resource.(*database.FhirPatient))
|
||||
case "Procedure":
|
||||
templateData.Procedure = append(templateData.Procedure, *resource.(*database.FhirProcedure))
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ all of the section narratives into a single narrative.
|
|||
{{if eq $section.Text nil }}
|
||||
{{$section.EmptyReason.Text}}
|
||||
{{else }}
|
||||
{{$section.Text.Div | safeHTML}}
|
||||
{{$section.Text.Div | safeHTMLPtr}}
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -1 +1,101 @@
|
|||
<div> header hello world</div>
|
||||
{{- /*gotype: github.com/fastenhealth/fasten-onprem/backend/pkg/utils/ips.NarrativeTemplateData*/ -}}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<h1>{{.Patient.Name | parseStringList | uniq | first}}</h1>
|
||||
<div>Patient Health Summary; Generated: {{.Composition.Date | date "2006-01-02"}}</div>
|
||||
<div>
|
||||
<strong>ID:</strong> {{.Composition.Identifier.Value}} <br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div style="width:100%; display: flex; justify-content: center;" id="outer">
|
||||
<div id="inner">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
height="100pt" viewBox="0 0 1640.000000 664.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,664.000000) scale(0.100000,-0.100000)"
|
||||
fill="#5b47fb" stroke="none">
|
||||
<path d="M3235 4879 c-114 -17 -220 -49 -314 -95 -76 -38 -110 -62 -176 -128
|
||||
-138 -136 -201 -298 -212 -538 l-6 -128 -123 0 -124 0 0 -280 0 -280 125 0
|
||||
125 0 0 -835 0 -835 340 0 340 0 0 835 0 835 185 0 185 0 0 280 0 280 -186 0
|
||||
-187 0 5 79 c7 129 58 203 157 231 20 6 71 13 114 17 l77 6 0 283 0 284 -132
|
||||
-1 c-73 -1 -160 -5 -193 -10z"/>
|
||||
<path d="M8330 4260 l0 -270 -135 0 -135 0 0 -280 0 -280 134 0 134 0 5 -532
|
||||
c3 -460 6 -543 21 -607 56 -241 182 -394 387 -471 116 -43 184 -51 457 -57
|
||||
l262 -6 0 292 0 291 -159 0 c-170 0 -207 8 -248 52 -40 43 -43 83 -43 571 l0
|
||||
467 225 0 225 0 0 280 0 280 -225 0 -225 0 0 270 0 270 -340 0 -340 0 0 -270z"/>
|
||||
<path d="M4378 4010 c-134 -24 -254 -72 -365 -147 -200 -134 -345 -350 -415
|
||||
-621 -27 -103 -31 -138 -35 -297 -4 -137 -1 -207 11 -294 47 -319 194 -582
|
||||
419 -747 166 -122 380 -184 596 -170 253 15 458 113 591 282 l45 57 3 -157 3
|
||||
-156 339 0 340 0 0 1115 0 1115 -340 0 -339 0 -3 -156 -3 -155 -50 62 c-94
|
||||
119 -226 204 -385 249 -84 24 -326 36 -412 20z m453 -590 c179 -34 324 -176
|
||||
374 -367 58 -220 -2 -475 -140 -601 -284 -259 -719 -110 -800 273 -19 90 -19
|
||||
233 0 314 64 271 302 431 566 381z"/>
|
||||
<path d="M6890 4014 c-201 -37 -265 -56 -385 -117 -113 -57 -238 -182 -288
|
||||
-287 -84 -177 -86 -375 -4 -550 39 -85 146 -191 242 -242 111 -58 193 -86 455
|
||||
-153 135 -35 270 -72 301 -84 205 -78 209 -271 7 -332 -124 -38 -274 -13 -366
|
||||
60 -40 33 -84 103 -96 154 l-6 27 -336 0 -335 0 6 -47 c10 -70 58 -205 96
|
||||
-271 19 -31 77 -100 129 -152 87 -88 106 -101 220 -158 514 -256 1200 -127
|
||||
1407 263 119 226 76 534 -99 701 -128 122 -255 177 -632 275 -125 32 -249 68
|
||||
-274 79 -105 47 -147 101 -140 180 10 103 91 154 243 154 123 0 183 -21 251
|
||||
-89 38 -37 57 -66 67 -101 l14 -49 313 -3 313 -2 -7 52 c-11 85 -63 227 -114
|
||||
312 -105 176 -303 308 -542 361 -73 16 -382 29 -440 19z"/>
|
||||
<path d="M10435 4009 c-291 -42 -536 -179 -700 -390 -170 -218 -250 -515 -226
|
||||
-835 6 -71 15 -154 21 -184 113 -560 563 -896 1160 -866 129 6 273 35 380 76
|
||||
291 113 517 354 605 647 l13 43 -362 0 -361 0 -20 -36 c-29 -55 -118 -130
|
||||
-183 -155 -74 -29 -211 -32 -293 -7 -147 46 -248 170 -280 346 -6 29 -7 57 -4
|
||||
62 4 6 279 10 775 10 l768 0 8 88 c4 49 2 141 -4 212 -48 540 -374 902 -886
|
||||
985 -98 16 -313 18 -411 4z m265 -540 c81 -12 175 -55 229 -104 52 -47 100
|
||||
-145 108 -218 l6 -57 -431 0 -430 0 9 43 c29 127 119 247 224 297 94 45 178
|
||||
56 285 39z"/>
|
||||
<path d="M13070 3995 c-166 -34 -295 -101 -407 -210 l-83 -80 0 142 0 143
|
||||
-340 0 -340 0 0 -1115 0 -1115 340 0 340 0 0 655 c0 446 4 671 11 707 26 120
|
||||
111 233 213 283 28 14 85 30 127 36 194 28 367 -51 445 -202 58 -113 57 -108
|
||||
61 -821 l4 -658 335 0 335 0 -4 743 c-3 707 -4 746 -24 832 -86 373 -308 599
|
||||
-653 661 -94 17 -275 16 -360 -1z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<strong>Author:</strong> {{.Composition.Identifier.System}} <br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="markdown-body">
|
||||
<table class="hapiPropertyTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Born</th>
|
||||
<th>Language</th>
|
||||
<th>Race/Ethnicity</th>
|
||||
<th>Address</th>
|
||||
<th>Phone</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{{default "Unknown" (.Patient.Birthdate | date "2006-01-02")}}
|
||||
</td>
|
||||
<td>
|
||||
{{default "Unknown" (.Patient.Language | parseMapList | pluckList "text" | join ",")}}
|
||||
</td>
|
||||
<td>
|
||||
Unknown / Unknown
|
||||
</td>
|
||||
<td>
|
||||
{{default "Unknown" (.Patient.Address | parseStringList | uniq | join "<br/>" | safeHTML)}}
|
||||
</td>
|
||||
<td>
|
||||
{{default "Unknown" (.Patient.Phone | parseStringList | uniq | join ", ")}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,275 @@
|
|||
<style>
|
||||
/**
|
||||
*** SIMPLE GRID
|
||||
*** (C) ZACH COLE 2016
|
||||
*** https://github.com/zachacole/Simple-Grid/blob/master/simple-grid.css
|
||||
**/
|
||||
|
||||
@import url(https://fonts.googleapis.com/css?family=Lato:400,300,300italic,400italic,700,700italic);
|
||||
|
||||
/* UNIVERSAL */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
/* ROOT FONT STYLES */
|
||||
|
||||
* {
|
||||
font-family: 'Lato', Helvetica, sans-serif;
|
||||
color: #333447;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* TYPOGRAPHY */
|
||||
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.375rem;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 200;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.font-light {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.font-regular {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.font-heavy {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* POSITIONING */
|
||||
|
||||
.left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.justify {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
/* ==== GRID SYSTEM ==== */
|
||||
|
||||
.container {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.row {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.row [class^="col"] {
|
||||
float: left;
|
||||
margin: 0.5rem 2%;
|
||||
min-height: 0.125rem;
|
||||
}
|
||||
|
||||
.col-1,
|
||||
.col-2,
|
||||
.col-3,
|
||||
.col-4,
|
||||
.col-5,
|
||||
.col-6,
|
||||
.col-7,
|
||||
.col-8,
|
||||
.col-9,
|
||||
.col-10,
|
||||
.col-11,
|
||||
.col-12 {
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
.col-1-sm {
|
||||
width: 4.33%;
|
||||
}
|
||||
|
||||
.col-2-sm {
|
||||
width: 12.66%;
|
||||
}
|
||||
|
||||
.col-3-sm {
|
||||
width: 21%;
|
||||
}
|
||||
|
||||
.col-4-sm {
|
||||
width: 29.33%;
|
||||
}
|
||||
|
||||
.col-5-sm {
|
||||
width: 37.66%;
|
||||
}
|
||||
|
||||
.col-6-sm {
|
||||
width: 46%;
|
||||
}
|
||||
|
||||
.col-7-sm {
|
||||
width: 54.33%;
|
||||
}
|
||||
|
||||
.col-8-sm {
|
||||
width: 62.66%;
|
||||
}
|
||||
|
||||
.col-9-sm {
|
||||
width: 71%;
|
||||
}
|
||||
|
||||
.col-10-sm {
|
||||
width: 79.33%;
|
||||
}
|
||||
|
||||
.col-11-sm {
|
||||
width: 87.66%;
|
||||
}
|
||||
|
||||
.col-12-sm {
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
.row::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.hidden-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 33.75em) { /* 540px */
|
||||
.container {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 45em) { /* 720px */
|
||||
.col-1 {
|
||||
width: 4.33%;
|
||||
}
|
||||
|
||||
.col-2 {
|
||||
width: 12.66%;
|
||||
}
|
||||
|
||||
.col-3 {
|
||||
width: 21%;
|
||||
}
|
||||
|
||||
.col-4 {
|
||||
width: 29.33%;
|
||||
}
|
||||
|
||||
.col-5 {
|
||||
width: 37.66%;
|
||||
}
|
||||
|
||||
.col-6 {
|
||||
width: 46%;
|
||||
}
|
||||
|
||||
.col-7 {
|
||||
width: 54.33%;
|
||||
}
|
||||
|
||||
.col-8 {
|
||||
width: 62.66%;
|
||||
}
|
||||
|
||||
.col-9 {
|
||||
width: 71%;
|
||||
}
|
||||
|
||||
.col-10 {
|
||||
width: 79.33%;
|
||||
}
|
||||
|
||||
.col-11 {
|
||||
width: 87.66%;
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
.hidden-sm {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 60em) { /* 960px */
|
||||
.container {
|
||||
width: 75%;
|
||||
max-width: 60rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<!-- Github Markdown CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown-light.min.css" integrity="sha512-Pmhg2i/F7+5+7SsdoUqKeH7UAZoVMYb1sxGOoJ0jWXAEHP0XV2H4CITyK267eHWp2jpj7rtqWNkmEOw1tNyYpg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,28 +1,12 @@
|
|||
{{- /*gotype: github.com/fastenhealth/fasten-onprem/backend/pkg/utils/ips.NarrativeTemplateData*/ -}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>title</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="script.js"></script>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.5.1/github-markdown-light.min.css" integrity="sha512-Pmhg2i/F7+5+7SsdoUqKeH7UAZoVMYb1sxGOoJ0jWXAEHP0XV2H4CITyK267eHWp2jpj7rtqWNkmEOw1tNyYpg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<style>
|
||||
.markdown-body {
|
||||
box-sizing: border-box;
|
||||
min-width: 200px;
|
||||
max-width: 980px;
|
||||
margin: 0 auto;
|
||||
padding: 45px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.markdown-body {
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{{template "styles.gohtml" .}}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"github.com/fastenhealth/fasten-onprem/backend/pkg"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/database"
|
||||
"github.com/fastenhealth/fasten-onprem/backend/pkg/utils/ips"
|
||||
"github.com/fastenhealth/gofhir-models/fhir401"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
|
@ -28,7 +27,7 @@ func GetIPSSummary(c *gin.Context) {
|
|||
logger := c.MustGet(pkg.ContextKeyTypeLogger).(*logrus.Entry)
|
||||
databaseRepo := c.MustGet(pkg.ContextKeyTypeDatabase).(database.DatabaseRepository)
|
||||
|
||||
ipsBundle, ipsComposititon, err := databaseRepo.GetInternationalPatientSummaryBundle(c)
|
||||
ipsExport, err := databaseRepo.GetInternationalPatientSummaryExport(c)
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while retrieving IPS summary", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
|
@ -36,7 +35,7 @@ func GetIPSSummary(c *gin.Context) {
|
|||
}
|
||||
|
||||
if c.Query("format") == "" {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": ipsBundle})
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": ipsExport.Bundle})
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -47,13 +46,13 @@ func GetIPSSummary(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
composititon := ipsComposititon.(*fhir401.Composition)
|
||||
composititon := ipsExport.Composition
|
||||
|
||||
if c.Query("format") == "html" {
|
||||
|
||||
logger.Debugln("Rendering HTML")
|
||||
//create string writer
|
||||
content, err := narrative.RenderTemplate("index.gohtml", ips.NarrativeTemplateData{Composition: composititon})
|
||||
content, err := narrative.RenderTemplate("index.gohtml", ips.NarrativeTemplateData{Composition: composititon, Patient: *ipsExport.Patient})
|
||||
if err != nil {
|
||||
logger.Errorln("An error occurred while executing template", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1640.000000pt" height="664.000000pt" viewBox="0 0 1640.000000 664.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<g transform="translate(0.000000,664.000000) scale(0.100000,-0.100000)"
|
||||
fill="#5b47fb" stroke="none">
|
||||
<path d="M3235 4879 c-114 -17 -220 -49 -314 -95 -76 -38 -110 -62 -176 -128
|
||||
-138 -136 -201 -298 -212 -538 l-6 -128 -123 0 -124 0 0 -280 0 -280 125 0
|
||||
125 0 0 -835 0 -835 340 0 340 0 0 835 0 835 185 0 185 0 0 280 0 280 -186 0
|
||||
-187 0 5 79 c7 129 58 203 157 231 20 6 71 13 114 17 l77 6 0 283 0 284 -132
|
||||
-1 c-73 -1 -160 -5 -193 -10z"/>
|
||||
<path d="M8330 4260 l0 -270 -135 0 -135 0 0 -280 0 -280 134 0 134 0 5 -532
|
||||
c3 -460 6 -543 21 -607 56 -241 182 -394 387 -471 116 -43 184 -51 457 -57
|
||||
l262 -6 0 292 0 291 -159 0 c-170 0 -207 8 -248 52 -40 43 -43 83 -43 571 l0
|
||||
467 225 0 225 0 0 280 0 280 -225 0 -225 0 0 270 0 270 -340 0 -340 0 0 -270z"/>
|
||||
<path d="M4378 4010 c-134 -24 -254 -72 -365 -147 -200 -134 -345 -350 -415
|
||||
-621 -27 -103 -31 -138 -35 -297 -4 -137 -1 -207 11 -294 47 -319 194 -582
|
||||
419 -747 166 -122 380 -184 596 -170 253 15 458 113 591 282 l45 57 3 -157 3
|
||||
-156 339 0 340 0 0 1115 0 1115 -340 0 -339 0 -3 -156 -3 -155 -50 62 c-94
|
||||
119 -226 204 -385 249 -84 24 -326 36 -412 20z m453 -590 c179 -34 324 -176
|
||||
374 -367 58 -220 -2 -475 -140 -601 -284 -259 -719 -110 -800 273 -19 90 -19
|
||||
233 0 314 64 271 302 431 566 381z"/>
|
||||
<path d="M6890 4014 c-201 -37 -265 -56 -385 -117 -113 -57 -238 -182 -288
|
||||
-287 -84 -177 -86 -375 -4 -550 39 -85 146 -191 242 -242 111 -58 193 -86 455
|
||||
-153 135 -35 270 -72 301 -84 205 -78 209 -271 7 -332 -124 -38 -274 -13 -366
|
||||
60 -40 33 -84 103 -96 154 l-6 27 -336 0 -335 0 6 -47 c10 -70 58 -205 96
|
||||
-271 19 -31 77 -100 129 -152 87 -88 106 -101 220 -158 514 -256 1200 -127
|
||||
1407 263 119 226 76 534 -99 701 -128 122 -255 177 -632 275 -125 32 -249 68
|
||||
-274 79 -105 47 -147 101 -140 180 10 103 91 154 243 154 123 0 183 -21 251
|
||||
-89 38 -37 57 -66 67 -101 l14 -49 313 -3 313 -2 -7 52 c-11 85 -63 227 -114
|
||||
312 -105 176 -303 308 -542 361 -73 16 -382 29 -440 19z"/>
|
||||
<path d="M10435 4009 c-291 -42 -536 -179 -700 -390 -170 -218 -250 -515 -226
|
||||
-835 6 -71 15 -154 21 -184 113 -560 563 -896 1160 -866 129 6 273 35 380 76
|
||||
291 113 517 354 605 647 l13 43 -362 0 -361 0 -20 -36 c-29 -55 -118 -130
|
||||
-183 -155 -74 -29 -211 -32 -293 -7 -147 46 -248 170 -280 346 -6 29 -7 57 -4
|
||||
62 4 6 279 10 775 10 l768 0 8 88 c4 49 2 141 -4 212 -48 540 -374 902 -886
|
||||
985 -98 16 -313 18 -411 4z m265 -540 c81 -12 175 -55 229 -104 52 -47 100
|
||||
-145 108 -218 l6 -57 -431 0 -430 0 9 43 c29 127 119 247 224 297 94 45 178
|
||||
56 285 39z"/>
|
||||
<path d="M13070 3995 c-166 -34 -295 -101 -407 -210 l-83 -80 0 142 0 143
|
||||
-340 0 -340 0 0 -1115 0 -1115 340 0 340 0 0 655 c0 446 4 671 11 707 26 120
|
||||
111 233 213 283 28 14 85 30 127 36 194 28 367 -51 445 -202 58 -113 57 -108
|
||||
61 -821 l4 -658 335 0 335 0 -4 743 c-3 707 -4 746 -24 832 -86 373 -308 599
|
||||
-653 661 -94 17 -275 16 -360 -1z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
5
go.mod
5
go.mod
|
@ -1,6 +1,8 @@
|
|||
module github.com/fastenhealth/fasten-onprem
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
toolchain go1.21.1
|
||||
|
||||
//replace github.com/fastenhealth/fasten-sources => ../fasten-sources
|
||||
|
||||
|
@ -12,6 +14,7 @@ replace github.com/mattn/go-sqlite3 v1.14.17 => github.com/jgiannuzzi/go-sqlite3
|
|||
|
||||
require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.3
|
||||
github.com/TwiN/deepmerge v0.2.1
|
||||
github.com/analogj/go-util v0.0.0-20210417161720-39b497cca03b
|
||||
github.com/dave/jennifer v1.6.1
|
||||
github.com/dominikbraun/graph v0.15.0
|
||||
|
|
6
go.sum
6
go.sum
|
@ -50,6 +50,8 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
|
|||
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g=
|
||||
github.com/TwiN/deepmerge v0.2.1 h1:GowJr9O4THTVW4awX63x1BVg1hgr4q+35XKKCYbwsSs=
|
||||
github.com/TwiN/deepmerge v0.2.1/go.mod h1:LVBmCEBQvibYSF8Gyl/NqhHXH7yIiT7Ozqf9dHxGPW0=
|
||||
github.com/analogj/go-util v0.0.0-20210417161720-39b497cca03b h1:Y/+MfmdKPPpVY7C6ggt/FpltFSitlpUtyJEdcQyFXQg=
|
||||
github.com/analogj/go-util v0.0.0-20210417161720-39b497cca03b/go.mod h1:bRSzJXgXnT5+Ihah7RSC7Cvp16UmoLn3wq6ROciS1Ow=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
|
@ -115,6 +117,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
|||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
|
@ -131,6 +134,7 @@ github.com/go-gormigrate/gormigrate/v2 v2.1.1/go.mod h1:L7nJ620PFDKei9QOhJzqA8kR
|
|||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
|
@ -195,6 +199,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-github/v54 v54.0.0 h1:OZdXwow4EAD5jEo5qg+dGFH2DpkyZvVsAehjvJuUL/c=
|
||||
github.com/google/go-github/v54 v54.0.0/go.mod h1:Sw1LXWHhXRZtzJ9LI5fyJg9wbQzYvFhW8W5P2yaAQ7s=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
|
@ -422,6 +427,7 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl
|
|||
github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI=
|
||||
github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
|
|
Loading…
Reference in New Issue