Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ANDROAPP-5826-TEI-Enrollment-Deletion-confirmation-dialog #3489

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading