From 44fc4b65e038cd583caa8ef1a903761036f24dc6 Mon Sep 17 00:00:00 2001 From: andresmr Date: Wed, 18 Dec 2024 10:06:16 +0100 Subject: [PATCH] fix: [ANDROAPP-6535] refactor use case Signed-off-by: andresmr --- .../SearchRepositoryImpl.java | 1 - .../RelationshipPresenterTest.kt | 20 +- .../data/EventRelationshipsRepository.kt | 129 +++++------ .../data/RelationshipsRepository.kt | 10 +- .../data/TrackerRelationshipsRepository.kt | 116 +++++----- .../domain/GetRelationshipsByType.kt | 9 +- .../relationships/model/RelationshipModel.kt | 2 - ...tionshipType.kt => RelationshipSection.kt} | 2 +- .../ui/mapper/RelationshipsUiStateMapper.kt | 4 +- .../relationships/RelationshipFakeModels.kt | 75 +++++++ .../TrackerRelationshipsRepositoryTest.kt | 134 +++++++----- .../domain/AddRelationshipTest.kt | 14 +- .../domain/GetRelationshipsByTypeTest.kt | 201 +++--------------- 13 files changed, 357 insertions(+), 360 deletions(-) rename tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/{RelationshipType.kt => RelationshipSection.kt} (86%) create mode 100644 tracker/src/test/kotlin/org/dhis2/tracker/relationships/RelationshipFakeModels.kt diff --git a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchRepositoryImpl.java b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchRepositoryImpl.java index bebd188c08..bd8763a0d3 100644 --- a/app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchRepositoryImpl.java +++ b/app/src/main/java/org/dhis2/usescases/searchTrackEntity/SearchRepositoryImpl.java @@ -451,7 +451,6 @@ private void setRelationshipsInfo(@NonNull SearchTeiModel searchTeiModel, Progra relationship, fromTei.geometry(), toTei.geometry(), - relationshipType, direction, relationshipTEIUid, RelationshipOwnerType.TEI, diff --git a/app/src/test/java/org/dhis2/usescases/teiDashboard/dashboardfragments/relationships/RelationshipPresenterTest.kt b/app/src/test/java/org/dhis2/usescases/teiDashboard/dashboardfragments/relationships/RelationshipPresenterTest.kt index c725f7ca2f..970ac07030 100644 --- a/app/src/test/java/org/dhis2/usescases/teiDashboard/dashboardfragments/relationships/RelationshipPresenterTest.kt +++ b/app/src/test/java/org/dhis2/usescases/teiDashboard/dashboardfragments/relationships/RelationshipPresenterTest.kt @@ -40,10 +40,6 @@ class RelationshipPresenterTest { private val relationshipMapsRepository: RelationshipMapsRepository = mock() private val analyticsHelper: AnalyticsHelper = mock() private val mapRelationshipsToFeatureCollection: MapRelationshipsToFeatureCollection = mock() - private val relationshipConstrain: RelationshipConstraint = mock() - private val relationshipType: RelationshipType = mock { - on { fromConstraint() } doReturn relationshipConstrain - } private val mapStyleConfiguration: MapStyleConfiguration = mock() private val relationshipsRepository: RelationshipsRepository = mock() private val avatarProvider: AvatarProvider = mock() @@ -82,23 +78,27 @@ class RelationshipPresenterTest { @Test fun `If user has permission should create a new relationship`() { + val relationshipTypeUid = "relationshipTypeUid" + val teiTypeToAdd = "teiTypeToAdd" + whenever( - d2.relationshipModule().relationshipService().hasAccessPermission(relationshipType), + relationshipsRepository.hasWritePermission(relationshipTypeUid), ) doReturn true - presenter.goToAddRelationship("teiType", relationshipType) + presenter.goToAddRelationship(relationshipTypeUid, teiTypeToAdd) - verify(view, times(1)).goToAddRelationship("teiUid", "teiType") + verify(view, times(1)).goToAddRelationship("teiUid", teiTypeToAdd) verify(view, times(0)).showPermissionError() } @Test fun `If user don't have permission should show an error`() { + val relationshipTypeUid = "relationshipTypeUid" whenever( - d2.relationshipModule().relationshipService().hasAccessPermission(relationshipType), + relationshipsRepository.hasWritePermission(relationshipTypeUid), ) doReturn false - presenter.goToAddRelationship("teiType", relationshipType) + presenter.goToAddRelationship(relationshipTypeUid, "teiTypeToAdd") verify(view, times(1)).showPermissionError() } @@ -193,7 +193,7 @@ class RelationshipPresenterTest { private fun getMockedTei(state: State): TrackedEntityInstance { return TrackedEntityInstance.builder() .uid("teiUid") - .state(state) + .aggregatedSyncState(state) .build() } diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/EventRelationshipsRepository.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/EventRelationshipsRepository.kt index b5e3ebcbf5..2e66cb95c4 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/EventRelationshipsRepository.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/EventRelationshipsRepository.kt @@ -8,6 +8,7 @@ import org.dhis2.tracker.relationships.model.RelationshipConstraintSide import org.dhis2.tracker.relationships.model.RelationshipDirection import org.dhis2.tracker.relationships.model.RelationshipModel import org.dhis2.tracker.relationships.model.RelationshipOwnerType +import org.dhis2.tracker.relationships.model.RelationshipSection import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.State import org.hisp.dhis.android.core.event.Event @@ -26,75 +27,66 @@ class EventRelationshipsRepository( private val profilePictureProvider: ProfilePictureProvider, ) : RelationshipsRepository(d2, resources) { - override suspend fun getRelationshipTypes(): List { + override suspend fun getRelationshipTypes(): List { val event = d2.eventModule().events().uid(eventUid).blockingGet() val programStageUid = event?.programStage() ?: "" - val relationshipWithEntitySide = d2.relationshipModule().relationshipService() + return d2.relationshipModule().relationshipService() .getRelationshipTypesForEvents( programStageUid = programStageUid, - ) + ).map { relationshipWithEntitySide -> + RelationshipSection( + uid = relationshipWithEntitySide.relationshipType.uid(), + title = getRelationshipTitle( + relationshipWithEntitySide.relationshipType, + relationshipWithEntitySide.entitySide, + ), + relationships = emptyList(), + side = when (relationshipWithEntitySide.entitySide) { + RelationshipConstraintType.TO -> RelationshipConstraintSide.TO + RelationshipConstraintType.FROM -> RelationshipConstraintSide.FROM + }, + entityToAdd = when (relationshipWithEntitySide.entitySide) { + RelationshipConstraintType.FROM -> + relationshipWithEntitySide.relationshipType.toConstraint() + ?.trackedEntityType()?.uid() - val relationships = d2.relationshipModule().relationships().getByItem( - RelationshipItem.builder().event( - RelationshipItemEvent.builder().event(eventUid).build(), - ).build(), - ) - - return relationshipWithEntitySide.map { - val filteredRelationships = relationships.filter { relationship -> - val sameSide = when (it.entitySide) { - RelationshipConstraintType.FROM -> { - relationship.from()?.event()?.event() == eventUid + RelationshipConstraintType.TO -> + relationshipWithEntitySide.relationshipType.fromConstraint() + ?.trackedEntityType()?.uid() } + ) + } + } - RelationshipConstraintType.TO -> { - relationship.to()?.event()?.event() == eventUid - } - } - relationship.relationshipType() == it.relationshipType.uid() && sameSide + override suspend fun getRelationshipsGroupedByTypeAndSide(relationshipSection: RelationshipSection): RelationshipSection { + val constraintType = when (relationshipSection.side) { + RelationshipConstraintSide.FROM -> RelationshipConstraintType.FROM + RelationshipConstraintSide.TO -> RelationshipConstraintType.TO + } + val relationshipType = d2.relationshipModule().relationshipTypes() + .withConstraints() + .uid(relationshipSection.uid) + .blockingGet() + + val relationships = d2.relationshipModule().relationships() + .getByItem( + RelationshipItem.builder() + .event( + RelationshipItemEvent.builder().event(eventUid).build(), + ).relationshipItemType(constraintType) + .build(), + ).filter { + it.relationshipType() == relationshipSection.uid }.mapNotNull { relationship -> mapToRelationshipModel( relationship = relationship, - relationshipType = it.relationshipType, + relationshipType = relationshipType, eventUid = eventUid, ) } - org.dhis2.tracker.relationships.model.RelationshipType( - uid = it.relationshipType.uid(), - title = getRelationshipTitle( - it.relationshipType, - it.entitySide, - ), - relationships = filteredRelationships, - side = when (it.entitySide) { - RelationshipConstraintType.TO -> RelationshipConstraintSide.TO - RelationshipConstraintType.FROM -> RelationshipConstraintSide.FROM - }, - entityToAdd = when (it.entitySide) { - RelationshipConstraintType.FROM -> - it.relationshipType.toConstraint()?.trackedEntityType()?.uid() - RelationshipConstraintType.TO -> - it.relationshipType.fromConstraint()?.trackedEntityType()?.uid() - } - ) - - } - - - } - - override fun createRelationship( - selectedTeiUid: String, - relationshipTypeUid: String, - relationshipSide: RelationshipConstraintSide, - ): Relationship { - val (fromUid, toUid) = when (relationshipSide) { - RelationshipConstraintSide.FROM -> Pair(eventUid, selectedTeiUid) - RelationshipConstraintSide.TO -> Pair(selectedTeiUid, eventUid) - } - return RelationshipHelper.eventToTeiRelationship( - fromUid, toUid, relationshipTypeUid + return relationshipSection.copy( + relationships = relationships ) } @@ -118,9 +110,23 @@ class EventRelationshipsRepository( ) } + override fun createRelationship( + selectedTeiUid: String, + relationshipTypeUid: String, + relationshipSide: RelationshipConstraintSide, + ): Relationship { + val (fromUid, toUid) = when (relationshipSide) { + RelationshipConstraintSide.FROM -> Pair(eventUid, selectedTeiUid) + RelationshipConstraintSide.TO -> Pair(selectedTeiUid, eventUid) + } + return RelationshipHelper.eventToTeiRelationship( + fromUid, toUid, relationshipTypeUid + ) + } + private fun mapToRelationshipModel( relationship: Relationship, - relationshipType: RelationshipType, + relationshipType: RelationshipType?, eventUid: String, ): RelationshipModel? { val relationshipOwnerUid: String? @@ -187,7 +193,6 @@ class EventRelationshipsRepository( relationship, fromGeometry, toGeometry, - relationshipType, direction, relationshipOwnerUid, RelationshipOwnerType.TEI, @@ -299,18 +304,18 @@ class EventRelationshipsRepository( private fun getValues( direction: RelationshipDirection, relationshipOwnerUid: String?, - relationshipType: RelationshipType, + relationshipType: RelationshipType?, relationship: Relationship ) = if (direction == RelationshipDirection.FROM) { Pair( getTeiAttributesForRelationship( relationshipOwnerUid, - relationshipType.fromConstraint(), + relationshipType?.fromConstraint(), relationship.created(), ), getEventValuesForRelationship( eventUid, - relationshipType.toConstraint(), + relationshipType?.toConstraint(), relationship.created(), ), ) @@ -318,12 +323,12 @@ class EventRelationshipsRepository( Pair( getEventValuesForRelationship( eventUid, - relationshipType.fromConstraint(), + relationshipType?.fromConstraint(), relationship.created(), ), getTeiAttributesForRelationship( relationshipOwnerUid, - relationshipType.toConstraint(), + relationshipType?.toConstraint(), relationship.created(), ), ) diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/RelationshipsRepository.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/RelationshipsRepository.kt index 2397a0f5f6..77c4062769 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/RelationshipsRepository.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/RelationshipsRepository.kt @@ -8,7 +8,7 @@ import org.dhis2.tracker.R import org.dhis2.tracker.relationships.model.RelationshipConstraintSide import org.dhis2.tracker.relationships.model.RelationshipModel import org.dhis2.tracker.relationships.model.RelationshipOwnerType -import org.dhis2.tracker.relationships.model.RelationshipType +import org.dhis2.tracker.relationships.model.RelationshipSection import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.ObjectStyle import org.hisp.dhis.android.core.event.Event @@ -19,6 +19,7 @@ import org.hisp.dhis.android.core.program.ProgramType import org.hisp.dhis.android.core.relationship.Relationship import org.hisp.dhis.android.core.relationship.RelationshipConstraint import org.hisp.dhis.android.core.relationship.RelationshipConstraintType +import org.hisp.dhis.android.core.relationship.RelationshipType import org.hisp.dhis.android.core.systeminfo.DHISVersion import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstance import java.util.Date @@ -30,7 +31,10 @@ abstract class RelationshipsRepository( private val d2: D2, private val resources: ResourceManager, ) { - abstract suspend fun getRelationshipTypes(): List + abstract suspend fun getRelationshipTypes(): List + + abstract suspend fun getRelationshipsGroupedByTypeAndSide(relationshipSection: RelationshipSection): RelationshipSection + abstract fun getRelationships(): Flow> abstract fun createRelationship( @@ -259,7 +263,7 @@ abstract class RelationshipsRepository( .blockingGet() protected fun getRelationshipTitle( - relationshipType: org.hisp.dhis.android.core.relationship.RelationshipType, + relationshipType: RelationshipType, entitySide: RelationshipConstraintType ): String { return when (entitySide) { diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepository.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepository.kt index 6ccd953dc9..6f1fb596aa 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepository.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepository.kt @@ -8,6 +8,7 @@ import org.dhis2.tracker.relationships.model.RelationshipConstraintSide import org.dhis2.tracker.relationships.model.RelationshipDirection import org.dhis2.tracker.relationships.model.RelationshipModel import org.dhis2.tracker.relationships.model.RelationshipOwnerType +import org.dhis2.tracker.relationships.model.RelationshipSection import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.Geometry import org.hisp.dhis.android.core.common.State @@ -28,66 +29,78 @@ class TrackerRelationshipsRepository( private val profilePictureProvider: ProfilePictureProvider, ) : RelationshipsRepository(d2, resources) { - override suspend fun getRelationshipTypes(): List { + override suspend fun getRelationshipTypes(): List { val tei = d2.trackedEntityModule().trackedEntityInstances() - .uid(teiUid).blockingGet() + .uid(teiUid).blockingGet() ?: return emptyList() val programUid = d2.enrollmentModule().enrollments() .uid(enrollmentUid).blockingGet()?.program() - val relationshipsWithEntitySide = d2.relationshipModule().relationshipService() + return d2.relationshipModule().relationshipService( ) .getRelationshipTypesForTrackedEntities( - trackedEntityType = tei!!.trackedEntityType()!!, + trackedEntityType = tei.trackedEntityType()!!, programUid = programUid, - ) - - val relationships = d2.relationshipModule().relationships().getByItem( - RelationshipItem.builder().trackedEntityInstance( - RelationshipItemTrackedEntityInstance.builder().trackedEntityInstance(teiUid) - .build(), - ).build(), - ) + ).map { relationshipWithEntitySide -> + RelationshipSection( + uid = relationshipWithEntitySide.relationshipType.uid(), + title = getRelationshipTitle( + relationshipWithEntitySide.relationshipType, + relationshipWithEntitySide.entitySide, + ), + relationships = emptyList(), + side = when (relationshipWithEntitySide.entitySide) { + RelationshipConstraintType.FROM -> RelationshipConstraintSide.FROM + RelationshipConstraintType.TO -> RelationshipConstraintSide.TO + }, + entityToAdd = when (relationshipWithEntitySide.entitySide) { + RelationshipConstraintType.FROM -> + relationshipWithEntitySide.relationshipType.toConstraint() + ?.trackedEntityType()?.uid() - return relationshipsWithEntitySide.map { - val filteredRelationships = relationships.filter { relationship -> - val sameSide = when (it.entitySide) { - RelationshipConstraintType.FROM -> { - relationship.from()?.trackedEntityInstance() - ?.trackedEntityInstance() == teiUid + RelationshipConstraintType.TO -> + relationshipWithEntitySide.relationshipType.fromConstraint() + ?.trackedEntityType()?.uid() } + ) + } + } - RelationshipConstraintType.TO -> { - relationship.to()?.trackedEntityInstance() - ?.trackedEntityInstance() == teiUid - } - } - relationship.relationshipType() == it.relationshipType.uid() && sameSide + override suspend fun getRelationshipsGroupedByTypeAndSide(relationshipSection: RelationshipSection): RelationshipSection { + val tei = d2.trackedEntityModule().trackedEntityInstances() + .uid(teiUid).blockingGet() + val programUid = d2.enrollmentModule().enrollments() + .uid(enrollmentUid).blockingGet()?.program() + val constraintType = when (relationshipSection.side) { + RelationshipConstraintSide.FROM -> RelationshipConstraintType.FROM + RelationshipConstraintSide.TO -> RelationshipConstraintType.TO + } + val relationshipType = d2.relationshipModule().relationshipTypes() + .withConstraints() + .uid(relationshipSection.uid) + .blockingGet() + + val relationships = d2.relationshipModule().relationships() + .getByItem( + RelationshipItem.builder() + .trackedEntityInstance( + RelationshipItemTrackedEntityInstance.builder() + .trackedEntityInstance(teiUid) + .build(), + ).relationshipItemType(constraintType) + .build(), + ) + .filter { + it.relationshipType() == relationshipSection.uid }.mapNotNull { relationship -> mapToRelationshipModel( relationship = relationship, - relationshipType = it.relationshipType, + relationshipType = relationshipType, tei = tei, programUid = programUid, ) } - org.dhis2.tracker.relationships.model.RelationshipType( - uid = it.relationshipType.uid(), - title = getRelationshipTitle( - it.relationshipType, - it.entitySide, - ), - relationships = filteredRelationships, - side = when (it.entitySide) { - RelationshipConstraintType.FROM -> RelationshipConstraintSide.FROM - RelationshipConstraintType.TO -> RelationshipConstraintSide.TO - }, - entityToAdd = when (it.entitySide) { - RelationshipConstraintType.FROM -> - it.relationshipType.toConstraint()?.trackedEntityType()?.uid() - RelationshipConstraintType.TO -> - it.relationshipType.fromConstraint()?.trackedEntityType()?.uid() - } - ) - } + return relationshipSection.copy( + relationships = relationships + ) } override fun getRelationships(): Flow> { @@ -135,7 +148,7 @@ class TrackerRelationshipsRepository( private fun mapToRelationshipModel( relationship: Relationship, - relationshipType: RelationshipType, + relationshipType: RelationshipType?, tei: TrackedEntityInstance?, programUid: String? ): RelationshipModel? { @@ -163,7 +176,7 @@ class TrackerRelationshipsRepository( fromGeometry = tei?.geometry() fromValues = getTeiAttributesForRelationship( teiUid, - relationshipType.fromConstraint(), + relationshipType?.fromConstraint(), relationship.created() ) fromProfilePic = tei?.let { profilePictureProvider(it, programUid) } @@ -180,7 +193,7 @@ class TrackerRelationshipsRepository( toGeometry = toTei?.geometry() toValues = getTeiAttributesForRelationship( toTei?.uid(), - relationshipType.toConstraint(), + relationshipType?.toConstraint(), relationship.created() ) toProfilePic = toTei?.let { profilePictureProvider(it, programUid) } @@ -199,7 +212,7 @@ class TrackerRelationshipsRepository( toGeometry = toEvent?.geometry() toValues = getEventValuesForRelationship( toEvent?.uid(), - relationshipType.toConstraint(), + relationshipType?.toConstraint(), relationship.created(), ) toProfilePic = "" @@ -218,7 +231,7 @@ class TrackerRelationshipsRepository( toGeometry = tei?.geometry() toValues = getTeiAttributesForRelationship( teiUid, - relationshipType.toConstraint(), + relationshipType?.toConstraint(), relationship.created(), ) toProfilePic = tei?.let { profilePictureProvider(it, programUid) } @@ -235,7 +248,7 @@ class TrackerRelationshipsRepository( fromGeometry = fromTei?.geometry() fromValues = getTeiAttributesForRelationship( fromTei?.uid(), - relationshipType.fromConstraint(), + relationshipType?.fromConstraint(), relationship.created(), ) fromProfilePic = fromTei?.let { profilePictureProvider(it, programUid) } @@ -253,7 +266,7 @@ class TrackerRelationshipsRepository( fromGeometry = fromEvent?.geometry() fromValues = getEventValuesForRelationship( fromEvent?.uid(), - relationshipType.fromConstraint(), + relationshipType?.fromConstraint(), relationship.created(), ) fromProfilePic = "" @@ -276,7 +289,6 @@ class TrackerRelationshipsRepository( relationship, fromGeometry, toGeometry, - relationshipType, direction, relationshipOwnerUid, relationshipOwnerType, diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByType.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByType.kt index a6b3f9338a..93da309d95 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByType.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByType.kt @@ -3,13 +3,16 @@ package org.dhis2.tracker.relationships.domain import kotlinx.coroutines.withContext import org.dhis2.commons.viewmodel.DispatcherProvider import org.dhis2.tracker.relationships.data.RelationshipsRepository -import org.dhis2.tracker.relationships.model.RelationshipType +import org.dhis2.tracker.relationships.model.RelationshipSection class GetRelationshipsByType( private val relationshipsRepository: RelationshipsRepository, private val dispatcher: DispatcherProvider, ) { - suspend operator fun invoke(): List = withContext(dispatcher.io()) { - relationshipsRepository.getRelationshipTypes() + suspend operator fun invoke(): List = withContext(dispatcher.io()) { + val relationshipSections = relationshipsRepository.getRelationshipTypes() + relationshipSections.map { relationshipSection -> + relationshipsRepository.getRelationshipsGroupedByTypeAndSide(relationshipSection) + } } } diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipModel.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipModel.kt index 999bda57fd..c82ded10a2 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipModel.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipModel.kt @@ -3,14 +3,12 @@ package org.dhis2.tracker.relationships.model import org.hisp.dhis.android.core.common.Geometry import org.hisp.dhis.android.core.common.ObjectStyle import org.hisp.dhis.android.core.relationship.Relationship -import org.hisp.dhis.android.core.relationship.RelationshipType import java.util.Date data class RelationshipModel( val relationship: Relationship, val fromGeometry: Geometry?, val toGeometry: Geometry?, - val relationshipType: RelationshipType, val direction: RelationshipDirection, val ownerUid: String, val ownerType: RelationshipOwnerType, diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipType.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipSection.kt similarity index 86% rename from tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipType.kt rename to tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipSection.kt index 537066f48c..5194484343 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipType.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/model/RelationshipSection.kt @@ -1,6 +1,6 @@ package org.dhis2.tracker.relationships.model -data class RelationshipType( +data class RelationshipSection( val uid: String, val title: String, val relationships : List, diff --git a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/ui/mapper/RelationshipsUiStateMapper.kt b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/ui/mapper/RelationshipsUiStateMapper.kt index 42092b3a8e..c8974f2d86 100644 --- a/tracker/src/main/kotlin/org/dhis2/tracker/relationships/ui/mapper/RelationshipsUiStateMapper.kt +++ b/tracker/src/main/kotlin/org/dhis2/tracker/relationships/ui/mapper/RelationshipsUiStateMapper.kt @@ -2,7 +2,7 @@ package org.dhis2.tracker.relationships.ui.mapper import org.dhis2.commons.date.DateLabelProvider import org.dhis2.tracker.relationships.model.RelationshipModel -import org.dhis2.tracker.relationships.model.RelationshipType +import org.dhis2.tracker.relationships.model.RelationshipSection import org.dhis2.tracker.relationships.ui.state.RelationshipItemUiState import org.dhis2.tracker.relationships.ui.state.RelationshipSectionUiState import org.dhis2.tracker.ui.AvatarProvider @@ -12,7 +12,7 @@ class RelationshipsUiStateMapper( private val dateLabelProvider: DateLabelProvider, ) { - fun map(relationships: List): List { + fun map(relationships: List): List { return relationships.map { relationshipType -> RelationshipSectionUiState( uid = relationshipType.uid, diff --git a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/RelationshipFakeModels.kt b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/RelationshipFakeModels.kt new file mode 100644 index 0000000000..43d3dafb56 --- /dev/null +++ b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/RelationshipFakeModels.kt @@ -0,0 +1,75 @@ +package org.dhis2.tracker.relationships + +import org.dhis2.tracker.relationships.model.RelationshipConstraintSide +import org.dhis2.tracker.relationships.model.RelationshipDirection +import org.dhis2.tracker.relationships.model.RelationshipModel +import org.dhis2.tracker.relationships.model.RelationshipOwnerType +import org.dhis2.tracker.relationships.model.RelationshipSection +import org.hisp.dhis.android.core.relationship.Relationship +import org.mockito.kotlin.mock +import java.util.Date + +val relationshipSection1 = RelationshipSection( + uid = "uid1", + title = "Relationship title 1", + relationships = emptyList(), + side = RelationshipConstraintSide.FROM, + entityToAdd = null, +) + +val relationshipSection2 = + RelationshipSection( + uid = "uid2", + title = "Relationship title 2", + relationships = emptyList(), + side = RelationshipConstraintSide.FROM, + entityToAdd = null, + ) + + val relationshipModel1 = RelationshipModel( + ownerType = RelationshipOwnerType.TEI, + ownerUid = "OwnerUid1", + canBeOpened = true, + fromValues = listOf( + "MainValue1" to "Value1", + "SecondMainValue1" to "SecondValue1", + ), + toValues = emptyList(), + fromImage = null, + toImage = null, + fromDefaultImageResource = 0, + toDefaultImageResource = 0, + ownerStyle = mock(), + fromLastUpdated = Date(), + toLastUpdated = Date(), + fromDescription = "Description 1", + toDescription = "Description 1", + fromGeometry = null, + toGeometry = null, + direction = RelationshipDirection.FROM, + relationship = Relationship.builder().uid("uid1").build() +) + + val relationshipModel2 = RelationshipModel( + ownerType = RelationshipOwnerType.TEI, + ownerUid = "OwnerUid2", + canBeOpened = true, + fromValues = listOf( + "MainValue2" to "Value2", + "SecondMainValue2" to "SecondValue2", + ), + toValues = emptyList(), + fromImage = null, + toImage = null, + fromDefaultImageResource = 0, + toDefaultImageResource = 0, + ownerStyle = mock(), + fromLastUpdated = Date(), + toLastUpdated = Date(), + fromDescription = "Description 2", + toDescription = "Description 2", + fromGeometry = null, + toGeometry = null, + direction = RelationshipDirection.FROM, + relationship = Relationship.builder().uid("uid2").build() +) \ No newline at end of file diff --git a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepositoryTest.kt b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepositoryTest.kt index 06e6d27b1e..e14dc6d334 100644 --- a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepositoryTest.kt +++ b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/data/TrackerRelationshipsRepositoryTest.kt @@ -1,12 +1,19 @@ package org.dhis2.tracker.relationships.data +import kotlinx.coroutines.test.runTest import org.dhis2.commons.resources.ResourceManager import org.dhis2.tracker.data.ProfilePictureProvider +import org.dhis2.tracker.relationships.relationshipSection1 +import org.dhis2.tracker.relationships.relationshipSection2 import org.hisp.dhis.android.core.D2 import org.hisp.dhis.android.core.common.ObjectWithUid import org.hisp.dhis.android.core.enrollment.Enrollment import org.hisp.dhis.android.core.relationship.RelationshipConstraint +import org.hisp.dhis.android.core.relationship.RelationshipConstraintType import org.hisp.dhis.android.core.relationship.RelationshipType +import org.hisp.dhis.android.core.relationship.RelationshipTypeWithEntitySide +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstance +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.mockito.Mockito @@ -22,78 +29,105 @@ class TrackerRelationshipsRepositoryTest { private val profilePictureProvider: ProfilePictureProvider = mock() private val d2: D2 = mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) + private val trackedEntityInstance: TrackedEntityInstance = mock() private val enrollment: Enrollment = mock() + private val teiUid = "teiUid" + private val enrollmentUid = "enrollmentUid" + private val trackedEntityType = "trackedEntityType" + @Before fun setup() { + whenever( + d2.trackedEntityModule() + .trackedEntityInstances() + .uid(teiUid) + .blockingGet() + ) doReturn trackedEntityInstance + whenever( + trackedEntityInstance.trackedEntityType() + ) doReturn trackedEntityType + whenever( d2.enrollmentModule() .enrollments() - .uid("enrollmentUid") + .uid(enrollmentUid) .blockingGet() ) doReturn enrollment trackerRelationshipsRepository = TrackerRelationshipsRepository( d2 = d2, resources = resources, - teiUid = "teiUid", - enrollmentUid = "enrollmentUid", + teiUid = teiUid, + enrollmentUid = enrollmentUid, profilePictureProvider = profilePictureProvider ) } @Test - fun shouldShowFromToNameRelationshipTitle() { - val relationshipName = "FromRelationship name" - - val program: ObjectWithUid = mock { - on { uid() } doReturn "programUid_1" - } - val fromConstraint: RelationshipConstraint = mock { - on { program() } doReturn program - } - //Given a TEI with relationship type in From constraint and related to a program - val relationshipType: RelationshipType = mock { - on { fromConstraint() } doReturn fromConstraint - on { fromToName() } doReturn relationshipName - } - - //When getting the relationship title + fun shouldGetRelationshipTypes() = runTest { + //Given + //A TEI enrolled in a program whenever(enrollment.program()) doReturn "programUid_1" - val title = trackerRelationshipsRepository.getRelationshipTitle( - relationshipType, - relationshipSide - ) - //Then the title should be the one from the From constraint - assert(title.first == relationshipName) + + //With two relationship types related + whenever( + d2.relationshipModule().relationshipService() + .getRelationshipTypesForTrackedEntities( + trackedEntityType = trackedEntityType, + programUid = "programUid_1" + ) + ) doReturn relationshipWithEntitySideList + + //When getting the relationship types + val relationshipTypes = trackerRelationshipsRepository.getRelationshipTypes() + + + //Then a relationshipSectionList is returned + assertEquals(relationshipTypes, expectedResult) } - @Test - fun shouldShowToFromNameRelationshipTitle() { - val relationshipName = "ToRelationship name" - - val program: ObjectWithUid = mock { - on { uid() } doReturn "programUid_2" - } - val toConstraint: RelationshipConstraint = mock { - on { program() } doReturn program - } - //Given a TEI with relationship type in To constraint and related to a program - val relationshipType: RelationshipType = mock { - on { toConstraint() } doReturn toConstraint - on { toFromName() } doReturn relationshipName - } - - //When getting the relationship title - whenever(enrollment.program()) doReturn "programUid_2" - - val title = trackerRelationshipsRepository.getRelationshipTitle( - relationshipType, - relationshipSide + + + private val relationshipTypeTeiToTei = RelationshipType.builder() + .uid("relationshipTypeUid1") + .fromToName("RelationshipType1 FROM") + .toFromName("RelationshipType1 TO") + .displayName("Tei to Tei relationship") + .fromConstraint( + RelationshipConstraint.builder() + .trackedEntityType( + ObjectWithUid.create(trackedEntityType) + ).build() + ) + .toConstraint( + RelationshipConstraint.builder() + .trackedEntityType( + ObjectWithUid.create("trackedEntityTypeUid2") + ) + .build() ) + .build() + + private val relationshipWithEntitySideList = listOf( + RelationshipTypeWithEntitySide( + relationshipType = relationshipTypeTeiToTei, + entitySide = RelationshipConstraintType.FROM + ), + RelationshipTypeWithEntitySide( + relationshipType = RelationshipType.builder() + .uid("relationshipTypeUid2") + .fromToName("RelationshipType2 FROM") + .toFromName("RelationshipType2 TO") + .displayName("relationshipType2") + .build(), + entitySide = RelationshipConstraintType.FROM + ) + ) - //Then the title should be the one from the To constraint - assert(title.first == relationshipName) - } + private val expectedResult = listOf( + relationshipSection1, + relationshipSection2, + ) } \ No newline at end of file diff --git a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/AddRelationshipTest.kt b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/AddRelationshipTest.kt index dc78c6c301..3eb3a3470e 100644 --- a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/AddRelationshipTest.kt +++ b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/AddRelationshipTest.kt @@ -4,7 +4,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.runTest import org.dhis2.commons.viewmodel.DispatcherProvider import org.dhis2.tracker.relationships.data.RelationshipsRepository -import org.dhis2.tracker.relationships.model.RelationshipDirection +import org.dhis2.tracker.relationships.model.RelationshipConstraintSide import org.hisp.dhis.android.core.relationship.Relationship import org.junit.Before import org.junit.Test @@ -34,7 +34,7 @@ class AddRelationshipTest { // Given user tries to add a relationship val selectedTeiUid = "selectedTeiUid" val relationshipTypeUid = "relationshipTypeUid" - val direction = RelationshipDirection.TO + val side = RelationshipConstraintSide.TO val relationship = Relationship.builder() .uid("relationshipUid") @@ -42,13 +42,13 @@ class AddRelationshipTest { // When whenever( - repository.createRelationship(selectedTeiUid, relationshipTypeUid, direction) + repository.createRelationship(selectedTeiUid, relationshipTypeUid, side) ) doReturn relationship whenever( repository.addRelationship(relationship) ) doReturn Result.success("relationshipUid") - val result = addRelationship(selectedTeiUid, relationshipTypeUid, direction) + val result = addRelationship(selectedTeiUid, relationshipTypeUid, side) // Then assert(result.isSuccess) @@ -59,7 +59,7 @@ class AddRelationshipTest { // Given user tries to add a relationship val selectedTeiUid = "selectedTeiUid" val relationshipTypeUid = "relationshipTypeUid" - val direction = RelationshipDirection.TO + val side = RelationshipConstraintSide.TO val relationship = Relationship.builder() .uid("relationshipUid") @@ -67,13 +67,13 @@ class AddRelationshipTest { // When whenever( - repository.createRelationship(selectedTeiUid, relationshipTypeUid, direction) + repository.createRelationship(selectedTeiUid, relationshipTypeUid, side) ) doReturn relationship whenever( repository.addRelationship(relationship) ) doReturn Result.failure(Exception("Failed to add relationship")) - val result = addRelationship(selectedTeiUid, relationshipTypeUid, direction) + val result = addRelationship(selectedTeiUid, relationshipTypeUid, side) // Then there is an error when adding relationship assert(result.isFailure) diff --git a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByTypeTest.kt b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByTypeTest.kt index 022a7bd34b..027800ff77 100644 --- a/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByTypeTest.kt +++ b/tracker/src/test/kotlin/org/dhis2/tracker/relationships/domain/GetRelationshipsByTypeTest.kt @@ -1,210 +1,77 @@ package org.dhis2.tracker.relationships.domain -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.test.runTest -import org.dhis2.commons.date.DateLabelProvider +import org.dhis2.commons.viewmodel.DispatcherProvider import org.dhis2.tracker.relationships.data.RelationshipsRepository -import org.dhis2.tracker.relationships.model.RelationshipDirection -import org.dhis2.tracker.relationships.model.RelationshipModel -import org.dhis2.tracker.relationships.model.RelationshipOwnerType -import org.dhis2.tracker.relationships.ui.state.RelationshipItemUiState -import org.dhis2.tracker.relationships.ui.state.RelationshipSectionUiState -import org.dhis2.tracker.ui.AvatarProvider -import org.dhis2.ui.avatar.AvatarProviderConfiguration -import org.hisp.dhis.android.core.relationship.Relationship -import org.hisp.dhis.android.core.relationship.RelationshipType +import org.dhis2.tracker.relationships.model.RelationshipSection +import org.dhis2.tracker.relationships.relationshipModel1 +import org.dhis2.tracker.relationships.relationshipModel2 +import org.dhis2.tracker.relationships.relationshipSection1 +import org.dhis2.tracker.relationships.relationshipSection2 import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock -import org.mockito.kotlin.times -import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -import java.util.Date class GetRelationshipsByTypeTest { private lateinit var getRelationshipsByType: GetRelationshipsByType private val relationshipsRepository: RelationshipsRepository = mock() - private val dateLabelProvider: DateLabelProvider = mock() - private val avatarProvider: AvatarProvider = mock { - on { getAvatar(any(), any(), any()) } doReturn AvatarProviderConfiguration.MainValueLabel( - firstMainValue = "M" - ) - } - private val relationshipType1: RelationshipType = mock { - on { uid() } doReturn "type1" - on { displayName() } doReturn "Relationship 1" - } - private val relationshipType2: RelationshipType = mock { - on { uid() } doReturn "type2" - on { displayName() } doReturn "Relationship 2" - } - private val relationship1: Relationship = mock { - on { uid() } doReturn "uid1" - } - private val relationship2: Relationship = mock { - on { uid() } doReturn "uid2" + private val dispatcherProvider: DispatcherProvider = mock { + on { io() } doReturn Dispatchers.Unconfined } @Before fun setup() { getRelationshipsByType = GetRelationshipsByType( relationshipsRepository = relationshipsRepository, - dateLabelProvider = dateLabelProvider, - avatarProvider = avatarProvider + dispatcher = dispatcherProvider, ) } @Test fun `invoke should return relationship sections grouped by type`() = runTest { //Given a list of relationship types and relationships - whenever(relationshipsRepository.getRelationshipTypes()) doReturn getRelationshipTypesMock() - whenever(relationshipsRepository.getRelationships()) doReturn getRelationshipsMock() + whenever(relationshipsRepository.getRelationshipTypes()) doReturn getRelationshipSectionsMock() whenever( - relationshipsRepository.getRelationshipTitle( - relationshipType1, - relationshipSide - ) - ) doReturn Pair("Relationship 1", RelationshipDirection.TO) + relationshipsRepository.getRelationshipsGroupedByTypeAndSide(relationshipSection1) + ) doReturn relationshipSection1.copy( + relationships = listOf(relationshipModel1) + ) + whenever( - relationshipsRepository.getRelationshipTitle( - relationshipType2, - relationshipSide - ) - ) doReturn Pair("Relationship 2", RelationshipDirection.TO) - whenever(dateLabelProvider.span(any())) doReturn "5 days ago" + relationshipsRepository.getRelationshipsGroupedByTypeAndSide(relationshipSection2) + ) doReturn relationshipSection2.copy( + relationships = listOf(relationshipModel2) + ) // When calling the use case to get the relationships grouped by type - val result = getRelationshipsByType().first() + val result = getRelationshipsByType() + assertEquals(expectedResult, result) - // Then a list of RelationshipSections should be returned - assertEquals(relationshipSections, result) - - // And verify that the repository and dateLabelProvider were called - verify(relationshipsRepository).getRelationshipTypes() - verify(relationshipsRepository).getRelationships() - verify(dateLabelProvider, times(2)).span(any()) - } + // Then a list of RelationshipSections with their relationships should be returned - private fun getRelationshipTypesMock(): Flow>> { - return flowOf( - listOf( - relationshipType1 to "teiType1", - relationshipType2 to "teiType2" - ) - ) } - private fun getRelationshipsMock(): Flow> { - val relationshipModel1 = RelationshipModel( - relationshipType = relationshipType1, - ownerType = RelationshipOwnerType.TEI, - ownerUid = "OwnerUid1", - canBeOpened = true, - fromValues = listOf( - "MainValue1" to "Value1", - "SecondMainValue1" to "SecondValue1", - ), - toValues = emptyList(), - fromImage = null, - toImage = null, - fromDefaultImageResource = 0, - toDefaultImageResource = 0, - ownerStyle = mock(), - fromLastUpdated = Date(), - toLastUpdated = Date(), - fromDescription = "Description 1", - toDescription = "Description 1", - fromGeometry = null, - toGeometry = null, - direction = RelationshipDirection.FROM, - relationship = relationship1 - ) - - val relationshipModel2 = RelationshipModel( - relationshipType = relationshipType2, - ownerType = RelationshipOwnerType.TEI, - ownerUid = "OwnerUid2", - canBeOpened = true, - fromValues = listOf( - "MainValue2" to "Value2", - "SecondMainValue2" to "SecondValue2", - ), - toValues = emptyList(), - fromImage = null, - toImage = null, - fromDefaultImageResource = 0, - toDefaultImageResource = 0, - ownerStyle = mock(), - fromLastUpdated = Date(), - toLastUpdated = Date(), - fromDescription = "Description 2", - toDescription = "Description 2", - fromGeometry = null, - toGeometry = null, - direction = RelationshipDirection.FROM, - relationship = relationship2 + private val expectedResult = listOf( + relationshipSection1.copy( + relationships = listOf(relationshipModel1), + ), + relationshipSection2.copy( + relationships = listOf(relationshipModel2), ) + ) - - return flowOf( - listOf(relationshipModel1, relationshipModel2) + private fun getRelationshipSectionsMock(): List { + return listOf( + relationshipSection1, + relationshipSection2, ) } - - private val relationshipSections = listOf( - RelationshipSectionUiState( - title = "Relationship 1", - relationships = listOf( - RelationshipItemUiState( - uid = "uid1", - title = "MainValue1: Value1", - description = "Description 1", - attributes = listOf( - "SecondMainValue1" to "SecondValue1" - ), - ownerType = RelationshipOwnerType.TEI, - ownerUid = "OwnerUid1", - avatar = AvatarProviderConfiguration.MainValueLabel( - firstMainValue = "M", - ), - canOpen = true, - lastUpdated = "5 days ago" - ) - ), - creationTEITypeUid = "teiType1", - relationshipType = relationshipType1, - direction = RelationshipDirection.TO - ), - RelationshipSectionUiState( - title = "Relationship 2", - relationships = listOf( - RelationshipItemUiState( - uid = "uid2", - title = "MainValue2: Value2", - description = "Description 2", - attributes = listOf( - "SecondMainValue2" to "SecondValue2" - ), - ownerType = RelationshipOwnerType.TEI, - ownerUid = "OwnerUid2", - avatar = AvatarProviderConfiguration.MainValueLabel( - firstMainValue = "M", - ), - canOpen = true, - lastUpdated = "5 days ago" - ) - ), - creationTEITypeUid = "teiType2", - relationshipType = relationshipType2, - direction = RelationshipDirection.TO - ) - ) } \ No newline at end of file