diff --git a/.gitignore b/.gitignore index 11dbe9dc3..fab06d91c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,5 @@ target/ tmp/ opensrp-giz-malawi/debug/ opensrp-giz-malawi/preview/ +opensrp-giz-malawi/releaseDebug/ *google-services.json \ No newline at end of file diff --git a/README.md b/README.md index 31f8e529a..cd75a5ad4 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ These instructions will get you a copy of the project up and running on your loc ## Prerequisites [Tools and Frameworks Setup](https://smartregister.atlassian.net/wiki/spaces/Documentation/pages/6619207/Tools+and+Frameworks+Setup) -## Development setup - ### Steps to set up -[OpenSRP android client app build](https://smartregister.atlassian.net/wiki/spaces/Documentation/pages/6619236/OpenSRP+App+Build) +- [OpenSRP android client app build](https://smartregister.atlassian.net/wiki/spaces/Documentation/pages/6619236/OpenSRP+App+Build) +- Add the client-id and client-secret values for the three environments i.e. stage, preview and production. Add these values to the `local.properties` as `client.id.[stage|preview|production]` and `client.secret.[stage|preview|production]`. +- Add the `google-services.json` to `opensrp-client-giz-malawi/opensrp-giz-malawi` ### Running the tests diff --git a/build.gradle b/build.gradle index c7334cc60..94191f599 100644 --- a/build.gradle +++ b/build.gradle @@ -39,8 +39,8 @@ subprojects { ext.androidToolsBuildGradle = '4.0.1' ext.androidBuildToolsVersion = '29.0.3' ext.androidMinSdkVersion = 18 - ext.androidCompileSdkVersion = 29 - ext.androidTargetSdkVersion = 29 + ext.androidCompileSdkVersion = 31 + ext.androidTargetSdkVersion = 31 ext.androidAnnotationsVersion = '3.0.1' ext.androidAnnotationsAPIVersion = '3.0.1' diff --git a/opensrp-giz-malawi/build.gradle b/opensrp-giz-malawi/build.gradle index 0273facee..b8d9a2ea8 100644 --- a/opensrp-giz-malawi/build.gradle +++ b/opensrp-giz-malawi/build.gradle @@ -25,6 +25,30 @@ jacoco { toolVersion = jacocoVersion } +Properties properties = new Properties() +if (project.rootProject.file("local.properties").exists()) { + properties.load(project.rootProject.file("local.properties").newDataInputStream()) +} else{ + project.logger.error("local.properties file does not exist") +} + +ext.getLocalProperty = { key -> + if (properties != null && properties.containsKey(key)) { + return properties[key] + } else { + project.logger.error(key + " could not be found. Setting it to an empty string") + return "\"\"" + } +} + + +ext.checkKeys = { keys -> + keys.each { key -> + if (properties == null || !properties.containsKey(key)) { + project.logger.error(key + " is missing from the local.properties") + } + } +} android { useLibrary 'org.apache.http.legacy' @@ -35,8 +59,8 @@ android { applicationId "org.smartregister.giz" minSdkVersion androidMinSdkVersion targetSdkVersion androidTargetSdkVersion - versionCode 46 - versionName "0.4.6" + versionCode 49 + versionName "0.4.9" multiDexEnabled true buildConfigField "long", "MAX_SERVER_TIME_DIFFERENCE", "1800000l" buildConfigField "boolean", "TIME_CHECK", "false" @@ -50,34 +74,7 @@ android { testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' - if (project.rootProject.file("local.properties").exists()) { - - Properties properties = new Properties() - properties.load(project.rootProject.file("local.properties").newDataInputStream()) - - if (properties != null && properties.containsKey("oauth.client.id")) { - - buildConfigField "String", "OAUTH_CLIENT_ID", properties["oauth.client.id"] - - } else { - project.logger.error("oauth.client.id variable is not set in your local.properties") - buildConfigField "String", "OAUTH_CLIENT_ID", "\"sample_client_id\"" - } - - - if (properties != null && properties.containsKey("oauth.client.secret")) { - - buildConfigField "String", "OAUTH_CLIENT_SECRET", properties["oauth.client.secret"] - - } else { - project.logger.error("oauth.client.secret variable is not set in your local.properties") - buildConfigField "String", "OAUTH_CLIENT_SECRET", "\"sample_client_secret\"" - } - } else { - buildConfigField "String", "OAUTH_CLIENT_ID", '""' - buildConfigField "String", "OAUTH_CLIENT_SECRET", '""' - } - + checkKeys(["oauth.client.id.production", "oauth.client.secret.production", "oauth.client.id.stage", "oauth.client.secret.stage", "oauth.client.id.preview", "oauth.client.secret.preview"]) javaCompileOptions { annotationProcessorOptions { @@ -128,6 +125,10 @@ android { buildConfigField "int", "GROWTH_MONITORING_SYNC_TIME", '15' buildConfigField "String[]", "LOCATION_LEVELS", '{"Country", "Province", "District", "Facility", "Village"}' buildConfigField "String[]", "HEALTH_FACILITY_LEVELS", '{"Country", "Province", "District", "Health Facility", "Village"}' + + buildConfigField "String", "OAUTH_CLIENT_ID", getLocalProperty("oauth.client.id.production") + buildConfigField "String", "OAUTH_CLIENT_SECRET", getLocalProperty("oauth.client.secret.production") + } releaseDebug { @@ -141,7 +142,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rule.pro' resValue "string", 'opensrp_url', '"https://opensrp.health.gov.mw/opensrp/"' buildConfigField "int", "OPENMRS_UNIQUE_ID_INITIAL_BATCH_SIZE", '10' - buildConfigField "int", "OPENMRS_UNIQUE_ID_BATCH_SIZE", '10' + buildConfigField "int", "OPENMRS_UNIQUE_ID_BATCH_SIZE", '2' buildConfigField "int", "OPENMRS_UNIQUE_ID_SOURCE", '2' buildConfigField "int", "VACCINE_SYNC_TIME", '0' buildConfigField "int", "DATABASE_VERSION", '20' @@ -157,6 +158,9 @@ android { buildConfigField "int", "GROWTH_MONITORING_SYNC_TIME", '15' buildConfigField "String[]", "LOCATION_LEVELS", '{"Country", "Province", "District", "Facility", "Village"}' buildConfigField "String[]", "HEALTH_FACILITY_LEVELS", '{"Country", "Province", "District", "Health Facility", "Village"}' + + buildConfigField "String", "OAUTH_CLIENT_ID", getLocalProperty("oauth.client.id.production") + buildConfigField "String", "OAUTH_CLIENT_SECRET", getLocalProperty("oauth.client.secret.production") } preview { @@ -185,6 +189,9 @@ android { buildConfigField "int", "GROWTH_MONITORING_SYNC_TIME", '15' buildConfigField "String[]", "LOCATION_LEVELS", '{"Country", "Province", "District", "Facility", "Village"}' buildConfigField "String[]", "HEALTH_FACILITY_LEVELS", '{"Country", "Province", "District", "Health Facility", "Village"}' + + buildConfigField "String", "OAUTH_CLIENT_ID", getLocalProperty("oauth.client.id.preview") + buildConfigField "String", "OAUTH_CLIENT_SECRET", getLocalProperty("oauth.client.secret.preview") } debug { @@ -210,6 +217,22 @@ android { buildConfigField "String[]", "LOCATION_LEVELS", '{"Country", "Province", "District", "Facility", "Village"}' buildConfigField "String[]", "HEALTH_FACILITY_LEVELS", '{"Country", "Province", "District", "Health Facility", "Village"}' testCoverageEnabled true + + buildConfigField "String", "OAUTH_CLIENT_ID", getLocalProperty("oauth.client.id.stage") + buildConfigField "String", "OAUTH_CLIENT_SECRET", getLocalProperty("oauth.client.secret.stage") + } + } + + // https://stackoverflow.com/a/27119543/152938 + applicationVariants.all { variant -> + variant.outputs.all { output -> + outputFileName = new File(outputFileName.replace(".apk", "-${defaultConfig.versionName}.apk")) + } + } + + testVariants.all { variant -> + variant.outputs.all { output -> + outputFileName = new File(outputFileName.replace(".apk", "-${defaultConfig.versionName}.apk")) } } @@ -232,6 +255,8 @@ android { } configurations.all { exclude group: 'com.github.lecho', module: 'hellocharts-library' + exclude group: 'com.evernote', module: 'android-job' + } } @@ -269,7 +294,7 @@ dependencies { exclude group: 'com.android.support', module: 'appcompat-v7' } - api('org.smartregister:opensrp-client-anc:2.0.3.29-LOCAL-SNAPSHOT@aar') { + api('org.smartregister:opensrp-client-anc:2.0.3.40-LOCAL-SNAPSHOT@aar') { transitive = true exclude group: 'id.zelory', module: 'compressor' exclude group: 'org.smartregister', module: 'opensrp-client-core' @@ -277,8 +302,8 @@ dependencies { exclude group: 'org.smartregister', module: 'opensrp-client-configurable-views' exclude group: 'com.android.support', module: 'appcompat-v7' } -// - api('org.smartregister:opensrp-client-native-form:2.1.11-SNAPSHOT@aar') { + + api('org.smartregister:opensrp-client-native-form:2.1.14.1-GIZ-SNAPSHOT@aar') { transitive = true exclude group: 'id.zelory', module: 'compressor' exclude group: 'com.android.support', module: 'recyclerview-v7' @@ -325,7 +350,7 @@ dependencies { exclude group: 'com.android.support', module: 'appcompat-v7' } - api('org.smartregister:opensrp-client-immunization:4.0.6-SNAPSHOT@aar') { + api('org.smartregister:opensrp-client-immunization:4.0.7-SNAPSHOT@aar') { transitive = true exclude group: 'id.zelory', module: 'compressor' exclude group: 'org.smartregister', module: 'opensrp-client-core' @@ -376,7 +401,10 @@ dependencies { // Because RxAndroid releases are few and far between, it is recommended you also // explicitly depend on RxJava's latest version for bug fixes and new features. implementation 'io.reactivex.rxjava2:rxjava:2.1.5' - implementation 'com.evernote:android-job:1.2.6' + implementation('com.github.devv911:android-job:1.4.5') { + exclude group: 'com.google.android', module: 'android' + } + implementation 'androidx.work:work-runtime:2.7.1' implementation 'com.github.lecho:hellocharts-android:1.5.8@aar' implementation 'id.zelory:compressor:2.1.1' implementation('com.google.android.material:material:1.0.0') { @@ -404,6 +432,8 @@ dependencies { implementation "androidx.multidex:multidex:2.0.1" testImplementation "androidx.work:work-testing:2.7.1" + testImplementation 'androidx.test:runner:1.3.0' + testImplementation 'androidx.test:core:1.3.0' def robolectricVersion = '4.1' diff --git a/opensrp-giz-malawi/src/main/AndroidManifest.xml b/opensrp-giz-malawi/src/main/AndroidManifest.xml index b35bd70ca..01b8a3fc9 100644 --- a/opensrp-giz-malawi/src/main/AndroidManifest.xml +++ b/opensrp-giz-malawi/src/main/AndroidManifest.xml @@ -50,6 +50,7 @@ android:name=".activity.LoginActivity" android:screenOrientation="portrait" android:theme="@style/AppTheme.Login" + android:exported="true" android:windowSoftInputMode="stateAlwaysHidden|adjustPan"> @@ -280,17 +281,18 @@ android:theme="@style/ChildTheme.NoActionBar" tools:replace="android:theme" /> - - - - - - - - - - - + + + + + + + + + + + + (loginView); mLoginInteractor = new LoginInteractor(this); mLoginModel = new BaseLoginModel(); + } @Override diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/processor/GizMalawiProcessorForJava.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/processor/GizMalawiProcessorForJava.java index f07eb8172..56a2c15fd 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/processor/GizMalawiProcessorForJava.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/processor/GizMalawiProcessorForJava.java @@ -7,6 +7,7 @@ import androidx.annotation.VisibleForTesting; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.gson.Gson; import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; @@ -471,6 +472,8 @@ private void processEventClient(@NonNull ClientClassification clientClassificati } catch (Exception e) { Timber.e(e); } + } else { + Timber.e("Skipping processing of event %s | %s because the client is null", event.getBaseEntityId(), new Gson().toJson(event)); } } diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/recievers/GizReprocessSyncStatusReceiver.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/recievers/GizReprocessSyncStatusReceiver.java new file mode 100644 index 000000000..d7dae0e1c --- /dev/null +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/recievers/GizReprocessSyncStatusReceiver.java @@ -0,0 +1,27 @@ +package org.smartregister.giz.recievers; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import org.smartregister.giz.job.GIZClientReprocessJob; + +import timber.log.Timber; + +import static org.smartregister.receiver.SyncStatusBroadcastReceiver.EXTRA_COMPLETE_STATUS; + +public class GizReprocessSyncStatusReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Timber.d("GIZ reprocess status receiver starting"); + Bundle data = intent.getExtras(); + if (data != null) { + boolean isComplete = data.getBoolean(EXTRA_COMPLETE_STATUS, false); + if (isComplete) { + GIZClientReprocessJob.scheduleJobImmediately(GIZClientReprocessJob.TAG); + } + } + + } +} diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizChildRegisterQueryProvider.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizChildRegisterQueryProvider.java index e3af90747..22d0f2132 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizChildRegisterQueryProvider.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizChildRegisterQueryProvider.java @@ -41,7 +41,7 @@ public String getCountExecuteQuery(String mainCondition, String filters) { private String getFilter(String filters) { if (StringUtils.isNotBlank(filters)) { - return String.format(" AND " + getDemographicTable() + ".first_name like '%%%1$s%%' " + " OR " + getDemographicTable() + ".last_name like '%%%1$s%%' " + " OR " + getDemographicTable() + ".opensrp_id like '%%%1$s%%' ", filters); + return String.format(" AND ( " + getDemographicTable() + ".first_name like '%%%1$s%%' " + " OR " + getDemographicTable() + ".last_name like '%%%1$s%%' " + " OR " + getDemographicTable() + ".opensrp_id like '%%%1$s%%' ) ", filters); } return ""; } @@ -91,4 +91,16 @@ public String[] mainColumns() { getMotherDetailsTable() + ".alt_phone_number as mother_guardian_number"}; } + @Override + public String getActiveChildrenQuery() { + return "SELECT count(id) FROM " + this.getChildDetailsTable() + " INNER JOIN " + this.getDemographicTable() + " ON "+ this.getDemographicTable() + ".id = " + this.getChildDetailsTable() + ".id WHERE (" + + "date_removed" + " IS NULL AND (" + this.getChildDetailsTable() + ".inactive is NOT true OR " + this.getChildDetailsTable() + ".inactive is NULL) AND " + "is_closed" + " IS NOT '1')" + + " AND " + this.getDemographicTable() + ".is_closed IS NOT '1'"; + } + + @Override + public String getActiveChildrenIds() { + return "SELECT " + this.getChildDetailsTable() + ".id" + " FROM " + this.getChildDetailsTable() + " INNER JOIN " + this.getDemographicTable() + " ON " + this.getChildDetailsTable() + "." + "id" + " = " + this.getDemographicTable() + "." + "id" + " WHERE (" + this.getChildDetailsTable() + "." + "date_removed" + " IS NULL AND (" + this.getChildDetailsTable() + ".inactive is NOT true OR " + this.getChildDetailsTable() + ".inactive is NULL) AND " + this.getChildDetailsTable() + "." + "is_closed" + " IS NOT '1') AND " + this.getDemographicTable() + ".is_closed IS NOT '1' ORDER BY " + this.getDemographicTable() + "." + "last_interacted_with" + " DESC "; + } + } diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizEventRepository.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizEventRepository.java index ea39e4748..4b88dc99d 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizEventRepository.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizEventRepository.java @@ -5,7 +5,18 @@ import net.sqlcipher.Cursor; import net.sqlcipher.database.SQLiteDatabase; +import org.apache.commons.lang3.StringUtils; +import org.smartregister.domain.Event; +import org.smartregister.giz.application.GizMalawiApplication; +import org.smartregister.giz.util.GizUtils; import org.smartregister.repository.BaseRepository; +import org.smartregister.repository.EventClientRepository; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import timber.log.Timber; public class GizEventRepository extends BaseRepository { @@ -21,4 +32,78 @@ public boolean hasEvent(@NonNull String baseEntityId, @NonNull String eventType) } return hasEvent; } + + public HashSet processSkippedClients() { + String missingClientsFromClientRegisterQuery = "SELECT DISTINCT baseEntityId, formSubmissionId FROM event WHERE baseEntityId IN (SELECT baseEntityId FROM client WHERE baseEntityId NOT IN (SELECT DISTINCT base_entity_id FROM client_register_type)) AND eventType LIKE '%Registration%'"; + String missingClientsFromECClientQuery = "SELECT DISTINCT baseEntityId, formSubmissionId FROM event WHERE baseEntityId IN (SELECT baseEntityId FROM client WHERE baseEntityId NOT IN (SELECT DISTINCT base_entity_id FROM ec_client)) AND eventType LIKE '%Registration%'"; + HashSet formSubmissionIDs = new HashSet<>(); + HashSet baseEntityIds = new HashSet<>(); + addFormSubmissionIds(formSubmissionIDs, baseEntityIds, missingClientsFromClientRegisterQuery); + addFormSubmissionIds(formSubmissionIDs, baseEntityIds, missingClientsFromECClientQuery); + + try { + Timber.e("Found %d skipped clients", formSubmissionIDs.size()); + if (formSubmissionIDs.size() > 0) { + GizUtils.initiateEventProcessing(new ArrayList<>(formSubmissionIDs)); + } + + Timber.d("Finished reprocessing events and clients"); + } catch (Exception e) { + Timber.e(e); + } + + return baseEntityIds; + } + + protected void addFormSubmissionIds(HashSet formSubmissionIds, HashSet baseEntityIds, String query) { + SQLiteDatabase database = getReadableDatabase(); + Cursor cursor = database.rawQuery(query, null); + int formSubmissionIdColIndex = cursor.getColumnIndex("formSubmissionId"); + int baseEntityIdColIndex = cursor.getColumnIndex("baseEntityId"); + + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + do { + formSubmissionIds.add(cursor.getString(formSubmissionIdColIndex)); + baseEntityIds.add(cursor.getString(baseEntityIdColIndex)); + } while (cursor.moveToNext()); + } + + cursor.close(); + } + + public List getEventsByBaseEntityId(String baseEntityId) { + ArrayList eventsList = new ArrayList<>(); + EventClientRepository eventClientRepository = GizMalawiApplication.getInstance().eventClientRepository(); + + if (StringUtils.isBlank(baseEntityId)) { + return eventsList; + } else { + Cursor cursor = null; + + try { + cursor = this.getReadableDatabase().rawQuery("SELECT json FROM event WHERE " + + EventClientRepository.event_column.baseEntityId.name() + + " = ? ORDER BY eventDate ASC", new String[]{baseEntityId}); + + while (cursor.moveToNext()) { + String jsonEventStr = cursor.getString(0); + jsonEventStr = jsonEventStr.replaceAll("'", ""); + Event event = eventClientRepository.convert(jsonEventStr, Event.class); + + eventsList.add(event); + } + + } catch (Exception var10) { + Timber.e(var10); + } finally { + if (cursor != null) { + cursor.close(); + } + + } + + return eventsList; + } + } } diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizMalawiRepository.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizMalawiRepository.java index 0d9702084..3b925bd89 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizMalawiRepository.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/repository/GizMalawiRepository.java @@ -5,8 +5,10 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; +import net.sqlcipher.Cursor; import net.sqlcipher.database.SQLiteDatabase; +import org.apache.commons.lang3.StringUtils; import org.smartregister.AllConstants; import org.smartregister.anc.library.repository.ContactTasksRepository; import org.smartregister.anc.library.repository.PartialContactRepository; @@ -15,7 +17,10 @@ import org.smartregister.child.util.Utils; import org.smartregister.child.util.VaccineOverdueCountRepositoryHelper; import org.smartregister.configurableviews.repository.ConfigurableViewsRepository; +import org.smartregister.domain.Client; +import org.smartregister.domain.Event; import org.smartregister.domain.db.Column; +import org.smartregister.domain.db.EventClient; import org.smartregister.giz.BuildConfig; import org.smartregister.giz.application.GizMalawiApplication; import org.smartregister.giz.util.GizConstants; diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/service/ReProcessSyncIntentService.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/service/ReProcessSyncIntentService.java new file mode 100644 index 000000000..03b973a69 --- /dev/null +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/service/ReProcessSyncIntentService.java @@ -0,0 +1,95 @@ +package org.smartregister.giz.service; + +import android.app.IntentService; +import android.content.Intent; + +import androidx.annotation.Nullable; + +import org.smartregister.Context; +import org.smartregister.CoreLibrary; +import org.smartregister.domain.Client; +import org.smartregister.domain.Event; +import org.smartregister.domain.db.EventClient; +import org.smartregister.giz.application.GizMalawiApplication; +import org.smartregister.giz.repository.GizEventRepository; +import org.smartregister.giz.util.GizConstants; +import org.smartregister.repository.AllSharedPreferences; +import org.smartregister.repository.EventClientRepository; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import timber.log.Timber; + +public class ReProcessSyncIntentService extends IntentService { + + public static final String TAG = "ReProcessSyncIntentService"; + + public ReProcessSyncIntentService() + { + super(TAG); + } + + public ReProcessSyncIntentService(String name) { + super(name); + } + + @Override + protected void onHandleIntent(@Nullable Intent intent) { + GizEventRepository gizEventRepository = GizMalawiApplication.getInstance().gizEventRepository(); + HashSet clientBaseEntityIds = gizEventRepository.processSkippedClients(); + + processSkippedClientEvents(gizEventRepository, clientBaseEntityIds); + + AllSharedPreferences allSharedPreferences = Context.getInstance().allSharedPreferences(); + boolean isProcessed = allSharedPreferences.getBooleanPreference(GizConstants.Pref.DEATH_AND_OPD_CLOSE_REPROCESSED); + if (!isProcessed) { + reprocessEventsOfType("OPD Close"); + reprocessEventsOfType("Death"); + + allSharedPreferences.saveBooleanPreference(GizConstants.Pref.DEATH_AND_OPD_CLOSE_REPROCESSED, true); + } + } + + private void processSkippedClientEvents(GizEventRepository gizEventRepository, HashSet clientBaseEntityIds) { + Timber.d("Processing events for %d skipped clients", clientBaseEntityIds.size()); + EventClientRepository eventClientRepository = GizMalawiApplication.getInstance().eventClientRepository(); + + for (String clientBaseEntityId: clientBaseEntityIds) { + Client client = eventClientRepository.fetchClientByBaseEntityId(clientBaseEntityId); + if (client.getDeathdate() != null) { + continue; + } + + List eventsList = gizEventRepository.getEventsByBaseEntityId(clientBaseEntityId); + + List eventClientList = new ArrayList<>(); + Timber.d("Processing %d events for client %s", eventsList.size(), clientBaseEntityId); + + for (Event event: eventsList) { + eventClientList.add(new EventClient(event, client)); + } + + try { + GizMalawiApplication.getInstance().getClientProcessor() + .processClient(eventClientList); + } catch (Exception e) { + Timber.e(e); + } + } + } + + protected void reprocessEventsOfType(String eventType) { + EventClientRepository eventClientRepository = GizMalawiApplication.getInstance().eventClientRepository(); + ArrayList eventTypes = new ArrayList<>(); + eventTypes.add(eventType); + List opdCloseEvents = eventClientRepository.fetchEventClientsByEventTypes(eventTypes); + + try { + GizMalawiApplication.getInstance().getClientProcessor().processClient(opdCloseEvents); + } catch (Exception e) { + Timber.e(e); + } + } +} diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizConstants.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizConstants.java index e5e56fcba..69eea592b 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizConstants.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizConstants.java @@ -85,6 +85,7 @@ public interface Pref { String APP_VERSION_CODE = "APP_VERSION_CODE"; String INDICATOR_DATA_INITIALISED = "INDICATOR_DATA_INITIALISED"; String URL_VERSION = "URL_VERSION"; + String DEATH_AND_OPD_CLOSE_REPROCESSED = "DEATH_AND_OPD_CLOSE_REPROCESSED"; } public interface File { diff --git a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizUtils.java b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizUtils.java index 2dd18d044..e72a74c87 100644 --- a/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizUtils.java +++ b/opensrp-giz-malawi/src/main/java/org/smartregister/giz/util/GizUtils.java @@ -185,11 +185,14 @@ public static boolean updateClientDeath(@NonNull EventClient eventClient) { } values.put(Constants.KEY.DOD, Utils.convertDateFormat(client.getDeathdate())); values.put(Constants.KEY.DATE_REMOVED, Utils.convertDateFormat(client.getDeathdate().toDate(), Utils.DB_DF)); + values.put(Constants.KEY.IS_CLOSED, true); + AllCommonsRepository allCommonsRepository = GizMalawiApplication.getInstance().context().allCommonsRepositoryobjects(GizConstants.TABLE_NAME.ALL_CLIENTS); if (allCommonsRepository != null) { allCommonsRepository.update(GizConstants.TABLE_NAME.ALL_CLIENTS, values, client.getBaseEntityId()); allCommonsRepository.updateSearch(client.getBaseEntityId()); } + return true; } return false; diff --git a/opensrp-giz-malawi/src/test/java/org/smartregister/giz/repository/GizEventRepositoryTest.java b/opensrp-giz-malawi/src/test/java/org/smartregister/giz/repository/GizEventRepositoryTest.java new file mode 100644 index 000000000..9fef81b1a --- /dev/null +++ b/opensrp-giz-malawi/src/test/java/org/smartregister/giz/repository/GizEventRepositoryTest.java @@ -0,0 +1,92 @@ +package org.smartregister.giz.repository; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.smartregister.giz.util.GizUtils; +import org.smartregister.repository.Repository; +import org.smartregister.view.activity.DrishtiApplication; + +import net.sqlcipher.Cursor; +import net.sqlcipher.database.SQLiteDatabase; +import java.util.HashSet; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({DrishtiApplication.class}) +public class GizEventRepositoryTest { + + private GizEventRepository repository; + private static final String BASE_ENTITY_ID = "base_entity_id"; + private static final String EVENT_TYPE = "event_type"; + private static final String FORM_SUBMISSION_ID = "form_submission_id"; + + @Mock + private SQLiteDatabase sqLiteDatabase; + + @Mock + private GizUtils gizUtils; + + @Mock + private Cursor cursor; + + @Mock + private Repository baseRepository; + + @Mock + private DrishtiApplication drishtiApplication; + + @Before + public void setUp() { + repository = new GizEventRepository(); + MockitoAnnotations.initMocks(this); + PowerMockito.mockStatic(DrishtiApplication.class); + when(DrishtiApplication.getInstance()).thenReturn(drishtiApplication); + when(drishtiApplication.getRepository()).thenReturn(baseRepository); + when(baseRepository.getReadableDatabase()).thenReturn(sqLiteDatabase); + } + + @Test + public void testHasEvent(){ + when(sqLiteDatabase.query( + "event", + new String[]{"baseEntityId"}, + "baseEntityId = ? and eventType = ? ", + new String[]{BASE_ENTITY_ID, EVENT_TYPE}, + null, + null, + null, + "1" + )).thenReturn(cursor); + + when(cursor.getCount()).thenReturn(1); + + boolean hasEvent = repository.hasEvent(BASE_ENTITY_ID, EVENT_TYPE); + + assertTrue(hasEvent); + } + + + + @Test + public void testAddFormSubmissionIds() { + when(baseRepository.getReadableDatabase()).thenReturn(sqLiteDatabase); + when(sqLiteDatabase.rawQuery("query", null)).thenReturn(cursor); + when(cursor.getCount()).thenReturn(1); + when(cursor.getColumnIndex("formSubmissionId")).thenReturn(0); + when(cursor.moveToFirst()).thenReturn(true); + when(cursor.getString(0)).thenReturn("formSubmissionId"); + + HashSet formSubmissionIds = new HashSet<>(); + repository.addFormSubmissionIds(formSubmissionIds, "query"); + + assertFalse(formSubmissionIds.isEmpty()); + } +}