Skip to content

Commit

Permalink
feat: episode of care retrieve and end (#202)
Browse files Browse the repository at this point in the history
  • Loading branch information
Muchogoc committed Mar 22, 2023
1 parent 520f690 commit a1f6067
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 48 deletions.
18 changes: 1 addition & 17 deletions pkg/clinical/infrastructure/datastore/cloudhealthcare/fhir.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"fmt"
"time"

"github.com/labstack/gommon/log"
"github.com/mitchellh/mapstructure"
"github.com/savannahghi/clinical/pkg/clinical/application/common/helpers"
"github.com/savannahghi/clinical/pkg/clinical/application/dto"
Expand Down Expand Up @@ -476,7 +475,7 @@ func (fh *StoreImpl) EndEncounter(

// EndEpisode ends an episode of care by patching it's status to "finished"
func (fh *StoreImpl) EndEpisode(
ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (bool, error) {
ctx context.Context, episodeID string) (bool, error) {
episodePayload, err := fh.GetFHIREpisodeOfCare(ctx, episodeID)
if err != nil {
return false, fmt.Errorf("unable to get episode with ID %s: %w", episodeID, err)
Expand All @@ -487,21 +486,6 @@ func (fh *StoreImpl) EndEpisode(
startTime = episodePayload.Resource.Period.Start
}

// Close all encounters in this visit

encounterConn, err := fh.SearchEpisodeEncounter(ctx, episodeID, tenant)
if err != nil {
return false, fmt.Errorf("unable to search episode encounter %w", err)
}

for _, edge := range encounterConn.Edges {
_, err = fh.EndEncounter(ctx, *edge.Node.ID)
if err != nil {
log.Printf("unable to end encounter %s", *edge.Node.ID)

continue
}
}
// // workaround for odd date comparison behavior on the Google Cloud Healthcare API
// the end time must be at least 24 hours after the start time
// so: if the time now is less than 24 hours after start, set the end to be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3761,7 +3761,6 @@ func TestStoreImpl_EndEpisode(t *testing.T) {
type args struct {
ctx context.Context
episodeID string
tenant dto.TenantIdentifiers
}
tests := []struct {
name string
Expand Down Expand Up @@ -3877,7 +3876,7 @@ func TestStoreImpl_EndEpisode(t *testing.T) {
}
}

got, err := fh.EndEpisode(tt.args.ctx, tt.args.episodeID, tt.args.tenant)
got, err := fh.EndEpisode(tt.args.ctx, tt.args.episodeID)
if (err != nil) != tt.wantErr {
t.Errorf("StoreImpl.EndEpisode() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type FHIRMock struct {
MockUpgradeEpisodeFn func(ctx context.Context, input domain.OTPEpisodeUpgradeInput) (*domain.EpisodeOfCarePayload, error)
MockSearchEpisodeEncounterFn func(ctx context.Context, episodeReference string, tenant dto.TenantIdentifiers) (*domain.FHIREncounterRelayConnection, error)
MockEndEncounterFn func(ctx context.Context, encounterID string) (bool, error)
MockEndEpisodeFn func(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (bool, error)
MockEndEpisodeFn func(ctx context.Context, episodeID string) (bool, error)
MockGetActiveEpisodeFn func(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (*domain.FHIREpisodeOfCare, error)
MockSearchFHIRServiceRequestFn func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers) (*domain.FHIRServiceRequestRelayConnection, error)
MockCreateFHIRServiceRequestFn func(ctx context.Context, input domain.FHIRServiceRequestInput) (*domain.FHIRServiceRequestRelayPayload, error)
Expand Down Expand Up @@ -223,15 +223,18 @@ func NewFHIRMock() *FHIRMock {
UUID := uuid.New().String()
PatientRef := "Patient/1"
OrgRef := "Organization/1"
st := domain.EpisodeOfCareStatusEnumActive
return &domain.FHIREpisodeOfCareRelayPayload{
Resource: &domain.FHIREpisodeOfCare{
ID: &UUID,
Status: &st,
Text: &domain.FHIRNarrative{},
Identifier: []*domain.FHIRIdentifier{},
StatusHistory: []*domain.FHIREpisodeofcareStatushistory{},
Type: []*domain.FHIRCodeableConcept{},
Diagnosis: []*domain.FHIREpisodeofcareDiagnosis{},
Patient: &domain.FHIRReference{
ID: &UUID,
Reference: &PatientRef,
},
ManagingOrganization: &domain.FHIRReference{
Expand Down Expand Up @@ -303,12 +306,21 @@ func NewFHIRMock() *FHIRMock {
return &domain.EpisodeOfCarePayload{}, nil
},
MockSearchEpisodeEncounterFn: func(ctx context.Context, episodeReference string, tenant dto.TenantIdentifiers) (*domain.FHIREncounterRelayConnection, error) {
return &domain.FHIREncounterRelayConnection{}, nil
id := gofakeit.UUID()
return &domain.FHIREncounterRelayConnection{
Edges: []*domain.FHIREncounterRelayEdge{
{
Node: &domain.FHIREncounter{
ID: &id,
},
},
},
}, nil
},
MockEndEncounterFn: func(ctx context.Context, encounterID string) (bool, error) {
return true, nil
},
MockEndEpisodeFn: func(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (bool, error) {
MockEndEpisodeFn: func(ctx context.Context, episodeID string) (bool, error) {
return true, nil
},
MockGetActiveEpisodeFn: func(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (*domain.FHIREpisodeOfCare, error) {
Expand Down Expand Up @@ -722,8 +734,8 @@ func (fh *FHIRMock) EndEncounter(ctx context.Context, encounterID string) (bool,
}

// EndEpisode is a mock implementation of EndEpisode method
func (fh *FHIRMock) EndEpisode(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (bool, error) {
return fh.MockEndEpisodeFn(ctx, episodeID, tenant)
func (fh *FHIRMock) EndEpisode(ctx context.Context, episodeID string) (bool, error) {
return fh.MockEndEpisodeFn(ctx, episodeID)
}

// GetActiveEpisode is a mock implementation of GetActiveEpisode method
Expand Down
2 changes: 1 addition & 1 deletion pkg/clinical/presentation/graph/clinical.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ extend type Query {
patientHealthTimeline(input: HealthTimelineInput!): HealthTimeline!
getMedicalData(patientID: String!): MedicalData

episodeOfCare(id: ID!): EpisodeOfCare
getEpisodeOfCare(id: ID!): EpisodeOfCare

# Encounter
listPatientEncounters(patientID: String!): [Encounter!]!
Expand Down
12 changes: 6 additions & 6 deletions pkg/clinical/presentation/graph/clinical.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 15 additions & 15 deletions pkg/clinical/presentation/graph/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pkg/clinical/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type FHIREpisodeOfCare interface {
UpdateFHIREpisodeOfCare(ctx context.Context, fhirResourceID string, payload map[string]interface{}) (*domain.FHIREpisodeOfCare, error)
HasOpenEpisode(ctx context.Context, patient domain.FHIRPatient, tenant dto.TenantIdentifiers) (bool, error)
OpenEpisodes(ctx context.Context, patientReference string, tenant dto.TenantIdentifiers) ([]*domain.FHIREpisodeOfCare, error)
EndEpisode(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (bool, error)
EndEpisode(ctx context.Context, episodeID string) (bool, error)
GetActiveEpisode(ctx context.Context, episodeID string, tenant dto.TenantIdentifiers) (*domain.FHIREpisodeOfCare, error)
}
type FHIRObservation interface {
Expand Down
53 changes: 52 additions & 1 deletion pkg/clinical/usecases/clinical/episode_of_care.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package clinical
import (
"context"
"fmt"

"github.com/google/uuid"
"github.com/savannahghi/clinical/pkg/clinical/application/common"
"github.com/savannahghi/clinical/pkg/clinical/application/dto"
"github.com/savannahghi/clinical/pkg/clinical/application/extensions"
Expand Down Expand Up @@ -97,6 +97,57 @@ func (c *UseCasesClinicalImpl) CreateEpisodeOfCare(ctx context.Context, input dt
return mapFHIREpisodeToEpisodeDTO(*episode.EpisodeOfCare), nil
}

func (c *UseCasesClinicalImpl) EndEpisodeOfCare(ctx context.Context, id string) (*dto.EpisodeOfCare, error) {
_, err := uuid.Parse(id)
if err != nil {
return nil, fmt.Errorf("invalid episode of care id: %s", id)
}

episode, err := c.infrastructure.FHIR.GetFHIREpisodeOfCare(ctx, id)
if err != nil {
return nil, fmt.Errorf("unable to get episode of care: %w", err)
}

identifiers, err := c.infrastructure.BaseExtension.GetTenantIdentifiers(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get tenant identifiers from context: %w", err)
}

// Close all encounters in this visit
encounterConn, err := c.infrastructure.FHIR.SearchEpisodeEncounter(ctx, id, *identifiers)
if err != nil {
return nil, fmt.Errorf("unable to search episode encounter %w", err)
}

for _, edge := range encounterConn.Edges {
_, err = c.infrastructure.FHIR.EndEncounter(ctx, *edge.Node.ID)
if err != nil {
return nil, fmt.Errorf("unable to end encounter %s: err: %w", *edge.Node.ID, err)
}
}

_, err = c.infrastructure.FHIR.EndEpisode(ctx, id)
if err != nil {
return nil, fmt.Errorf("unable to end episode of care: %w", err)
}

return mapFHIREpisodeToEpisodeDTO(*episode.Resource), nil
}

func (c *UseCasesClinicalImpl) GetEpisodeOfCare(ctx context.Context, id string) (*dto.EpisodeOfCare, error) {
_, err := uuid.Parse(id)
if err != nil {
return nil, fmt.Errorf("invalid episode of care id: %s", id)
}

episode, err := c.infrastructure.FHIR.GetFHIREpisodeOfCare(ctx, id)
if err != nil {
return nil, fmt.Errorf("unable to get episode of care: %w", err)
}

return mapFHIREpisodeToEpisodeDTO(*episode.Resource), nil
}

func mapFHIREpisodeToEpisodeDTO(episode domain.FHIREpisodeOfCare) *dto.EpisodeOfCare {
return &dto.EpisodeOfCare{
ID: *episode.ID,
Expand Down
Loading

0 comments on commit a1f6067

Please sign in to comment.