• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OpenSRP / opensrp-client-child / #798

pending completion
#798

Pull #302

github-actions

web-flow
Merge 67ae6b5c4 into c099d4f8b
Pull Request #302: Migrate core to 6 - Memory Leak Fixes

4929 of 9038 relevant lines covered (54.54%)

0.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.32
opensrp-child/src/main/java/org/smartregister/child/interactor/ChildRegisterInteractor.java
1
package org.smartregister.child.interactor;
2

3
import android.text.TextUtils;
4

5
import androidx.annotation.NonNull;
6
import androidx.annotation.VisibleForTesting;
7

8
import org.apache.commons.lang3.StringUtils;
9
import org.apache.commons.lang3.tuple.Triple;
10
import org.joda.time.LocalDate;
11
import org.joda.time.LocalTime;
12
import org.json.JSONException;
13
import org.json.JSONObject;
14
import org.smartregister.CoreLibrary;
15
import org.smartregister.child.ChildLibrary;
16
import org.smartregister.child.contract.ChildRegisterContract;
17
import org.smartregister.child.domain.ChildEventClient;
18
import org.smartregister.child.domain.UpdateRegisterParams;
19
import org.smartregister.child.event.ClientDirtyFlagEvent;
20
import org.smartregister.child.util.AppExecutors;
21
import org.smartregister.child.util.ChildAppProperties;
22
import org.smartregister.child.util.ChildJsonFormUtils;
23
import org.smartregister.child.util.Constants;
24
import org.smartregister.child.util.Utils;
25
import org.smartregister.clientandeventmodel.Client;
26
import org.smartregister.clientandeventmodel.Event;
27
import org.smartregister.clientandeventmodel.FormEntityConstants;
28
import org.smartregister.domain.UniqueId;
29
import org.smartregister.growthmonitoring.GrowthMonitoringLibrary;
30
import org.smartregister.growthmonitoring.domain.HeightWrapper;
31
import org.smartregister.growthmonitoring.domain.WeightWrapper;
32
import org.smartregister.immunization.ImmunizationLibrary;
33
import org.smartregister.immunization.domain.Vaccine;
34
import org.smartregister.immunization.repository.VaccineRepository;
35
import org.smartregister.repository.AllSharedPreferences;
36
import org.smartregister.repository.EventClientRepository;
37
import org.smartregister.repository.UniqueIdRepository;
38
import org.smartregister.sync.ClientProcessorForJava;
39
import org.smartregister.sync.helper.ECSyncHelper;
40
import org.smartregister.util.AppProperties;
41

42
import java.util.ArrayList;
43
import java.util.Date;
44
import java.util.List;
45
import java.util.Map;
46

47
import timber.log.Timber;
48

49
/**
50
 * Created by ndegwamartin on 25/02/2019.
51
 */
52
public class ChildRegisterInteractor implements ChildRegisterContract.Interactor {
53

54
    public static final String TAG = ChildRegisterInteractor.class.getName();
1✔
55
    private AppExecutors appExecutors;
56

57
    public ChildRegisterInteractor() {
58
        this(new AppExecutors());
1✔
59
    }
1✔
60

61
    @VisibleForTesting
62
    ChildRegisterInteractor(AppExecutors appExecutors) {
1✔
63
        this.appExecutors = appExecutors;
1✔
64
    }
1✔
65

66
    @Override
67
    public void onDestroy(boolean isChangingConfiguration) {
68
        //TODO set presenter or model to null
69
    }
1✔
70

71
    @Override
72
    public void getNextUniqueId(final Triple<String, Map<String, String>, String> triple, final ChildRegisterContract.InteractorCallBack callBack) {
73
        if (getUniqueIdRepository().countUnUsedIds() < 2) {
1✔
74
            callBack.onNoUniqueId();
1✔
75
            Timber.d( "ChildRegisterInteractor --> getNextUniqueId: Unique ids are less than 2 required to register mother and child");
1✔
76
            return;
1✔
77
        }
78
        Runnable runnable = () -> {
1✔
79
            UniqueId uniqueId = getUniqueIdRepository().getNextUniqueId();
1✔
80
            final String openmrsId = uniqueId != null ? uniqueId.getOpenmrsId() : "";
1✔
81
            appExecutors.mainThread().execute(() -> {
1✔
82
                if (StringUtils.isBlank(openmrsId)) {
1✔
83
                    callBack.onNoUniqueId();
1✔
84
                } else {
85
                    callBack.onUniqueIdFetched(triple, openmrsId);
1✔
86
                }
87
            });
1✔
88
        };
1✔
89

90
        appExecutors.diskIO().execute(runnable);
1✔
91
    }
1✔
92

93
    @Override
94
    public void saveRegistration(final List<ChildEventClient> childEventClientList, final String jsonString,
95
                                 final UpdateRegisterParams updateRegisterParams,
96
                                 final ChildRegisterContract.InteractorCallBack callBack) {
97

98
        Runnable runnable = () -> {
1✔
99
            saveRegistration(childEventClientList, jsonString, updateRegisterParams);
1✔
100
            appExecutors.mainThread().execute(() -> callBack.onRegistrationSaved(updateRegisterParams.isEditMode()));
1✔
101
        };
1✔
102

103
        appExecutors.diskIO().execute(runnable);
1✔
104
    }
1✔
105

106
    @Override
107
    public void removeChildFromRegister(final String closeFormJsonString, final String providerId) {
108
        Runnable runnable = new Runnable() {
1✔
109
            @Override
110
            public void run() {
111
                //TODO add functionality to remove child from register
112
            }
1✔
113
        };
114

115
        appExecutors.diskIO().execute(runnable);
1✔
116
    }
1✔
117

118
    public void saveRegistration(List<ChildEventClient> childEventClientList, String jsonString, UpdateRegisterParams params) {
119
        try {
120
            List<String> currentFormSubmissionIds = new ArrayList<>();
1✔
121

122
            for (int i = 0; i < childEventClientList.size(); i++) {
1✔
123
                try {
124
                    ChildEventClient childEventClient = childEventClientList.get(i);
1✔
125
                    Client baseClient = childEventClient.getClient();
1✔
126
                    Event baseEvent = childEventClient.getEvent();
1✔
127

128
                    if (baseClient != null) {
1✔
129
                        JSONObject clientJson = new JSONObject(ChildJsonFormUtils.gson.toJson(baseClient));
1✔
130
                        if (params.isEditMode()) {
1✔
131
                            //Create new Father registration event in the case where the father details are provided while updating child/mother details.
132
                            if (Constants.EventType.FATHER_REGISTRATION.equalsIgnoreCase(baseEvent.getEventType())) {
×
133
                                addClient(jsonString, params, baseClient, clientJson);
×
134
                            } else {
135
                                try {
136
                                    ChildJsonFormUtils.mergeAndSaveClient(baseClient);
×
137
                                } catch (Exception e) {
×
138
                                    Timber.e(e, "ChildRegisterInteractor --> mergeAndSaveClient");
×
139
                                }
×
140
                            }
141
                        } else {
142
                            addClient(jsonString, params, baseClient, clientJson);
1✔
143
                        }
144
                    }
145

146
                    addEvent(params, currentFormSubmissionIds, baseEvent);
1✔
147
                    updateOpenSRPId(jsonString, params, baseClient);
1✔
148
                    addImageLocation(jsonString, i, baseClient, baseEvent);
1✔
149

150
                    //Broadcast after all processing is done
151
                    if (Constants.CHILD_TYPE.equals(baseEvent.getEntityType())) {
1✔
152
                        Utils.postEvent(new ClientDirtyFlagEvent(baseClient.getBaseEntityId(), baseEvent.getEventType()));
×
153
                    }
154
                } catch (Exception e) {
1✔
155
                    Timber.e(e, "ChildRegisterInteractor --> saveRegistration loop");
1✔
156
                }
×
157
            }
158

159
            long lastSyncTimeStamp = getAllSharedPreferences().fetchLastUpdatedAtDate(0);
1✔
160
            Date lastSyncDate = new Date(lastSyncTimeStamp);
1✔
161
            ChildLibrary.getInstance().getClientProcessorForJava().processClient(getSyncHelper().getEvents(currentFormSubmissionIds));
×
162

163
            getAllSharedPreferences().saveLastUpdatedAtDate(lastSyncDate.getTime());
×
164
        } catch (Exception e) {
1✔
165
            Timber.e(e, "ChildRegisterInteractor --> saveRegistration");
1✔
166
        }
×
167
    }
1✔
168

169
    private void addClient(String jsonString, UpdateRegisterParams params, Client baseClient, JSONObject clientJson) throws JSONException {
170
        getSyncHelper().addClient(baseClient.getBaseEntityId(), clientJson);
1✔
171

172
        processOtherBirthRegistrationEncounters(jsonString, params, baseClient, clientJson);
1✔
173
    }
1✔
174

175
    private void processOtherBirthRegistrationEncounters(String jsonString, UpdateRegisterParams params, Client baseClient, JSONObject clientJson) throws JSONException {
176
        processWeight(baseClient.getIdentifiers(), jsonString, params, clientJson);
1✔
177
        processHeight(baseClient.getIdentifiers(), jsonString, params, clientJson);
1✔
178
        processTetanus(baseClient.getIdentifiers(), jsonString, params, clientJson);
1✔
179
    }
1✔
180

181
    private void addImageLocation(String jsonString, int i, Client baseClient, Event baseEvent) {
182
        if (baseClient != null || baseEvent != null) {
1✔
183
            String imageLocation = null;
1✔
184
            if (i == 0) {
1✔
185
                imageLocation = ChildJsonFormUtils.getFieldValue(jsonString, Constants.KEY.PHOTO);
1✔
186
            } else if (i == 1) {
×
187
                imageLocation = ChildJsonFormUtils.getFieldValue(jsonString, ChildJsonFormUtils.STEP2, Constants.KEY.PHOTO);
×
188
            }
189

190
            if (StringUtils.isNotBlank(imageLocation)) {
1✔
191
                ChildJsonFormUtils.saveImage(baseEvent.getProviderId(), baseClient.getBaseEntityId(), imageLocation);
×
192
            }
193
        }
194
    }
1✔
195

196
    private void updateOpenSRPId(String jsonString, UpdateRegisterParams params, Client baseClient) {
197
        if (baseClient != null) {
1✔
198
            if (params.isEditMode()) {
1✔
199
                // Unassign current OPENSRP ID
200
                try {
201
                    String newOpenSRPId = baseClient.getIdentifier(ChildJsonFormUtils.ZEIR_ID).replace("-", "");
×
202
                    String currentOpenSRPId = ChildJsonFormUtils.getString(jsonString, ChildJsonFormUtils.CURRENT_ZEIR_ID).replace("-", "");
×
203
                    if (!newOpenSRPId.equals(currentOpenSRPId)) {
×
204
                        //OPENSRP ID was changed
205
                        getUniqueIdRepository().open(currentOpenSRPId);
×
206
                    }
207
                } catch (Exception e) {//might crash if M_ZEIR
×
208
                    Timber.d(e, "ChildRegisterInteractor --> unassign opensrp id");
×
209
                }
×
210
            } else {
211
                //mark OPENSRP ID as used
212
                markUniqueIdAsUsed(baseClient.getIdentifier(ChildJsonFormUtils.ZEIR_ID));
1✔
213
                markUniqueIdAsUsed(baseClient.getIdentifier(ChildJsonFormUtils.M_ZEIR_ID));
1✔
214
                markUniqueIdAsUsed(baseClient.getIdentifier(ChildJsonFormUtils.F_ZEIR_ID));
1✔
215
            }
216
        }
217
    }
1✔
218

219
    private void markUniqueIdAsUsed(String openSrpId) {
220
        try {
221
            if (StringUtils.isNotBlank(openSrpId))
1✔
222
                getUniqueIdRepository().close(openSrpId);
1✔
223
        } catch (Exception e) {
×
224
            Timber.e(e);
×
225
        }
1✔
226
    }
1✔
227

228
    private void addEvent(UpdateRegisterParams params, List<String> currentFormSubmissionIds, Event baseEvent) throws JSONException {
229
        if (baseEvent != null) {
1✔
230
            JSONObject eventJson = new JSONObject(ChildJsonFormUtils.gson.toJson(baseEvent));
1✔
231
            getSyncHelper().addEvent(baseEvent.getBaseEntityId(), eventJson, params.getStatus());
1✔
232
            currentFormSubmissionIds.add(eventJson.getString(EventClientRepository.event_column.formSubmissionId.toString()));
1✔
233
        }
234
    }
1✔
235

236
    public ECSyncHelper getSyncHelper() {
237
        return ChildLibrary.getInstance().getEcSyncHelper();
×
238
    }
239

240
    @Override
241
    public void processWeight(@NonNull Map<String, String> identifiers, @NonNull String jsonEnrollmentFormString, @NonNull UpdateRegisterParams params, @NonNull JSONObject clientJson) throws JSONException {
242
        String weight = ChildJsonFormUtils.getFieldValue(jsonEnrollmentFormString, ChildJsonFormUtils.STEP1, Constants.KEY.BIRTH_WEIGHT);
1✔
243

244
        // This prevents a crash when the birthdate of a mother is not available in the clientJson
245
        // We also don't need to process the mother's weight & height
246
        if (StringUtils.isNotBlank(weight) && !isClientMother(identifiers)) {
1✔
247
            WeightWrapper weightWrapper = new WeightWrapper();
1✔
248
            weightWrapper.setGender(clientJson.getString(FormEntityConstants.Person.gender.name()));
1✔
249
            weightWrapper.setWeight(!TextUtils.isEmpty(weight) ? Float.valueOf(weight) : null);
1✔
250
            LocalDate localDate = new LocalDate(Utils.getChildBirthDate(clientJson));
1✔
251
            weightWrapper.setUpdatedWeightDate(localDate.toDateTime(LocalTime.MIDNIGHT), (new LocalDate()).isEqual(localDate));//This is the weight of birth so reference date should be the DOB
1✔
252
            weightWrapper.setId(clientJson.getString(Constants.Client.BASE_ENTITY_ID));
1✔
253
            weightWrapper.setDob(Utils.getChildBirthDate(clientJson));
1✔
254

255
            Utils.recordWeight(GrowthMonitoringLibrary.getInstance().weightRepository(), weightWrapper, params.getStatus());
1✔
256
        }
257
    }
1✔
258

259
    @Override
260
    public void processHeight(@NonNull Map<String, String> identifiers, @NonNull String jsonEnrollmentFormString, @NonNull UpdateRegisterParams params, @NonNull JSONObject clientJson) throws JSONException {
261
        String height = ChildJsonFormUtils.getFieldValue(jsonEnrollmentFormString, ChildJsonFormUtils.STEP1, Constants.KEY.BIRTH_HEIGHT);
1✔
262

263
        // This prevents a crash when the birthdate of a mother is not available in the clientJson
264
        // We also don't need to process the mother's weight & height
265
        if (StringUtils.isNotBlank(height) && !isClientMother(identifiers)) {
1✔
266
            HeightWrapper heightWrapper = new HeightWrapper();
×
267
            heightWrapper.setGender(clientJson.getString(FormEntityConstants.Person.gender.name()));
×
268
            heightWrapper.setHeight(!TextUtils.isEmpty(height) ? Float.parseFloat(height) : 0);
×
269
            LocalDate localDate = new LocalDate(Utils.getChildBirthDate(clientJson));
×
270
            heightWrapper.setUpdatedHeightDate(localDate.toDateTime(LocalTime.MIDNIGHT), (new LocalDate()).isEqual(localDate));
×
271
            heightWrapper.setId(clientJson.getString(Constants.Client.BASE_ENTITY_ID));
×
272
            heightWrapper.setDob(Utils.getChildBirthDate(clientJson));
×
273

274
            Utils.recordHeight(GrowthMonitoringLibrary.getInstance().heightRepository(), heightWrapper, params.getStatus());
×
275
        }
276
    }
1✔
277

278
    @Override
279
    public void processTetanus(@NonNull Map<String, String> identifiers, @NonNull String jsonEnrollmentFormString, @NonNull UpdateRegisterParams params, @NonNull JSONObject clientJson) throws JSONException {
280
        String tetanusProtection = ChildJsonFormUtils.getFieldValue(jsonEnrollmentFormString, ChildJsonFormUtils.STEP1, Constants.KEY.BIRTH_TETANUS_PROTECTION);
1✔
281

282
        if (StringUtils.isNotBlank(tetanusProtection) && !isClientMother(identifiers) && tetanusProtection.contains("Yes")) {
1✔
283
            VaccineRepository vaccineRepository = ImmunizationLibrary.getInstance().vaccineRepository();
1✔
284

285
            // only insert vaccine if not already saved
286
            Vaccine existingVaccine = vaccineRepository.findByBaseEntityIdAndVaccineName(clientJson.getString(Constants.Client.BASE_ENTITY_ID), Constants.VACCINE_CODE.TETANUS);
1✔
287

288
            if (existingVaccine == null) {
1✔
289
                Vaccine vaccineObj = getTetanusVaccineObject(clientJson);
×
290
                Utils.addVaccine(vaccineRepository, vaccineObj);
×
291
            }
292
        }
293
    }
1✔
294

295
    protected Vaccine getTetanusVaccineObject(JSONObject clientJson) throws JSONException {
296
        Vaccine vaccineObj = new Vaccine();
1✔
297
        vaccineObj.setBaseEntityId(clientJson.getString(Constants.Client.BASE_ENTITY_ID));
1✔
298
        vaccineObj.setName(Constants.VACCINE_CODE.TETANUS);
1✔
299
        vaccineObj.setDate((new LocalDate(Utils.getChildBirthDate(clientJson))).toDate());
1✔
300
        vaccineObj.setAnmId(ChildLibrary.getInstance().context().allSharedPreferences().fetchRegisteredANM());
1✔
301
        vaccineObj.setLocationId(ChildJsonFormUtils.getProviderLocationId(ChildLibrary.getInstance().context().applicationContext()));
1✔
302
        vaccineObj.setChildLocationId(ChildJsonFormUtils.getChildLocationId(ChildLibrary.getInstance().context().allSharedPreferences().fetchDefaultLocalityId(vaccineObj.getAnmId()), ChildLibrary.getInstance().context().allSharedPreferences()));
1✔
303

304
        if (getAppProperties().isTrue(ChildAppProperties.KEY.TETANUS_VACCINE_AT_BIRTH_EVENT))
1✔
305
            vaccineObj.setSyncStatus(VaccineRepository.TYPE_Unsynced);
1✔
306
        else
307
            vaccineObj.setSyncStatus(VaccineRepository.TYPE_Synced);
1✔
308

309
        vaccineObj.setFormSubmissionId(ChildJsonFormUtils.generateRandomUUIDString());
1✔
310
        vaccineObj.setOutOfCatchment(vaccineObj.getLocationId() != null && !vaccineObj.getLocationId().equals(ChildLibrary.getInstance().context().allSharedPreferences().fetchDefaultLocalityId(ChildLibrary.getInstance().context().allSharedPreferences().fetchRegisteredANM())) ? 1 : 0);
1✔
311
        vaccineObj.setCreatedAt(new Date());
1✔
312
        return vaccineObj;
1✔
313
    }
314

315
    @Override
316
    public boolean isClientMother(@NonNull Map<String, String> identifiers) {
317
        return identifiers.containsKey(ChildJsonFormUtils.M_ZEIR_ID);
1✔
318
    }
319

320
    public AllSharedPreferences getAllSharedPreferences() {
321
        return Utils.context().allSharedPreferences();
×
322
    }
323

324
    public ClientProcessorForJava getClientProcessorForJava() {
325
        return ChildLibrary.getInstance().getClientProcessorForJava();
×
326
    }
327

328
    public UniqueIdRepository getUniqueIdRepository() {
329
        return ChildLibrary.getInstance().getUniqueIdRepository();
×
330
    }
331

332
    protected AppProperties getAppProperties() {
333
        return CoreLibrary.getInstance().context().getAppProperties();
1✔
334
    }
335

336
    public enum type {SAVED, UPDATED}
×
337

338
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc