Skip to content

Commit

Permalink
Merge pull request #3489 from simpledotorg/ANDROAPP-5826-TEI-Enrollme…
Browse files Browse the repository at this point in the history
…nt-Deletion-confirmation-dialog

ANDROAPP-5826-TEI-Enrollment-Deletion-confirmation-dialog
  • Loading branch information
andresmr authored Feb 13, 2024
2 parents 23d412c + b328daf commit dc60ddf
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,13 @@ interface DashboardRepository {

fun saveCatOption(eventUid: String?, catOptionComboUid: String?)

fun deleteTeiIfPossible(): Single<Boolean>
fun checkIfDeleteTeiIsPossible(): Boolean

fun deleteEnrollmentIfPossible(enrollmentUid: String): Single<Boolean>
fun deleteTei(): Single<Boolean>

fun checkIfDeleteEnrollmentIsPossible(enrollmentUid: String): Boolean

fun deleteEnrollment(enrollmentUid: String): Single<Boolean>

fun getNoteCount(): Single<Int>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import io.reactivex.Single
import io.reactivex.functions.Function
import org.dhis2.commons.data.tuples.Pair
import org.dhis2.commons.resources.ResourceManager
import org.dhis2.utils.AuthorityException
import org.dhis2.utils.DateUtils
import org.dhis2.utils.ValueUtils
import org.hisp.dhis.android.core.D2
Expand Down Expand Up @@ -386,58 +385,53 @@ class DashboardRepositoryImpl(
}
}

override fun deleteTeiIfPossible(): Single<Boolean> {
return Single.fromCallable {
val local = d2.trackedEntityModule()
.trackedEntityInstances()
.uid(teiUid)
.blockingGet()
?.state() == State.TO_POST
val hasAuthority = d2.userModule()
.authorities()
.byName().eq("F_TEI_CASCADE_DELETE")
.one().blockingExists()
local || hasAuthority
}.flatMap { canDelete: Boolean ->
if (canDelete) {
return@flatMap d2.trackedEntityModule()
.trackedEntityInstances()
.uid(teiUid)
.delete()
.andThen<Boolean>(Single.fromCallable<Boolean> { true })
} else {
return@flatMap Single.fromCallable<Boolean> { false }
}
}
override fun checkIfDeleteTeiIsPossible(): Boolean {
val local = d2.trackedEntityModule()
.trackedEntityInstances()
.uid(teiUid)
.blockingGet()
?.state() == State.TO_POST
val hasAuthority = d2.userModule()
.authorities()
.byName().eq("F_TEI_CASCADE_DELETE")
.one().blockingExists()

return local || hasAuthority
}

override fun deleteTei(): Single<Boolean> {
return d2.trackedEntityModule()
.trackedEntityInstances()
.uid(teiUid)
.delete()
.andThen(Single.fromCallable { true })
}

override fun deleteEnrollmentIfPossible(enrollmentUid: String): Single<Boolean> {
override fun checkIfDeleteEnrollmentIsPossible(enrollmentUid: String): Boolean {
val local = d2.enrollmentModule()
.enrollments()
.uid(enrollmentUid)
.blockingGet()!!.state() == State.TO_POST
val hasAuthority = d2.userModule()
.authorities()
.byName().eq("F_ENROLLMENT_CASCADE_DELETE")
.one().blockingExists()

return local || hasAuthority
}

override fun deleteEnrollment(enrollmentUid: String): Single<Boolean> {
return Single.fromCallable {
val local = d2.enrollmentModule()
.enrollments()
.uid(enrollmentUid)
.blockingGet()!!.state() == State.TO_POST
val hasAuthority = d2.userModule()
.authorities()
.byName().eq("F_ENROLLMENT_CASCADE_DELETE")
.one().blockingExists()
local || hasAuthority
}.flatMap { canDelete: Boolean ->
if (canDelete) {
return@flatMap Single.fromCallable<Boolean> {
val enrollmentObjectRepository = d2.enrollmentModule()
.enrollments().uid(enrollmentUid)
enrollmentObjectRepository.setStatus(
enrollmentObjectRepository.blockingGet()!!.status()!!,
)
enrollmentObjectRepository.blockingDelete()
d2.enrollmentModule().enrollments().byTrackedEntityInstance().eq(teiUid)
.byDeleted().isFalse
.byStatus().eq(EnrollmentStatus.ACTIVE).blockingGet().isNotEmpty()
}
} else {
return@flatMap Single.error<Boolean>(AuthorityException(null))
}
val enrollmentObjectRepository =
d2.enrollmentModule()
.enrollments().uid(enrollmentUid)
enrollmentObjectRepository.setStatus(
enrollmentObjectRepository.blockingGet()!!.status()!!,
)
enrollmentObjectRepository.blockingDelete()
!d2.enrollmentModule().enrollments().byTrackedEntityInstance().eq(teiUid)
.byDeleted().isFalse
.byStatus().eq(EnrollmentStatus.ACTIVE).blockingGet().isEmpty()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,9 @@ public interface Presenter {
void trackDashboardRelationships();

void trackDashboardNotes();

Boolean checkIfTEICanBeDeleted();

Boolean checkIfEnrollmentCanBeDeleted(String enrollmentUid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import org.dhis2.commons.sync.OnDismissListener
import org.dhis2.commons.sync.SyncContext
import org.dhis2.databinding.ActivityDashboardMobileBinding
import org.dhis2.ui.ThemeManager
import org.dhis2.ui.dialogs.bottomsheet.DeleteBottomSheetDialog
import org.dhis2.usescases.enrollment.EnrollmentActivity
import org.dhis2.usescases.enrollment.EnrollmentActivity.Companion.getIntent
import org.dhis2.usescases.general.ActivityGlobalAbstract
Expand Down Expand Up @@ -133,6 +134,7 @@ class TeiDashboardMobileActivity :
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
if (savedInstanceState != null && savedInstanceState.containsKey(Constants.TRACKED_ENTITY_INSTANCE)) {
teiUid = savedInstanceState.getString(Constants.TRACKED_ENTITY_INSTANCE)
Expand Down Expand Up @@ -563,8 +565,18 @@ class TeiDashboardMobileActivity :
.menu(this, menu)
.onMenuInflated { popupMenu: PopupMenu ->
val deleteTeiItem = popupMenu.menu.findItem(R.id.deleteTei)
deleteTeiItem.title =
String.format(deleteTeiItem.title.toString(), presenter.teType)
val showDeleteTeiItem = presenter.checkIfTEICanBeDeleted()
if (showDeleteTeiItem) {
deleteTeiItem.isVisible = true
deleteTeiItem.title =
String.format(deleteTeiItem.title.toString(), presenter.teType)
} else {
deleteTeiItem.isVisible = false
}

val deleteEnrollmentItem = popupMenu.menu.findItem(R.id.deleteEnrollment)
deleteEnrollmentItem.isVisible = presenter.checkIfEnrollmentCanBeDeleted(enrollmentUid)

if (enrollmentUid != null) {
val status = presenter.getEnrollmentStatus(enrollmentUid)
if (status == EnrollmentStatus.COMPLETED) {
Expand All @@ -586,9 +598,10 @@ class TeiDashboardMobileActivity :
analyticsHelper.setEvent(SHOW_HELP, CLICK, SHOW_HELP)
showTutorial(true)
}

R.id.markForFollowUp -> dashboardViewModel.onFollowUp(programModel)
R.id.deleteTei -> presenter.deleteTei()
R.id.deleteEnrollment -> presenter.deleteEnrollment()
R.id.deleteTei -> showDeleteTEIConfirmationDialog()
R.id.deleteEnrollment -> showRemoveEnrollmentConfirmationDialog()
R.id.programSelector -> presenter.onEnrollmentSelectorClick()
R.id.groupEvents -> groupByStage?.setValue(true)
R.id.showTimeline -> groupByStage?.setValue(false)
Expand Down Expand Up @@ -654,6 +667,35 @@ class TeiDashboardMobileActivity :
}
}

private fun showDeleteTEIConfirmationDialog() {
DeleteBottomSheetDialog(
title = getString(R.string.delete_tei_dialog_title).format(presenter.teType),
description = getString(R.string.delete_tei_dialog_message).format(presenter.teType),
mainButtonText = getString(R.string.delete),
deleteForever = true,
onMainButtonClick = {
presenter.deleteTei()
},
).show(
supportFragmentManager,
DeleteBottomSheetDialog.TAG,
)
}

private fun showRemoveEnrollmentConfirmationDialog() {
DeleteBottomSheetDialog(
title = getString(R.string.remove_enrollment_dialog_title).format(programModel.currentProgram.displayName()),
description = getString(R.string.remove_enrollment_dialog_message).format(programModel.currentProgram.displayName()),
mainButtonText = getString(R.string.remove),
onMainButtonClick = {
presenter.deleteEnrollment()
},
).show(
supportFragmentManager,
DeleteBottomSheetDialog.TAG,
)
}

override fun onRelationshipMapLoaded() {
binding.toolbarProgress.hide()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package org.dhis2.usescases.teiDashboard;

import static androidx.core.content.ContextCompat.getString;

import com.google.gson.reflect.TypeToken;

import org.dhis2.R;
import org.dhis2.commons.prefs.Preference;
import org.dhis2.commons.prefs.PreferenceProvider;
import org.dhis2.commons.schedulers.SchedulerProvider;
Expand All @@ -26,13 +23,11 @@

import static org.dhis2.commons.matomo.Actions.OPEN_NOTES;
import static org.dhis2.commons.matomo.Actions.OPEN_RELATIONSHIPS;
import static org.dhis2.utils.analytics.AnalyticsConstants.ACTIVE_FOLLOW_UP;
import static org.dhis2.utils.analytics.AnalyticsConstants.CLICK;
import static org.dhis2.utils.analytics.AnalyticsConstants.DELETE_ENROLL;
import static org.dhis2.utils.analytics.AnalyticsConstants.DELETE_TEI;
import static org.dhis2.commons.matomo.Actions.OPEN_ANALYTICS;
import static org.dhis2.commons.matomo.Categories.DASHBOARD;
import static org.dhis2.utils.analytics.AnalyticsConstants.FOLLOW_UP;

public class TeiDashboardPresenter implements TeiDashboardContracts.Presenter {

Expand Down Expand Up @@ -135,6 +130,16 @@ public void trackDashboardNotes() {
matomoAnalyticsController.trackEvent(DASHBOARD, OPEN_NOTES, CLICK);
}

@Override
public Boolean checkIfTEICanBeDeleted() {
return dashboardRepository.checkIfDeleteTeiIsPossible();
}

@Override
public Boolean checkIfEnrollmentCanBeDeleted(String enrollmentUid) {
return dashboardRepository.checkIfDeleteEnrollmentIsPossible(enrollmentUid);
}

@Override
public void onEnrollmentSelectorClick() {
view.goToEnrollmentList();
Expand All @@ -150,7 +155,7 @@ public void setProgram(Program program) {
@Override
public void deleteTei() {
compositeDisposable.add(
dashboardRepository.deleteTeiIfPossible()
dashboardRepository.deleteTei()
.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.ui())
.subscribe(
Expand All @@ -170,7 +175,7 @@ public void deleteTei() {
@Override
public void deleteEnrollment() {
compositeDisposable.add(
dashboardRepository.deleteEnrollmentIfPossible(
dashboardRepository.deleteEnrollment(
dashboardProgramModel.getCurrentEnrollment().uid()
)
.subscribeOn(schedulerProvider.io())
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -975,4 +975,8 @@
<string name="remove">Remove</string>
<string name="coordinates">Coordinates</string>
<string name="no_data_access">You don’t have access to data.\nContact your administrator.</string>
<string name="delete_tei_dialog_title">Delete this %s?</string>
<string name="delete_tei_dialog_message">This %s and all its data across all programs will be deleted. This action cannot be undone.</string>
<string name="remove_enrollment_dialog_title">Remove from %s?</string>
<string name="remove_enrollment_dialog_message">Data from %s will de deleted. This action cannot be undone.</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ class TeiDashboardPresenterTest {
)
presenter.dashboardProgramModel = dashboardProgramModel
whenever(
repository.deleteEnrollmentIfPossible(dashboardProgramModel.currentEnrollment.uid()),
repository.deleteEnrollment(dashboardProgramModel.currentEnrollment.uid()),
) doReturn Single.error(AuthorityException(null))
presenter.deleteEnrollment()

Expand All @@ -246,7 +246,7 @@ class TeiDashboardPresenterTest {
)
presenter.dashboardProgramModel = dashboardProgramModel
whenever(
repository.deleteEnrollmentIfPossible(dashboardProgramModel.currentEnrollment.uid()),
repository.deleteEnrollment(dashboardProgramModel.currentEnrollment.uid()),
) doReturn Single.just(true)
presenter.deleteEnrollment()

Expand All @@ -256,15 +256,15 @@ class TeiDashboardPresenterTest {

@Test
fun `Should not deleteTei if it doesn't has permission`() {
whenever(repository.deleteTeiIfPossible()) doReturn Single.just(false)
whenever(repository.deleteTei()) doReturn Single.just(false)
presenter.deleteTei()

verify(view).authorityErrorMessage()
}

@Test
fun `Should deleteTei if it has permission`() {
whenever(repository.deleteTeiIfPossible()) doReturn Single.just(true)
whenever(repository.deleteTei()) doReturn Single.just(true)
presenter.deleteTei()

verify(analyticsHelper).setEvent(DELETE_TEI, CLICK, DELETE_TEI)
Expand Down
Loading

0 comments on commit dc60ddf

Please sign in to comment.