From 87d3054480d389faebf2102d9398e0ab9a316b6a Mon Sep 17 00:00:00 2001 From: Volker Schmidt Date: Tue, 30 Jul 2019 14:26:00 +0200 Subject: [PATCH] Adds support for DHIS2 program stage to FHIR Questionnaire. --- .../main/resources/default-application.yml | 1 + .../AbstractProgramStageFhirRestAppTest.java | 6 +- .../r4/R4ProgramMetadataFhirRestAppTest.java | 35 +-- ...R4ProgramStageMetadataFhirRestAppTest.java | 221 ++++++++++++++++++ ...stractEnrollmentTransformationAppTest.java | 22 +- ...ractProgramStageTransformationAppTest.java | 10 +- .../adapter/dhis/test/all-program-stages.json | 185 +++++++++++++++ .../dhis/test/default-program-stage.json | 101 ++++++++ .../dhis/test/single-program-stage.json | 99 ++++++++ .../sync/impl/DhisResourceRepositoryImpl.java | 10 +- .../program/ImmutableProgramStage.java | 7 + .../dhis/tracker/program/ProgramStage.java | 2 + .../program/ProgramStageMetadataService.java | 40 ++++ .../dhis/tracker/program/WritableProgram.java | 4 +- .../tracker/program/WritableProgramStage.java | 19 +- .../program/impl/DhisProgramStages.java | 62 +++++ .../impl/ProgramMetadataServiceImpl.java | 4 +- .../impl/ProgramStageMetadataServiceImpl.java | 86 +++++++ .../impl/ProgramMetadataServiceImplTest.java | 38 +-- .../ProgramStageMetadataServiceImplTest.java | 156 +++++++++++++ .../program/impl/emptyProgramStages.json | 3 + .../tracker/program/impl/programStage.json | 11 + .../tracker/program/impl/programStages.json | 24 ++ ...gramPlanDefinition.StructureDefinition.xml | 6 +- ...ogramQuestionnaire.StructureDefinition.xml | 16 +- .../R4ProgramMetadataToFhirDataProvider.java | 3 +- ...tadataToFhirPlanDefinitionTransformer.java | 3 +- ...rogramStageMetadataToFhirDataProvider.java | 70 ++++++ ...etadataToFhirQuestionnaireTransformer.java | 158 +++++++++++++ ...ProgramMetadataToFhirDataProviderTest.java | 2 +- ...taToFhirPlanDefinitionTransformerTest.java | 2 +- ...amStageMetadataToFhirDataProviderTest.java | 93 ++++++++ ...ataToFhirQuestionnaireTransformerTest.java | 170 ++++++++++++++ ...rogramStageMetadataToFhirDataProvider.java | 66 ++++++ ...etadataToFhirQuestionnaireTransformer.java | 93 ++++++++ ...ramStageMetadataToFhirRequestResolver.java | 76 ++++++ ...0.41_10_0__Plan_Definition_Sample_Data.sql | 2 + 37 files changed, 1843 insertions(+), 63 deletions(-) create mode 100644 app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramStageMetadataFhirRestAppTest.java create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/all-program-stages.json create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-program-stage.json create mode 100644 app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageMetadataService.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/DhisProgramStages.java create mode 100644 dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImpl.java create mode 100644 dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImplTest.java create mode 100644 dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyProgramStages.json create mode 100644 dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStage.json create mode 100644 dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStages.json create mode 100644 fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProvider.java create mode 100644 fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformer.java create mode 100644 fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProviderTest.java create mode 100644 fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformerTest.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirDataProvider.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirQuestionnaireTransformer.java create mode 100644 fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/ProgramStageMetadataToFhirRequestResolver.java diff --git a/app/src/main/resources/default-application.yml b/app/src/main/resources/default-application.yml index 1feb5c15..2fb496db 100644 --- a/app/src/main/resources/default-application.yml +++ b/app/src/main/resources/default-application.yml @@ -357,6 +357,7 @@ dhis2.fhir-adapter: resource-types: - ORGANIZATION_UNIT - PROGRAM_METADATA + - PROGRAM_STAGE_METADATA - TRACKED_ENTITY - PROGRAM_STAGE_EVENT # The queue that is used to store distributed requests to synchronize the data from diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java index b7ed5cd6..a5683b12 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/AbstractProgramStageFhirRestAppTest.java @@ -69,12 +69,14 @@ protected void expectProgramStageMetadataRequests() throws Exception .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/EPDyQuoRnXk.json?" + "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid," + "name,valueType," + - "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory," + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name," + + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," + + "program%5Bid%5D,lastUpdated,name," + "description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + "options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramMetadataFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramMetadataFhirRestAppTest.java index 695d91d2..e86e33b7 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramMetadataFhirRestAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramMetadataFhirRestAppTest.java @@ -80,7 +80,8 @@ public void getPlanDefinitionWithInvalidAuthorization() .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/EPDyQuoRnXk.json?" + "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid," + "name,valueType," + - "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory," + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); @@ -107,13 +108,14 @@ private void getPlanDefinition() throws Exception .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tracked-entity-type.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/EPDyQuoRnXk.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name," + + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," + + "program%5Bid%5D,lastUpdated,name," + "description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + "options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); userDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name," + + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name," + "description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + "options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/all-programs.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); @@ -121,7 +123,7 @@ private void getPlanDefinition() throws Exception final IGenericClient client = createGenericClient(); client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); PlanDefinition planDefinition = client.read().resource( PlanDefinition.class ).withId( "EPDyQuoRnXk" ).execute(); - Assert.assertEquals( "Child Programme", planDefinition.getName() ); + Assert.assertEquals( "Child Programme", planDefinition.getTitle() ); systemDhis2Server.verify(); userDhis2Server.verify(); @@ -148,7 +150,7 @@ private void getPlanDefinitionNotExists() userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/0dXIdLNUNEn.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name," + + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name," + "description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + "options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withStatus( HttpStatus.NOT_FOUND ).contentType( MediaType.APPLICATION_JSON ).body( "{}" ) ); @@ -211,8 +213,9 @@ public void getPlanDefinitionByIdentifierWithoutAuthorization() public void getPlanDefinitionByIdentifierInvalidAuthorization() { userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) - .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + - "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable," + + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + + "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable," + "captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=code:eq:OU_1234" ) ) .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); @@ -239,8 +242,9 @@ private void getPlanDefinitionByIdentifier() throws Exception "fields=id,name,trackedEntityTypeAttributes%5Bid,name,valueType,mandatory,trackedEntityAttribute%5Bid,name,code,valueType,generated,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-tracked-entity-type.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); userDhis2Server.expect( ExpectedCount.between( 1, 2 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) - .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + - "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable," + + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + + "withoutRegistration," + + "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable," + "captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=code:eq:PD_1234" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); @@ -251,7 +255,7 @@ private void getPlanDefinitionByIdentifier() throws Exception client.search().forResource( PlanDefinition.class ).where( PlanDefinition.IDENTIFIER.exactly().systemAndIdentifier( "http://www.dhis2.org/dhis2-fhir-adapter/systems/plan-definition-identifier", "PD_1234" ) ).returnBundle( Bundle.class ).execute(); Assert.assertEquals( 1, bundle.getEntry().size() ); PlanDefinition planDefinition = (PlanDefinition) bundle.getEntry().get( 0 ).getResource(); - Assert.assertEquals( "Child Programme", planDefinition.getName() ); + Assert.assertEquals( "Child Programme", planDefinition.getTitle() ); systemDhis2Server.verify(); userDhis2Server.verify(); @@ -270,13 +274,14 @@ public void searchPlanDefinitionInvalidAuthorization() userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?filter=name:$ilike:Test&paging=true&page=1&pageSize=10&order=id&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture," + "displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D," + - "programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue," + + "programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName," + + "valueType,optionSetValue," + "optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); final IGenericClient client = createGenericClient(); client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); - client.search().forResource( PlanDefinition.class ).where( PlanDefinition.NAME.matches().value( "Test" ) ).returnBundle( Bundle.class ).execute(); + client.search().forResource( PlanDefinition.class ).where( PlanDefinition.TITLE.matches().value( "Test" ) ).returnBundle( Bundle.class ).execute(); } @Test @@ -289,15 +294,15 @@ public void searchPlanDefinition() throws Exception userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?filter=name:$ilike:Child%20Programme&paging=true&page=1&pageSize=10&order=id&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture," + "selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name," + - "code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName," + + "code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName," + "valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); final IGenericClient client = createGenericClient(); client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); - Bundle bundle = client.search().forResource( PlanDefinition.class ).where( PlanDefinition.NAME.matches().value( "Child Programme" ) ).returnBundle( Bundle.class ).execute(); + Bundle bundle = client.search().forResource( PlanDefinition.class ).where( PlanDefinition.TITLE.matches().value( "Child Programme" ) ).returnBundle( Bundle.class ).execute(); Assert.assertEquals( 1, bundle.getEntry().size() ); PlanDefinition planDefinition = (PlanDefinition) bundle.getEntry().get( 0 ).getResource(); - Assert.assertEquals( "Child Programme", planDefinition.getName() ); + Assert.assertEquals( "Child Programme", planDefinition.getTitle() ); } } diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramStageMetadataFhirRestAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramStageMetadataFhirRestAppTest.java new file mode 100644 index 00000000..b86a8b22 --- /dev/null +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/server/r4/R4ProgramStageMetadataFhirRestAppTest.java @@ -0,0 +1,221 @@ +package org.dhis2.fhir.adapter.fhir.server.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; +import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import org.apache.commons.io.IOUtils; +import org.dhis2.fhir.adapter.AbstractAppTest; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Questionnaire; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.ExpectedCount; + +import javax.annotation.Nonnull; +import java.nio.charset.StandardCharsets; + +import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +/** + * R4 tests for rest interfaces that access + * DHIS2 program stage metadata. + * + * @author volsch + */ +public class R4ProgramStageMetadataFhirRestAppTest extends AbstractAppTest +{ + @Nonnull + @Override + protected FhirVersion getFhirVersion() + { + return FhirVersion.R4; + } + + @Test( expected = AuthenticationException.class ) + public void getQuestionnaireWithoutAuthorization() + { + final IGenericClient client = createGenericClient(); + client.read().resource( Questionnaire.class ).withId( "MsWxkiY6tMS" ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void getQuestionnaireWithInvalidAuthorization() + { + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages/MsWxkiY6tMS.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.read().resource( Questionnaire.class ).withId( "MsWxkiY6tMS" ).execute(); + } + + @Test + public void getQuestionnaireRepeated() throws Exception + { + getQuestionnaire(); + getQuestionnaire(); + } + + private void getQuestionnaire() throws Exception + { + systemDhis2Server.reset(); + userDhis2Server.reset(); + + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages/MsWxkiY6tMS.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + Questionnaire planDefinition = client.read().resource( Questionnaire.class ).withId( "MsWxkiY6tMS" ).execute(); + Assert.assertEquals( "Birth", planDefinition.getTitle() ); + + systemDhis2Server.verify(); + userDhis2Server.verify(); + } + + @Test( expected = ResourceNotFoundException.class ) + public void getQuestionnaireNotExistsRepeated() + { + try + { + getQuestionnaireNotExists(); + Assert.fail( "Exception expected also an first invocation." ); + } + catch ( ResourceNotFoundException e ) + { + getQuestionnaireNotExists(); + } + } + + private void getQuestionnaireNotExists() + { + systemDhis2Server.reset(); + userDhis2Server.reset(); + + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages/0dXIdLNUNEn.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withStatus( HttpStatus.NOT_FOUND ).contentType( MediaType.APPLICATION_JSON ).body( "{}" ) ); + + try + { + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + client.read().resource( Questionnaire.class ).withId( "0dXIdLNUNEn" ).execute(); + } + catch ( ResourceNotFoundException e ) + { + systemDhis2Server.verify(); + userDhis2Server.verify(); + throw e; + } + } + + @Test( expected = ResourceNotFoundException.class ) + public void getQuestionnaireRuleNotFoundRepeated() + { + try + { + getQuestionnaireNotExists(); + Assert.fail( "Exception expected also an first invocation." ); + } + catch ( ResourceNotFoundException e ) + { + getQuestionnaireNotExists(); + } + } + + private void getQuestionnaireRuleNotFound() + { + systemDhis2Server.reset(); + userDhis2Server.reset(); + + try + { + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + client.read().resource( Questionnaire.class ).withId( "ldXIdLNUNEn" ).execute(); + } + catch ( ResourceNotFoundException e ) + { + systemDhis2Server.verify(); + userDhis2Server.verify(); + throw e; + } + } + + @Test( expected = AuthenticationException.class ) + public void searchQuestionnaireWithoutAuthorization() + { + final IGenericClient client = createGenericClient(); + client.search().forResource( Questionnaire.class ).where( Questionnaire.TITLE.matches().value( "Test" ) ).returnBundle( Bundle.class ).execute(); + } + + @Test( expected = AuthenticationException.class ) + public void searchQuestionnaireInvalidAuthorization() + { + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6aW52YWxpZF8x" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages.json?filter=name:$ilike:Test&paging=true&page=1&pageSize=10&order=id&fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withStatus( HttpStatus.UNAUTHORIZED ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "invalid_1" ) ); + client.search().forResource( Questionnaire.class ).where( Questionnaire.TITLE.matches().value( "Test" ) ).returnBundle( Bundle.class ).execute(); + } + + @Test + public void searchQuestionnaire() throws Exception + { + userDhis2Server.expect( ExpectedCount.once(), method( HttpMethod.GET ) ).andExpect( header( "Authorization", "Basic Zmhpcl9jbGllbnQ6Zmhpcl9jbGllbnRfMQ==" ) ) + .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programStages.json?filter=name:$ilike:Birth&paging=true&page=1&pageSize=10&order=id&fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-program-stage.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); + + final IGenericClient client = createGenericClient(); + client.registerInterceptor( new BasicAuthInterceptor( "fhir_client", "fhir_client_1" ) ); + Bundle bundle = client.search().forResource( Questionnaire.class ).where( Questionnaire.TITLE.matches().value( "Birth" ) ).returnBundle( Bundle.class ).execute(); + Assert.assertEquals( 1, bundle.getEntry().size() ); + Questionnaire planDefinition = (Questionnaire) bundle.getEntry().get( 0 ).getResource(); + Assert.assertEquals( "Birth", planDefinition.getTitle() ); + } +} diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/enrollment/AbstractEnrollmentTransformationAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/enrollment/AbstractEnrollmentTransformationAppTest.java index 7b0009fc..aec89b39 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/enrollment/AbstractEnrollmentTransformationAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/enrollment/AbstractEnrollmentTransformationAppTest.java @@ -50,17 +50,16 @@ protected void expectMetadataRequests() throws Exception { systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs/EPDyQuoRnXk.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name," + - "description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + - "options%5Bcode,name%5D%5D%5D%5D%5D" ) ) + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," + + "program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType," + + "optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + - "withoutRegistration," + - "captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + - "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + - "name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) + "withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid," + + "program%5Bid%5D," + + "lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue," + + "optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/all-programs.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/trackedEntityTypes/MCPQUTHX1Ze.json?fields=id,name,trackedEntityTypeAttributes%5Bid,name,valueType,mandatory,trackedEntityAttribute%5Bid,name,code,valueType,generated," + @@ -75,9 +74,10 @@ protected void expectMetadataRequests() throws Exception .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-tracked-entity-type.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&" + - "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType," + - "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + - "allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) + "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid," + + "name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate," + + "minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" + + "&filter=name:eq:Child%20Programme" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); } } diff --git a/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/programstage/AbstractProgramStageTransformationAppTest.java b/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/programstage/AbstractProgramStageTransformationAppTest.java index 742bfca8..1cfadd70 100644 --- a/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/programstage/AbstractProgramStageTransformationAppTest.java +++ b/app/src/test/java/org/dhis2/fhir/adapter/fhir/transform/fhir/impl/programstage/AbstractProgramStageTransformationAppTest.java @@ -52,7 +52,9 @@ protected void expectMetadataRequests() throws Exception systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration," + "withoutRegistration," + - "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable," + + "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name," + + "description," + + "repeatable," + "captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) @@ -70,8 +72,10 @@ protected void expectMetadataRequests() throws Exception .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/default-tracked-entity-type.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); systemDhis2Server.expect( ExpectedCount.between( 0, 1 ), method( HttpMethod.GET ) ).andExpect( header( "Authorization", testConfiguration.getDhis2SystemAuthorization() ) ) .andExpect( requestTo( dhis2BaseUrl + "/api/" + dhis2ApiVersion + "/programs.json?paging=false&" + - "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType," + - "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid," + + "name,valueType," + + "mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements%5Bid,compulsory," + "allowProvidedElsewhere,dataElement%5Bid,name,code,description,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D&filter=name:eq:Child%20Programme" ) ) .andRespond( withSuccess( IOUtils.resourceToString( "/org/dhis2/fhir/adapter/dhis/test/single-program.json", StandardCharsets.UTF_8 ), MediaType.APPLICATION_JSON ) ); } diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/all-program-stages.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/all-program-stages.json new file mode 100644 index 00000000..99a77892 --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/all-program-stages.json @@ -0,0 +1,185 @@ +{ + "programStages": [ + { + "name": "Birth", + "id": "MsWxkiY6tMS", + "program": { + "id": "EPDyQuoRnXk" + }, + "generatedByEnrollmentDate": false, + "repeatable": false, + "minDaysFromStart": 0, + "programStageDataElements": [ + { + "id": "uRAfo19lLtY", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_391382", + "name": "MCH Apgar comment", + "id": "wquzcS4X6He", + "formName": "Apgar comment", + "valueType": "TEXT", + "optionSetValue": false + } + }, + { + "id": "Ije8HSPh71d", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006098", + "name": "MCH Apgar Score", + "id": "uzKeaNjgQz9", + "formName": "Apgar Score", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "GLrVTw75zSK", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2005736", + "name": "MCH Weight (g)", + "id": "BnplxU2jGvX", + "formName": "Weight (g)", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "aQd5KKFge1U", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006101", + "name": "MCH BCG dose", + "id": "Lon4lYDF0SH", + "formName": "BCG dose", + "valueType": "BOOLEAN", + "optionSetValue": false + } + }, + { + "id": "lm3Cxju7CL0", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006104", + "name": "MCH OPV dose", + "id": "ft7iD5ZzPxJ", + "formName": "OPV dose", + "valueType": "TEXT", + "optionSetValue": true, + "optionSet": { + "name": "MNCH Polio doses (0-3)", + "id": "kzgQRhOCadd", + "options": [ + { + "code": "0", + "name": "Dose 0" + }, + { + "code": "1", + "name": "Dose 1" + }, + { + "code": "2", + "name": "Dose 2" + }, + { + "code": "3", + "name": "Dose 3" + } + ] + } + } + } + ] + }, + { + "name": "Baby Postnatal", + "id": "qowTSevVSkd", + "program": { + "id": "EPDyQuoRnXk" + }, + "generatedByEnrollmentDate": false, + "repeatable": false, + "minDaysFromStart": 6, + "programStageDataElements": [ + { + "id": "s7bKmA7gfXq", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006099", + "name": "MCH Infant Weight (g)", + "id": "UnN0Jdrfr4o", + "formName": "Infant Weight (g)", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "g1eWTx5nsNx", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006125", + "name": "MCH Measles dose", + "id": "KBLBjsTfNSS", + "formName": "Measles dose", + "valueType": "BOOLEAN", + "optionSetValue": false + } + }, + { + "id": "TKnlmmxUEss", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006126", + "name": "MCH Yellow fever dose", + "id": "TNg7ABaHeP7", + "formName": "Yellow fever dose", + "valueType": "BOOLEAN", + "optionSetValue": false + } + }, + { + "id": "mx5k0I1SLDt", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006105", + "name": "MCH DPT dose", + "id": "vNGGmCPNfky", + "formName": "DPT dose", + "valueType": "TEXT", + "optionSetValue": true, + "optionSet": { + "name": "MNCH DPT doses (1-3)", + "id": "udkr3ihaeD3", + "options": [ + { + "code": "1", + "name": "Dose 1" + }, + { + "code": "2", + "name": "Dose 2" + }, + { + "code": "3", + "name": "Dose 3" + } + ] + } + } + } + ] + } + ] +} diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-program-stage.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-program-stage.json new file mode 100644 index 00000000..15a57544 --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/default-program-stage.json @@ -0,0 +1,101 @@ +{ + "pager": { "page": 1, "pageCount": 1, "total": 0, "pageSize": 1 }, + "programStages": [ + { + "name": "Birth", + "id": "MsWxkiY6tMS", + "generatedByEnrollmentDate": false, + "repeatable": false, + "minDaysFromStart": 0, + "programStageDataElements": [ + { + "id": "uRAfo19lLtY", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_391382", + "name": "MCH Apgar comment", + "id": "wquzcS4X6He", + "formName": "Apgar comment", + "valueType": "TEXT", + "optionSetValue": false + } + }, + { + "id": "Ije8HSPh71d", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006098", + "name": "MCH Apgar Score", + "id": "uzKeaNjgQz9", + "formName": "Apgar Score", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "GLrVTw75zSK", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2005736", + "name": "MCH Weight (g)", + "id": "BnplxU2jGvX", + "formName": "Weight (g)", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "aQd5KKFge1U", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006101", + "name": "MCH BCG dose", + "id": "Lon4lYDF0SH", + "formName": "BCG dose", + "valueType": "BOOLEAN", + "optionSetValue": false + } + }, + { + "id": "lm3Cxju7CL0", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006104", + "name": "MCH OPV dose", + "id": "ft7iD5ZzPxJ", + "formName": "OPV dose", + "valueType": "TEXT", + "optionSetValue": true, + "optionSet": { + "name": "MNCH Polio doses (0-3)", + "id": "kzgQRhOCadd", + "options": [ + { + "code": "0", + "name": "Dose 0" + }, + { + "code": "1", + "name": "Dose 1" + }, + { + "code": "2", + "name": "Dose 2" + }, + { + "code": "3", + "name": "Dose 3" + } + ] + } + } + } + ] + } + ] +} diff --git a/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json new file mode 100644 index 00000000..1bad997c --- /dev/null +++ b/app/src/test/resources/org/dhis2/fhir/adapter/dhis/test/single-program-stage.json @@ -0,0 +1,99 @@ +{ + "name": "Birth", + "id": "MsWxkiY6tMS", + "program": { + "id": "EPDyQuoRnXk" + }, + "generatedByEnrollmentDate": false, + "repeatable": false, + "minDaysFromStart": 0, + "programStageDataElements": [ + { + "id": "uRAfo19lLtY", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_391382", + "name": "MCH Apgar comment", + "id": "wquzcS4X6He", + "formName": "Apgar comment", + "valueType": "TEXT", + "optionSetValue": false + } + }, + { + "id": "Ije8HSPh71d", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006098", + "name": "MCH Apgar Score", + "id": "uzKeaNjgQz9", + "formName": "Apgar Score", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "GLrVTw75zSK", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2005736", + "name": "MCH Weight (g)", + "id": "BnplxU2jGvX", + "formName": "Weight (g)", + "valueType": "NUMBER", + "optionSetValue": false + } + }, + { + "id": "aQd5KKFge1U", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006101", + "name": "MCH BCG dose", + "id": "Lon4lYDF0SH", + "formName": "BCG dose", + "valueType": "BOOLEAN", + "optionSetValue": false + } + }, + { + "id": "lm3Cxju7CL0", + "compulsory": false, + "allowProvidedElsewhere": false, + "dataElement": { + "code": "DE_2006104", + "name": "MCH OPV dose", + "id": "ft7iD5ZzPxJ", + "formName": "OPV dose", + "valueType": "TEXT", + "optionSetValue": true, + "optionSet": { + "name": "MNCH Polio doses (0-3)", + "id": "kzgQRhOCadd", + "options": [ + { + "code": "0", + "name": "Dose 0" + }, + { + "code": "1", + "name": "Dose 1" + }, + { + "code": "2", + "name": "Dose 2" + }, + { + "code": "3", + "name": "Dose 3" + } + ] + } + } + } + ] +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java index fef873ad..5d44677c 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/sync/impl/DhisResourceRepositoryImpl.java @@ -39,6 +39,7 @@ import org.dhis2.fhir.adapter.dhis.tracker.program.Event; import org.dhis2.fhir.adapter.dhis.tracker.program.EventService; import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramMetadataService; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityInstance; import org.dhis2.fhir.adapter.dhis.tracker.trackedentity.TrackedEntityService; import org.slf4j.Logger; @@ -65,6 +66,8 @@ public class DhisResourceRepositoryImpl implements DhisResourceRepository private final ProgramMetadataService programMetadataService; + private final ProgramStageMetadataService programStageMetadataService; + private final TrackedEntityService trackedEntityService; private final EnrollmentService enrollmentService; @@ -72,10 +75,12 @@ public class DhisResourceRepositoryImpl implements DhisResourceRepository private final EventService eventService; public DhisResourceRepositoryImpl( @Nonnull OrganizationUnitService organizationUnitService, ProgramMetadataService programMetadataService, - @Nonnull TrackedEntityService trackedEntityService, @Nonnull EnrollmentService enrollmentService, @Nonnull EventService eventService ) + @Nonnull ProgramStageMetadataService programStageMetadataService, @Nonnull TrackedEntityService trackedEntityService, + @Nonnull EnrollmentService enrollmentService, @Nonnull EventService eventService ) { this.organizationUnitService = organizationUnitService; this.programMetadataService = programMetadataService; + this.programStageMetadataService = programStageMetadataService; this.trackedEntityService = trackedEntityService; this.enrollmentService = enrollmentService; this.eventService = eventService; @@ -91,6 +96,8 @@ public Optional findRefreshed( @Nonnull DhisResourceId d return organizationUnitService.findOneByReference( new Reference( dhisResourceId.getId(), ReferenceType.ID ) ); case PROGRAM_METADATA: return programMetadataService.findOneByReference( new Reference( dhisResourceId.getId(), ReferenceType.ID ) ); + case PROGRAM_STAGE_METADATA: + return programStageMetadataService.findOneByReference( new Reference( dhisResourceId.getId(), ReferenceType.ID ) ); case TRACKED_ENTITY: return trackedEntityService.findOneByIdRefreshed( dhisResourceId.getId() ); case PROGRAM_STAGE_EVENT: @@ -112,6 +119,7 @@ public Optional findRefreshedDeleted( @Nonnull DhisResou return eventService.findOneDeletedById( dhisResourceId.getId() ); case ORGANIZATION_UNIT: case PROGRAM_METADATA: + case PROGRAM_STAGE_METADATA: case TRACKED_ENTITY: case ENROLLMENT: throw new UnsupportedOperationException( "Retrieving deleted " + dhisResourceId.getType() + " DHIS resource items is not supported." ); diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ImmutableProgramStage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ImmutableProgramStage.java index 405d180e..bb461091 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ImmutableProgramStage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ImmutableProgramStage.java @@ -66,6 +66,13 @@ public Set getAllReferences() return delegate.getAllReferences(); } + @JsonIgnore + @Override + public String getProgramId() + { + return delegate.getProgramId(); + } + @JsonIgnore @Override public String getId() diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java index 435f596b..0535b110 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStage.java @@ -48,6 +48,8 @@ @Scriptable public interface ProgramStage extends DhisResource, DhisMetadata { + String getProgramId(); + boolean isRepeatable(); boolean isCaptureCoordinates(); diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageMetadataService.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageMetadataService.java new file mode 100644 index 00000000..ac5093e7 --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/ProgramStageMetadataService.java @@ -0,0 +1,40 @@ +package org.dhis2.fhir.adapter.dhis.tracker.program; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.service.DhisMetadataService; + +/** + * Metadata service for DHIS2 program stages. + * + * @author volsch + */ +public interface ProgramStageMetadataService extends DhisMetadataService +{ +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgram.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgram.java index 457168ae..ceecf229 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgram.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgram.java @@ -139,12 +139,12 @@ public void setDescription( String description ) @Override public String getTrackedEntityTypeId() { - return (trackedEntityType == null) ? null : trackedEntityType.getId(); + return trackedEntityType == null ? null : trackedEntityType.getId(); } public void setTrackedEntityTypeId( String trackedEntityTypeId ) { - this.trackedEntityType = (trackedEntityTypeId == null) ? null : new Id( trackedEntityTypeId ); + this.trackedEntityType = trackedEntityTypeId == null ? null : new Id( trackedEntityTypeId ); } @Override diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgramStage.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgramStage.java index 588b057c..d0474ce4 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgramStage.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/WritableProgramStage.java @@ -34,6 +34,7 @@ import org.dhis2.fhir.adapter.dhis.model.DhisResourceId; import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.model.Id; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -48,6 +49,11 @@ public class WritableProgramStage extends AbstractDhisMetadata implements Progra { private static final long serialVersionUID = -7544648580734783374L; + private ZonedDateTime lastUpdated; + + @JsonProperty + private Id program; + private String id; private String name; @@ -74,6 +80,17 @@ public class WritableProgramStage extends AbstractDhisMetadata implements Progra @JsonIgnore private transient volatile Map dataElementsByCode; + @JsonIgnore + public String getProgramId() + { + return program == null ? null : program.getId(); + } + + public void setProgramId( String programId ) + { + program = programId == null ? null : new Id( programId ); + } + @Override public String getId() { @@ -262,7 +279,7 @@ public boolean isDeleted() @Override public ZonedDateTime getLastUpdated() { - return null; + return lastUpdated; } @Override diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/DhisProgramStages.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/DhisProgramStages.java new file mode 100644 index 00000000..8757310e --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/DhisProgramStages.java @@ -0,0 +1,62 @@ +package org.dhis2.fhir.adapter.dhis.tracker.program.impl; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dhis2.fhir.adapter.dhis.service.impl.DhisMetadataItems; +import org.dhis2.fhir.adapter.dhis.tracker.program.WritableProgramStage; + +import java.io.Serializable; +import java.util.List; + +/** + * Container object used for DHIS2 program stages. + * + * @author volsch + */ +public class DhisProgramStages extends DhisMetadataItems implements Serializable +{ + private static final long serialVersionUID = 1084527285362478422L; + + @JsonProperty( "programStages" ) + public List getProgramStages() + { + return getItems(); + } + + public void setProgramStages( List programStages ) + { + setItems( programStages ); + } + + public List toModel() + { + return getItems(); + } +} diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImpl.java index a17179c8..eaa0e56d 100644 --- a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImpl.java +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImpl.java @@ -53,9 +53,7 @@ public class ProgramMetadataServiceImpl extends AbstractDhisMetadataServiceImpl< "registration,withoutRegistration,captureCoordinates,trackedEntityType[id]," + "programTrackedEntityAttributes[id,name,valueType,mandatory,allowFutureDate," + "trackedEntityAttribute[id,name,code,valueType,generated]]," + - "programStages[id,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + - "programStageDataElements[id,compulsory,allowProvidedElsewhere," + - "dataElement[id,name,code,formName,valueType,optionSetValue,optionSet[id,name,options[code,name]]]]]"; + "programStages[" + ProgramStageMetadataServiceImpl.FIELDS + "]"; public ProgramMetadataServiceImpl( @Nonnull @Qualifier( "systemDhis2RestTemplate" ) RestTemplate systemRestTemplate, @Nonnull @Qualifier( "userDhis2RestTemplate" ) RestTemplate userRestTemplate ) { diff --git a/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImpl.java b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImpl.java new file mode 100644 index 00000000..554f04bd --- /dev/null +++ b/dhis/src/main/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImpl.java @@ -0,0 +1,86 @@ +package org.dhis2.fhir.adapter.dhis.tracker.program.impl; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.service.impl.AbstractDhisMetadataServiceImpl; +import org.dhis2.fhir.adapter.dhis.service.impl.DhisMetadataItems; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStage; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; +import org.dhis2.fhir.adapter.dhis.tracker.program.WritableProgramStage; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Nonnull; + +/** + * Implementation of a {@link ProgramStageMetadataService}. + * + * @author volsch + */ +@Service +public class ProgramStageMetadataServiceImpl extends AbstractDhisMetadataServiceImpl implements ProgramStageMetadataService +{ + protected static final String FIELDS = "id,program[id],lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart," + + "programStageDataElements[id,compulsory,allowProvidedElsewhere,dataElement[id,name,code,formName,valueType,optionSetValue,optionSet[id,name,options[code,name]]]]"; + + public ProgramStageMetadataServiceImpl( @Nonnull @Qualifier( "systemDhis2RestTemplate" ) RestTemplate systemRestTemplate, @Nonnull @Qualifier( "userDhis2RestTemplate" ) RestTemplate userRestTemplate ) + { + super( systemRestTemplate, userRestTemplate ); + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.PROGRAM_STAGE_METADATA; + } + + @Nonnull + @Override + protected Class getItemClass() + { + return WritableProgramStage.class; + } + + @Nonnull + @Override + protected Class> getItemsClass() + { + return DhisProgramStages.class; + } + + @Nonnull + @Override + protected String getFieldNames() + { + return FIELDS; + } +} diff --git a/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImplTest.java b/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImplTest.java index 27653d09..c12402da 100644 --- a/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImplTest.java +++ b/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramMetadataServiceImplTest.java @@ -82,9 +82,10 @@ public void setUp() public void findMetadataByReferenceId() throws IOException { mockServer.expect( requestTo( "http://localhost:8080/api/programs/93783.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + - "captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + - "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ) + "captureCoordinates,trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name," + + "description," + + "repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name," + + "options%5Bcode,name%5D%5D%5D%5D%5D" ) ) .andExpect( method( HttpMethod.GET ) ).andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/program.json" ), MediaType.APPLICATION_JSON ) ); Optional ou = service.findMetadataByReference( new Reference( "93783", ReferenceType.ID ) ); @@ -95,8 +96,10 @@ public void findMetadataByReferenceId() throws IOException @Test public void findMetadataByReferenceIdNotFound() { - mockServer.expect( requestTo( "http://localhost:8080/api/programs/93783.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( + "http://localhost:8080/api/programs/93783.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable," + + "captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( MockRestResponseCreators.withStatus( HttpStatus.NOT_FOUND ).body( "{}" ).contentType( MediaType.APPLICATION_JSON ) ); @@ -107,8 +110,9 @@ public void findMetadataByReferenceIdNotFound() @Test( expected = HttpServerErrorException.class ) public void findMetadataByReferenceIdServerError() { - mockServer.expect( requestTo( "http://localhost:8080/api/programs/93783.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( + "http://localhost:8080/api/programs/93783.json?fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D%5D" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( MockRestResponseCreators.withServerError() ); service.findMetadataByReference( new Reference( "93783", ReferenceType.ID ) ); @@ -117,8 +121,9 @@ public void findMetadataByReferenceIdServerError() @Test public void findMetadataByReferenceCode() throws IOException { - mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + + "captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=code:eq:OU_3783" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programs.json" ), MediaType.APPLICATION_JSON ) ); @@ -131,8 +136,9 @@ public void findMetadataByReferenceCode() throws IOException @Test public void findMetadataByReferenceCodeNotFound() throws IOException { - mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + + "captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=code:eq:OU_3783" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyPrograms.json" ), MediaType.APPLICATION_JSON ) ); @@ -144,8 +150,9 @@ public void findMetadataByReferenceCodeNotFound() throws IOException @Test public void findMetadataByReferenceName() throws IOException { - mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + + "captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=name:eq:Freetown" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programs.json" ), MediaType.APPLICATION_JSON ) ); @@ -158,8 +165,9 @@ public void findMetadataByReferenceName() throws IOException @Test public void findMetadataByReferenceNameNotFound() throws IOException { - mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration,captureCoordinates," + - "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,name,description,repeatable,captureCoordinates," + + mockServer.expect( requestTo( "http://localhost:8080/api/programs.json?paging=false&fields=id,name,code,description,lastUpdated,selectIncidentDatesInFuture,selectEnrollmentDatesInFuture,displayIncidentDate,registration,withoutRegistration," + + "captureCoordinates," + + "trackedEntityType%5Bid%5D,programTrackedEntityAttributes%5Bid,name,valueType,mandatory,allowFutureDate,trackedEntityAttribute%5Bid,name,code,valueType,generated%5D%5D,programStages%5Bid,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates," + "generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory,allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode," + "name%5D%5D%5D%5D%5D&filter=name:eq:Freetown" ) ).andExpect( method( HttpMethod.GET ) ) .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyPrograms.json" ), MediaType.APPLICATION_JSON ) ); diff --git a/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImplTest.java b/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImplTest.java new file mode 100644 index 00000000..eba3e0b4 --- /dev/null +++ b/dhis/src/test/java/org/dhis2/fhir/adapter/dhis/tracker/program/impl/ProgramStageMetadataServiceImplTest.java @@ -0,0 +1,156 @@ +package org.dhis2.fhir.adapter.dhis.tracker.program.impl; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.apache.commons.io.IOUtils; +import org.dhis2.fhir.adapter.dhis.model.Reference; +import org.dhis2.fhir.adapter.dhis.model.ReferenceType; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStage; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; +import org.dhis2.fhir.adapter.model.ValueType; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.test.web.client.response.MockRestResponseCreators; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.util.Optional; + +import static org.junit.Assert.*; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; + +/** + * Unit tests for {@link ProgramStageMetadataServiceImpl}. + * + * @author volsch + */ +public class ProgramStageMetadataServiceImplTest +{ + private RestTemplate systemRestTemplate; + + private RestTemplate userRestTemplate; + + private MockRestServiceServer mockServer; + + private ProgramStageMetadataService service; + + @Before + public void setUp() + { + systemRestTemplate = new RestTemplateBuilder().rootUri( "http://localhost:8080/api" ).build(); + userRestTemplate = new RestTemplateBuilder().rootUri( "http://localhost:8080/api" ).build(); + mockServer = MockRestServiceServer.createServer( systemRestTemplate ); + service = new ProgramStageMetadataServiceImpl( systemRestTemplate, userRestTemplate ); + } + + @Test + public void findMetadataByReferenceId() throws IOException + { + mockServer.expect( requestTo( "http://localhost:8080/api/programStages/93783.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid," + + "compulsory," + + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ) + .andExpect( method( HttpMethod.GET ) ).andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStage.json" ), MediaType.APPLICATION_JSON ) ); + + Optional ou = service.findMetadataByReference( new Reference( "93783", ReferenceType.ID ) ); + Assert.assertTrue( ou.isPresent() ); + assertProgramStage( ou.get() ); + } + + @Test + public void findMetadataByReferenceIdNotFound() + { + mockServer.expect( requestTo( "http://localhost:8080/api/programStages/93783.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ).andExpect( method( HttpMethod.GET ) ) + .andRespond( MockRestResponseCreators.withStatus( HttpStatus.NOT_FOUND ).body( "{}" ).contentType( MediaType.APPLICATION_JSON ) ); + + Optional ou = service.findMetadataByReference( new Reference( "93783", ReferenceType.ID ) ); + Assert.assertFalse( ou.isPresent() ); + } + + @Test( expected = HttpServerErrorException.class ) + public void findMetadataByReferenceIdServerError() + { + mockServer.expect( requestTo( "http://localhost:8080/api/programStages/93783.json?fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D" ) ).andExpect( method( HttpMethod.GET ) ) + .andRespond( MockRestResponseCreators.withServerError() ); + service.findMetadataByReference( new Reference( "93783", ReferenceType.ID ) ); + } + + @Test + public void findMetadataByReferenceName() throws IOException + { + mockServer.expect( requestTo( "http://localhost:8080/api/programStages.json?paging=false&fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D&filter=name:eq:Birth" ) ).andExpect( method( HttpMethod.GET ) ) + .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStages.json" ), MediaType.APPLICATION_JSON ) ); + + Optional ou = service.findMetadataByReference( new Reference( "Birth", ReferenceType.NAME ) ); + Assert.assertTrue( ou.isPresent() ); + assertProgramStage( ou.get() ); + } + + @Test + public void findMetadataByReferenceNameNotFound() throws IOException + { + mockServer.expect( requestTo( "http://localhost:8080/api/programStages.json?paging=false&fields=id,program%5Bid%5D,lastUpdated,name,description,repeatable,captureCoordinates,generatedByEnrollmentDate,minDaysFromStart,programStageDataElements%5Bid,compulsory," + + "allowProvidedElsewhere,dataElement%5Bid,name,code,formName,valueType,optionSetValue,optionSet%5Bid,name,options%5Bcode,name%5D%5D%5D%5D&filter=name:eq:xBirth" ) ).andExpect( method( HttpMethod.GET ) ) + .andRespond( withSuccess( IOUtils.resourceToByteArray( "/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyPrograms.json" ), MediaType.APPLICATION_JSON ) ); + + Optional ou = service.findMetadataByReference( new Reference( "xBirth", ReferenceType.NAME ) ); + Assert.assertFalse( ou.isPresent() ); + } + + private void assertProgramStage( ProgramStage programStage ) + { + assertNotNull( programStage ); + assertEquals( "A03MvHHogjR", programStage.getId() ); + assertEquals( "IpHINAT79UW", programStage.getProgramId() ); + assertEquals( "Birth", programStage.getName() ); + assertEquals( 2, programStage.getMinDaysFromStart() ); + assertNotNull( programStage.getDataElements() ); + assertEquals( "a3kGcGDCuk6", programStage.getDataElements().get( 0 ).getElement().getId() ); + assertEquals( "MCH Apgar Score", programStage.getDataElements().get( 0 ).getElement().getName() ); + assertEquals( "DE_2006098", programStage.getDataElements().get( 0 ).getElement().getCode() ); + assertEquals( ValueType.NUMBER, programStage.getDataElements().get( 0 ).getElement().getValueType() ); + assertTrue( programStage.getDataElements().get( 0 ).isAllowProvidedElsewhere() ); + assertTrue( programStage.getDataElements().get( 0 ).isCompulsory() ); + assertNull( programStage.getDataElements().get( 0 ).getElement().getOptionSet() ); + assertTrue( programStage.isGeneratedByEnrollmentDate() ); + assertTrue( programStage.isCaptureCoordinates() ); + assertTrue( programStage.isRepeatable() ); + } +} \ No newline at end of file diff --git a/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyProgramStages.json b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyProgramStages.json new file mode 100644 index 00000000..6c232bc6 --- /dev/null +++ b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/emptyProgramStages.json @@ -0,0 +1,3 @@ +{ + "programStages": [ ] +} \ No newline at end of file diff --git a/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStage.json b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStage.json new file mode 100644 index 00000000..93b9829f --- /dev/null +++ b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStage.json @@ -0,0 +1,11 @@ +{ + "name": "Birth", "id": "A03MvHHogjR", "program": { "id": "IpHINAT79UW" }, "generatedByEnrollmentDate": true, "repeatable": true, "captureCoordinates": true, "minDaysFromStart": 2, "programStageDataElements": [ + { "id": "LBNxoXdMnkv", "compulsory": true, "allowProvidedElsewhere": true, "dataElement": { "code": "DE_2006098", "name": "MCH Apgar Score", "id": "a3kGcGDCuk6", "valueType": "NUMBER", "optionSetValue": false } }, + { + "id": "O4dwFWakvGO", "compulsory": false, "allowProvidedElsewhere": false, "dataElement": { + "code": "DE_2006104", "name": "MCH OPV dose", "id": "ebaJjqltK5N", "valueType": "TEXT", "optionSetValue": true, + "optionSet": { "name": "MNCH Polio doses (0-3)", "id": "kzgQRhOCadd", "options": [ { "code": "0", "name": "Dose 0" }, { "code": "1", "name": "Dose 1" } ] } + } + } +] +} diff --git a/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStages.json b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStages.json new file mode 100644 index 00000000..8be57dd1 --- /dev/null +++ b/dhis/src/test/resources/org/dhis2/fhir/adapter/dhis/tracker/program/impl/programStages.json @@ -0,0 +1,24 @@ +{ + "programStages": [ + { + "name": "Birth", "id": "A03MvHHogjR", "program": { "id": "IpHINAT79UW" }, "generatedByEnrollmentDate": true, "repeatable": true, "captureCoordinates": true, "minDaysFromStart": 2, "programStageDataElements": [ + { "id": "LBNxoXdMnkv", "compulsory": true, "allowProvidedElsewhere": true, "dataElement": { "code": "DE_2006098", "name": "MCH Apgar Score", "id": "a3kGcGDCuk6", "valueType": "NUMBER", "optionSetValue": false } }, + { + "id": "O4dwFWakvGO", "compulsory": false, "allowProvidedElsewhere": false, "dataElement": { + "code": "DE_2006104", "name": "MCH OPV dose", "id": "ebaJjqltK5N", "valueType": "TEXT", "optionSetValue": true, + "optionSet": { "name": "MNCH Polio doses (0-3)", "id": "kzgQRhOCadd", "options": [ { "code": "0", "name": "Dose 0" }, { "code": "1", "name": "Dose 1" } ] } + } + } + ] + }, { + "name": "Baby Postnatal", "id": "ZzYYXq4fJie", "generatedByEnrollmentDate": false, "repeatable": false, "captureCoordinates": false, "minDaysFromStart": 6, "programStageDataElements": [ + { "id": "ztoQtbuXzsI", "compulsory": false, "allowProvidedElsewhere": true, "dataElement": { "code": "DE_2006099", "name": "MCH Infant Weight (g)", "id": "GQY2lXrypjO", "valueType": "NUMBER", "optionSetValue": false } } + ] + } + ], "programTrackedEntityAttributes": [ + { + "name": "Child Programme First name", "id": "l2T72XzBCLd", "program": { "id": "IpHINAT79UW" }, "valueType": "TEXT", "allowFutureDate": true, "mandatory": true, + "trackedEntityAttribute": { "code": "MMD_PER_NAM", "name": "First name", "id": "w75KJ2mc4zz", "generated": true, "valueType": "TEXT" } + }, { "name": "Child Programme Last name", "id": "XmRd2ZDjWhF", "valueType": "TEXT", "allowFutureDate": false, "mandatory": false, "trackedEntityAttribute": { "name": "Last name", "id": "zDhUuAYrxNC", "generated": false, "valueType": "TEXT" } } +] +} diff --git a/docs/fhir/profiles/TrackerProgramPlanDefinition.StructureDefinition.xml b/docs/fhir/profiles/TrackerProgramPlanDefinition.StructureDefinition.xml index 38b47048..bf33d0bb 100644 --- a/docs/fhir/profiles/TrackerProgramPlanDefinition.StructureDefinition.xml +++ b/docs/fhir/profiles/TrackerProgramPlanDefinition.StructureDefinition.xml @@ -96,13 +96,9 @@ - - - - - + diff --git a/docs/fhir/profiles/TrackerProgramQuestionnaire.StructureDefinition.xml b/docs/fhir/profiles/TrackerProgramQuestionnaire.StructureDefinition.xml index 0702ebad..eeef7fc0 100644 --- a/docs/fhir/profiles/TrackerProgramQuestionnaire.StructureDefinition.xml +++ b/docs/fhir/profiles/TrackerProgramQuestionnaire.StructureDefinition.xml @@ -96,9 +96,13 @@ + + + + - + @@ -186,6 +190,10 @@ + + + + @@ -200,6 +208,12 @@ + + + + + + diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProvider.java index 180a4560..da5594af 100644 --- a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProvider.java +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProvider.java @@ -65,6 +65,7 @@ public Set getFhirVersions() @Override protected void initSearchFilter( @Nonnull FhirVersion fhirVersion, @Nonnull RuleInfo ruleInfo, @Nonnull SearchFilter searchFilter ) { - searchFilter.add( PlanDefinition.SP_NAME, SearchParamType.STRING, "name" ); + searchFilter.add( PlanDefinition.SP_NAME, SearchParamType.STRING, "code" ); + searchFilter.add( PlanDefinition.SP_TITLE, SearchParamType.STRING, "name" ); } } diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformer.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformer.java index 6002c267..44333c79 100644 --- a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformer.java +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformer.java @@ -92,7 +92,8 @@ protected boolean transformInternal( @Nonnull FhirClient fhirClient, @Nonnull Dh } fhirPlanDefinition.setUrl( dhisProgram.getId() ); - fhirPlanDefinition.setName( dhisProgram.getName() ); + fhirPlanDefinition.setName( dhisProgram.getCode() ); + fhirPlanDefinition.setTitle( dhisProgram.getName() ); fhirPlanDefinition.setStatus( Enumerations.PublicationStatus.ACTIVE ); fhirPlanDefinition.setDescription( dhisProgram.getDescription() ); fhirPlanDefinition.setAction( null ); diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProvider.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProvider.java new file mode 100644 index 00000000..5801cc6b --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProvider.java @@ -0,0 +1,70 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.program.AbstractProgramStageMetadataToFhirDataProvider; +import org.dhis2.fhir.adapter.fhir.transform.dhis.search.SearchFilter; +import org.dhis2.fhir.adapter.fhir.transform.dhis.search.SearchParamType; +import org.hl7.fhir.r4.model.Questionnaire; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import java.util.Set; + +/** + * R4 specific version of DHIS2 Program Stage Metadata data provider. + * + * @author volsch + */ +@Component +public class R4ProgramStageMetadataToFhirDataProvider extends AbstractProgramStageMetadataToFhirDataProvider +{ + public R4ProgramStageMetadataToFhirDataProvider( @Nonnull ScriptExecutor scriptExecutor, @Nonnull ProgramStageMetadataService programStageMetadataService ) + { + super( scriptExecutor, programStageMetadataService ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + protected void initSearchFilter( @Nonnull FhirVersion fhirVersion, @Nonnull RuleInfo ruleInfo, @Nonnull SearchFilter searchFilter ) + { + searchFilter.add( Questionnaire.SP_TITLE, SearchParamType.STRING, "name" ); + } +} diff --git a/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformer.java b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformer.java new file mode 100644 index 00000000..2575b8ee --- /dev/null +++ b/fhir-r4/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformer.java @@ -0,0 +1,158 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStage; +import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirClient; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.DhisToFhirTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.program.AbstractProgramStageMetadataToFhirQuestionnaireTransformer; +import org.dhis2.fhir.adapter.fhir.transform.scripted.AccessibleScriptedDhisMetadata; +import org.dhis2.fhir.adapter.lock.LockManager; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Enumerations; +import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent; +import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Set; + +import static org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType.*; + +/** + * R4 specific version of DHIS2 Program Stage Metadata to FHIR Questionnaire transformer. + * + * @author volsch + */ +@Component +public class R4ProgramStageMetadataToFhirQuestionnaireTransformer extends AbstractProgramStageMetadataToFhirQuestionnaireTransformer +{ + public R4ProgramStageMetadataToFhirQuestionnaireTransformer( @Nonnull ScriptExecutor scriptExecutor, @Nonnull LockManager lockManager, @Nonnull SystemRepository systemRepository, @Nonnull FhirResourceRepository fhirResourceRepository, + @Nonnull FhirDhisAssignmentRepository fhirDhisAssignmentRepository, @Nonnull OrganizationUnitService organizationUnitService ) + { + super( scriptExecutor, lockManager, systemRepository, fhirResourceRepository, fhirDhisAssignmentRepository, organizationUnitService ); + } + + @Nonnull + @Override + public Set getFhirVersions() + { + return FhirVersion.R4_ONLY; + } + + @Override + protected boolean transformInternal( @Nonnull FhirClient fhirClient, @Nonnull DhisToFhirTransformerContext context, @Nonnull RuleInfo ruleInfo, @Nonnull Map scriptVariables, + @Nonnull AccessibleScriptedDhisMetadata input, @Nonnull IBaseResource output ) + { + final ProgramStage dhisProgramStage = (ProgramStage) input.getDhisResource(); + final Questionnaire fhirQuestionnaire = (Questionnaire) output; + + fhirQuestionnaire.setUrl( dhisProgramStage.getId() ); + fhirQuestionnaire.setTitle( dhisProgramStage.getName() ); + fhirQuestionnaire.setStatus( Enumerations.PublicationStatus.ACTIVE ); + fhirQuestionnaire.setDescription( dhisProgramStage.getDescription() ); + fhirQuestionnaire.setItem( null ); + + dhisProgramStage.getDataElements().forEach( dataElement -> { + final QuestionnaireItemType type = convertValueType( dataElement.getElement().getValueType() ); + + if ( type != null ) + { + final QuestionnaireItemComponent itemComponent = fhirQuestionnaire.addItem(); + + itemComponent.setLinkId( dataElement.getElementId() ); + itemComponent.setText( dataElement.getElement().getName() ); + itemComponent.setRequired( dataElement.isCompulsory() ); + itemComponent.setType( type ); + + if ( dataElement.getElement().isOptionSetValue() ) + { + dataElement.getElement().getOptionSet().getOptions().forEach( option -> itemComponent.addAnswerOption().setValue( + new Coding().setCode( option.getCode() ).setDisplay( option.getName() ) ) ); + } + } + } ); + + return true; + } + + @Nullable + protected QuestionnaireItemType convertValueType( @Nonnull ValueType valueType ) + { + switch ( valueType ) + { + case TEXT: + case EMAIL: + case LETTER: + case ORGANISATION_UNIT: + case PHONE_NUMBER: + case TRACKER_ASSOCIATE: + case URL: + case USERNAME: + return STRING; + case LONG_TEXT: + return TEXT; + case INTEGER: + case INTEGER_POSITIVE: + case INTEGER_NEGATIVE: + case INTEGER_ZERO_OR_POSITIVE: + return INTEGER; + case NUMBER: + case PERCENTAGE: + case UNIT_INTERVAL: + return DECIMAL; + case DATETIME: + case AGE: + return DATETIME; + case DATE: + return DATE; + case TIME: + return TIME; + case BOOLEAN: + case TRUE_ONLY: + return BOOLEAN; + } + + // unhandled data type + return null; + } +} diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProviderTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProviderTest.java index 4798edd1..6ed3a090 100644 --- a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProviderTest.java +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirDataProviderTest.java @@ -79,7 +79,7 @@ public void getFhirVersions() @Test public void searchFilterName() throws URISyntaxException { - final SearchFilterCollector searchFilterCollector = new SearchFilterCollector( Collections.singletonMap( "name", Collections.singletonList( "Child Programme" ) ) ); + final SearchFilterCollector searchFilterCollector = new SearchFilterCollector( Collections.singletonMap( "title", Collections.singletonList( "Child Programme" ) ) ); final SearchFilter searchFilter = new SearchFilter( searchFilterCollector, false ); provider.initSearchFilter( FhirVersion.R4, new RuleInfo<>( new ProgramMetadataRule(), Collections.emptyList() ), searchFilter ); diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformerTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformerTest.java index 3d14b07b..adccd703 100644 --- a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformerTest.java +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramMetadataToFhirPlanDefinitionTransformerTest.java @@ -152,7 +152,7 @@ public void transformInternal() transformer.transformInternal( fhirClient, context, new RuleInfo<>( new ProgramMetadataRule(), Collections.emptyList() ), new HashMap<>(), new WritableScriptedDhisMetadata( program, scriptExecutionContext ), fhirPlanDefinition ); - Assert.assertEquals( "Test Program", fhirPlanDefinition.getName() ); + Assert.assertEquals( "Test Program", fhirPlanDefinition.getTitle() ); Assert.assertEquals( "Test Description", fhirPlanDefinition.getDescription() ); Assert.assertEquals( 2, fhirPlanDefinition.getAction().size() ); diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProviderTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProviderTest.java new file mode 100644 index 00000000..8b2c37f7 --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirDataProviderTest.java @@ -0,0 +1,93 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.search.SearchFilter; +import org.dhis2.fhir.adapter.fhir.transform.dhis.search.SearchFilterCollector; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.web.util.DefaultUriBuilderFactory; +import org.springframework.web.util.UriBuilder; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Unit tests for {@link R4ProgramStageMetadataToFhirDataProvider}. + * + * @author volsch + */ +public class R4ProgramStageMetadataToFhirDataProviderTest +{ + @Mock + private ScriptExecutor scriptExecutor; + + @Mock + private ProgramStageMetadataService programStageMetadataService; + + @InjectMocks + private R4ProgramStageMetadataToFhirDataProvider provider; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void getFhirVersions() + { + Assert.assertEquals( FhirVersion.R4_ONLY, provider.getFhirVersions() ); + } + + @Test + public void searchFilterName() throws URISyntaxException + { + final SearchFilterCollector searchFilterCollector = new SearchFilterCollector( Collections.singletonMap( "title", Collections.singletonList( "Birth" ) ) ); + final SearchFilter searchFilter = new SearchFilter( searchFilterCollector, false ); + + provider.initSearchFilter( FhirVersion.R4, new RuleInfo<>( new ProgramStageMetadataRule(), Collections.emptyList() ), searchFilter ); + + final List variables = new ArrayList<>(); + UriBuilder uriBuilder = new DefaultUriBuilderFactory().builder(); + uriBuilder = searchFilterCollector.add( uriBuilder, variables ); + + Assert.assertEquals( new URI( "?filter=%5Bname:$ilike:Birth%5D" ), uriBuilder.build( variables ) ); + } +} diff --git a/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformerTest.java b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformerTest.java new file mode 100644 index 00000000..3cf0b25c --- /dev/null +++ b/fhir-r4/src/test/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/r4/R4ProgramStageMetadataToFhirQuestionnaireTransformerTest.java @@ -0,0 +1,170 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.r4; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.WritableDataElement; +import org.dhis2.fhir.adapter.dhis.model.WritableOption; +import org.dhis2.fhir.adapter.dhis.model.WritableOptionSet; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.dhis.tracker.program.WritableProgramStage; +import org.dhis2.fhir.adapter.dhis.tracker.program.WritableProgramStageDataElement; +import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirClient; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.metadata.model.RuleInfo; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemRepository; +import org.dhis2.fhir.adapter.fhir.model.FhirVersion; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.DhisToFhirTransformerContext; +import org.dhis2.fhir.adapter.fhir.transform.scripted.WritableScriptedDhisMetadata; +import org.dhis2.fhir.adapter.lock.LockManager; +import org.dhis2.fhir.adapter.model.ValueType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Questionnaire; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; + +/** + * Unit tests for {@link R4ProgramStageMetadataToFhirQuestionnaireTransformer}. + * + * @author volsch + */ +public class R4ProgramStageMetadataToFhirQuestionnaireTransformerTest +{ + @Mock + private ScriptExecutor scriptExecutor; + + @Mock + private LockManager lockManager; + + @Mock + private SystemRepository systemRepository; + + @Mock + private FhirResourceRepository fhirResourceRepository; + + @Mock + private FhirDhisAssignmentRepository fhirDhisAssignmentRepository; + + @Mock + private OrganizationUnitService organizationUnitService; + + @Mock + private DhisToFhirTransformerContext context; + + @Mock + private FhirClient fhirClient; + + @Mock + private ScriptExecutionContext scriptExecutionContext; + + @InjectMocks + private R4ProgramStageMetadataToFhirQuestionnaireTransformer transformer; + + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + @Test + public void getFhirVersions() + { + Assert.assertEquals( FhirVersion.R4_ONLY, transformer.getFhirVersions() ); + } + + @Test + public void transformInternal() + { + final WritableProgramStage programStage = new WritableProgramStage(); + programStage.setId( "b1234567890" ); + programStage.setName( "Test Stage 1" ); + programStage.setDescription( "Test Description 1" ); + programStage.setRepeatable( false ); + programStage.setDataElements( new ArrayList<>() ); + + WritableProgramStageDataElement programStageDataElement = new WritableProgramStageDataElement(); + WritableDataElement dataElement = new WritableDataElement(); + dataElement.setId( "d0123456789" ); + dataElement.setName( "Value 1" ); + dataElement.setValueType( ValueType.TEXT ); + programStageDataElement.setCompulsory( false ); + programStageDataElement.setElement( dataElement ); + programStage.getDataElements().add( programStageDataElement ); + + WritableOptionSet optionSet = new WritableOptionSet(); + optionSet.setOptions( new ArrayList<>() ); + optionSet.getOptions().add( new WritableOption( "5", "Test Value 1" ) ); + optionSet.getOptions().add( new WritableOption( "7", "Test Value 2" ) ); + + programStageDataElement = new WritableProgramStageDataElement(); + dataElement = new WritableDataElement(); + dataElement.setId( "d1123456789" ); + dataElement.setName( "Value 2" ); + dataElement.setValueType( ValueType.INTEGER ); + dataElement.setOptionSetValue( true ); + dataElement.setOptionSet( optionSet ); + programStageDataElement.setCompulsory( true ); + programStageDataElement.setElement( dataElement ); + programStage.getDataElements().add( programStageDataElement ); + + final Questionnaire fhirQuestionnaire = new Questionnaire(); + + transformer.transformInternal( fhirClient, context, new RuleInfo<>( new ProgramStageMetadataRule(), Collections.emptyList() ), new HashMap<>(), + new WritableScriptedDhisMetadata( programStage, scriptExecutionContext ), fhirQuestionnaire ); + + Assert.assertEquals( "b1234567890", fhirQuestionnaire.getUrl() ); + Assert.assertEquals( "Test Stage 1", fhirQuestionnaire.getTitle() ); + Assert.assertEquals( "Test Description 1", fhirQuestionnaire.getDescription() ); + Assert.assertEquals( 2, fhirQuestionnaire.getItem().size() ); + + Assert.assertEquals( "d0123456789", fhirQuestionnaire.getItem().get( 0 ).getLinkId() ); + Assert.assertEquals( "Value 1", fhirQuestionnaire.getItem().get( 0 ).getText() ); + Assert.assertEquals( 0, fhirQuestionnaire.getItem().get( 0 ).getAnswerOption().size() ); + Assert.assertFalse( fhirQuestionnaire.getItem().get( 0 ).getRequired() ); + + Assert.assertEquals( "d1123456789", fhirQuestionnaire.getItem().get( 1 ).getLinkId() ); + Assert.assertEquals( "Value 2", fhirQuestionnaire.getItem().get( 1 ).getText() ); + Assert.assertEquals( 2, fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().size() ); + Assert.assertTrue( fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().get( 0 ).getValue() instanceof Coding ); + Assert.assertEquals( "5", ( (Coding) fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().get( 0 ).getValue() ).getCode() ); + Assert.assertEquals( "Test Value 1", ( (Coding) fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().get( 0 ).getValue() ).getDisplay() ); + Assert.assertEquals( "7", ( (Coding) fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().get( 1 ).getValue() ).getCode() ); + Assert.assertEquals( "Test Value 2", ( (Coding) fhirQuestionnaire.getItem().get( 1 ).getAnswerOption().get( 1 ).getValue() ).getDisplay() ); + Assert.assertTrue( fhirQuestionnaire.getItem().get( 1 ).getRequired() ); + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirDataProvider.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirDataProvider.java new file mode 100644 index 00000000..05062a36 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirDataProvider.java @@ -0,0 +1,66 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.program; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStage; +import org.dhis2.fhir.adapter.dhis.tracker.program.ProgramStageMetadataService; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.DhisToFhirDataProvider; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.AbstractDhisMetadataToFhirDataProvider; + +import javax.annotation.Nonnull; + +/** + * Abstract implementation of {@link DhisToFhirDataProvider} for DHIS2 Program Stage Metadata. + * + * @author volsch + */ +public abstract class AbstractProgramStageMetadataToFhirDataProvider extends AbstractDhisMetadataToFhirDataProvider +{ + public AbstractProgramStageMetadataToFhirDataProvider( @Nonnull ScriptExecutor scriptExecutor, @Nonnull ProgramStageMetadataService programStageMetadataService ) + { + super( scriptExecutor, programStageMetadataService ); + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.PROGRAM_STAGE_METADATA; + } + + @Nonnull + @Override + protected Class getRuleClass() + { + return ProgramStageMetadataRule.class; + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirQuestionnaireTransformer.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirQuestionnaireTransformer.java new file mode 100644 index 00000000..0bc8ba45 --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/AbstractProgramStageMetadataToFhirQuestionnaireTransformer.java @@ -0,0 +1,93 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.program; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.dhis.orgunit.OrganizationUnitService; +import org.dhis2.fhir.adapter.fhir.data.repository.FhirDhisAssignmentRepository; +import org.dhis2.fhir.adapter.fhir.metadata.model.FhirResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.model.ProgramStageMetadataRule; +import org.dhis2.fhir.adapter.fhir.metadata.repository.SystemRepository; +import org.dhis2.fhir.adapter.fhir.repository.FhirResourceRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutor; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.DhisToFhirTransformer; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.AbstractReadOnlyDhisMetadataToTypedFhirTransformer; +import org.dhis2.fhir.adapter.fhir.transform.scripted.AccessibleScriptedDhisMetadata; +import org.dhis2.fhir.adapter.lock.LockManager; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; + +/** + * Implementation of {@link DhisToFhirTransformer} for transforming DHIS2 + * program stage metadata to FHIR Questionnaire. + * + * @param the concrete type of the FHIR resource into which the DHIS2 resource should be transformed. + * @author volsch + */ +public abstract class AbstractProgramStageMetadataToFhirQuestionnaireTransformer extends AbstractReadOnlyDhisMetadataToTypedFhirTransformer +{ + private final Logger logger = LoggerFactory.getLogger( getClass() ); + + public AbstractProgramStageMetadataToFhirQuestionnaireTransformer( @Nonnull ScriptExecutor scriptExecutor, @Nonnull LockManager lockManager, @Nonnull SystemRepository systemRepository, @Nonnull FhirResourceRepository fhirResourceRepository, + @Nonnull FhirDhisAssignmentRepository fhirDhisAssignmentRepository, @Nonnull OrganizationUnitService organizationUnitService ) + { + super( scriptExecutor, lockManager, systemRepository, fhirResourceRepository, fhirDhisAssignmentRepository ); + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.PROGRAM_STAGE_METADATA; + } + + @Nonnull + @Override + protected FhirResourceType getFhirResourceType() + { + return FhirResourceType.QUESTIONNAIRE; + } + + @Nonnull + @Override + public Class getDhisResourceClass() + { + return AccessibleScriptedDhisMetadata.class; + } + + @Nonnull + @Override + public Class getRuleClass() + { + return ProgramStageMetadataRule.class; + } +} diff --git a/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/ProgramStageMetadataToFhirRequestResolver.java b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/ProgramStageMetadataToFhirRequestResolver.java new file mode 100644 index 00000000..4186ebae --- /dev/null +++ b/fhir/src/main/java/org/dhis2/fhir/adapter/fhir/transform/dhis/impl/metadata/program/ProgramStageMetadataToFhirRequestResolver.java @@ -0,0 +1,76 @@ +package org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.program; + +/* + * Copyright (c) 2004-2019, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import org.dhis2.fhir.adapter.dhis.model.DhisMetadata; +import org.dhis2.fhir.adapter.dhis.model.DhisResource; +import org.dhis2.fhir.adapter.dhis.model.DhisResourceType; +import org.dhis2.fhir.adapter.fhir.metadata.repository.FhirClientRepository; +import org.dhis2.fhir.adapter.fhir.metadata.repository.RuleRepository; +import org.dhis2.fhir.adapter.fhir.script.ScriptExecutionContext; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.DhisToFhirRequestResolver; +import org.dhis2.fhir.adapter.fhir.transform.dhis.impl.metadata.AbstractDhisMetadataToFhirRequestResolver; +import org.dhis2.fhir.adapter.fhir.transform.dhis.model.DhisRequest; +import org.dhis2.fhir.adapter.fhir.transform.scripted.ImmutableScriptedDhisMetadata; +import org.dhis2.fhir.adapter.fhir.transform.scripted.ScriptedDhisResource; +import org.dhis2.fhir.adapter.fhir.transform.scripted.WritableScriptedDhisMetadata; +import org.springframework.stereotype.Component; + +import javax.annotation.Nonnull; + +/** + * Implementation of {@link DhisToFhirRequestResolver} for DHIS2 program stage metadata. + * + * @author volsch + */ +@Component +public class ProgramStageMetadataToFhirRequestResolver extends AbstractDhisMetadataToFhirRequestResolver +{ + private final ScriptExecutionContext scriptExecutionContext; + + public ProgramStageMetadataToFhirRequestResolver( @Nonnull FhirClientRepository fhirClientRepository, @Nonnull RuleRepository ruleRepository, @Nonnull ScriptExecutionContext scriptExecutionContext ) + { + super( fhirClientRepository, ruleRepository ); + this.scriptExecutionContext = scriptExecutionContext; + } + + @Nonnull + @Override + public DhisResourceType getDhisResourceType() + { + return DhisResourceType.PROGRAM_STAGE_METADATA; + } + + @Nonnull + @Override + public ScriptedDhisResource convert( @Nonnull DhisResource dhisResource, @Nonnull DhisRequest dhisRequest ) + { + return new ImmutableScriptedDhisMetadata( new WritableScriptedDhisMetadata( (DhisMetadata) dhisResource, scriptExecutionContext ) ); + } +} diff --git a/fhir/src/main/resources/db/migration/sample/V1.1.0.41_10_0__Plan_Definition_Sample_Data.sql b/fhir/src/main/resources/db/migration/sample/V1.1.0.41_10_0__Plan_Definition_Sample_Data.sql index e21ec8fd..e3918522 100644 --- a/fhir/src/main/resources/db/migration/sample/V1.1.0.41_10_0__Plan_Definition_Sample_Data.sql +++ b/fhir/src/main/resources/db/migration/sample/V1.1.0.41_10_0__Plan_Definition_Sample_Data.sql @@ -34,5 +34,7 @@ WHERE id='73cd99c5-0ca8-42ad-a53b-1891fccce08f'; -- virtual subscription for FHIR organizations INSERT INTO fhir_client_resource (id, version, fhir_client_id, fhir_resource_type, exp_only, fhir_criteria_parameters, description) VALUES ('2520acc5-86b4-4716-ae0f-ea0531eb885a', 0, '73cd99c5-0ca8-42ad-a53b-1891fccce08f', 'PLAN_DEFINITION', TRUE, NULL, 'Virtual subscription for all Plan Definitions.'); +INSERT INTO fhir_client_resource (id, version, fhir_client_id, fhir_resource_type, exp_only, fhir_criteria_parameters, description) +VALUES ('0918c4f3-995c-4130-b607-b28023a1a3a0', 0, '73cd99c5-0ca8-42ad-a53b-1891fccce08f', 'QUESTIONNAIRE', TRUE, NULL, 'Virtual subscription for all Questionnaires.'); INSERT INTO fhir_client_resource_update(id) VALUES ('2520acc5-86b4-4716-ae0f-ea0531eb885a');