Skip to content

Commit

Permalink
chore: check if an assessment has already been done in any given enco…
Browse files Browse the repository at this point in the history
…unter

- this ensures that the same assessment is not repeated in the same encounter

Signed-off-by: Kathurima Kimathi <kathurimakimathi415@gmail.com>
  • Loading branch information
KathurimaKimathi committed Feb 16, 2024
1 parent 9b75aa6 commit a0bc997
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 19 deletions.
1 change: 1 addition & 0 deletions pkg/clinical/presentation/graph/clinical.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ extend type Mutation {
createQuestionnaireResponse(
questionnaireID: String!
encounterID: String!
screeningType: ScreeningTypeEnum!
input: QuestionnaireResponseInput!
): String!

Expand Down
4 changes: 2 additions & 2 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.

24 changes: 17 additions & 7 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.

45 changes: 37 additions & 8 deletions pkg/clinical/usecases/clinical/questionnaire_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import (
)

// CreateQuestionnaireResponse creates a questionnaire response
func (u *UseCasesClinicalImpl) CreateQuestionnaireResponse(ctx context.Context, questionnaireID string, encounterID string, input dto.QuestionnaireResponse) (string, error) {
func (u *UseCasesClinicalImpl) CreateQuestionnaireResponse(
ctx context.Context, questionnaireID string, encounterID string,
screeningType domain.ScreeningTypeEnum, input dto.QuestionnaireResponse) (string, error) {
questionnaireResponse := &domain.FHIRQuestionnaireResponse{}

err := mapstructure.Decode(input, questionnaireResponse)
Expand All @@ -30,19 +32,22 @@ func (u *UseCasesClinicalImpl) CreateQuestionnaireResponse(ctx context.Context,
return "", fmt.Errorf("cannot create a questionnaire response in a finished encounter")
}

// TODO: Ensure user cannot submit the same risk assessment twice in the same encounter

patientID := encounter.Resource.Subject.ID
patientReference := fmt.Sprintf("Patient/%s", *patientID)
encounterReference := fmt.Sprintf("Encounter/%s", *encounter.Resource.ID)

// check if an assessment has already been done with the same encounter
err = u.checkIfAssessmentHasBeenDone(ctx, screeningType, encounterReference, patientReference)
if err != nil {
return "", err
}

questionnaireResponse.Source = &domain.FHIRReference{
ID: patientID,
Reference: &patientReference,
Display: encounter.Resource.Subject.Display,
}

encounterReference := fmt.Sprintf("Encounter/%s", *encounter.Resource.ID)

questionnaireResponse.Encounter = &domain.FHIRReference{
ID: encounter.Resource.ID,
Reference: &encounterReference,
Expand Down Expand Up @@ -87,6 +92,31 @@ func (u *UseCasesClinicalImpl) CreateQuestionnaireResponse(ctx context.Context,
return riskLevel, nil
}

// checkIfAssessmentHasBeenDone is a helper function to check if the assessment has already been completed
func (u *UseCasesClinicalImpl) checkIfAssessmentHasBeenDone(ctx context.Context, screeningType domain.ScreeningTypeEnum, encounterReference, patientReference string) error {
searchParams := map[string]interface{}{
"encounter": encounterReference,
"patient": patientReference,
"_text": screeningType.Text(),
}

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

results, err := u.infrastructure.FHIR.SearchFHIRRiskAssessment(ctx, searchParams, *identifiers, dto.Pagination{})
if err != nil {
return err
}

if len(results.Edges) > 0 {
return fmt.Errorf("a %s questionnaire response for patient %s already exists for encounter %s", screeningType.Text(), patientReference, encounterReference)
}

return nil
}

// generateQuestionnaireReviewSummary takes a questionnaire response and
// analyzes it to determine the risk stratification based on three distinct groups:
// symptoms, family history, and risk factors. The assumption is that the
Expand All @@ -109,8 +139,7 @@ func (u *UseCasesClinicalImpl) generateQuestionnaireReviewSummary(
}

switch *questionnaire.Resource.Name {
// TODO: Make this a controlled enum?
case "Cervical Cancer Screening":
case domain.CervicalCancerScreeningTypeEnum.Text():
var symptomsScore, riskFactorsScore, totalScore int

for _, item := range questionnaireResponse.Item {
Expand Down Expand Up @@ -141,7 +170,7 @@ func (u *UseCasesClinicalImpl) generateQuestionnaireReviewSummary(
questionnaireResponseID,
common.HighRiskCIELCode,
"High Risk",
domain.CervicalCancerScreeningTypeEnum.Text(), // TODO: This is TEMPORARY. A follow up PR is to follow supplying the value from params
domain.CervicalCancerScreeningTypeEnum.Text(),
)
if err != nil {
return "", err
Expand Down
49 changes: 48 additions & 1 deletion pkg/clinical/usecases/clinical/questionnaire_response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
fakePubSubMock "github.com/savannahghi/clinical/pkg/clinical/infrastructure/services/pubsub/mock"
fakeUploadMock "github.com/savannahghi/clinical/pkg/clinical/infrastructure/services/upload/mock"
clinicalUsecase "github.com/savannahghi/clinical/pkg/clinical/usecases/clinical"
"github.com/savannahghi/firebasetools"
)

func setupMockFHIRFunctions(fakeFHIR *fakeFHIRMock.FHIRMock, score int) {
Expand Down Expand Up @@ -75,6 +76,7 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
input dto.QuestionnaireResponse
questionnaireID string
encounterID string
screeningType domain.ScreeningTypeEnum
}
tests := []struct {
name string
Expand All @@ -88,6 +90,7 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
input: dto.QuestionnaireResponse{},
questionnaireID: ID,
encounterID: ID,
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: true,
},
Expand Down Expand Up @@ -135,6 +138,7 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
ctx: context.Background(),
encounterID: gofakeit.UUID(),
questionnaireID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: false,
},
Expand All @@ -144,6 +148,7 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
ctx: context.Background(),
encounterID: gofakeit.UUID(),
questionnaireID: gofakeit.UUID(),
screeningType: domain.CervicalCancerScreeningTypeEnum,
},
wantErr: false,
},
Expand Down Expand Up @@ -183,6 +188,24 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
},
wantErr: true,
},
{
name: "Sad Case - unable to get tenant identifiers",
args: args{
ctx: context.Background(),
encounterID: gofakeit.UUID(),
questionnaireID: gofakeit.UUID(),
},
wantErr: true,
},
{
name: "Sad Case - unable to search for risk assessment",
args: args{
ctx: context.Background(),
encounterID: gofakeit.UUID(),
questionnaireID: gofakeit.UUID(),
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -229,6 +252,13 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
}

if tt.name == "Happy Case - Create questionnaire response and generate review summary - Cervical Cancer - High Risk" {
fakeFHIR.MockSearchFHIRRiskAssessmentFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRRiskAssessmentRelayConnection, error) {
return &domain.FHIRRiskAssessmentRelayConnection{
Edges: []*domain.FHIRRiskAssessmentRelayEdge{},
PageInfo: &firebasetools.PageInfo{},
}, nil
}

fakeFHIR.MockGetFHIRQuestionnaireFn = func(ctx context.Context, id string) (*domain.FHIRQuestionnaireRelayPayload, error) {
questionnaireName := "Cervical Cancer Screening"
return &domain.FHIRQuestionnaireRelayPayload{
Expand Down Expand Up @@ -277,6 +307,13 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
}

if tt.name == "Happy Case - Create questionnaire response and generate review summary - Cervical Cancer - Low Risk" {
fakeFHIR.MockSearchFHIRRiskAssessmentFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRRiskAssessmentRelayConnection, error) {
return &domain.FHIRRiskAssessmentRelayConnection{
Edges: []*domain.FHIRRiskAssessmentRelayEdge{},
PageInfo: &firebasetools.PageInfo{},
}, nil
}

fakeFHIR.MockGetFHIRQuestionnaireFn = func(ctx context.Context, id string) (*domain.FHIRQuestionnaireRelayPayload, error) {
questionnaireName := "Cervical Cancer Screening"
return &domain.FHIRQuestionnaireRelayPayload{
Expand Down Expand Up @@ -347,8 +384,18 @@ func TestUseCasesClinicalImpl_CreateQuestionnaireResponse(t *testing.T) {
if tt.name == "Sad Case - Fail to record risk assessment - High Risk" {
setupMockFHIRFunctions(fakeFHIR, 3)
}
if tt.name == "Sad Case - unable to get tenant identifiers" {
fakeExt.MockGetTenantIdentifiersFn = func(ctx context.Context) (*dto.TenantIdentifiers, error) {
return nil, fmt.Errorf("failed to get tenant identifiers")
}
}
if tt.name == "Sad Case - unable to search for risk assessment" {
fakeFHIR.MockSearchFHIRRiskAssessmentFn = func(ctx context.Context, params map[string]interface{}, tenant dto.TenantIdentifiers, pagination dto.Pagination) (*domain.FHIRRiskAssessmentRelayConnection, error) {
return nil, fmt.Errorf("failed to search for risk assessment")
}
}

_, err := q.CreateQuestionnaireResponse(tt.args.ctx, tt.args.questionnaireID, tt.args.encounterID, tt.args.input)
_, err := q.CreateQuestionnaireResponse(tt.args.ctx, tt.args.questionnaireID, tt.args.encounterID, tt.args.screeningType, tt.args.input)
if (err != nil) != tt.wantErr {
t.Errorf("UseCasesClinicalImpl.CreateQuestionnaireResponse() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/clinical/usecases/usecases.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ type Clinical interface {

// Questionnaire
CreateQuestionnaire(ctx context.Context, questionnaireInput *domain.FHIRQuestionnaire) (*domain.FHIRQuestionnaire, error)
CreateQuestionnaireResponse(ctx context.Context, questionnaireID string, encounterID string, input dto.QuestionnaireResponse) (string, error)
CreateQuestionnaireResponse(ctx context.Context, questionnaireID, encounterID string, screeningType domain.ScreeningTypeEnum, input dto.QuestionnaireResponse) (string, error)
ListQuestionnaires(ctx context.Context, searchParam *string, pagination *dto.Pagination) (*dto.QuestionnaireConnection, error)
RecordConsent(ctx context.Context, input dto.ConsentInput) (*dto.ConsentOutput, error)

Expand Down

0 comments on commit a0bc997

Please sign in to comment.