From 31deb6944c0f2a6032aff5e725ea4d72b97a7e0f Mon Sep 17 00:00:00 2001 From: EspiraMarvin Date: Tue, 22 Aug 2023 16:56:04 +0300 Subject: [PATCH] add conditions to patient timeline --- pkg/clinical/usecases/clinical/timeline.go | 60 +++ .../usecases/clinical/timeline_test.go | 352 +++++++++++++++++- 2 files changed, 411 insertions(+), 1 deletion(-) diff --git a/pkg/clinical/usecases/clinical/timeline.go b/pkg/clinical/usecases/clinical/timeline.go index be15e397..f9508c98 100644 --- a/pkg/clinical/usecases/clinical/timeline.go +++ b/pkg/clinical/usecases/clinical/timeline.go @@ -226,10 +226,70 @@ func (c *UseCasesClinicalImpl) PatientTimeline(ctx context.Context, patientID st } } + // search conditions + conditionResourceFunc := func(wg *sync.WaitGroup, mut *sync.Mutex) { + defer wg.Done() + + conn, err := c.infrastructure.FHIR.SearchFHIRCondition(ctx, patientFilterParams, *identifiers, dto.Pagination{Skip: true}) + if err != nil { + utils.ReportErrorToSentry(err) + log.Errorf("Condition search error: %v", err) + + return + } + + for _, edge := range conn.Conditions { + if edge.ID == nil { + continue + } + + if edge.Code.Coding == nil { + continue + } + + if len(edge.Code.Coding) < 1 { + continue + } + + if len(edge.Category) < 1 { + continue + } + + if len(edge.Note) < 1 { + continue + } + + if edge.OnsetDateTime == nil { + continue + } + + if err != nil { + utils.ReportErrorToSentry(err) + log.Errorf("date conversion error: %v", err) + + return + } + + timelineResource := dto.TimelineResource{ + ID: *edge.ID, + ResourceType: dto.ResourceTypeCondition, + Name: edge.Code.Coding[0].Display, + Value: edge.ClinicalStatus.Text, + Status: edge.Category[0].Text, + Date: *edge.OnsetDateTime, + } + + mut.Lock() + timeline = append(timeline, timelineResource) + mut.Unlock() + } + } + resources := []timelineResourceFunc{ allergyIntoleranceResourceFunc, observationResourceFunc, medicationStatementResourceFunc, + conditionResourceFunc, } for _, resource := range resources { diff --git a/pkg/clinical/usecases/clinical/timeline_test.go b/pkg/clinical/usecases/clinical/timeline_test.go index fad50a13..18f61888 100644 --- a/pkg/clinical/usecases/clinical/timeline_test.go +++ b/pkg/clinical/usecases/clinical/timeline_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "testing" + "time" "github.com/brianvoe/gofakeit" "github.com/savannahghi/clinical/pkg/clinical/application/dto" @@ -272,6 +273,62 @@ func TestClinicalUseCaseImpl_PatientTimeline(t *testing.T) { }, wantErr: false, }, + { + name: "Sad Case - Fail to search condition", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil node id", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil code", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil code coding", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil category", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil onset datetime", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, + { + name: "Sad Case - Fail to get condition - nil note", + args: args{ + ctx: context.Background(), + patientID: gofakeit.UUID(), + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -322,6 +379,80 @@ func TestClinicalUseCaseImpl_PatientTimeline(t *testing.T) { }, nil } + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + statusSystem := scalarutils.URI("http://terminology.hl7.org/CodeSystem/condition-clinical") + status := "inactive" + note := scalarutils.Markdown("Fever Fever") + noteTime := time.Now() + uri := scalarutils.URI("1234567345") + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + + ID: &id, + Text: &domain.FHIRNarrative{}, + Identifier: []*domain.FHIRIdentifier{}, + ClinicalStatus: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &statusSystem, + Code: scalarutils.Code(string(status)), + Display: string(status), + }, + }, + Text: string(status), + }, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &uri, + Code: scalarutils.Code("1234"), + Display: "1234567", + }, + }, + Text: "1234", + }, + OnsetDateTime: &scalarutils.Date{}, + RecordedDate: &scalarutils.Date{}, + Subject: &domain.FHIRReference{ + ID: &id, + }, + Note: []*domain.FHIRAnnotation{ + { + Time: ¬eTime, + Text: ¬e, + }, + }, + Encounter: &domain.FHIRReference{ + ID: &id, + }, + Category: []*domain.FHIRCodeableConcept{ + { + ID: &id, + Coding: []*domain.FHIRCoding{ + { + ID: &id, + System: (*scalarutils.URI)(&id), + Version: &id, + Code: "PROBLEM_LIST_ITEM", + Display: gofakeit.BeerAlcohol(), + UserSelected: new(bool), + }, + }, + Text: "PROBLEM_LIST_ITEM", + }, + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + fakeFHIR.MockSearchFHIRObservationFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRObservations, error) { status := dto.ObservationStatusFinal return &domain.PagedFHIRObservations{ @@ -771,7 +902,9 @@ func TestClinicalUseCaseImpl_PatientTimeline(t *testing.T) { Encounter: &domain.FHIRReference{ ID: new(string), }, - // RecordedDate: nil, + OnsetPeriod: &domain.FHIRPeriod{ + Start: "2000-01-01", + }, }, }, HasNextPage: false, @@ -1172,6 +1305,223 @@ func TestClinicalUseCaseImpl_PatientTimeline(t *testing.T) { } } + if tt.name == "Sad Case - Fail to search condition" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + return &domain.PagedFHIRCondition{}, fmt.Errorf("failed to get condition") + } + } + + if tt.name == "Sad Case - Fail to get condition - nil node id" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + statusSystem := scalarutils.URI("http://terminology.hl7.org/CodeSystem/condition-clinical") + status := "inactive" + uri := scalarutils.URI("1234567345") + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ClinicalStatus: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &statusSystem, + Code: scalarutils.Code(string(status)), + Display: string(status), + }, + }, + Text: string(status), + }, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &uri, + Code: scalarutils.Code("1234"), + Display: "1234567", + }, + }, + Text: "1234", + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + + if tt.name == "Sad Case - Fail to get condition - nil code" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ID: &id, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{}, + Text: "1234", + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + + if tt.name == "Sad Case - Fail to get condition - nil code coding" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ID: &id, + Code: &domain.FHIRCodeableConcept{ + Text: "1234", + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + + if tt.name == "Sad Case - Fail to get condition - nil category" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + uri := scalarutils.URI("1234567345") + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ID: &id, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &uri, + Code: scalarutils.Code("1234"), + Display: "1234567", + }, + }, + Text: "1234", + }, + Category: []*domain.FHIRCodeableConcept{}, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + + if tt.name == "Sad Case - Fail to get condition - nil onset datetime" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + uri := scalarutils.URI("1234567345") + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ID: &id, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &uri, + Code: scalarutils.Code("1234"), + Display: "1234567", + }, + }, + Text: "1234", + }, + Category: []*domain.FHIRCodeableConcept{ + { + ID: &id, + Coding: []*domain.FHIRCoding{ + { + ID: &id, + System: (*scalarutils.URI)(&id), + Version: &id, + Code: "PROBLEM_LIST_ITEM", + Display: gofakeit.BeerAlcohol(), + UserSelected: new(bool), + }, + }, + Text: "PROBLEM_LIST_ITEM", + }, + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + + if tt.name == "Sad Case - Fail to get condition - nil note" { + fakeFHIR.MockSearchFHIRConditionFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.PagedFHIRCondition, error) { + id := gofakeit.UUID() + uri := scalarutils.URI("1234567345") + note := scalarutils.Markdown("Fever Fever") + noteTime := time.Now() + return &domain.PagedFHIRCondition{ + Conditions: []domain.FHIRCondition{ + { + ID: &id, + Text: &domain.FHIRNarrative{}, + Code: &domain.FHIRCodeableConcept{ + Coding: []*domain.FHIRCoding{ + { + System: &uri, + Code: scalarutils.Code("1234"), + Display: "1234567", + }, + }, + Text: "1234", + }, + Note: []*domain.FHIRAnnotation{ + { + Time: ¬eTime, + Text: ¬e, + }, + }, + Category: []*domain.FHIRCodeableConcept{ + { + ID: &id, + Coding: []*domain.FHIRCoding{ + { + ID: &id, + System: (*scalarutils.URI)(&id), + Version: &id, + Code: "PROBLEM_LIST_ITEM", + Display: gofakeit.BeerAlcohol(), + UserSelected: new(bool), + }, + }, + Text: "PROBLEM_LIST_ITEM", + }, + }, + }, + }, + HasNextPage: false, + NextCursor: "", + HasPreviousPage: false, + PreviousCursor: "", + TotalCount: 0, + }, nil + } + } + got, err := u.PatientTimeline(tt.args.ctx, tt.args.patientID) if (err != nil) != tt.wantErr { t.Errorf("ClinicalUseCaseImpl.PatientTimeline() error = %v, wantErr %v", err, tt.wantErr)