From 939d3f11c53a739659f553d7a4c59743d5fd5f80 Mon Sep 17 00:00:00 2001 From: Amr Salaheddin Abdelhady <52531091+amrsalah3@users.noreply.github.com> Date: Tue, 27 Sep 2022 09:33:21 +0200 Subject: [PATCH] AC-1045: Migrate formadmission package from MVP to MVVM architecture --- .../api/repository/EncounterRepository.kt | 105 +++++++ .../library/api/repository/FormRepository.kt | 12 + .../api/repository/ProviderRepository.java | 180 ++++------- .../api/services/EncounterService.java | 28 +- .../library/dao/EncounterCreateRoomDAO.java | 7 +- .../library/dao/FormResourceDAO.java | 2 +- .../library/databases/AppDatabase.java | 2 +- .../library/databases/AppDatabaseHelper.kt | 23 +- .../library/models/Encountercreate.kt | 12 +- .../android_sdk/library/models/Result.kt | 3 + .../EncounterCreateTypeConverter.kt | 29 ++ .../android_sdk/utilities/FormService.kt | 1 - .../src/main/res/values/strings.xml | 4 +- openmrs-client/build.gradle | 8 +- .../formadmission/FormAdmissionActivity.kt | 53 ++-- .../formadmission/FormAdmissionContract.kt | 39 --- .../formadmission/FormAdmissionFragment.kt | 186 ++++++------ .../formadmission/FormAdmissionPresenter.kt | 147 --------- .../formadmission/FormAdmissionViewModel.kt | 146 +++++++++ .../ProviderManagerDashboardPresenter.java | 18 +- .../res/layout/fragment_form_admission.xml | 279 ++++++++++-------- .../src/main/res/values-hi/strings.xml | 8 +- .../src/main/res/values/strings.xml | 8 +- .../openmrs/mobile/test/ACUnitTestBase.java | 9 +- .../mobile/test/ResourceSerializerTest.java | 22 +- .../FormAdmissionPresenterTest.java | 207 ------------- .../FormDisplayPagePresenterTest.java | 20 +- .../test/presenters/LoginPresenterTest.java | 86 +++--- ...ProviderManagerDashboardPresenterTest.java | 26 +- .../viewmodels/FormAdmissionViewModelTest.kt | 143 +++++++++ .../viewmodels}/FormListViewModelTest.kt | 3 +- .../mobile/utilities/DateUtilsTest.java | 36 +-- 32 files changed, 954 insertions(+), 898 deletions(-) create mode 100644 openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/EncounterRepository.kt create mode 100644 openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/typeConverters/EncounterCreateTypeConverter.kt delete mode 100644 openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionContract.kt delete mode 100644 openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionPresenter.kt create mode 100644 openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionViewModel.kt delete mode 100644 openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormAdmissionPresenterTest.java create mode 100644 openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormAdmissionViewModelTest.kt rename openmrs-client/src/test/java/org/openmrs/mobile/{activities/formlist => test/viewmodels}/FormListViewModelTest.kt (97%) diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/EncounterRepository.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/EncounterRepository.kt new file mode 100644 index 000000000..2d22cb379 --- /dev/null +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/EncounterRepository.kt @@ -0,0 +1,105 @@ +package com.openmrs.android_sdk.library.api.repository + +import com.openmrs.android_sdk.library.dao.PatientDAO +import com.openmrs.android_sdk.library.dao.VisitDAO +import com.openmrs.android_sdk.library.databases.AppDatabaseHelper +import com.openmrs.android_sdk.library.models.Encounter +import com.openmrs.android_sdk.library.models.EncounterType +import com.openmrs.android_sdk.library.models.Encountercreate +import com.openmrs.android_sdk.library.models.ResultType +import com.openmrs.android_sdk.utilities.NetworkUtils +import com.openmrs.android_sdk.utilities.execute +import rx.Observable +import javax.inject.Inject +import javax.inject.Singleton +import java.util.concurrent.Callable + +@Singleton +class EncounterRepository @Inject constructor() : BaseRepository() { + + /** + * Saves an encounter to local database and to server when online. + * + * @param encounterCreate the Encountercreate object submit + * @return ResultType of operation result: full success, local success, or error. + */ + fun saveEncounter(encounterCreate: Encountercreate): Observable { + return AppDatabaseHelper.createObservableIO(Callable { + val patient = PatientDAO().findPatientByID(encounterCreate.patientId.toString()) + val activeVisit = VisitDAO().getActiveVisitByPatientId(encounterCreate.patientId).execute() + if (patient == null || activeVisit == null || encounterCreate.synced) { + return@Callable ResultType.EncounterSubmissionError + } + + encounterCreate.visit = activeVisit.uuid + val encId = encounterCreate.id + if (encId == null || getEncounterCreateFromDB(encId).execute() == null) { + encounterCreate.id = saveEncounterCreateToDB(encounterCreate).execute() + } + + if (patient.isSynced && NetworkUtils.isOnline()) { + restApi.createEncounter(encounterCreate).execute().run { + if (isSuccessful) { + val encounter: Encounter = body()!! + encounter.encounterType = EncounterType(encounterCreate.formname) + for (i in encounterCreate.observations.indices) { + encounter.observations[i].displayValue = encounterCreate.observations[i].value + } + + // Update the visit linked to this encounter + activeVisit.encounters += encounter + VisitDAO().saveOrUpdate(activeVisit, encounterCreate.patientId!!).execute() + + updateEncounterCreate(encounterCreate.apply { synced = true }).execute() + + return@Callable ResultType.EncounterSubmissionSuccess + } else { + throw Exception("syncEncounter error: ${message()}") + } + } + } else { + // Update patient locally + patient.addEncounters(encounterCreate.id) + PatientDAO().updatePatient(patient.id!!, patient) + // EncounterService will run to upload the encounter when online + return@Callable ResultType.EncounterSubmissionLocalSuccess + } + }) + } + + /** + * Gets EncounterCreate object from database by its ID + * + * @param id id of the EncounterCreate to be fetched + * @return EncounterCreate object found + */ + fun getEncounterCreateFromDB(id: Long): Observable { + return AppDatabaseHelper.createObservableIO(Callable { + return@Callable db.encounterCreateRoomDAO().getCreatedEncountersByID(id) + }) + } + + /** + * Saves Encountercreate object to database to be used to create an encounter in the server later. + * + * @param encounterCreate the EncounterCreate to be saved + * @return the id of the entry saved to the database + */ + fun saveEncounterCreateToDB(encounterCreate: Encountercreate): Observable { + return AppDatabaseHelper.createObservableIO(Callable { + return@Callable db.encounterCreateRoomDAO().addEncounterCreated(encounterCreate) + }) + } + + /** + * Updates an existing encounterCreate object in the database. + * + * @param encounterCreate the EncounterCreate to be updated + * @return the number of updated rows in the database + */ + fun updateEncounterCreate(encounterCreate: Encountercreate): Observable { + return AppDatabaseHelper.createObservableIO(Callable { + return@Callable db.encounterCreateRoomDAO().updateExistingEncounter(encounterCreate) + }) + } +} diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/FormRepository.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/FormRepository.kt index 0d05ae99b..98fe4209b 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/FormRepository.kt +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/FormRepository.kt @@ -22,6 +22,18 @@ class FormRepository @Inject constructor() : BaseRepository() { }) } + /** + * Fetches a resource form by the form's name. + * + * @param name the form name + * @return an observable form resource entity + */ + fun fetchFormResourceByName(name: String): Observable { + return AppDatabaseHelper.createObservableIO(Callable { + return@Callable db.formResourceDAO().getFormResourceByName(name) + }) + } + /** * Creates a form. * diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/ProviderRepository.java b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/ProviderRepository.java index 8d3aaab39..4ce49edfb 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/ProviderRepository.java +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/repository/ProviderRepository.java @@ -14,8 +14,22 @@ package com.openmrs.android_sdk.library.api.repository; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; +import static com.openmrs.android_sdk.library.databases.AppDatabaseHelper.createObservableIO; +import static com.openmrs.android_sdk.utilities.ApplicationConstants.API.FULL; +import static com.openmrs.android_sdk.utilities.ApplicationConstants.API.REST_ENDPOINT; +import static com.openmrs.android_sdk.utilities.ApplicationConstants.API.TAG_ADMISSION_LOCATION; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.HashSet; +import java.util.List; + +import okhttp3.ResponseBody; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import rx.Observable; + import androidx.work.Constraints; import androidx.work.Data; import androidx.work.NetworkType; @@ -23,7 +37,6 @@ import com.openmrs.android_sdk.R; import com.openmrs.android_sdk.library.OpenMRSLogger; -import com.openmrs.android_sdk.library.OpenmrsAndroid; import com.openmrs.android_sdk.library.api.RestApi; import com.openmrs.android_sdk.library.api.workers.provider.AddProviderWorker; import com.openmrs.android_sdk.library.api.workers.provider.DeleteProviderWorker; @@ -34,23 +47,15 @@ import com.openmrs.android_sdk.library.models.Provider; import com.openmrs.android_sdk.library.models.Resource; import com.openmrs.android_sdk.library.models.Results; -import com.openmrs.android_sdk.utilities.ApplicationConstants; import com.openmrs.android_sdk.utilities.NetworkUtils; import com.openmrs.android_sdk.utilities.ToastUtil; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; -import java.util.List; - -import okhttp3.ResponseBody; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - /** * The type Provider repository. */ +@Singleton public class ProviderRepository extends BaseRepository { ProviderRoomDAO providerRoomDao; @@ -58,6 +63,7 @@ public class ProviderRepository extends BaseRepository { /** * Instantiates a new Provider repository. */ + @Inject public ProviderRepository() { providerRoomDao = db.providerRoomDAO(); } @@ -84,70 +90,43 @@ public void setProviderRoomDao(ProviderRoomDAO providerRoomDao) { /** * Gets providers. * - * @return the providers + * @return a list of providers */ - public LiveData> getProviders() { - - MutableLiveData> providerLiveData = new MutableLiveData<>(); - if (NetworkUtils.isOnline()) { - restApi.getProviderList().enqueue(new Callback>() { - @Override - public void onResponse(@NotNull Call> call, @NotNull Response> response) { - if (response.isSuccessful()) { - if (!response.body().getResults().isEmpty()) { - List serversList = response.body().getResults(); - - List providerUuids = providerRoomDao.getCurrentUUIDs().blockingGet(); - HashSet checkUuids = new HashSet<>(); - - for (String element : providerUuids) { - if (element != null) - checkUuids.add(element); - } - - providerUuids.clear(); - providerUuids = null; - - for (Provider provider : serversList) { - if (checkUuids.contains(provider.getUuid()) == false) { - providerRoomDao.addProvider(provider); - } - - checkUuids.remove(provider.getUuid()); - } - - for (String uuid : checkUuids) { - providerRoomDao.deleteByUuid(uuid); - } - - providerLiveData.setValue(providerRoomDao.getProviderList().blockingGet()); - } else { - providerLiveData.setValue(providerRoomDao.getProviderList().blockingGet()); + public Observable> getProviders() { + return createObservableIO(() -> { + // If not online, fetch providers locally + if (!NetworkUtils.isOnline()) { + ToastUtil.notify(context.getString(R.string.offline_provider_fetch)); + logger.e("offline providers fetched couldn't sync with the database device offline"); + return providerRoomDao.getProviderList().blockingGet(); + } + providerRoomDao.deleteAll(); + // Otherwise (online), fetch remote providers + Response> response = restApi.getProviderList().execute(); + if (response.isSuccessful()) { + List serverList = response.body().getResults(); + if (!serverList.isEmpty()) { + // Sync local DB with server's providers + List providerUuids = providerRoomDao.getCurrentUUIDs().blockingGet(); + HashSet checkUuids = new HashSet<>(providerUuids); + + for (Provider provider : serverList) { + if (!checkUuids.contains(provider.getUuid())) { + providerRoomDao.addProvider(provider); } - } else { - logger.e("Reading providers failed. Response: " + response.errorBody()); - ToastUtil.error(OpenmrsAndroid.getInstance().getString(R.string.unable_to_fetch_providers)); - providerLiveData.setValue(providerRoomDao.getProviderList().blockingGet()); + checkUuids.remove(provider.getUuid()); + } + // Remove local providers that are not present in server now + for (String uuid : checkUuids) { + providerRoomDao.deleteByUuid(uuid); } } + } else { + logger.e("Error fetching providers from the server: " + response.errorBody().string()); + } - @Override - public void onFailure(@NotNull Call> call, @NotNull Throwable t) { - logger.e("Reading providers failed.", t); - ToastUtil.error(OpenmrsAndroid.getInstance().getString(R.string.unable_to_fetch_providers)); - providerLiveData.setValue(providerRoomDao.getProviderList().blockingGet()); - } - }); - } else { - - // offline data synced - providerLiveData.setValue(providerRoomDao.getProviderList().blockingGet()); - - //offline notify - ToastUtil.notify(context.getString(R.string.offline_provider_fetch)); - logger.e("offline providers fetched couldnt sync with the database device offline"); - } - return providerLiveData; + return providerRoomDao.getProviderList().blockingGet(); + }); } /** @@ -296,57 +275,28 @@ public void onFailure(@NotNull Call call, @NotNull Throwable t) { * Gets location. * * @param url the url - * @return the location + * @return a list of location entities */ - public LiveData> getLocation(String url) { - MutableLiveData> locations = new MutableLiveData<>(); - if (NetworkUtils.hasNetwork()) { - String locationEndPoint = url + ApplicationConstants.API.REST_ENDPOINT + "location"; - Call> call = - restApi.getLocations(locationEndPoint, ApplicationConstants.API.TAG_ADMISSION_LOCATION, ApplicationConstants.API.FULL); - call.enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) { - locations.setValue(response.body().getResults()); - } else { - locations.setValue(null); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - locations.setValue(null); - } - }); - } else { - locations.setValue(null); - } - return locations; + public Observable> getLocations(String url) { + return createObservableIO(() -> { + String locationEndPoint = url + REST_ENDPOINT + "location"; + Response> response = + restApi.getLocations(locationEndPoint, TAG_ADMISSION_LOCATION, FULL).execute(); + if (response.isSuccessful()) return response.body().getResults(); + else throw new Exception("fetch provider location error: " + response.message()); + }); } /** * Gets encounter roles. * - * @return the encounter roles + * @return a list of resources of encounter roles */ - public LiveData> getEncounterRoles() { - MutableLiveData> encounterRoles = new MutableLiveData<>(); - restApi.getEncounterRoles().enqueue(new Callback>() { - @Override - public void onResponse(Call> call, Response> response) { - if (response.isSuccessful()) { - encounterRoles.setValue(response.body().getResults()); - } else { - encounterRoles.setValue(null); - } - } - - @Override - public void onFailure(Call> call, Throwable t) { - encounterRoles.setValue(null); - } + public Observable> getEncounterRoles() { + return createObservableIO(() -> { + Response> response = restApi.getEncounterRoles().execute(); + if (response.isSuccessful()) return response.body().getResults(); + else throw new Exception("fetch encounter roles error: " + response.message()); }); - return encounterRoles; } } diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/services/EncounterService.java b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/services/EncounterService.java index 023a9ac2e..38a0de9a1 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/services/EncounterService.java +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/api/services/EncounterService.java @@ -26,6 +26,7 @@ import com.openmrs.android_sdk.library.OpenmrsAndroid; import com.openmrs.android_sdk.library.api.RestApi; import com.openmrs.android_sdk.library.api.RestServiceBuilder; +import com.openmrs.android_sdk.library.api.repository.EncounterRepository; import com.openmrs.android_sdk.library.api.repository.VisitRepository; import com.openmrs.android_sdk.library.dao.PatientDAO; import com.openmrs.android_sdk.library.dao.VisitDAO; @@ -185,29 +186,16 @@ private void linkvisit(Long patientid, String formname, Encounter encounter, Enc @Override protected void onHandleIntent(Intent intent) { - if (NetworkUtils.isOnline()) { + if (!NetworkUtils.isOnline()) return; - List encountercreatelist = AppDatabase.getDatabase(OpenmrsAndroid.getInstance().getApplicationContext()) - .encounterCreateRoomDAO() - .getAllCreatedEncounters(); + List encounterCreateList = AppDatabase.getDatabase(OpenmrsAndroid.getInstance().getApplicationContext()) + .encounterCreateRoomDAO() + .getAllCreatedEncounters(); - for (final Encountercreate encountercreate : encountercreatelist) { - if (!encountercreate.getSynced() && - new PatientDAO().findPatientByID(Long.toString(encountercreate.getPatientId())).isSynced()) { - new VisitDAO().getActiveVisitByPatientId(encountercreate.getPatientId()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(visit -> { - if (visit != null) { - encountercreate.setVisit(visit.getUuid()); - syncEncounter(encountercreate); - } else { - startNewVisitForEncounter(encountercreate); - } - }); - } + for (final Encountercreate encounterCreate : encounterCreateList) { + if (!encounterCreate.getSynced()) { + new EncounterRepository().saveEncounter(encounterCreate).subscribe(); } - } else { - ToastUtil.error(getString(R.string.form_data_will_be_synced_later_error_message)); } } } diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/EncounterCreateRoomDAO.java b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/EncounterCreateRoomDAO.java index 61cf465ff..b8a5ec17e 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/EncounterCreateRoomDAO.java +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/EncounterCreateRoomDAO.java @@ -10,6 +10,8 @@ package com.openmrs.android_sdk.library.dao; +import java.util.List; + import androidx.room.Dao; import androidx.room.Insert; import androidx.room.Query; @@ -17,8 +19,6 @@ import com.openmrs.android_sdk.library.models.Encountercreate; -import java.util.List; - /** * The interface Encounter create room dao. */ @@ -38,10 +38,9 @@ public interface EncounterCreateRoomDAO { * Update existing encounter int. * * @param encountercreate the encountercreate - * @return the int */ @Update - int updateExistingEncounter(Encountercreate encountercreate); + void updateExistingEncounter(Encountercreate encountercreate); /** * Gets all created encounters. diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/FormResourceDAO.java b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/FormResourceDAO.java index 5d471bcd1..166670e05 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/FormResourceDAO.java +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/dao/FormResourceDAO.java @@ -36,7 +36,7 @@ public interface FormResourceDAO { * @return the form resource by name */ @Query("SELECT * FROM forms WHERE name = :name") - Single getFormResourceByName(String name); + FormResourceEntity getFormResourceByName(String name); /** * Gets form resource list. diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabase.java b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabase.java index e8f6a6a6e..cbfe31db4 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabase.java +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabase.java @@ -58,7 +58,7 @@ EncounterType.class, Encountercreate.class, AllergyEntity.class}, - version = 1) + version = 3) public abstract class AppDatabase extends RoomDatabase { diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabaseHelper.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabaseHelper.kt index 768472ef1..1c87319ec 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabaseHelper.kt +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/databases/AppDatabaseHelper.kt @@ -19,8 +19,25 @@ import com.openmrs.android_sdk.library.OpenmrsAndroid import com.openmrs.android_sdk.library.dao.EncounterDAO import com.openmrs.android_sdk.library.dao.ObservationDAO import com.openmrs.android_sdk.library.dao.PatientDAO -import com.openmrs.android_sdk.library.databases.entities.* -import com.openmrs.android_sdk.library.models.* +import com.openmrs.android_sdk.library.databases.entities.AllergyEntity +import com.openmrs.android_sdk.library.databases.entities.ConceptEntity +import com.openmrs.android_sdk.library.databases.entities.EncounterEntity +import com.openmrs.android_sdk.library.databases.entities.LocationEntity +import com.openmrs.android_sdk.library.databases.entities.ObservationEntity +import com.openmrs.android_sdk.library.databases.entities.PatientEntity +import com.openmrs.android_sdk.library.databases.entities.VisitEntity +import com.openmrs.android_sdk.library.models.Allergen +import com.openmrs.android_sdk.library.models.Allergy +import com.openmrs.android_sdk.library.models.Encounter +import com.openmrs.android_sdk.library.models.EncounterType +import com.openmrs.android_sdk.library.models.Observation +import com.openmrs.android_sdk.library.models.Patient +import com.openmrs.android_sdk.library.models.PatientIdentifier +import com.openmrs.android_sdk.library.models.PersonAddress +import com.openmrs.android_sdk.library.models.PersonName +import com.openmrs.android_sdk.library.models.Resource +import com.openmrs.android_sdk.library.models.Visit +import com.openmrs.android_sdk.library.models.VisitType import com.openmrs.android_sdk.utilities.ApplicationConstants import com.openmrs.android_sdk.utilities.DateUtils import com.openmrs.android_sdk.utilities.DateUtils.convertTime @@ -85,7 +102,7 @@ object AppDatabaseHelper { } encounterEntity.encounterDateTime = encounter.encounterDatetime.toString() encounterEntity.encounterType = encounter.encounterType!!.display - encounterEntity.patientUuid = encounter.patientUUID + encounterEntity.patientUuid = encounter.patient?.uuid encounterEntity.formUuid = encounter.formUuid if (null == encounter.location) { encounterEntity.locationUuid = null diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Encountercreate.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Encountercreate.kt index c10494960..e1fa183f2 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Encountercreate.kt +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Encountercreate.kt @@ -10,10 +10,14 @@ package com.openmrs.android_sdk.library.models -import androidx.room.* -import com.openmrs.android_sdk.library.models.typeConverters.ObservationListConverter +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverters import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName +import com.openmrs.android_sdk.library.models.typeConverters.EncounterProviderCreateTypeConverter +import com.openmrs.android_sdk.library.models.typeConverters.ObservationListConverter import java.io.Serializable /** @@ -61,16 +65,14 @@ class Encountercreate : Serializable { @SerializedName("form") @Expose - @Ignore var formUuid: String? = null @SerializedName("location") @Expose - @Ignore var location: String? = null + @TypeConverters(EncounterProviderCreateTypeConverter::class) @SerializedName("encounterProviders") @Expose - @Ignore var encounterProvider: List = ArrayList() } diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Result.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Result.kt index 8498ca32f..08934164b 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Result.kt +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/Result.kt @@ -32,4 +32,7 @@ enum class ResultType { PatientUpdateSuccess, PatientUpdateLocalSuccess, PatientUpdateError, + EncounterSubmissionSuccess, + EncounterSubmissionLocalSuccess, + EncounterSubmissionError } diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/typeConverters/EncounterCreateTypeConverter.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/typeConverters/EncounterCreateTypeConverter.kt new file mode 100644 index 000000000..147a5ab09 --- /dev/null +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/library/models/typeConverters/EncounterCreateTypeConverter.kt @@ -0,0 +1,29 @@ +package com.openmrs.android_sdk.library.models.typeConverters + +import androidx.room.TypeConverter +import com.google.gson.GsonBuilder +import com.google.gson.reflect.TypeToken +import com.openmrs.android_sdk.library.models.EncounterProviderCreate +import java.io.Serializable +import java.lang.reflect.Modifier + +object EncounterProviderCreateTypeConverter : Serializable { + @JvmStatic + @TypeConverter + fun fromString(value: String?): List { + val listType = object : TypeToken?>() {}.type + val builder = GsonBuilder() + builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC) + val gson = builder.create() + return gson.fromJson(value, listType) + } + + @JvmStatic + @TypeConverter + fun listToString(list: List?): String { + val builder = GsonBuilder() + builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC) + val gson = builder.create() + return gson.toJson(list) + } +} diff --git a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/utilities/FormService.kt b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/utilities/FormService.kt index e9b2638fb..c40800b27 100644 --- a/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/utilities/FormService.kt +++ b/openmrs-android-sdk/src/main/java/com/openmrs/android_sdk/utilities/FormService.kt @@ -63,6 +63,5 @@ object FormService { return AppDatabase.getDatabase(OpenmrsAndroid.getInstance()?.getApplicationContext()) .formResourceDAO() .getFormResourceByName(name) - .blockingGet() } } diff --git a/openmrs-android-sdk/src/main/res/values/strings.xml b/openmrs-android-sdk/src/main/res/values/strings.xml index bf6485174..72bf5aa19 100644 --- a/openmrs-android-sdk/src/main/res/values/strings.xml +++ b/openmrs-android-sdk/src/main/res/values/strings.xml @@ -328,7 +328,7 @@ Surgeon - offline providers fetched couldnt sync with the database device offline + offline providers fetched couldn\'t sync with the database device offline provider will be synced to the server when device gets connected to network updated provider will be synced to the server when device gets connected to network Provider will be removed from the server when you\'re back online @@ -378,7 +378,7 @@ Exit application - \"Patient not yet registered. No internet connection. Form data is saved locally and will sync when internet connection is restored. \" + Patient not yet registered. No internet connection. Form data is saved locally and will sync when internet connection is restored. Sync is off. Turn on sync to save form data. diff --git a/openmrs-client/build.gradle b/openmrs-client/build.gradle index 8b428d90c..bc1a6f2c4 100644 --- a/openmrs-client/build.gradle +++ b/openmrs-client/build.gradle @@ -189,8 +189,6 @@ dependencies { implementation "org.jdeferred:jdeferred-android-aar:${versions.jdeferred}" implementation "com.google.guava:guava:${versions.guava}" - // Leak Canary - debugImplementation "com.squareup.leakcanary:leakcanary-android:${versions.leakcanary}" // Google place api implementation "com.google.android.libraries.places:places:${versions.placesAPI}" @@ -218,6 +216,7 @@ dependencies { testImplementation( 'org.mockito:mockito-core:2.8.9', 'org.mockito:mockito-inline:2.13.0', + "org.mockito.kotlin:mockito-kotlin:4.0.0", 'junit:junit:4.12', "org.junit.jupiter:junit-jupiter:5.8.2", 'org.powermock:powermock-api-mockito2:2.0.2', @@ -227,6 +226,11 @@ dependencies { ) testImplementation "android.arch.core:core-testing:${versions.coreTesting}" kaptTest "com.google.dagger:hilt-compiler:${versions.hilt}" + + // Leak Canary + debugImplementation "com.squareup.leakcanary:leakcanary-android:${versions.leakcanary}" + // Debug database + debugImplementation 'com.amitshekhar.android:debug-db:1.0.6' } kapt { diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionActivity.kt b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionActivity.kt index 1a897a681..bcaaff494 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionActivity.kt +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionActivity.kt @@ -14,50 +14,41 @@ package org.openmrs.mobile.activities.formadmission import android.os.Bundle -import android.view.Menu +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.ENCOUNTERTYPE +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.FORM_NAME +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.PATIENT_ID_BUNDLE +import dagger.hilt.android.AndroidEntryPoint import org.openmrs.mobile.R import org.openmrs.mobile.activities.ACBaseActivity -import com.openmrs.android_sdk.utilities.ApplicationConstants +@AndroidEntryPoint class FormAdmissionActivity : ACBaseActivity() { - var patientID: Long? = null - var encounterType: String? = null - var formName: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_form_admission) - val actionBar = supportActionBar - if (actionBar != null) { - actionBar.elevation = 0f - actionBar.setDisplayHomeAsUpEnabled(true) - actionBar.setTitle(R.string.admission) + + supportActionBar?.run { + elevation = 0f + setDisplayHomeAsUpEnabled(true) + setTitle(R.string.admission) } - val bundle = intent.extras - if (bundle != null) { - patientID = bundle.getLong(ApplicationConstants.BundleKeys.PATIENT_ID_BUNDLE) - encounterType = bundle[ApplicationConstants.BundleKeys.ENCOUNTERTYPE] as String? - formName = bundle[ApplicationConstants.BundleKeys.FORM_NAME] as String? + + var patientID: Long? = null + var encounterType: String? = null + var formName: String? = null + intent.extras?.let { + patientID = it.getLong(PATIENT_ID_BUNDLE) + encounterType = it.getString(ENCOUNTERTYPE) + formName = it.getString(FORM_NAME) } + var formAdmissionFragment = supportFragmentManager.findFragmentById(R.id.admissionFormContentFrame) as FormAdmissionFragment? if (formAdmissionFragment == null) { - formAdmissionFragment = FormAdmissionFragment.newInstance() + formAdmissionFragment = FormAdmissionFragment.newInstance(patientID!!, encounterType!!, formName!!) } if (!formAdmissionFragment.isActive) { - addFragmentToActivity(supportFragmentManager, - formAdmissionFragment, R.id.admissionFormContentFrame) - } - FormAdmissionPresenter(formAdmissionFragment, patientID, encounterType, formName, applicationContext) - } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - super.onCreateOptionsMenu(menu) - return true - } - - companion object { - fun newInstance(): FormAdmissionFragment { - return FormAdmissionFragment() + addFragmentToActivity(supportFragmentManager, formAdmissionFragment, R.id.admissionFormContentFrame) } } -} \ No newline at end of file +} diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionContract.kt b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionContract.kt deleted file mode 100644 index 74221fabe..000000000 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionContract.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * The contents of this file are subject to the OpenMRS Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://license.openmrs.org - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * Copyright (C) OpenMRS, LLC. All Rights Reserved. - */ -package org.openmrs.mobile.activities.formadmission - -import com.openmrs.android_sdk.library.databases.entities.LocationEntity -import com.openmrs.android_sdk.library.models.Provider -import com.openmrs.android_sdk.library.models.Resource -import org.openmrs.mobile.activities.BasePresenterContract -import org.openmrs.mobile.activities.BaseView - -interface FormAdmissionContract { - interface View : BaseView { - fun updateProviderAdapter(providerList: List?) - fun showToast(error: String?) - fun updateLocationAdapter(locationList: List?) - fun enableSubmitButton(value: Boolean) - fun quitFormEntry() - fun updateEncounterRoleList(encounterRoleList: List?) - } - - interface Presenter : BasePresenterContract { - fun getProviders(formAdmissionFragment: FormAdmissionFragment?) - fun updateViews(providerList: List?) - fun getLocation(url: String?, formAdmissionFragment: FormAdmissionFragment?) - fun getEncounterRoles(formAdmissionFragment: FormAdmissionFragment?) - fun createEncounter(providerUUID: String?, locationUUID: String?, encounterRoleUUID: String?) - } -} \ No newline at end of file diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionFragment.kt b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionFragment.kt index 4de08e7bb..9faa860e0 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionFragment.kt +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionFragment.kt @@ -21,131 +21,147 @@ import android.view.ViewGroup import android.widget.AdapterView import android.widget.AdapterView.OnItemSelectedListener import android.widget.ArrayAdapter +import androidx.core.os.bundleOf +import androidx.fragment.app.viewModels +import androidx.lifecycle.Observer import com.openmrs.android_sdk.library.OpenmrsAndroid -import com.openmrs.android_sdk.library.databases.entities.LocationEntity -import com.openmrs.android_sdk.library.models.Provider -import com.openmrs.android_sdk.library.models.Resource +import com.openmrs.android_sdk.library.models.Result +import com.openmrs.android_sdk.library.models.ResultType.EncounterSubmissionLocalSuccess +import com.openmrs.android_sdk.library.models.ResultType.EncounterSubmissionSuccess +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.ENCOUNTERTYPE +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.FORM_NAME +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.PATIENT_ID_BUNDLE +import com.openmrs.android_sdk.utilities.ApplicationConstants.LOCATION import com.openmrs.android_sdk.utilities.ToastUtil -import com.openmrs.android_sdk.utilities.ToastUtil.showShortToast +import dagger.hilt.android.AndroidEntryPoint import org.openmrs.mobile.R -import org.openmrs.mobile.activities.ACBaseFragment +import org.openmrs.mobile.activities.BaseFragment import org.openmrs.mobile.databinding.FragmentFormAdmissionBinding +import org.openmrs.mobile.utilities.makeGone +import org.openmrs.mobile.utilities.makeVisible +import org.openmrs.mobile.utilities.observeOnce import java.text.SimpleDateFormat -import java.util.* +import java.util.Calendar -class FormAdmissionFragment : ACBaseFragment(), FormAdmissionContract.View { +@AndroidEntryPoint +class FormAdmissionFragment : BaseFragment() { private var _binding: FragmentFormAdmissionBinding? = null private val binding get() = _binding!! - private var providerUUID: String? = "" - private var locationUUID: String? = "" - private var encounterRoleUUID: String? = "" - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + private val viewModel: FormAdmissionViewModel by viewModels() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = FragmentFormAdmissionBinding.inflate(inflater, container, false) - val root: View = binding.root - initFragmentFields() - mPresenter?.getEncounterRoles(this) - mPresenter?.getProviders(this) - mPresenter?.getLocation(OpenmrsAndroid.getServerUrl(), this) - return root + + setupObserver() + + return binding.root } - private fun initFragmentFields() { + private fun setupObserver() = with(viewModel) { + result.observe(viewLifecycleOwner, Observer { result -> + when (result) { + is Result.Loading -> showLoading(true) + is Result.Success -> { + setupProviderSpinner(providers.keys.toList()) + setupEncounterRoleSpinner(encounterRoles.keys.toList()) + setupTargetLocationSpinner(targetLocations.keys.toList()) + restoreState() + showLoading(false) + } + is Result.Error -> { + ToastUtil.error(getString(R.string.error_occurred)) + showLoading(false) + } + else -> throw IllegalStateException() + } + }) + } + + private fun restoreState() = with(binding) { val currentDate = Calendar.getInstance().time @SuppressLint("SimpleDateFormat") val df = SimpleDateFormat("dd/MM/yyyy") - with(binding) { - admissionDateHeader.text = df.format(currentDate) - submitButton.setOnClickListener { createEncounter() } - cancelButton.setOnClickListener { quitFormEntry() } - } + + admissionDateHeader.text = df.format(currentDate) + submitButton.setOnClickListener { submitAdmission() } + cancelButton.setOnClickListener { requireActivity().finish() } + + admittedBySpinner.setSelection(viewModel.providerListPosition) + encounterRoleSpinner.setSelection(viewModel.encounterRoleListPosition) + admittedToSpinner.setSelection(viewModel.targetLocationListPosition) + } - private fun createEncounter() { - if (providerUUID!!.isEmpty() || locationUUID!!.isEmpty() || encounterRoleUUID!!.isEmpty()) { - showShortToast(requireContext(), ToastUtil.ToastType.ERROR, getString(R.string.admission_fields_required)) + private fun showLoading(loading: Boolean) = with(binding) { + if (loading) { + transparentScreen.makeVisible() + progressBar.makeVisible() } else { - mPresenter!!.createEncounter(providerUUID, locationUUID, encounterRoleUUID) + transparentScreen.makeGone() + progressBar.makeGone() } } - override fun updateProviderAdapter(providerList: List?) { - val providers = arrayOfNulls(providerList!!.size) - for (i in providerList.indices) { - providers[i] = providerList[i]!!.display - } - val adapterAdmittedBy = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, providers) - binding.admittedBySpinner.adapter = adapterAdmittedBy - binding.admittedBySpinner.onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) { - val providerDisplay = binding.admittedBySpinner.selectedItem.toString() - for (i in providerList.indices) { - if (providerDisplay == providerList[i]!!.display) { - providerUUID = providerList[i]!!.uuid - } - } + private fun setupProviderSpinner(providers: List) = with(binding.admittedBySpinner) { + adapter = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, providers) + onItemSelectedListener = object : OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + viewModel.selectProvider(selectedItem.toString(), selectedItemPosition) } override fun onNothingSelected(parent: AdapterView<*>?) {} } } - override fun updateLocationAdapter(locationList: List?) { - val locations = arrayOfNulls(locationList!!.size) - for (i in locationList.indices) { - locations[i] = locationList[i]!!.display - } - val adapterAdmittedTo = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, locations) - binding.admittedToSpinner.adapter = adapterAdmittedTo - binding.admittedToSpinner.onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) { - val locationDisplay = binding.admittedToSpinner.selectedItem.toString() - for (i in locationList.indices) { - if (locationDisplay == locationList[i]!!.display) { - locationUUID = locationList[i]!!.uuid - } - } + private fun setupEncounterRoleSpinner(encounterRoles: List) = with(binding.encounterRoleSpinner) { + adapter = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, encounterRoles) + onItemSelectedListener = object : OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + viewModel.selectEncounterRole(selectedItem.toString(), selectedItemPosition) } override fun onNothingSelected(parent: AdapterView<*>?) {} } } - override fun updateEncounterRoleList(encounterRoleList: List?) { - val encounterRole = arrayOfNulls(encounterRoleList!!.size) - for (i in encounterRoleList.indices) { - encounterRole[i] = encounterRoleList[i]!!.display - } - val adapterEncounterRole = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, encounterRole) - binding.encounterRoleSpinner.adapter = adapterEncounterRole - binding.encounterRoleSpinner.onItemSelectedListener = object : OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) { - val encounterRoleDisplay = binding.encounterRoleSpinner.selectedItem.toString() - for (i in encounterRoleList.indices) { - if (encounterRoleDisplay == encounterRoleList[i]!!.display) { - encounterRoleUUID = encounterRoleList[i]!!.uuid - } - } + private fun setupTargetLocationSpinner(locations: List) = with(binding.admittedToSpinner) { + adapter = ArrayAdapter(requireActivity(), android.R.layout.simple_list_item_1, locations) + onItemSelectedListener = object : OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + viewModel.selectTargetLocation(selectedItem.toString(), selectedItemPosition) } override fun onNothingSelected(parent: AdapterView<*>?) {} } } - override fun showToast(error: String?) { - error(error!!) - } - - override fun enableSubmitButton(value: Boolean) { - binding.submitButton.isEnabled = value - } - - override fun quitFormEntry() { - requireActivity().finish() + private fun submitAdmission() { + showLoading(true) + viewModel.submitAdmission().observeOnce(viewLifecycleOwner, Observer { result -> + when (result) { + EncounterSubmissionSuccess -> { + ToastUtil.success(getString(R.string.form_submitted_successfully)) + requireActivity().finish() + } + EncounterSubmissionLocalSuccess -> { + ToastUtil.notify(getString(R.string.form_data_sync_is_off_message)) + requireActivity().finish() + } + else -> ToastUtil.error(getString(R.string.form_data_submit_error)) + } + showLoading(false) + }) } companion object { - fun newInstance(): FormAdmissionFragment { - return FormAdmissionFragment() + fun newInstance(patientID: Long, encounterType: String, + formName: String, currentLocation: String = OpenmrsAndroid.getServerUrl()) = FormAdmissionFragment().apply { + arguments = bundleOf( + PATIENT_ID_BUNDLE to patientID, + ENCOUNTERTYPE to encounterType, + FORM_NAME to formName, + LOCATION to currentLocation + ) } } @@ -153,4 +169,4 @@ class FormAdmissionFragment : ACBaseFragment(), super.onDestroyView() _binding = null } -} \ No newline at end of file +} diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionPresenter.kt b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionPresenter.kt deleted file mode 100644 index 6e796d798..000000000 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionPresenter.kt +++ /dev/null @@ -1,147 +0,0 @@ -/* - * The contents of this file are subject to the OpenMRS Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://license.openmrs.org - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * Copyright (C) OpenMRS, LLC. All Rights Reserved. - */ -package org.openmrs.mobile.activities.formadmission - -import android.content.Context -import androidx.lifecycle.Observer -import com.openmrs.android_sdk.library.OpenMRSLogger -import com.openmrs.android_sdk.library.dao.PatientDAO -import com.openmrs.android_sdk.library.databases.AppDatabase -import com.openmrs.android_sdk.library.databases.entities.LocationEntity -import com.openmrs.android_sdk.library.models.* -import com.openmrs.android_sdk.utilities.FormService.getFormResourceByName -import com.openmrs.android_sdk.utilities.ToastUtil.success -import org.openmrs.mobile.R -import org.openmrs.mobile.activities.BasePresenter -import com.openmrs.android_sdk.library.api.services.EncounterService -import com.openmrs.android_sdk.library.api.RestApi -import com.openmrs.android_sdk.library.api.RestServiceBuilder -import com.openmrs.android_sdk.library.api.repository.ProviderRepository -import org.openmrs.mobile.application.OpenMRS -import com.openmrs.android_sdk.library.listeners.retrofitcallbacks.DefaultResponseCallback - -class FormAdmissionPresenter : BasePresenter, FormAdmissionContract.Presenter { - private var view: FormAdmissionContract.View - private var patientID: Long? = null - private var encounterType: String? = null - private var formName: String? = null - private var formUUID: String? = null - private var mPatient: Patient? = null - private var restApi: RestApi - private var mContext: Context - private var providerRepository: ProviderRepository - - constructor(view: FormAdmissionContract.View, patientID: Long?, encounterType: String?, formName: String?, context: Context) { - this.view = view - this.patientID = patientID - this.encounterType = encounterType - this.formName = formName - mPatient = PatientDAO().findPatientByID((patientID!!).toString()) - formUUID = getFormResourceByName(formName).uuid - restApi = RestServiceBuilder.createService(RestApi::class.java) - this.view.setPresenter(this) - mContext = context - providerRepository = ProviderRepository() - } - - constructor(formAdmissionView: FormAdmissionContract.View, restApi: RestApi, context: Context, logger: OpenMRSLogger) { - view = formAdmissionView - this.restApi = restApi - view.setPresenter(this) - mContext = context - providerRepository = ProviderRepository(restApi, logger); - } - - override fun subscribe() { - //the function to start with - } - - override fun getProviders(formAdmissionFragment: FormAdmissionFragment?) { - providerRepository.providers.observe(formAdmissionFragment!!, Observer { providerList: List? -> updateViews(providerList) }) - } - - override fun updateViews(providerList: List?) { - if (providerList != null && providerList.isNotEmpty()) { - view.updateProviderAdapter(providerList) - } else { - view.showToast(mContext.resources.getString(R.string.error_occurred)) - view.enableSubmitButton(false) - } - } - - override fun getLocation(url: String?, formAdmissionFragment: FormAdmissionFragment?) { - providerRepository.getLocation(url).observe(formAdmissionFragment!!, Observer { locationList: List? -> updateLocationList(locationList) }) - } - - fun updateLocationList(locationList: List?) { - if (locationList != null && locationList.isNotEmpty()) { - view.updateLocationAdapter(locationList) - } else { - view.enableSubmitButton(false) - view.showToast(mContext.resources.getString(R.string.error_occurred)) - } - } - - override fun getEncounterRoles(formAdmissionFragment: FormAdmissionFragment?) { - providerRepository.encounterRoles.observe(formAdmissionFragment!!, Observer { encounterRolesList: List? -> updateEncounterRoles(encounterRolesList) }) - } - - fun updateEncounterRoles(encounterRolesList: List?) { - if (encounterRolesList != null && encounterRolesList.isNotEmpty()) { - view.updateEncounterRoleList(encounterRolesList) - } else { - view.enableSubmitButton(false) - view.showToast(mContext.resources.getString(R.string.error_occurred)) - } - } - - override fun createEncounter(providerUUID: String?, locationUUID: String?, encounterRoleUUID: String?) { - view.enableSubmitButton(false) - val encountercreate = Encountercreate() - encountercreate.patient = mPatient!!.uuid - encountercreate.encounterType = encounterType - encountercreate.formname = formName - encountercreate.patientId = patientID - encountercreate.formUuid = formUUID - encountercreate.location = locationUUID - val observations: List = ArrayList() - encountercreate.observations = observations - val encounterProviderCreate: MutableList = ArrayList() - encounterProviderCreate.add(EncounterProviderCreate(providerUUID!!, encounterRoleUUID!!)) - encountercreate.encounterProvider = encounterProviderCreate - val id = AppDatabase.getDatabase(OpenMRS.getInstance().applicationContext) - .encounterCreateRoomDAO() - .addEncounterCreated(encountercreate) - encountercreate.id = id - if (!mPatient!!.isSynced) { - mPatient!!.addEncounters(encountercreate.id) - mPatient!!.id?.let { PatientDAO().updatePatient(it, mPatient) } - view.showToast(mContext.resources.getString(R.string.form_data_will_be_synced_later_error_message)) - view.enableSubmitButton(true) - } else { - EncounterService().addEncounter(encountercreate, object : DefaultResponseCallback { - override fun onResponse() { - view.enableSubmitButton(true) - success(mContext.getString(R.string.form_submitted_successfully)) - view.quitFormEntry() - } - - override fun onErrorResponse(errorMessage: String) { - error(errorMessage) - view.enableSubmitButton(true) - } - }) - } - } -} diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionViewModel.kt b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionViewModel.kt new file mode 100644 index 000000000..02e1e1295 --- /dev/null +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/formadmission/FormAdmissionViewModel.kt @@ -0,0 +1,146 @@ +package org.openmrs.mobile.activities.formadmission + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.SavedStateHandle +import com.openmrs.android_sdk.library.api.repository.EncounterRepository +import com.openmrs.android_sdk.library.api.repository.FormRepository +import com.openmrs.android_sdk.library.api.repository.ProviderRepository +import com.openmrs.android_sdk.library.dao.PatientDAO +import com.openmrs.android_sdk.library.databases.entities.LocationEntity +import com.openmrs.android_sdk.library.models.EncounterProviderCreate +import com.openmrs.android_sdk.library.models.Encountercreate +import com.openmrs.android_sdk.library.models.Patient +import com.openmrs.android_sdk.library.models.Provider +import com.openmrs.android_sdk.library.models.Resource +import com.openmrs.android_sdk.library.models.ResultType +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.ENCOUNTERTYPE +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.FORM_NAME +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.PATIENT_ID_BUNDLE +import com.openmrs.android_sdk.utilities.ApplicationConstants.LOCATION +import com.openmrs.android_sdk.utilities.execute +import dagger.hilt.android.lifecycle.HiltViewModel +import org.openmrs.mobile.activities.BaseViewModel +import rx.Observable +import rx.android.schedulers.AndroidSchedulers +import javax.inject.Inject + +@HiltViewModel +class FormAdmissionViewModel @Inject constructor( + private val patientDAO: PatientDAO, + private val formRepository: FormRepository, + private val encounterRepository: EncounterRepository, + private val providerRepository: ProviderRepository, + private val savedStateHandle: SavedStateHandle +) : BaseViewModel() { + + /* UI */ + var providerListPosition: Int = 0 + var encounterRoleListPosition: Int = 0 + var targetLocationListPosition: Int = 0 + + private val patientId: Long = savedStateHandle.get(PATIENT_ID_BUNDLE)!! + private val encounterType: String = savedStateHandle.get(ENCOUNTERTYPE)!! + private val formName: String = savedStateHandle.get(FORM_NAME)!! + private val currentLocation: String = savedStateHandle.get(LOCATION)!! + + val patient: Patient = patientDAO.findPatientByID(patientId.toString()) + + /* Lists of form fields */ + var providers: LinkedHashMap = linkedMapOf() + private set + var encounterRoles: LinkedHashMap = linkedMapOf() + private set + var targetLocations: LinkedHashMap = linkedMapOf() + private set + + /* UUIDs of the selected items in form lists */ + var providerUuid: String? = null + private set + var encounterRoleUuid: String? = null + private set + var targetLocationUuid: String? = null + private set + + private val listsObservables + get() = listOf( + providerRepository.getProviders().map { list -> + providers = LinkedHashMap().apply { + list.forEach { put(it.display!!, it) } + } + }, + providerRepository.getEncounterRoles().map { list -> + encounterRoles = LinkedHashMap().apply { + list.forEach { put(it.display!!, it) } + } + }, + providerRepository.getLocations(currentLocation).map { list -> + targetLocations = LinkedHashMap().apply { + list.forEach { put(it.display!!, it) } + } + } + ) + + + init { + fetchFormFields() + } + + private fun fetchFormFields() { + setLoading() + addSubscription(Observable.merge(listsObservables) + .observeOn(AndroidSchedulers.mainThread()) + .doOnCompleted { + if (providers.isNotEmpty() && encounterRoles.isNotEmpty() && targetLocations.isNotEmpty()) { + setContent(Unit) + } else { + setError(Throwable("Some form field lists are empty")) + } + } + .subscribe({}, { + clearSubscriptions() + setError(it) + }) + ) + } + + fun selectProvider(providerName: String, listPosition: Int) { + providerListPosition = listPosition + providerUuid = providers[providerName]!!.uuid + } + + fun selectEncounterRole(roleName: String, listPosition: Int) { + encounterRoleListPosition = listPosition + encounterRoleUuid = encounterRoles[roleName]!!.uuid + } + + fun selectTargetLocation(locationName: String, listPosition: Int) { + targetLocationListPosition = listPosition + targetLocationUuid = targetLocations[locationName]!!.uuid + } + + fun submitAdmission(): LiveData { + val resultLiveData = MutableLiveData() + + addSubscription(Observable.fromCallable { + val enc = Encountercreate() + enc.patient = patient.uuid + enc.encounterType = encounterType + enc.formname = formName + enc.patientId = patientId + enc.formUuid = formRepository.fetchFormResourceByName(formName).execute().uuid + enc.location = targetLocationUuid + enc.encounterProvider = listOf(EncounterProviderCreate(providerUuid!!, encounterRoleUuid!!)) + return@fromCallable enc + } + .flatMap { encounterCreate -> encounterRepository.saveEncounter(encounterCreate) } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + { resultLiveData.value = it }, + { resultLiveData.value = ResultType.EncounterSubmissionError } + ) + ) + + return resultLiveData + } +} diff --git a/openmrs-client/src/main/java/org/openmrs/mobile/activities/providermanagerdashboard/ProviderManagerDashboardPresenter.java b/openmrs-client/src/main/java/org/openmrs/mobile/activities/providermanagerdashboard/ProviderManagerDashboardPresenter.java index f6bd132a4..6fe4e4f95 100644 --- a/openmrs-client/src/main/java/org/openmrs/mobile/activities/providermanagerdashboard/ProviderManagerDashboardPresenter.java +++ b/openmrs-client/src/main/java/org/openmrs/mobile/activities/providermanagerdashboard/ProviderManagerDashboardPresenter.java @@ -14,19 +14,21 @@ package org.openmrs.mobile.activities.providermanagerdashboard; -import androidx.fragment.app.Fragment; +import java.util.List; -import com.openmrs.android_sdk.library.models.Provider; -import com.openmrs.android_sdk.utilities.ToastUtil; +import rx.android.schedulers.AndroidSchedulers; + +import androidx.fragment.app.Fragment; -import org.jetbrains.annotations.NotNull; -import org.openmrs.mobile.activities.BasePresenter; import com.openmrs.android_sdk.library.api.RestApi; import com.openmrs.android_sdk.library.api.RestServiceBuilder; import com.openmrs.android_sdk.library.api.repository.ProviderRepository; import com.openmrs.android_sdk.library.listeners.retrofitcallbacks.DefaultResponseCallback; +import com.openmrs.android_sdk.library.models.Provider; +import com.openmrs.android_sdk.utilities.ToastUtil; -import java.util.List; +import org.jetbrains.annotations.NotNull; +import org.openmrs.mobile.activities.BasePresenter; public class ProviderManagerDashboardPresenter extends BasePresenter implements ProviderManagerDashboardContract.Presenter, DefaultResponseCallback { private RestApi restApi; @@ -50,7 +52,7 @@ public ProviderManagerDashboardPresenter(@NotNull ProviderManagerDashboardContra @Override public void getProviders(Fragment fragment) { - providerRepository.getProviders().observe(fragment, this::updateViews); + providerRepository.getProviders().observeOn(AndroidSchedulers.mainThread()).subscribe(this::updateViews); } @Override @@ -92,4 +94,4 @@ public void onErrorResponse(String errorMessage) { public void onResponse() { providerManagerView.refreshUI(); } -} \ No newline at end of file +} diff --git a/openmrs-client/src/main/res/layout/fragment_form_admission.xml b/openmrs-client/src/main/res/layout/fragment_form_admission.xml index c97e91761..14e1cb906 100644 --- a/openmrs-client/src/main/res/layout/fragment_form_admission.xml +++ b/openmrs-client/src/main/res/layout/fragment_form_admission.xml @@ -1,139 +1,162 @@ - - + android:layout_height="match_parent" + app:layout_constraintTop_toTopOf="parent"> - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_margin="20dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openmrs-client/src/main/res/values-hi/strings.xml b/openmrs-client/src/main/res/values-hi/strings.xml index 7efce4bcd..ac6eee0c7 100644 --- a/openmrs-client/src/main/res/values-hi/strings.xml +++ b/openmrs-client/src/main/res/values-hi/strings.xml @@ -417,8 +417,6 @@ रोगी %1$s अपडेट किया गया "रोगी %1$s को सर्वर त्रुटि के कारण समन्‍वयित नहीं किया जा सकता है " सर्वर त्रुटि के कारण रोगी की फोटो को सिंक नहीं किया जा सकता है: %1$s - रोगी अभी तक पंजीकृत नहीं है। कोई इंटरनेट कनेक्शन नहीं। प्रपत्र डेटा स्थानीय रूप से सहेजा जाता है और इंटरनेट कनेक्शन बहाल होने पर सिंक होगा। - सिंक बंद है। फ़ॉर्म डेटा सहेजने के लिए सिंक चालू करें। अज्ञात रोगी दर्ज किया गया सर्वर वर्तमान में नीचे है, कृपया एक अलग चुनें। मेनू से फॉर्म एंट्री का चयन करें @@ -431,6 +429,10 @@ ऑनलाइन वापस आने पर प्रदाता को सर्वर से हटा दिया जाएगा "ऐप से बाहर निकलने के लिए कृपया BACK पर फिर से क्लिक करें " + + सिंक बंद है। फ़ॉर्म डेटा सहेजने के लिए सिंक चालू करें। + फॉर्म जमा करने में त्रुटि + प्रवेश फार्म An error Occurred, Try Again Later !!! @@ -438,7 +440,7 @@ Please Select Required Field Admission Date : Admitted By : - Provider Role : + Provider Role : Admitted To : diff --git a/openmrs-client/src/main/res/values/strings.xml b/openmrs-client/src/main/res/values/strings.xml index dc7d67997..49b523483 100644 --- a/openmrs-client/src/main/res/values/strings.xml +++ b/openmrs-client/src/main/res/values/strings.xml @@ -392,9 +392,9 @@ Exit application - - \"Patient not yet registered. No internet connection. Form data is saved locally and will sync when internet connection is restored. \" - Sync is off. Turn on sync to save form data. + + Form submitted locally and can\'t be viewed now. Turn on sync and internet connection to upload it. + Form submission error All fields cannot be empty @@ -482,7 +482,7 @@ Please Select Required Field Admission Date : Admitted By : - Provider Role : + Encounter Role : Admitted To : Admitted To %1$s Discharged From %1$s diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/ACUnitTestBase.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/ACUnitTestBase.java index 61ce8886d..469ffca23 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/ACUnitTestBase.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/ACUnitTestBase.java @@ -14,7 +14,7 @@ package org.openmrs.mobile.test; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import java.util.ArrayList; @@ -71,9 +71,9 @@ public void initMocks() { } protected void mockActiveAndroidContext() { - Context context = PowerMockito.mock(Context.class); - ContentResolver resolver = PowerMockito.mock(ContentResolver.class); - ContentValues vals = PowerMockito.mock(ContentValues.class); + Context context = Mockito.mock(Context.class); + ContentResolver resolver = Mockito.mock(ContentResolver.class); + ContentValues vals = Mockito.mock(ContentValues.class); try { PowerMockito.whenNew(ContentValues.class).withNoArguments().thenReturn(vals); @@ -154,6 +154,7 @@ protected Provider createProvider(Long id, String identifier) { provider.setUuid(id.toString()); provider.setRetired(false); provider.setIdentifier(identifier); + provider.setDisplay(identifier); return provider; } diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/ResourceSerializerTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/ResourceSerializerTest.java index 1eaf33eea..4fc93c0ac 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/ResourceSerializerTest.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/ResourceSerializerTest.java @@ -14,6 +14,17 @@ package org.openmrs.mobile.test; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsNot.not; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; import com.openmrs.android_sdk.library.databases.entities.LocationEntity; import com.openmrs.android_sdk.library.models.IdentifierType; import com.openmrs.android_sdk.library.models.Patient; @@ -21,23 +32,12 @@ import com.openmrs.android_sdk.library.models.PersonName; import com.openmrs.android_sdk.utilities.DateUtils; import com.openmrs.android_sdk.utilities.ResourceSerializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import java.util.Arrays; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.IsNot.not; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.Silent.class) public class ResourceSerializerTest { diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormAdmissionPresenterTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormAdmissionPresenterTest.java deleted file mode 100644 index a3c79ff97..000000000 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormAdmissionPresenterTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * The contents of this file are subject to the OpenMRS Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://license.openmrs.org - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - * License for the specific language governing rights and limitations - * under the License. - * - * Copyright (C) OpenMRS, LLC. All Rights Reserved. - */ - -package org.openmrs.mobile.test.presenters; - -import android.content.Context; -import android.content.res.Resources; - -import androidx.arch.core.executor.testing.InstantTaskExecutorRule; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.Observer; - -import com.openmrs.android_sdk.library.OpenMRSLogger; -import com.openmrs.android_sdk.library.OpenmrsAndroid; -import com.openmrs.android_sdk.library.dao.ProviderRoomDAO; -import com.openmrs.android_sdk.library.databases.entities.LocationEntity; -import com.openmrs.android_sdk.library.models.Provider; -import com.openmrs.android_sdk.library.models.Resource; -import com.openmrs.android_sdk.utilities.NetworkUtils; -import com.openmrs.android_sdk.utilities.ToastUtil; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.openmrs.mobile.activities.formadmission.FormAdmissionContract; -import org.openmrs.mobile.activities.formadmission.FormAdmissionFragment; -import org.openmrs.mobile.activities.formadmission.FormAdmissionPresenter; -import com.openmrs.android_sdk.library.api.RestApi; -import com.openmrs.android_sdk.library.api.repository.ProviderRepository; -import org.openmrs.mobile.application.OpenMRS; -import org.openmrs.mobile.test.ACUnitTestBase; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import io.reactivex.Single; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.RETURNS_MOCKS; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({NetworkUtils.class, ToastUtil.class, OpenMRS.class, OpenMRSLogger.class,OpenmrsAndroid.class}) -public class FormAdmissionPresenterTest extends ACUnitTestBase { - @Rule - public InstantTaskExecutorRule taskExecutorRule = new InstantTaskExecutorRule(); - MutableLiveData> providerLiveData = Mockito.mock(MutableLiveData.class); - List providerList; - List resourceList; - List locationList; - Provider providerOne = createProvider(1l, "doctor"); - Provider providerTwo = createProvider(2l, "nurse"); - LocationEntity locationEntityOne = new LocationEntity("entity 1"); - LocationEntity locationEntityTwo = new LocationEntity("entity 2"); - Resource resourceOne = new Resource("uuid", "display", new ArrayList<>(), 1L); - Resource resourceTwo = new Resource("uuid 2", "display 2", new ArrayList<>(), 2L); - @Mock - private RestApi restApi; - @Mock - private FormAdmissionContract.View formAdmissionView; - @Mock - private Observer> observer; - @Mock - private Observer> locationObserver; - @Mock - private Observer> resourceObserver; - @Mock - private OpenMRSLogger openMRSLogger; - @Mock - private OpenMRS openMRS; - @Mock - private Context context; - @Mock - private Resources resources; - private FormAdmissionPresenter formAdmissionPresenter; - private ProviderRepository providerRepository; - private FormAdmissionFragment fragment = new FormAdmissionFragment(); - - @Before - public void setUp() { - mockStaticMethods(); - providerList = Arrays.asList(providerOne, providerTwo); - locationList = Arrays.asList(locationEntityOne, locationEntityTwo); - resourceList = Arrays.asList(resourceOne, resourceTwo); - providerLiveData.postValue(providerList); - - this.providerRepository = new ProviderRepository(restApi, openMRSLogger); - ProviderRoomDAO providerRoomDao = Mockito.mock(ProviderRoomDAO.class, RETURNS_MOCKS); - ProviderRoomDAO spyProviderRoomDao = spy(providerRoomDao); - - Single listSingle = Mockito.mock(Single.class); - doNothing().when(spyProviderRoomDao).updateProviderByUuid(Mockito.anyString(), Mockito.anyLong(), Mockito.any(), Mockito.anyString(), Mockito.anyString()); - when(spyProviderRoomDao.getProviderList()).thenReturn(listSingle); - when(listSingle.blockingGet()).thenReturn(providerList); - - this.providerRepository.setProviderRoomDao(spyProviderRoomDao); - - formAdmissionPresenter = new FormAdmissionPresenter(formAdmissionView, restApi, context, openMRSLogger); - } - - @Test - public void shouldGetProviders_AllOK() { - Mockito.lenient().when(NetworkUtils.isOnline()).thenReturn(true); - Mockito.lenient().when(restApi.getProviderList()).thenReturn(mockSuccessCall(providerList)); - - formAdmissionPresenter.updateViews(providerList); - providerRepository.getProviders().observeForever(observer); - - verify(restApi).getProviderList(); - verify(formAdmissionView).updateProviderAdapter(providerList); - } - - @Test - public void shouldGetProviders_Error() { - Mockito.lenient().when(NetworkUtils.isOnline()).thenReturn(true); - Mockito.lenient().when(restApi.getProviderList()).thenReturn(mockErrorCall(401)); - - providerRepository.getProviders().observeForever(observer); - verify(restApi).getProviderList(); - } - - @Test - public void shouldGetAdmissionLocation_AllOK() { - Mockito.lenient().when(NetworkUtils.hasNetwork()).thenReturn(true); - Mockito.lenient().when(restApi.getLocations(any(), anyString(), anyString())) - .thenReturn(mockSuccessCall(locationList)); - formAdmissionPresenter.updateLocationList(locationList); - providerRepository.getLocation("some url").observeForever(locationObserver); - verify(formAdmissionView).updateLocationAdapter(locationList); - } - - @Test - public void shouldLoadLocations_errorResponse() { - Mockito.lenient().when(NetworkUtils.hasNetwork()).thenReturn(true); - Mockito.lenient().when(restApi.getLocations(any(), anyString(), anyString())) - .thenReturn(mockErrorCall(401)); - - Resources res = Mockito.mock(context.getResources().getClass()); - PowerMockito.when(context.getResources()).thenReturn(res); - Mockito.when(res.getString(Mockito.anyInt())).thenReturn("error_message"); - - formAdmissionPresenter.updateLocationList(null); - providerRepository.getLocation("some url").observeForever(locationObserver); - verify(formAdmissionView).showToast(anyString()); - verify(formAdmissionView).enableSubmitButton(false); - } - - @Test - public void shouldGetEncounterRoles_AllOK() { - Mockito.lenient().when(NetworkUtils.hasNetwork()).thenReturn(true); - Mockito.lenient().when(restApi.getEncounterRoles()) - .thenReturn(mockSuccessCall(resourceList)); - formAdmissionPresenter.updateEncounterRoles(resourceList); - providerRepository.getEncounterRoles().observeForever(resourceObserver); - verify(formAdmissionView).updateEncounterRoleList(resourceList); - } - - @Test - public void shouldLoadEncounterRoles_errorResponse() { - Mockito.lenient().when(NetworkUtils.hasNetwork()).thenReturn(true); - Mockito.lenient().when(restApi.getEncounterRoles()) - .thenReturn(mockErrorCall(401)); - - Resources res = Mockito.mock(context.getResources().getClass()); - PowerMockito.when(context.getResources()).thenReturn(res); - Mockito.when(res.getString(Mockito.anyInt())).thenReturn("error_message"); - - formAdmissionPresenter.updateEncounterRoles(null); - providerRepository.getEncounterRoles().observeForever(resourceObserver); - verify(formAdmissionView).showToast(anyString()); - verify(formAdmissionView).enableSubmitButton(false); - } - - private void mockStaticMethods() { - PowerMockito.mockStatic(NetworkUtils.class); - PowerMockito.mockStatic(OpenMRS.class); - PowerMockito.mockStatic(OpenMRSLogger.class); - PowerMockito.mockStatic(OpenmrsAndroid.class); - Mockito.lenient().when(OpenMRS.getInstance()).thenReturn(openMRS); - PowerMockito.mockStatic(ToastUtil.class); - PowerMockito.when(OpenmrsAndroid.getOpenMRSLogger()).thenReturn(openMRSLogger); - PowerMockito.when(context.getApplicationContext()).thenReturn(context); - PowerMockito.when(context.getResources()).thenReturn(resources); - } -} diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormDisplayPagePresenterTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormDisplayPagePresenterTest.java index 22e1725b8..cb7380326 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormDisplayPagePresenterTest.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/FormDisplayPagePresenterTest.java @@ -14,6 +14,11 @@ package org.openmrs.mobile.test.presenters; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.List; + import android.widget.LinearLayout; import com.openmrs.android_sdk.library.models.Page; @@ -22,6 +27,7 @@ import com.openmrs.android_sdk.library.models.Section; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; @@ -29,14 +35,8 @@ import org.openmrs.mobile.activities.formdisplay.FormDisplayPagePresenter; import org.openmrs.mobile.application.OpenMRS; import org.openmrs.mobile.test.ACUnitTestBase; -import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.verify; - @PrepareForTest({OpenMRS.class}) public class FormDisplayPagePresenterTest extends ACUnitTestBase { @@ -51,11 +51,15 @@ public class FormDisplayPagePresenterTest extends ACUnitTestBase { private String sectionLabel = "section label"; private String questionLabel = "question label"; + @BeforeClass + public static void beforeClass() { + Mockito.mockStatic(OpenMRS.class); + } + @Before public void setUp() { presenter = new FormDisplayPagePresenter(mFormDisplayPageView, mPage); - PowerMockito.mockStatic(OpenMRS.class); - PowerMockito.when(OpenMRS.getInstance()).thenReturn(openMRS); + Mockito.when(OpenMRS.getInstance()).thenReturn(openMRS); } @Test diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/LoginPresenterTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/LoginPresenterTest.java index 34946cfd2..e54b31350 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/LoginPresenterTest.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/LoginPresenterTest.java @@ -14,10 +14,24 @@ package org.openmrs.mobile.test.presenters; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import java.util.ArrayList; +import java.util.Collections; + +import rx.Observable; import android.content.Context; import com.openmrs.android_sdk.library.OpenMRSLogger; import com.openmrs.android_sdk.library.OpenmrsAndroid; +import com.openmrs.android_sdk.library.api.RestApi; +import com.openmrs.android_sdk.library.api.RestServiceBuilder; +import com.openmrs.android_sdk.library.api.repository.VisitRepository; import com.openmrs.android_sdk.library.dao.EncounterDAO; import com.openmrs.android_sdk.library.dao.LocationDAO; import com.openmrs.android_sdk.library.dao.VisitDAO; @@ -29,38 +43,25 @@ import com.openmrs.android_sdk.utilities.NetworkUtils; import com.openmrs.android_sdk.utilities.StringUtils; +import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mindrot.jbcrypt.BCrypt; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; import org.openmrs.mobile.R; import org.openmrs.mobile.activities.login.LoginContract; import org.openmrs.mobile.activities.login.LoginFragment; import org.openmrs.mobile.activities.login.LoginPresenter; -import com.openmrs.android_sdk.library.api.RestApi; -import com.openmrs.android_sdk.library.api.RestServiceBuilder; -import org.openmrs.mobile.services.UserService; -import com.openmrs.android_sdk.library.api.repository.VisitRepository; import org.openmrs.mobile.application.OpenMRS; import org.openmrs.mobile.net.AuthorizationManager; +import org.openmrs.mobile.services.UserService; import org.openmrs.mobile.test.ACUnitTestBaseRx; -import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; -import java.util.ArrayList; -import java.util.Collections; - -import rx.Observable; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - @PrepareForTest({OpenMRS.class, NetworkUtils.class, LocationDAO.class, RestServiceBuilder.class, StringUtils.class,OpenmrsAndroid.class}) @PowerMockIgnore("javax.net.ssl.*") @@ -85,13 +86,36 @@ public class LoginPresenterTest extends ACUnitTestBaseRx { private UserService userService; private LoginPresenter presenter; + MockedStatic mockedStatic; + + @BeforeClass + public static void setup() { + Mockito.mockStatic(OpenMRS.class); + Mockito.mockStatic(LocationDAO.class); + Mockito.mockStatic(StringUtils.class); + Mockito.mockStatic(NetworkUtils.class); + Mockito.mockStatic(OpenmrsAndroid.class); + } + @Before public void setUp() { super.setUp(); VisitRepository visitRepository = new VisitRepository(openMRSLogger, restApi, visitDAO, locationDAO, encounterDAO); presenter = new LoginPresenter(restApi, visitRepository, locationDAO, userService, view, openMRS, openMRSLogger, authorizationManager); - mockStaticMethods(); + + Mockito.lenient().when(OpenmrsAndroid.getServerUrl()).thenReturn("http://www.some_server_url.com"); + Mockito.lenient().when(OpenmrsAndroid.getHashedPassword()).thenReturn(ApplicationConstants.EMPTY_STRING); + Mockito.when(OpenMRS.getInstance()).thenReturn(openMRS); + mockedStatic = Mockito.mockStatic(RestServiceBuilder.class); + Mockito.when(RestServiceBuilder.createService(any(), any(), any())).thenReturn(restApi); + } + + @Override + @After + public void tearDown() { + super.tearDown(); + mockedStatic.close(); } @Test @@ -272,10 +296,9 @@ public void shouldLoadLocationsInOfflineMode_nonEmptyList() { @Test public void shouldStartFormListServiceWhenAuthenticated() { - Context context = PowerMockito.mock(Context.class); - PowerMockito.mockStatic(OpenMRS.class); - PowerMockito.when(OpenMRS.getInstance()).thenReturn(openMRS); - PowerMockito.when(openMRS.getApplicationContext()).thenReturn(context); + Context context = Mockito.mock(Context.class); + Mockito.when(OpenMRS.getInstance()).thenReturn(openMRS); + Mockito.when(openMRS.getApplicationContext()).thenReturn(context); LoginFragment loginFragment = LoginFragment.newInstance(); try { loginFragment.userAuthenticated(); @@ -286,15 +309,15 @@ public void shouldStartFormListServiceWhenAuthenticated() { } private void mockNetworkConnection(boolean isNetwork) { - PowerMockito.when(NetworkUtils.hasNetwork()).thenReturn(isNetwork); + Mockito.when(NetworkUtils.hasNetwork()).thenReturn(isNetwork); } private void mockNonEmptyCredentials(boolean isNonEmpty) { - PowerMockito.when(StringUtils.notEmpty(anyString())).thenReturn(isNonEmpty); + Mockito.when(StringUtils.notEmpty(anyString())).thenReturn(isNonEmpty); } private void mockOnlineMode(boolean isOnline) { - PowerMockito.when(NetworkUtils.isOnline()).thenReturn(isOnline); + Mockito.when(NetworkUtils.isOnline()).thenReturn(isOnline); } private void mockLastUser(String user, String password, String url) { @@ -303,17 +326,4 @@ private void mockLastUser(String user, String password, String url) { Mockito.lenient().when(OpenmrsAndroid.getPassword()).thenReturn(password); Mockito.lenient().when(OpenmrsAndroid.getHashedPassword()).thenReturn(BCrypt.hashpw(password, BCrypt.gensalt(ApplicationConstants.DEFAULT_BCRYPT_ROUND))); } - - private void mockStaticMethods() { - PowerMockito.mockStatic(OpenMRS.class); - PowerMockito.mockStatic(LocationDAO.class); - PowerMockito.mockStatic(StringUtils.class); - PowerMockito.mockStatic(NetworkUtils.class); - PowerMockito.mockStatic(OpenmrsAndroid.class); - Mockito.lenient().when(OpenmrsAndroid.getServerUrl()).thenReturn("http://www.some_server_url.com"); - Mockito.lenient().when(OpenmrsAndroid.getHashedPassword()).thenReturn(ApplicationConstants.EMPTY_STRING); - PowerMockito.when(OpenMRS.getInstance()).thenReturn(openMRS); - PowerMockito.mockStatic(RestServiceBuilder.class); - PowerMockito.when(RestServiceBuilder.createService(any(), any(), any())).thenReturn(restApi); - } } diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/ProviderManagerDashboardPresenterTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/ProviderManagerDashboardPresenterTest.java index 9d8ec085f..8193c69d6 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/ProviderManagerDashboardPresenterTest.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/presenters/ProviderManagerDashboardPresenterTest.java @@ -14,6 +14,16 @@ package org.openmrs.mobile.test.presenters; +import static org.mockito.Mockito.RETURNS_MOCKS; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import androidx.arch.core.executor.testing.InstantTaskExecutorRule; import androidx.fragment.app.Fragment; import androidx.lifecycle.MutableLiveData; @@ -21,6 +31,8 @@ import com.openmrs.android_sdk.library.OpenMRSLogger; import com.openmrs.android_sdk.library.OpenmrsAndroid; +import com.openmrs.android_sdk.library.api.RestApi; +import com.openmrs.android_sdk.library.api.repository.ProviderRepository; import com.openmrs.android_sdk.library.dao.ProviderRoomDAO; import com.openmrs.android_sdk.library.models.Provider; import com.openmrs.android_sdk.utilities.NetworkUtils; @@ -33,23 +45,11 @@ import org.mockito.Mockito; import org.openmrs.mobile.activities.providermanagerdashboard.ProviderManagerDashboardContract; import org.openmrs.mobile.activities.providermanagerdashboard.ProviderManagerDashboardPresenter; -import com.openmrs.android_sdk.library.api.RestApi; -import com.openmrs.android_sdk.library.api.repository.ProviderRepository; import org.openmrs.mobile.application.OpenMRS; import org.openmrs.mobile.test.ACUnitTestBase; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.mockito.Mockito.RETURNS_MOCKS; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @PrepareForTest({NetworkUtils.class, ToastUtil.class, OpenMRS.class, OpenMRSLogger.class,OpenmrsAndroid.class}) public class ProviderManagerDashboardPresenterTest extends ACUnitTestBase { @Rule @@ -104,7 +104,7 @@ public void shouldGetProviders_AllOK() { when(restApi.getProviderList()).thenReturn(mockSuccessCall(providerList)); providerManagerDashboardPresenter.updateViews(providerList); - providerRepository.getProviders().observeForever(observer); + //providerRepository.getProviders().observeForever(observer); verify(restApi).getProviderList(); verify(providerManagerView).updateAdapter(providerList); diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormAdmissionViewModelTest.kt b/openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormAdmissionViewModelTest.kt new file mode 100644 index 000000000..b0a62d893 --- /dev/null +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormAdmissionViewModelTest.kt @@ -0,0 +1,143 @@ +package org.openmrs.mobile.test.viewmodels + +import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import androidx.lifecycle.SavedStateHandle +import com.openmrs.android_sdk.library.api.repository.EncounterRepository +import com.openmrs.android_sdk.library.api.repository.FormRepository +import com.openmrs.android_sdk.library.api.repository.ProviderRepository +import com.openmrs.android_sdk.library.dao.PatientDAO +import com.openmrs.android_sdk.library.databases.entities.FormResourceEntity +import com.openmrs.android_sdk.library.databases.entities.LocationEntity +import com.openmrs.android_sdk.library.models.Patient +import com.openmrs.android_sdk.library.models.Resource +import com.openmrs.android_sdk.library.models.ResultType.EncounterSubmissionError +import com.openmrs.android_sdk.library.models.ResultType.EncounterSubmissionSuccess +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.ENCOUNTERTYPE +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.FORM_NAME +import com.openmrs.android_sdk.utilities.ApplicationConstants.BundleKeys.PATIENT_ID_BUNDLE +import com.openmrs.android_sdk.utilities.ApplicationConstants.LOCATION +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.Mockito.anyString +import org.mockito.kotlin.any +import org.openmrs.mobile.activities.formadmission.FormAdmissionViewModel +import org.openmrs.mobile.test.ACUnitTestBaseRx +import rx.Observable +import java.util.ArrayList + +@RunWith(JUnit4::class) +class FormAdmissionViewModelTest : ACUnitTestBaseRx() { + + @get:Rule + val instantTaskExecutorRule = InstantTaskExecutorRule() + + @Mock + lateinit var patientDAO: PatientDAO + + @Mock + lateinit var formRepository: FormRepository + + @Mock + lateinit var encounterRepository: EncounterRepository + + @Mock + lateinit var providerRepository: ProviderRepository + + lateinit var savedStateHandle: SavedStateHandle + + lateinit var viewModel: FormAdmissionViewModel + + private val providerList = listOf( + createProvider(1L, "doctor"), + createProvider(2L, "nurse") + ) + private val encounterRoleList = listOf( + Resource("uuid", "display", ArrayList(), 1L), + Resource("uuid 2", "display 2", ArrayList(), 2L) + ) + private val targetLocationList = listOf( + LocationEntity("entity 1"), + LocationEntity("entity 2") + ) + private val formResource = FormResourceEntity().apply { uuid = "UUUUU" } + + @Before + override fun setUp() { + super.setUp() + savedStateHandle = SavedStateHandle().apply { + set(PATIENT_ID_BUNDLE, 88L) + set(ENCOUNTERTYPE, "test encounter type") + set(FORM_NAME, "test form name") + set(LOCATION, "test location") + } + + initObservables() + + viewModel = FormAdmissionViewModel(patientDAO, formRepository, encounterRepository, + providerRepository, savedStateHandle) + } + + private fun initObservables() { + `when`(patientDAO.findPatientByID(anyString())).thenReturn(Patient()) + `when`(providerRepository.getProviders()).thenReturn(Observable.just(providerList)) + `when`(providerRepository.getEncounterRoles()).thenReturn(Observable.just(encounterRoleList)) + `when`(providerRepository.getLocations(anyString())).thenReturn(Observable.just(targetLocationList)) + `when`(formRepository.fetchFormResourceByName(anyString())).thenReturn(Observable.just(formResource)) + } + + @Test + fun selectProvider() { + val position = 0 + val provider = providerList[position] + + viewModel.selectProvider(providerName = provider.display!!, listPosition = position) + + assertEquals(position, viewModel.providerListPosition) + assertEquals(provider.uuid, viewModel.providerUuid) + } + + @Test + fun selectEncounterRole() { + val position = 0 + val encounter = encounterRoleList[position] + + viewModel.selectEncounterRole(roleName = encounter.display!!, listPosition = position) + + assertEquals(position, viewModel.encounterRoleListPosition) + assertEquals(encounter.uuid, viewModel.encounterRoleUuid) + } + + @Test + fun selectTargetLocation() { + val position = 0 + val targetLocation = targetLocationList[position] + + viewModel.selectTargetLocation(locationName = targetLocation.display!!, listPosition = position) + + assertEquals(position, viewModel.targetLocationListPosition) + assertEquals(targetLocation.uuid, viewModel.targetLocationUuid) + } + + @Test + fun submitAdmission() { + viewModel.selectProvider(providerList[0].display!!, 0) + viewModel.selectEncounterRole(encounterRoleList[0].display!!, 0) + viewModel.selectTargetLocation(targetLocationList[0].display!!, 0) + + `when`(encounterRepository.saveEncounter(any())).thenReturn(Observable.just(EncounterSubmissionSuccess)) + viewModel.submitAdmission().observeForever { result -> + assertEquals(EncounterSubmissionSuccess, result) + } + + `when`(encounterRepository.saveEncounter(any())).thenReturn(Observable.just(EncounterSubmissionError)) + viewModel.submitAdmission().observeForever { result -> + assertEquals(EncounterSubmissionError, result) + } + } +} diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/activities/formlist/FormListViewModelTest.kt b/openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormListViewModelTest.kt similarity index 97% rename from openmrs-client/src/test/java/org/openmrs/mobile/activities/formlist/FormListViewModelTest.kt rename to openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormListViewModelTest.kt index 6764089ac..8a36960cc 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/activities/formlist/FormListViewModelTest.kt +++ b/openmrs-client/src/test/java/org/openmrs/mobile/test/viewmodels/FormListViewModelTest.kt @@ -1,4 +1,4 @@ -package org.openmrs.mobile.activities.formlist +package org.openmrs.mobile.test.viewmodels import androidx.arch.core.executor.testing.InstantTaskExecutorRule import com.google.gson.Gson @@ -17,6 +17,7 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.Mockito.`when` +import org.openmrs.mobile.activities.formlist.FormListViewModel import org.openmrs.mobile.test.ACUnitTestBaseRx import rx.Observable diff --git a/openmrs-client/src/test/java/org/openmrs/mobile/utilities/DateUtilsTest.java b/openmrs-client/src/test/java/org/openmrs/mobile/utilities/DateUtilsTest.java index 959edb267..1e0a95787 100644 --- a/openmrs-client/src/test/java/org/openmrs/mobile/utilities/DateUtilsTest.java +++ b/openmrs-client/src/test/java/org/openmrs/mobile/utilities/DateUtilsTest.java @@ -14,6 +14,18 @@ package org.openmrs.mobile.utilities; + import static junit.framework.Assert.assertFalse; + import static junit.framework.TestCase.assertTrue; + import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertNotSame; + import static org.junit.Assert.assertNull; + import static org.mockito.Mockito.when; + + import java.text.SimpleDateFormat; + import java.util.Date; + import java.util.Locale; + import java.util.TimeZone; + import android.content.res.Resources; import com.openmrs.android_sdk.utilities.DateUtils; @@ -23,29 +35,15 @@ import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.junit.Before; + import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; - import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; + import org.mockito.Mockito; import org.openmrs.mobile.application.OpenMRS; - import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; - import org.powermock.modules.junit4.PowerMockRunner; - - import java.text.SimpleDateFormat; - import java.util.Date; - import java.util.Locale; - import java.util.TimeZone; - - import static junit.framework.Assert.assertFalse; - import static junit.framework.TestCase.assertTrue; - import static org.junit.Assert.assertEquals; - import static org.junit.Assert.assertNotSame; - import static org.junit.Assert.assertNull; - import static org.powermock.api.mockito.PowerMockito.when; - @RunWith(PowerMockRunner.class) @PrepareForTest({OpenMRS.class, Resources.class}) public class DateUtilsTest { private static final String TEST_TIMEZONE; @@ -126,9 +124,13 @@ public class DateUtilsTest { @Rule public TimeZoneRule timeZoneRule = new TimeZoneRule(TimeZone.getTimeZone("PST8PDT")); + @BeforeClass + public static void beforeClass() { + Mockito.mockStatic(OpenMRS.class); + } + @Before public void setUp() { - PowerMockito.mockStatic(OpenMRS.class); when(OpenMRS.getInstance()).thenReturn(openMRS); Locale.setDefault(Locale.US); TimeZone.setDefault(TimeZone.getTimeZone(TEST_TIMEZONE));