• 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

81.35
opensrp-child/src/main/java/org/smartregister/child/util/ChildJsonFormUtils.java
1
package org.smartregister.child.util;
2

3
import android.annotation.SuppressLint;
4
import android.app.Activity;
5
import android.content.ContentValues;
6
import android.content.Context;
7
import android.content.Intent;
8
import android.graphics.Bitmap;
9
import android.telephony.TelephonyManager;
10
import android.text.TextUtils;
11

12
import androidx.annotation.NonNull;
13
import androidx.annotation.Nullable;
14
import androidx.core.util.Pair;
15

16
import com.google.common.collect.ImmutableSet;
17
import com.google.common.reflect.TypeToken;
18
import com.vijay.jsonwizard.constants.JsonFormConstants;
19
import com.vijay.jsonwizard.domain.Form;
20

21
import org.apache.commons.lang3.StringUtils;
22
import org.apache.commons.lang3.math.NumberUtils;
23
import org.apache.commons.lang3.tuple.Triple;
24
import org.jetbrains.annotations.NotNull;
25
import org.joda.time.LocalDateTime;
26
import org.json.JSONArray;
27
import org.json.JSONException;
28
import org.json.JSONObject;
29
import org.smartregister.AllConstants;
30
import org.smartregister.CoreLibrary;
31
import org.smartregister.child.ChildLibrary;
32
import org.smartregister.child.R;
33
import org.smartregister.child.activity.BaseChildFormActivity;
34
import org.smartregister.child.domain.ChildEventClient;
35
import org.smartregister.child.domain.ChildMetadata;
36
import org.smartregister.child.domain.FormLocationTree;
37
import org.smartregister.child.domain.Identifiers;
38
import org.smartregister.child.domain.MoveToCatchmentEvent;
39
import org.smartregister.child.enums.LocationHierarchy;
40
import org.smartregister.child.model.ChildMotherDetailModel;
41
import org.smartregister.clientandeventmodel.Address;
42
import org.smartregister.clientandeventmodel.Client;
43
import org.smartregister.clientandeventmodel.Event;
44
import org.smartregister.clientandeventmodel.FormEntityConstants;
45
import org.smartregister.clientandeventmodel.Obs;
46
import org.smartregister.commonregistry.AllCommonsRepository;
47
import org.smartregister.commonregistry.CommonPersonObjectClient;
48
import org.smartregister.domain.Observation;
49
import org.smartregister.domain.Photo;
50
import org.smartregister.domain.ProfileImage;
51
import org.smartregister.domain.Response;
52
import org.smartregister.domain.ResponseStatus;
53
import org.smartregister.domain.db.EventClient;
54
import org.smartregister.domain.form.FormLocation;
55
import org.smartregister.domain.tag.FormTag;
56
import org.smartregister.immunization.domain.jsonmapping.Vaccine;
57
import org.smartregister.immunization.domain.jsonmapping.VaccineGroup;
58
import org.smartregister.immunization.util.VaccinatorUtils;
59
import org.smartregister.location.helper.LocationHelper;
60
import org.smartregister.repository.AllSharedPreferences;
61
import org.smartregister.repository.BaseRepository;
62
import org.smartregister.repository.EventClientRepository;
63
import org.smartregister.repository.ImageRepository;
64
import org.smartregister.repository.UniqueIdRepository;
65
import org.smartregister.sync.helper.ECSyncHelper;
66
import org.smartregister.util.AssetHandler;
67
import org.smartregister.util.EasyMap;
68
import org.smartregister.util.FormUtils;
69
import org.smartregister.util.ImageUtils;
70
import org.smartregister.util.JsonFormUtils;
71
import org.smartregister.view.LocationPickerView;
72
import org.smartregister.view.activity.DrishtiApplication;
73

74
import java.io.File;
75
import java.io.FileNotFoundException;
76
import java.io.FileOutputStream;
77
import java.io.IOException;
78
import java.io.OutputStream;
79
import java.text.SimpleDateFormat;
80
import java.util.ArrayList;
81
import java.util.Arrays;
82
import java.util.Calendar;
83
import java.util.Collections;
84
import java.util.Date;
85
import java.util.HashMap;
86
import java.util.HashSet;
87
import java.util.Iterator;
88
import java.util.List;
89
import java.util.Locale;
90
import java.util.Map;
91
import java.util.Set;
92
import java.util.UUID;
93

94
import timber.log.Timber;
95

96
/**
97
 * Created by ndegwamartin on 26/02/2019.
98
 */
99
public class ChildJsonFormUtils extends JsonFormUtils {
1✔
100
    public static final String METADATA = "metadata";
101
    public static final String ENCOUNTER_TYPE = "encounter_type";
102
    public static final int REQUEST_CODE_GET_JSON = 2244;
103
    public static final String CURRENT_OPENSRP_ID = "current_opensrp_id";
104
    public static final String READ_ONLY = "read_only";
105
    public static final String STEP2 = "step2";
106
    public static final String RELATIONAL_ID = "relational_id";
107
    public static final String CURRENT_ZEIR_ID = "current_zeir_id";
108
    public static final String ZEIR_ID = "ZEIR_ID";
109
    public static final String updateBirthRegistrationDetailsEncounter = "Update Birth Registration";
110
    public static final String BCG_SCAR_EVENT = "Bcg Scar";
111
    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(com.vijay.jsonwizard.utils.FormUtils.NATIIVE_FORM_DATE_FORMAT_PATTERN, Locale.ENGLISH);
1✔
112
    public static final String GENDER = "gender";
113
    public static final String M_ZEIR_ID = "M_ZEIR_ID";
114
    public static final String F_ZEIR_ID = "F_ZEIR_ID";
115
    private static final String ENCOUNTER = "encounter";
116
    private static final String IDENTIFIERS = "identifiers";
117
    private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
1✔
118
    private static final String OPENSRP_ID = "opensrp_id";
119
    private static final String FORM_SUBMISSION_FIELD = "formsubmissionField";
120
    private static final String LABEL_TEXT_STYLE = "label_text_style";
121
    private static final String RECURRING_SERVICES_FILE = "services.json";
122
    private static final Map<String, Set<String>> eventTypeMap = new HashMap<String, Set<String>>() {
1✔
123
        {
124
            put(Constants.KEY.FATHER, ImmutableSet.of(Constants.EventType.FATHER_REGISTRATION, Constants.EventType.UPDATE_FATHER_DETAILS));
1✔
125
            put(Constants.KEY.MOTHER, ImmutableSet.of(Constants.EventType.NEW_WOMAN_REGISTRATION, Constants.EventType.UPDATE_MOTHER_DETAILS));
1✔
126
        }
1✔
127
    };
128

129
    /**
130
     * Populate metadata onto form
131
     *
132
     * @param form              JSONObject of form
133
     * @param formName          Name of form to be processed
134
     * @param id                Entity ID
135
     * @param currentLocationId Current location of
136
     * @param metadata          Map of metadata to be loaded to form
137
     * @return JSONObject of form populated with entityId, locationId and any metadata in map
138
     * @throws Exception
139
     */
140
    public static JSONObject getFormAsJson(JSONObject form, String formName, String id, String currentLocationId, Map<String, String> metadata) throws Exception {
141
        if (form == null) {
1✔
142
            return null;
1✔
143
        }
144

145
        String zeirId = id;
1✔
146
        form.getJSONObject(METADATA).put(ENCOUNTER_LOCATION, currentLocationId);
1✔
147

148
        if (Utils.metadata().childRegister.formName.equals(formName)) {
1✔
149
            if (StringUtils.isBlank(zeirId)) {
1✔
150
                zeirId = Utils.getNextOpenMrsId();
×
151
                if (StringUtils.isBlank(zeirId) || (ChildLibrary.getInstance().getUniqueIdRepository().countUnUsedIds() < 1L)) {
×
152
                    Timber.e("ChildJsonFormUtils --> UniqueIds are empty or only one unused found");
×
153
                    return null;
×
154
                }
155
            }
156

157
            if (StringUtils.isNotBlank(zeirId)) {
1✔
158
                zeirId = zeirId.replace("-", "");
1✔
159
            }
160

161
            Map<String, String> locationMetadata = ChildJsonFormUtils.addRegistrationFormLocationHierarchyQuestions(form);
1✔
162
            metadata.putAll(locationMetadata);
1✔
163

164
            metadata.put(ChildJsonFormUtils.ZEIR_ID, zeirId); //inject zeir id into the form
1✔
165

166
            prePopulateJsonFormFields(form, metadata, new ArrayList<>());
1✔
167
        } else if (formName.equals(Utils.metadata().childRegister.outOfCatchmentFormName)) {
1✔
168
            if (StringUtils.isNotBlank(zeirId)) {
1✔
169
                zeirId = zeirId.replace("-", "");
1✔
170
            } else {
171
                JSONArray fields = form.getJSONObject(ChildJsonFormUtils.STEP1).getJSONArray(ChildJsonFormUtils.FIELDS);
×
172
                for (int i = 0; i < fields.length(); i++) {
×
173
                    if (fields.getJSONObject(i).getString(ChildJsonFormUtils.KEY).equals(ChildJsonFormUtils.ZEIR_ID)) {
×
174
                        fields.getJSONObject(i).put(READ_ONLY, false);
×
175
                        break;
×
176
                    }
177
                }
178
            }
179

180
            JSONObject stepOne = form.getJSONObject(ChildJsonFormUtils.STEP1);
1✔
181
            JSONArray jsonArray = stepOne.getJSONArray(ChildJsonFormUtils.FIELDS);
1✔
182
            for (int i = 0; i < jsonArray.length(); i++) {
1✔
183
                JSONObject jsonObject = jsonArray.getJSONObject(i);
1✔
184
                if (jsonObject.getString(ChildJsonFormUtils.KEY).equalsIgnoreCase(ChildJsonFormUtils.ZEIR_ID)) {
1✔
185
                    jsonObject.remove(ChildJsonFormUtils.VALUE);
1✔
186
                    jsonObject.put(ChildJsonFormUtils.VALUE, zeirId);
1✔
187
                }
188
            }
189

190
            ChildJsonFormUtils.addAvailableVaccines(ChildLibrary.getInstance().context().applicationContext(), form);
1✔
191
        } else {
1✔
192
            Timber.w("ChildJsonFormUtils --> Unsupported form requested for launch %s", formName);
×
193
        }
194
        Timber.d("ChildJsonFormUtils --> form is %s", form.toString());
1✔
195

196
        return form;
1✔
197
    }
198

199
    /**
200
     * Generate location tree for location type fields
201
     *
202
     * @param form JSON form object
203
     * @return Map of key-value pairs with location openmrs_entity_id as key and the location id as the value
204
     */
205
    public static Map<String, String> addRegistrationFormLocationHierarchyQuestions(JSONObject form) {
206
        try {
207
            JSONArray questions = com.vijay.jsonwizard.utils.FormUtils.getMultiStepFormFields(form);
1✔
208

209
            List<String> allLevels = getLocationLevels();
1✔
210
            List<String> healthFacilities = getHealthFacilityLevels();
1✔
211

212
            String defaultFacilityString = generateLocationString(healthFacilities);
1✔
213
            String defaultLocationString = generateLocationString(allLevels);
1✔
214

215
            return updateLocationTree(questions, defaultLocationString, defaultFacilityString, allLevels, healthFacilities);
1✔
216
        } catch (Exception e) {
×
217
            Timber.e(e, "ChildJsonFormUtils --> addRegistrationFormLocationHierarchyQuestions");
×
218
            return null;
×
219
        }
220
    }
221

222
    /**
223
     * Generate a JSON array of user's assigned location names
224
     *
225
     * @param locationTags List of location tag names
226
     * @return JSON array of default location names
227
     */
228
    private static String generateLocationString(List<String> locationTags) {
229
        List<String> locationNames = LocationHelper.getInstance().generateDefaultLocationHierarchy(locationTags);
1✔
230
        return AssetHandler.javaToJsonString(locationNames, new TypeToken<List<String>>() {
1✔
231
        }.getType());
1✔
232
    }
233

234
    /**
235
     * Generate form location tree hierarchy
236
     *
237
     * @param locationTags  List of location levels to be displayed in the tree hierarchy
238
     * @param showOther     Flag on whether to display the "Other" option in the tree
239
     * @param selectableTag Tag name of level that should be selectable in the tree
240
     * @return FormLocationTree object
241
     */
242
    private static FormLocationTree generateFormLocationTree(List<String> locationTags, boolean showOther, String selectableTag) {
243
        ArrayList<String> allowedLevels = (ArrayList<String>) locationTags;
1✔
244

245
        if (!StringUtils.isBlank(selectableTag)) {
1✔
246
            int finalIndex = locationTags.indexOf(selectableTag) + 1;
1✔
247
            allowedLevels = finalIndex <= locationTags.size() - 1 ? new ArrayList<>(locationTags.subList(0, finalIndex)) : (ArrayList<String>) locationTags;
1✔
248
        }
249

250
        List<FormLocation> formLocationList = LocationHelper.getInstance().generateLocationHierarchyTree(showOther, allowedLevels);
1✔
251

252
        String locationsString = AssetHandler.javaToJsonString(formLocationList, new TypeToken<List<FormLocation>>() {
1✔
253
        }.getType());
1✔
254

255
        return new FormLocationTree(locationsString, formLocationList);
1✔
256
    }
257

258
    /**
259
     * Add questions for each vaccine group
260
     *
261
     * @param context Form context
262
     * @param form    JSON form object
263
     */
264
    public static void addAvailableVaccines(Context context, JSONObject form) {
265
        List<VaccineGroup> supportedVaccines = VaccinatorUtils.getSupportedVaccines(context);
1✔
266
        if (supportedVaccines != null && !supportedVaccines.isEmpty() && form != null) {
1✔
267
            // For each of the vaccine groups, create a checkbox question
268
            try {
269
                JSONArray questionList = getQuestionList(context, form);
1✔
270

271
                HashMap<String, ArrayList<JSONObject>> vaccineTypeConstraints = generateVaccineTypeConstraints(supportedVaccines);
1✔
272

273
                for (VaccineGroup curVaccineGroup : supportedVaccines) {
1✔
274
                    JSONObject curQuestion = getCurQuestion(context, curVaccineGroup);
1✔
275

276
                    JSONArray options = new JSONArray();
1✔
277
                    for (Vaccine curVaccine : curVaccineGroup.vaccines) {
1✔
278
                        ArrayList<String> definedVaccineNames = new ArrayList<>();
1✔
279
                        if (curVaccine.vaccine_separator != null) {
1✔
280
                            String rawNames = curVaccine.name;
1✔
281
                            String separator = curVaccine.vaccine_separator;
1✔
282
                            String[] split = rawNames.split(separator);
1✔
283
                            definedVaccineNames.addAll(Arrays.asList(split));
1✔
284
                        } else {
1✔
285
                            definedVaccineNames.add(curVaccine.name);
1✔
286
                        }
287

288
                        for (String curVaccineName : definedVaccineNames) {
1✔
289
                            JSONObject curVaccines = new JSONObject();
1✔
290
                            curVaccines.put(JsonFormConstants.KEY, curVaccineName);
1✔
291
                            curVaccines.put("text", VaccinatorUtils.getTranslatedVaccineName(context, curVaccineName));
1✔
292
                            curVaccines.put("value", "false");
1✔
293
                            JSONArray constraints = new JSONArray();
1✔
294

295
                            // Add the constraints
296
                            if (vaccineTypeConstraints.containsKey(curVaccine.type)) {
1✔
297
                                for (JSONObject curConstraint : vaccineTypeConstraints.get(curVaccine.type)) {
1✔
298
                                    if (!curConstraint.getString("vaccine").equals(curVaccineName)) {
1✔
299
                                        JSONObject constraintClone = new JSONObject(curConstraint.toString());
1✔
300
                                        constraintClone.remove("vaccine");
1✔
301
                                        constraints.put(constraintClone);
1✔
302
                                    }
303
                                }
1✔
304
                            }
305

306
                            if (constraints.length() > 0) {
1✔
307
                                curVaccines.put("constraints", constraints);
1✔
308
                            }
309

310
                            options.put(curVaccines);
1✔
311
                        }
1✔
312
                    }
1✔
313

314
                    curQuestion.put("options", options);
1✔
315
                    questionList.put(curQuestion);
1✔
316
                }
1✔
317
            } catch (JSONException e) {
×
318
                Timber.e(e, "ChildJsonFormUtils --> addAvailableVaccines");
×
319
            }
1✔
320
        }
321
        addRecurringServices(context, form);
1✔
322
    }
1✔
323

324
    public static void addRecurringServices(Context context, JSONObject form) {
325
        boolean showRecurringServices = Boolean.parseBoolean(ChildLibrary.getInstance().getProperties()
1✔
326
                .getProperty(ChildAppProperties.KEY.SHOW_OUT_OF_CATCHMENT_RECURRING_SERVICES, "false"));
1✔
327
        JSONArray fields = fields(form, JsonFormConstants.STEP1);
1✔
328
        if (showRecurringServices && fields != null) {
1✔
329

330
            JSONObject recurringServiceQuestion = new JSONObject();
1✔
331
            try {
332
                recurringServiceQuestion.put(KEY, Constants.KEY.RECURRING_SERVICE_TYPES);
1✔
333
                recurringServiceQuestion.put(JsonFormConstants.TYPE, JsonFormConstants.CHECK_BOX);
1✔
334
                recurringServiceQuestion.put(JsonFormConstants.LABEL, context.getString(R.string.recurring_services_provided));
1✔
335
                recurringServiceQuestion.put(JsonFormConstants.TEXT_COLOR, "#000000");
1✔
336
                recurringServiceQuestion.put(LABEL_TEXT_STYLE, "bold");
1✔
337
                recurringServiceQuestion.put(OPENMRS_ENTITY_PARENT, Constants.KEY.RECURRING_SERVICE_TYPES);
1✔
338
                recurringServiceQuestion.put(OPENMRS_ENTITY, CONCEPT);
1✔
339
                recurringServiceQuestion.put(OPENMRS_ENTITY_ID, Constants.KEY.RECURRING_SERVICE_TYPES);
1✔
340

341
                JSONArray options = createRecurringServiceOptions(context);
1✔
342

343
                if (options != null && options.length() > 0) {
1✔
344
                    recurringServiceQuestion.put(JsonFormConstants.OPTIONS_FIELD_NAME, options);
1✔
345
                    fields.put(recurringServiceQuestion);
1✔
346
                }
347
            } catch (JSONException e) {
×
348
                Timber.e(e);
×
349
            }
1✔
350
        }
351
    }
1✔
352

353
    private static JSONArray createRecurringServiceOptions(Context context) throws JSONException {
354
        JSONArray options = new JSONArray();
1✔
355
        JSONArray serviceArray = getArrayFromFile(context, RECURRING_SERVICES_FILE);
1✔
356
        JSONObject serviceJson = serviceArray.getJSONObject(0);
1✔
357
        if (serviceJson.has(Constants.JSON_FORM_KEY.SERVVICES)) {
1✔
358
            JSONArray services = serviceJson.getJSONArray(Constants.JSON_FORM_KEY.SERVVICES);
1✔
359
            for (int i = 0; i < services.length(); i++) {
1✔
360
                JSONObject service = services.getJSONObject(i);
1✔
361
                if (service.has(Constants.TYPE)) {
1✔
362
                    String serviceType = service.getString(Constants.TYPE);
1✔
363
                    String serviceKey = serviceType.replaceAll(" ", "_").toLowerCase(Locale.ENGLISH);
1✔
364
                    JSONObject option = new JSONObject();
1✔
365
                    option.put(JsonFormConstants.KEY, serviceKey);
1✔
366
                    option.put(JsonFormConstants.TEXT, VaccinatorUtils.getTranslatedVaccineName(context, serviceType));
1✔
367
                    options.put(option);
1✔
368
                }
369
            }
370
        }
371
        return options;
1✔
372
    }
373

374
    @NotNull
375
    public static JSONArray getArrayFromFile(Context context, String fileName) throws JSONException {
376
        return new JSONArray(AssetHandler.readFileFromAssetsFolder(fileName, context));
1✔
377
    }
378

379
    @NotNull
380
    private static HashMap<String, ArrayList<JSONObject>> generateVaccineTypeConstraints(List<VaccineGroup> supportedVaccines) throws JSONException {
381
        HashMap<String, ArrayList<JSONObject>> vaccineTypeConstraints = new HashMap<>();
1✔
382
        for (VaccineGroup curVaccineGroup : supportedVaccines) {
1✔
383
            for (Vaccine curVaccine : curVaccineGroup.vaccines) {
1✔
384
                if (!vaccineTypeConstraints.containsKey(curVaccine.type)) {
1✔
385
                    vaccineTypeConstraints.put(curVaccine.type, new ArrayList<>());
1✔
386
                }
387
                ArrayList<String> vaccineNamesDefined = new ArrayList<>();
1✔
388
                if (curVaccine.vaccine_separator != null) {
1✔
389
                    String unSplitNames = curVaccine.name;
1✔
390
                    String separator = curVaccine.vaccine_separator;
1✔
391
                    String[] splitValues = unSplitNames.split(separator);
1✔
392
                    vaccineNamesDefined.addAll(Arrays.asList(splitValues));
1✔
393
                } else {
1✔
394
                    vaccineNamesDefined.add(curVaccine.name);
1✔
395
                }
396

397
                for (String curVaccineName : vaccineNamesDefined) {
1✔
398
                    JSONObject curConstraint = getCurConstraint(curVaccineGroup, curVaccine, curVaccineName);
1✔
399
                    vaccineTypeConstraints.get(curVaccine.type).add(curConstraint);
1✔
400
                }
1✔
401
            }
1✔
402
        }
1✔
403
        return vaccineTypeConstraints;
1✔
404
    }
405

406
    @NotNull
407
    private static JSONArray getQuestionList(Context context, JSONObject form) throws JSONException {
408
        JSONArray questionList = form.getJSONObject("step1").getJSONArray("fields");
1✔
409
        JSONObject vaccinationLabel = new JSONObject();
1✔
410
        vaccinationLabel.put(JsonFormConstants.KEY, "Vaccines_Provided_Label");
1✔
411
        vaccinationLabel.put("type", "label");
1✔
412
        vaccinationLabel.put("label_text_size", "20sp");
1✔
413
        vaccinationLabel.put("label_text_style", "bold");
1✔
414
        vaccinationLabel.put("text_color", "#000000");
1✔
415
        vaccinationLabel.put("text", context.getString(R.string.which_vaccinations_were_provided));
1✔
416
        vaccinationLabel.put("openmrs_entity_parent", "-");
1✔
417
        vaccinationLabel.put("openmrs_entity", "-");
1✔
418
        vaccinationLabel.put("openmrs_entity_id", "-");
1✔
419
        questionList.put(vaccinationLabel);
1✔
420
        return questionList;
1✔
421
    }
422

423
    @NotNull
424
    private static JSONObject getCurConstraint(VaccineGroup curVaccineGroup, Vaccine curVaccine, String curVaccineName) throws JSONException {
425
        JSONObject curConstraint = new JSONObject();
1✔
426
        curConstraint.put("vaccine", curVaccineName);
1✔
427
        curConstraint.put("type", "array");
1✔
428
        curConstraint.put("ex",
1✔
429
                "notEqualTo(step1:" + curVaccineGroup.id + ", \"[\"" + curVaccineName + "\"]\")");
430
        curConstraint.put("err", "Cannot be given with the other " + curVaccine.type + " dose");
1✔
431
        return curConstraint;
1✔
432
    }
433

434
    private static JSONObject getCurQuestion(Context context, VaccineGroup curVaccineGroup) throws JSONException {
435
        JSONObject curQuestion = new JSONObject();
1✔
436
        curQuestion.put(JsonFormConstants.KEY, curVaccineGroup.id);
1✔
437
        curQuestion.put("type", "check_box");
1✔
438
        curQuestion.put("is_vaccine_group", true);
1✔
439
        curQuestion.put("label", VaccinatorUtils.translate(context, curVaccineGroup.name));
1✔
440
        curQuestion.put("openmrs_entity_parent", "-");
1✔
441
        curQuestion.put("openmrs_entity", "-");
1✔
442
        curQuestion.put("openmrs_entity_id", "-");
1✔
443
        return curQuestion;
1✔
444
    }
445

446
    /**
447
     * Fetch configured locations levels
448
     *
449
     * @return List of location level names
450
     */
451
    @NotNull
452
    private static List<String> getLocationLevels() {
453
        return Utils.metadata().getLocationLevels();
1✔
454
    }
455

456
    /**
457
     * Fetch configured list of health facility levels
458
     *
459
     * @return List of health facility level names
460
     */
461
    @NotNull
462
    private static List<String> getHealthFacilityLevels() {
463
        return Utils.metadata().getHealthFacilityLevels();
1✔
464
    }
465

466
    /**
467
     * Fetch list of configured allowed levels
468
     *
469
     * @return List of allowed level names
470
     */
471
    @NotNull
472
    private static List<String> getAllowedLevels() {
473
        return LocationHelper.getInstance().getAllowedLevels();
1✔
474
    }
475

476
    private static Map<String, String> updateLocationTree(JSONArray questions, String defaultLocationString, String defaultFacilityString, List<String> allLevels, List<String> healthFacilities) throws JSONException {
477
        Map<String, String> locationMetadata = new HashMap<>();
1✔
478

479
        ChildMetadata childMetadata = Utils.metadata();
1✔
480
        LocationHierarchy locationHierarchy;//Default
481
        if (childMetadata.getFieldsWithLocationHierarchy() != null && !childMetadata.getFieldsWithLocationHierarchy().isEmpty()) {
1✔
482

483
            FormLocationTree upToFacilities = generateFormLocationTree(healthFacilities, false, null);
1✔
484
            FormLocationTree upToFacilitiesWithOther = generateFormLocationTree(healthFacilities, true, null);
1✔
485
            FormLocationTree entireTree = generateFormLocationTree(allLevels, true, null);
1✔
486

487
            List<FormLocation> formLocations = LocationHelper.getInstance().generateLocationHierarchyTree(false, getAllowedLevels());
1✔
488

489
            for (int i = 0; i < questions.length(); i++) {
1✔
490

491
                JSONObject widget = questions.getJSONObject(i);
1✔
492

493
                if (widget.has(JsonFormConstants.TYPE) && widget.getString(JsonFormConstants.TYPE).equals(JsonFormConstants.TREE)) {
1✔
494

495
                    String key = widget.optString(JsonFormConstants.KEY);
1✔
496
                    String hierarchyType = widget.optString(Constants.JSON_FORM_KEY.HIERARCHY);
1✔
497

498
                    locationHierarchy = !StringUtils.isBlank(hierarchyType) ? LocationHierarchy.valueOf(hierarchyType.toUpperCase(Locale.ENGLISH)) : LocationHierarchy.ENTIRE_TREE;
1✔
499

500
                    if (StringUtils.isNotBlank(key) && childMetadata.getFieldsWithLocationHierarchy().contains(widget.optString(JsonFormConstants.KEY))) {
1✔
501
                        switch (locationHierarchy) {
1✔
502
                            case FACILITY_ONLY:
503
                                if (StringUtils.isNotBlank(upToFacilities.getFormLocationString())) {
×
504
                                    addLocationTree(key, widget, upToFacilities.getFormLocationString(), JsonFormConstants.TREE);
×
505
                                }
506
                                if (StringUtils.isNotBlank(defaultFacilityString)) {
×
507
                                    addLocationTreeDefault(key, widget, defaultFacilityString);
×
508
                                }
509
                                break;
510
                            case FACILITY_WITH_OTHER:
511
                                if (StringUtils.isNotBlank(upToFacilitiesWithOther.getFormLocationString())) {
×
512
                                    addLocationTree(key, widget, upToFacilitiesWithOther.getFormLocationString(), JsonFormConstants.TREE);
×
513
                                }
514
                                if (StringUtils.isNotBlank(defaultFacilityString)) {
×
515
                                    addLocationTreeDefault(key, widget, defaultFacilityString);
×
516
                                }
517
                                break;
518
                            case ENTIRE_TREE:
519
                                String selectableTag = widget.optString(Constants.JSON_FORM_KEY.SELECTABLE);
1✔
520
                                if (StringUtils.isNotBlank(selectableTag)) {
1✔
521
                                    entireTree = generateFormLocationTree(allLevels, true, selectableTag);
×
522
                                }
523
                                if (StringUtils.isNotBlank(entireTree.getFormLocationString())) {
1✔
524
                                    addLocationTree(key, widget, entireTree.getFormLocationString(), JsonFormConstants.TREE);
1✔
525
                                }
526
                                if (StringUtils.isNotBlank(defaultLocationString)) {
1✔
527
                                    addLocationTreeDefault(key, widget, defaultLocationString);
1✔
528
                                }
529
                                break;
530
                            default:
531
                                break;
532
                        }
533
                    }
534

535
                    generateLocationMetadata(locationMetadata, formLocations, widget);
1✔
536
                }
537
            }
538
        }
539

540
        return locationMetadata;
1✔
541
    }
542

543
    private static void generateLocationMetadata(Map<String, String> locationMetadata, List<FormLocation> formLocations, JSONObject widget) throws JSONException {
544
        String selectableTag = widget.optString(Constants.JSON_FORM_KEY.SELECTABLE);
1✔
545
        if (StringUtils.isNotBlank(selectableTag)) {
1✔
546
            String locationKey = getSelectableKey(formLocations, selectableTag);
×
547

548
            String prefix = getJsonFieldEntityId(widget, Constants.ENTITY.MOTHER);
×
549
            String addressKey = widget.optString(JsonFormConstants.OPENMRS_ENTITY_ID);
×
550
            locationMetadata.put(prefix + addressKey, LocationHelper.getInstance().getOpenMrsLocationId(locationKey));
×
551
        }
552
    }
1✔
553

554
    @NotNull
555
    private static String getJsonFieldEntityId(JSONObject jsonObject, String entity) throws JSONException {
556
        return jsonObject.has(ChildJsonFormUtils.ENTITY_ID) && jsonObject.getString(ChildJsonFormUtils.ENTITY_ID).equalsIgnoreCase(Constants.KEY.MOTHER) ? (entity + "_") : "";
×
557
    }
558

559
    /**
560
     * Returns the form location key from a location hierarchy given a specific location tag
561
     *
562
     * @param formLocations Location tree to be searched
563
     * @param selectableTag Location tag to filter the location node
564
     * @return Location key
565
     */
566
    private static String getSelectableKey(List<FormLocation> formLocations, String selectableTag) {
567
        if (formLocations != null && !formLocations.isEmpty()) {
×
568
            for (FormLocation location : formLocations) {
×
569
                if (location.level.equalsIgnoreCase(selectableTag)) {
×
570
                    return location.key;
×
571
                } else {
572
                    return getSelectableKey(location.nodes, selectableTag);
×
573
                }
574
            }
575
        }
576

577
        return null;
×
578
    }
579

580
    private static void addLocationTree(@NonNull String widgetKey, @NonNull JSONObject widget,
581
                                        @NonNull String updateString, @NonNull String treeType) {
582
        try {
583
            if (widgetKey.equals(widget.optString(JsonFormConstants.KEY))) {
1✔
584
                widget.put(treeType, new JSONArray(updateString));
1✔
585
            }
586
        } catch (JSONException e) {
1✔
587
            Timber.e(e, "ChildJsonFormUtils --> addLocationTree");
1✔
588
        }
1✔
589
    }
1✔
590

591
    private static void addLocationTreeDefault(@NonNull String widgetKey, @NonNull JSONObject widget,
592
                                               @NonNull String updateString) {
593
        addLocationTree(widgetKey, widget, updateString, JsonFormConstants.DEFAULT);
1✔
594
    }
1✔
595

596
    /**
597
     * Record death of child
598
     *
599
     * @param context    Form context
600
     * @param jsonString JSON form
601
     * @param locationId Location Id
602
     * @param entityId   Child Id
603
     */
604
    public static void saveReportDeceased(Context context, String jsonString,
605
                                          String locationId, String entityId) {
606
        try {
607
            EventClientRepository db = ChildLibrary.getInstance().eventClientRepository();
1✔
608
            JSONObject jsonForm = new JSONObject(jsonString);
1✔
609

610
            JSONArray fields = fields(jsonForm);
1✔
611
            if (fields == null) {
1✔
612
                return;
×
613
            }
614

615
            String encounterDateField = getFieldValue(fields, "Date_of_Death");
1✔
616

617
            String encounterType = getString(jsonForm, ENCOUNTER_TYPE);
1✔
618
            JSONObject metadata = getJSONObject(jsonForm, METADATA);
1✔
619

620
            Date encounterDate = new Date();
1✔
621
            String encounterDateTimeString = null;
1✔
622
            if (StringUtils.isNotBlank(encounterDateField)) {
1✔
623
                encounterDateTimeString = formatDate(encounterDateField);
1✔
624
                Date dateTime = formatDate(encounterDateField, false);
1✔
625
                if (dateTime != null) {
1✔
626
                    encounterDate = dateTime;
1✔
627
                }
628
            }
629

630
            Event event = getEventAndTag(entityId, encounterType, encounterDate, Constants.KEY.CHILD);
1✔
631
            addSaveReportDeceasedObservations(fields, event);
1✔
632
            updateMetadata(metadata, event);
1✔
633

634
            if (event != null) {
1✔
635
                createDeathEventObject(context, entityId, db, encounterDate, encounterDateTimeString, event);
1✔
636

637
                ContentValues values = new ContentValues();
1✔
638
                values.put(Constants.KEY.DOD, encounterDateField);
1✔
639
                values.put(Constants.KEY.DATE_REMOVED, Utils.getTodaysDate());
1✔
640
                updateChildFTSTables(values, entityId);
1✔
641

642
                updateDateOfRemoval(entityId, encounterDateTimeString);//TO DO Refactor  with better
1✔
643

644
                // Utils.postEvent(new ClientDirtyFlagEvent(entityId, encounterType));
645
            }
646

647
            processClients(Utils.getAllSharedPreferences(), ChildLibrary.getInstance().getEcSyncHelper());
×
648
        } catch (Exception e) {
1✔
649
            Timber.e(e, "ChildJsonFormUtils --> saveReportDeceased");
1✔
650
        }
×
651
    }
1✔
652

653
    private static void addSaveReportDeceasedObservations(JSONArray fields, Event event) {
654
        for (int i = 0; i < fields.length(); i++) {
1✔
655
            JSONObject jsonObject = getJSONObject(fields, i);
1✔
656
            String value = getString(jsonObject, VALUE);
1✔
657
            if (StringUtils.isNotBlank(value)) {
1✔
658
                addObservation(event, jsonObject);
1✔
659
            }
660
        }
661
    }
1✔
662

663
    private static void updateMetadata(JSONObject metadata, Event event) {
664
        if (metadata != null) {
1✔
665
            Iterator<?> keys = metadata.keys();
1✔
666

667
            while (keys.hasNext()) {
1✔
668
                String key = (String) keys.next();
1✔
669
                JSONObject jsonObject = getJSONObject(metadata, key);
1✔
670
                String value = getString(jsonObject, VALUE);
1✔
671
                if (StringUtils.isNotBlank(value)) {
1✔
672
                    String entityVal = getString(jsonObject, OPENMRS_ENTITY);
1✔
673
                    if (entityVal != null) {
1✔
674
                        if (entityVal.equals(CONCEPT)) {
1✔
675
                            addToJSONObject(jsonObject, KEY, key);
1✔
676
                            addObservation(event, jsonObject);
1✔
677
                        } else if (entityVal.equals(ENCOUNTER)) {
1✔
678
                            String entityIdVal = getString(jsonObject, OPENMRS_ENTITY_ID);
1✔
679
                            if (entityIdVal.equals(FormEntityConstants.Encounter.encounter_date.name())) {
1✔
680
                                Date eDate = formatDate(value, false);
1✔
681
                                if (eDate != null) {
1✔
682
                                    event.setEventDate(eDate);
1✔
683
                                }
684
                            }
685
                        }
686
                    }
687
                }
688
            }
1✔
689
        }
690
    }
1✔
691

692
    private static void processClients(AllSharedPreferences allSharedPreferences, @NonNull ECSyncHelper ecSyncHelper) throws Exception {
693
        long lastSyncTimeStamp = allSharedPreferences.fetchLastUpdatedAtDate(0);
1✔
694
        Date lastSyncDate = new Date(lastSyncTimeStamp);
1✔
695

696
        List<EventClient> eventList = new ArrayList<>();
1✔
697
        eventList.addAll(ecSyncHelper.getEvents(lastSyncDate, BaseRepository.TYPE_Unprocessed));
1✔
698
        eventList.addAll(ecSyncHelper.getEvents(lastSyncDate, BaseRepository.TYPE_Unsynced));
1✔
699

700
        ChildLibrary.getInstance().getClientProcessorForJava().processClient(eventList);
1✔
701
        allSharedPreferences.saveLastUpdatedAtDate(lastSyncDate.getTime());
1✔
702
    }
1✔
703

704
    private static Event getEvent(String providerId, String locationId, String entityId, String encounterType, Date encounterDate, String childType) {
705
        Event event = (Event) new Event().withBaseEntityId(entityId) //should be different for main and subform
1✔
706
                .withEventDate(encounterDate).withEventType(encounterType).withLocationId(locationId)
1✔
707
                .withProviderId(providerId).withEntityType(childType)
1✔
708
                .withFormSubmissionId(generateRandomUUIDString()).withDateCreated(new Date());
1✔
709
        return event;
1✔
710
    }
711

712
    private static Event getEventAndTag(String entityId, String encounterType, Date encounterDate, String childType) {
713

714
        Event event = getEvent(null, null, entityId, encounterType, encounterDate, childType);
1✔
715

716
        ChildJsonFormUtils.tagSyncMetadata(event);
1✔
717

718
        return event;
1✔
719
    }
720

721
    private static void createDeathEventObject(Context context,
722
                                               String entityId, EventClientRepository db, Date encounterDate,
723
                                               String encounterDateTimeString, Event event) throws JSONException {
724

725
        JSONObject eventJson = new JSONObject(ChildJsonFormUtils.gson.toJson(event));
1✔
726

727
        //After saving, Unsync(remove) this event's details
728
        //List<JSONObject> jsonEvents = new ArrayList<>();
729
        ///jsonEvents.add(eventJson);
730

731
        //Update client to deceased
732
        JSONObject client = db.getClientByBaseEntityId(eventJson.getString(Constants.Client.BASE_ENTITY_ID));
1✔
733
        client.put(FormEntityConstants.Person.deathdate.name(), encounterDateTimeString);
1✔
734
        client.put(FormEntityConstants.Person.deathdate_estimated.name(), false);
1✔
735
        client.put(Constants.JSON_FORM_KEY.DEATH_DATE_APPROX, false);
1✔
736

737
        db.addorUpdateClient(entityId, client);
1✔
738

739
        //Add Death Event for child to flag for Server delete
740
        db.addEvent(event.getBaseEntityId(), eventJson);
1✔
741

742
        //Update Child Entity to include death date
743
        Event updateChildDetailsEvent = getEventAndTag(entityId, ChildJsonFormUtils.updateBirthRegistrationDetailsEncounter, encounterDate, Constants.CHILD_TYPE);
1✔
744

745
        addMetaData(context, updateChildDetailsEvent, new Date());
1✔
746

747
        JSONObject eventJsonUpdateChildEvent = new JSONObject(ChildJsonFormUtils.gson.toJson(updateChildDetailsEvent));
1✔
748

749
        db.addEvent(entityId, eventJsonUpdateChildEvent); //Add event to flag server update
1✔
750
    }
1✔
751

752
    public static void updateChildFTSTables(ContentValues values, String entityId) {
753
        //Update REGISTER and FTS Tables
754
        String tableName = Utils.metadata().getRegisterQueryProvider().getDemographicTable();
1✔
755
        AllCommonsRepository allCommonsRepository = ChildLibrary.getInstance().context().allCommonsRepositoryobjects(tableName);
1✔
756
        if (allCommonsRepository != null) {
1✔
757
            allCommonsRepository.update(tableName, values, entityId);
1✔
758
            updateChildFTSTablesSearchOnly(tableName, Arrays.asList(entityId));
1✔
759
        }
760
    }
1✔
761

762
    /**
763
     * Update All FTS for each client
764
     *
765
     * @param tableName
766
     * @param entityIds
767
     */
768
    public static void updateChildFTSTablesSearchOnly(String tableName, List<String> entityIds) {
769
        ChildLibrary.getInstance().context().allCommonsRepositoryobjects(tableName).updateSearch(entityIds);
1✔
770
    }
1✔
771

772
    /**
773
     * Add event form metadata
774
     *
775
     * @param context Form context
776
     * @param event   Event
777
     * @param start   Start date
778
     * @return Event update with metadata
779
     */
780
    @SuppressLint("MissingPermission")
781
    public static Event addMetaData(Context context, Event event, Date start) {
782
        Map<String, String> metaFields = new HashMap<>();
1✔
783
        metaFields.put("deviceid", "163149AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
784
        metaFields.put("end", "163138AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
785
        metaFields.put("start", "163137AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
786
        Calendar calendar = Calendar.getInstance();
1✔
787

788
        String end = DATE_TIME_FORMAT.format(calendar.getTime());
1✔
789

790
        Obs obs = new Obs();
1✔
791
        obs.setFieldCode("163137AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
792
        obs.setValue(DATE_TIME_FORMAT.format(start));
1✔
793
        obs.setFieldType("concept");
1✔
794
        obs.setFieldDataType("start");
1✔
795
        event.addObs(obs);
1✔
796

797
        obs = new Obs();
1✔
798
        obs.setFieldCode("163138AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
799
        obs.setValue(end);
1✔
800
        obs.setFieldDataType("end");
1✔
801
        event.addObs(obs);
1✔
802

803
        String deviceId = "";
1✔
804
        try {
805
            TelephonyManager mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
1✔
806
            deviceId = mTelephonyManager.getSimSerialNumber(); //Already handled by native form
×
807
        } catch (SecurityException e) {
×
808
            Timber.w(e, "ChildJsonFormUtils --> MissingPermission --> getSimSerialNumber");
×
809
        } catch (NullPointerException e) {
1✔
810
            Timber.w(e);
1✔
811
        }
×
812
        obs = new Obs();
1✔
813
        obs.setFieldCode("163149AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
1✔
814
        obs.setValue(deviceId);
1✔
815
        obs.setFieldDataType("deviceid");
1✔
816
        event.addObs(obs);
1✔
817

818
        return event;
1✔
819
    }
820

821
    /**
822
     * Tag an event with metadata fields LocationId, ChildLocationId, Data strategy in use, Team, TeamId, Database Version and Client App Version
823
     *
824
     * @param event to tag
825
     * @return Tagged event
826
     */
827
    public static Event tagSyncMetadata(@NonNull Event event) {
828

829
        AllSharedPreferences allSharedPreferences = Utils.getAllSharedPreferences();
1✔
830
        String providerId = allSharedPreferences.fetchRegisteredANM();
1✔
831
        event.setProviderId(providerId);
1✔
832
        event.setLocationId(getProviderLocationId(ChildLibrary.getInstance().context().applicationContext()));
1✔
833

834
        String childLocationId = getChildLocationId(allSharedPreferences.fetchDefaultLocalityId(providerId), allSharedPreferences);
1✔
835
        event.setChildLocationId(childLocationId);
1✔
836
        event.setTeam(allSharedPreferences.fetchDefaultTeam(providerId));
1✔
837
        event.setTeamId(allSharedPreferences.fetchDefaultTeamId(providerId));
1✔
838

839
        event.addDetails(AllConstants.DATA_STRATEGY, allSharedPreferences.fetchCurrentDataStrategy());
1✔
840

841
        try {
842
            addObservation(AllConstants.DATA_STRATEGY, allSharedPreferences.fetchCurrentDataStrategy(), Observation.TYPE.TEXT, event);
1✔
843
        } catch (JSONException jsonException) {
×
844
            Timber.e(jsonException);
×
845
        }
1✔
846

847
        event.setClientDatabaseVersion(ChildLibrary.getInstance().getDatabaseVersion());
1✔
848
        event.setClientApplicationVersion(ChildLibrary.getInstance().getApplicationVersion());
1✔
849
        event.setClientApplicationVersionName(ChildLibrary.getInstance().getApplicationVersionName());
1✔
850
        return event;
1✔
851
    }
852

853
    /**
854
     * Tag an client with metadata fields LocationId, ChildLocationId, Data strategy in use, Team, TeamId, Database Version and Client App Version
855
     *
856
     * @param client to tag
857
     * @return Tagged client
858
     */
859
    public static Client tagSyncMetadata(@NonNull Client client) {
860

861
        AllSharedPreferences allSharedPreferences = Utils.getAllSharedPreferences();
1✔
862
        String providerId = allSharedPreferences.fetchRegisteredANM();
1✔
863
        client.setLocationId(getProviderLocationId(ChildLibrary.getInstance().context().applicationContext()));
1✔
864
        client.setTeamId(allSharedPreferences.fetchDefaultTeamId(providerId));
1✔
865
        client.setClientDatabaseVersion(ChildLibrary.getInstance().getDatabaseVersion());
1✔
866
        client.setClientApplicationVersion(ChildLibrary.getInstance().getApplicationVersion());
1✔
867
        client.setClientApplicationVersionName(ChildLibrary.getInstance().getApplicationVersionName());
1✔
868
        return client;
1✔
869
    }
870

871
    /**
872
     * Get child's location Id
873
     *
874
     * @param defaultLocationId    Default location Id
875
     * @param allSharedPreferences Saved preferences
876
     * @return Location Id of child
877
     */
878
    @Nullable
879
    public static String getChildLocationId(@NonNull String defaultLocationId, @NonNull AllSharedPreferences allSharedPreferences) {
880
        String currentLocality = allSharedPreferences.fetchCurrentLocality();
1✔
881

882
        try {
883
            if (StringUtils.isNotBlank(currentLocality)) {
1✔
884
                String currentLocalityId = LocationHelper.getInstance().getOpenMrsLocationId(currentLocality);
1✔
885
                if (StringUtils.isNotBlank(currentLocalityId) && !defaultLocationId.equalsIgnoreCase(currentLocalityId)) {
1✔
886
                    return AllConstants.DATA_CAPTURE_STRATEGY.ADVANCED.equals(allSharedPreferences.fetchCurrentDataStrategy()) ? Constants.ADVANCED_DATA_CAPTURE_STRATEGY_PREFIX + VaccinatorUtils.createIdentifier(currentLocalityId) : currentLocalityId;
1✔
887
                }
888
            }
889
        } catch (Exception e) {
×
890
            Timber.e(e);
×
891
        }
1✔
892

893
        return null;
1✔
894
    }
895

896
    public static void updateDateOfRemoval(String baseEntityId, String dateOfRemovalString) {
897
        ContentValues contentValues = new ContentValues();
1✔
898

899
        if (dateOfRemovalString != null) {
1✔
900
            contentValues.put(Constants.KEY.DATE_REMOVED, dateOfRemovalString);
1✔
901
        }
902

903
        ChildLibrary.getInstance().eventClientRepository().getWritableDatabase()
1✔
904
                .update(Utils.metadata().getRegisterQueryProvider().getDemographicTable(), contentValues, Constants.KEY.BASE_ENTITY_ID + " = ?",
1✔
905
                        new String[]{baseEntityId});
906
    }
1✔
907

908
    /**
909
     * Generic method for obtaining location for submitting event. Defaults to team location;
910
     *
911
     * @param context Android context required for location picker view
912
     * @return Location id used to sync events
913
     */
914
    public static String getProviderLocationId(Context context) {
915

916
        AllSharedPreferences allSharedPreferences = org.smartregister.util.Utils.getAllSharedPreferences();
1✔
917

918
        return ChildLibrary.getInstance().getProperties().isTrue(ChildAppProperties.KEY.SYNC_BY_DEFAULT_FACILITY_ID_ENABLED) ?
1✔
919
                allSharedPreferences.fetchDefaultLocalityId(allSharedPreferences.fetchRegisteredANM()) : getProviderCurrentSelectedLocationId(context, allSharedPreferences);
1✔
920
    }
921

922
    protected static String getProviderCurrentSelectedLocationId(Context context, AllSharedPreferences allSharedPreferences) {
923
        try {
924
            String currentLocality = allSharedPreferences.getPreference(AllConstants.CURRENT_LOCATION_ID);
1✔
925
            String openMrsLocationId = LocationHelper.getInstance().getOpenMrsLocationId(currentLocality);
1✔
926
            if (StringUtils.isNotBlank(openMrsLocationId)) return currentLocality;
1✔
927
        } catch (NullPointerException exception) {
1✔
928
            LocationPickerView locationPickerView = ChildLibrary.getInstance().getLocationPickerView(context);
1✔
929
            if (locationPickerView != null) {
1✔
930
                String locationId = LocationHelper.getInstance().getOpenMrsLocationId(locationPickerView.getSelectedItem());
×
931
                if (StringUtils.isNotBlank(locationId)) return locationId;
×
932
            }
933
            Timber.e(exception);
1✔
934
        }
1✔
935
        return allSharedPreferences.fetchDefaultLocalityId(allSharedPreferences.fetchRegisteredANM());
1✔
936
    }
937

938
    public static ChildEventClient processChildDetailsForm(String jsonString, FormTag formTag) {
939
        try {
940
            Triple<Boolean, JSONObject, JSONArray> registrationFormParams = validateParameters(jsonString);
1✔
941

942
            if (!registrationFormParams.getLeft()) {
1✔
943
                return null;
×
944
            }
945

946
            JSONObject jsonForm = registrationFormParams.getMiddle();
1✔
947
            JSONArray fields = registrationFormParams.getRight();
1✔
948

949
            String entityId = getString(jsonForm, ENTITY_ID);
1✔
950
            if (StringUtils.isBlank(entityId)) {
1✔
951
                entityId = generateRandomUUIDString();
1✔
952
            }
953

954
            processGender(fields);//multi language to re visit
1✔
955

956
            processLocationFields(fields);
1✔
957

958
            lastInteractedWith(fields);
1✔
959

960
            dobUnknownUpdateFromAge(fields, Constants.CHILD_TYPE);
1✔
961

962
            JSONObject dobUnknownObject = getFieldJSONObject(fields, Constants.JSON_FORM_KEY.DATE_BIRTH);
1✔
963

964
            String date = dobUnknownObject.getString(Constants.KEY.VALUE);
1✔
965
            dobUnknownObject.put(Constants.KEY.VALUE, Utils.reverseHyphenatedString(date) + " 12:00:00");
1✔
966

967
            Client baseClient = ChildJsonFormUtils.createBaseClient(fields, formTag, entityId);
1✔
968
            baseClient.setRelationalBaseEntityId(getString(jsonForm, Constants.KEY.RELATIONAL_ID));//mama
1✔
969
            baseClient.setClientType(Constants.CHILD_TYPE);
1✔
970
            tagSyncMetadata(baseClient);
1✔
971

972
            Event baseEvent = ChildJsonFormUtils.createEvent(fields, getJSONObject(jsonForm, METADATA),
1✔
973
                    formTag, entityId, jsonForm.getString(ChildJsonFormUtils.ENCOUNTER_TYPE), Constants.CHILD_TYPE);
1✔
974

975
            for (int i = baseEvent.getObs().size() - 1; i > -1; i--) {
1✔
976
                Obs obs = baseEvent.getObs().get(i);
1✔
977

978
                if (obs != null && "mother_hiv_status".equals(obs.getFormSubmissionField())) {
1✔
979
                    List<Object> values = obs.getValues();
1✔
980

981
                    if (values != null && values.size() == 1 && values.get(0) == null) {
1✔
982
                        baseEvent.getObs().remove(obs);
1✔
983
                    }
984
                }
985
            }
986

987
            ChildJsonFormUtils.tagSyncMetadata(baseEvent);// tag docs
1✔
988

989
            //Add previous relational ids if they existed.
990
            addRelationships(baseClient, jsonString);
1✔
991

992
            tagClientLocation(baseClient, baseEvent);
1✔
993

994
            return new ChildEventClient(baseClient, baseEvent);
1✔
995
        } catch (Exception e) {
×
996
            Timber.e(e, "ChildJsonFormUtils --> processChildDetailsForm");
×
997
            return null;
×
998
        }
999
    }
1000

1001
    protected static Triple<Boolean, JSONObject, JSONArray> validateParameters(String jsonString) {
1002
        JSONObject jsonForm = toJSONObject(jsonString);
1✔
1003
        JSONArray fields = fields(jsonForm);
1✔
1004
        return Triple.of(jsonForm != null && fields != null, jsonForm, fields);
1✔
1005
    }
1006

1007
    protected static void processGender(JSONArray fields) {
1008
        try {
1009
            //TO DO Will need re-architecting later to support more languages, perhaps update the selector widget
1010

1011
            JSONObject genderObject = getFieldJSONObject(fields, Constants.SEX);
1✔
1012
            String genderValue = "";
1✔
1013

1014
            String rawGender = genderObject.getString(JsonFormConstants.VALUE);
1✔
1015
            char rawGenderChar = !TextUtils.isEmpty(rawGender) ? rawGender.charAt(0) : ' ';
1✔
1016
            switch (rawGenderChar) {
1✔
1017
                case 'm':
1018
                case 'M':
1019
                    genderValue = "Male";
1✔
1020
                    break;
1✔
1021

1022
                case 'f':
1023
                case 'F':
1024
                    genderValue = "Female";
×
1025
                    break;
×
1026

1027
                default:
1028
                    break;
1029

1030
            }
1031

1032
            genderObject.put(Constants.KEY.VALUE, genderValue);
1✔
1033
        } catch (JSONException e) {
×
1034
            Timber.e(e, "ChildJsonFormUtils --> processGender");
×
1035
        }
1✔
1036
    }
1✔
1037

1038
    /**
1039
     * Update value tag for fields of type tree with the locationId
1040
     *
1041
     * @param fields JSONArray of form fields
1042
     * @throws JSONException
1043
     */
1044
    protected static void processLocationFields(JSONArray fields) throws JSONException {
1045
        for (int i = 0; i < fields.length(); i++) {
1✔
1046
            if (fields.getJSONObject(i).has(JsonFormConstants.TYPE) && fields.getJSONObject(i).getString(JsonFormConstants.TYPE).equals(JsonFormConstants.TREE)) {
1✔
1047
                try {
1048
                    String rawValue = fields.getJSONObject(i).getString(JsonFormConstants.VALUE);
1✔
1049
                    JSONArray valueArray = new JSONArray(rawValue);
×
1050
                    if (valueArray.length() > 0) {
×
1051
                        String lastLocationName = valueArray.getString(valueArray.length() - 1);
×
1052
                        String lastLocationId = LocationHelper.getInstance().getOpenMrsLocationId(lastLocationName);
×
1053
                        fields.getJSONObject(i).put(JsonFormConstants.VALUE, lastLocationId);
×
1054
                    }
1055
                } catch (Exception e) {
1✔
1056
                    Timber.e(e, "JsonFormUitls --> processLocationFields");
1✔
1057
                }
×
1058
            }
1059
        }
1060
    }
1✔
1061

1062
    protected static void lastInteractedWith(JSONArray fields) {
1063
        try {
1064
            JSONObject lastInteractedWith = new JSONObject();
1✔
1065
            lastInteractedWith.put(Constants.KEY.KEY, Constants.JSON_FORM_KEY.LAST_INTERACTED_WITH);
1✔
1066
            lastInteractedWith.put(Constants.KEY.VALUE, Calendar.getInstance().getTimeInMillis());
1✔
1067
            fields.put(lastInteractedWith);
1✔
1068
        } catch (JSONException e) {
×
1069
            Timber.e(e, "ChildJsonFormUtils --> lastInteractedWith");
×
1070
        }
1✔
1071
    }
1✔
1072

1073
    protected static void dobUnknownUpdateFromAge(JSONArray fields, String entity) {
1074
        try {
1075

1076
            String dobUnknownField = entity.equalsIgnoreCase(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_DATE_BIRTH_UNKNOWN : Constants.JSON_FORM_KEY.DATE_BIRTH_UNKNOWN;
1✔
1077
            String dobField = entity.equalsIgnoreCase(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_DATE_BIRTH : Constants.JSON_FORM_KEY.DATE_BIRTH;
1✔
1078
            String dobAgeField = entity.equalsIgnoreCase(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_AGE : Constants.JSON_FORM_KEY.AGE;
1✔
1079

1080
            JSONObject dobUnknownObject = getFieldJSONObject(fields, dobUnknownField);
1✔
1081
            if (dobUnknownObject != null) {
1✔
1082

1083
                JSONArray options = getJSONArray(dobUnknownObject, Constants.JSON_FORM_KEY.OPTIONS);
1✔
1084
                boolean isDobUnknown = Boolean.valueOf(ChildJsonFormUtils.getFieldValue(options, dobUnknownField));
1✔
1085

1086
                if (isDobUnknown) {
1✔
1087

1088
                    String ageString = getFieldValue(fields, dobAgeField);
1✔
1089
                    if (StringUtils.isNotBlank(ageString) && StringUtils.isNumeric(ageString)) {
1✔
1090
                        int age = Integer.valueOf(ageString);
1✔
1091
                        JSONObject dobJSONObject = getFieldJSONObject(fields, dobField);
1✔
1092
                        dobJSONObject.put(VALUE, Utils.getDob(age));
1✔
1093

1094
                        //Mark the birth date as an approximation
1095
                        JSONObject isBirthdateApproximate = new JSONObject();
1✔
1096
                        isBirthdateApproximate.put(Constants.KEY.KEY, FormEntityConstants.Person.birthdate_estimated);
1✔
1097
                        isBirthdateApproximate.put(Constants.KEY.VALUE, Constants.BOOLEAN_INT.TRUE);
1✔
1098
                        isBirthdateApproximate.put(Constants.OPENMRS.ENTITY, Constants.OPENMRS_ENTITY.PERSON);//Required for value to be processed
1✔
1099
                        isBirthdateApproximate.put(Constants.OPENMRS.ENTITY_ID, FormEntityConstants.Person.birthdate_estimated);
1✔
1100
                        isBirthdateApproximate.put(ChildJsonFormUtils.ENTITY_ID, dobUnknownObject.getString(ChildJsonFormUtils.ENTITY_ID));
×
1101
                        fields.put(isBirthdateApproximate);
×
1102

1103
                    }
1104
                } else {
×
1105
                    //Else to override dob unknown flag incase it was already previously saved on the db
1106

1107
                    JSONObject dobUnknownValue = new JSONObject();
1✔
1108
                    dobUnknownValue.put(JsonFormConstants.KEY, dobUnknownField);
1✔
1109
                    dobUnknownValue.put(JsonFormConstants.VALUE, "false");
1✔
1110

1111
                    JSONArray dobUnknownValueArray = new JSONArray();
1✔
1112
                    dobUnknownValueArray.put(dobUnknownValue);
1✔
1113

1114
                    dobUnknownObject.put(JsonFormConstants.VALUE, dobUnknownValueArray);
1✔
1115
                }
1116
            }
1117
        } catch (JSONException e) {
1✔
1118
            Timber.e(e, "ChildJsonFormUtils --> dobUnknownUpdateFromAge");
1✔
1119
        }
1✔
1120
    }
1✔
1121

1122
    public static void mergeAndSaveClient(Client baseClient) throws Exception {
1123
        JSONObject updatedClientJson = new JSONObject(ChildJsonFormUtils.gson.toJson(baseClient));
1✔
1124
        JSONObject originalClientJsonObject = ChildLibrary.getInstance().getEcSyncHelper().getClient(baseClient.getBaseEntityId());
1✔
1125
        JSONObject mergedJson = ChildJsonFormUtils.merge(originalClientJsonObject, updatedClientJson);
1✔
1126
        //TODO Save edit log ?
1127
        ChildLibrary.getInstance().getEcSyncHelper().addClient(baseClient.getBaseEntityId(), mergedJson);
1✔
1128
    }
1✔
1129

1130
    public static void saveImage(String providerId, String entityId, String imageLocation) {
1131
        try {
1132
            if (StringUtils.isBlank(imageLocation)) {
1✔
1133
                return;
×
1134
            }
1135

1136
            File file = new File(imageLocation);
1✔
1137
            if (!file.exists()) {
1✔
1138
                return;
×
1139
            }
1140

1141
            Bitmap compressedImageFile = ChildLibrary.getInstance().getCompressor().compressToBitmap(file);
1✔
1142
            saveStaticImageToDisk(compressedImageFile, providerId, entityId);
1✔
1143
        } catch (IOException e) {
×
1144
            Timber.e(e, JsonFormConstants.class.getCanonicalName());
×
1145
        }
1✔
1146
    }
1✔
1147

1148
    private static void saveStaticImageToDisk(Bitmap image, String providerId, String entityId) {
1149
        if (image == null || StringUtils.isBlank(providerId) || StringUtils.isBlank(entityId)) {
1✔
1150
            return;
×
1151
        }
1152
        OutputStream os = null;
1✔
1153

1154
        try {
1155
            if (StringUtils.isNotBlank(entityId)) {
1✔
1156
                final String absoluteFileName = DrishtiApplication.getAppDir() + File.separator + entityId + ".JPEG";
1✔
1157

1158
                File outputFile = new File(absoluteFileName);
1✔
1159
                os = new FileOutputStream(outputFile);
1✔
1160
                Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG;
1✔
1161
                image.compress(compressFormat, 100, os);
1✔
1162
                // insert into the db
1163
                ProfileImage profileImage = new ProfileImage();
1✔
1164
                profileImage.setImageid(UUID.randomUUID().toString());
1✔
1165
                profileImage.setAnmId(providerId);
1✔
1166
                profileImage.setEntityID(entityId);
1✔
1167
                profileImage.setFilepath(absoluteFileName);
1✔
1168
                profileImage.setFilecategory("profilepic");
1✔
1169
                profileImage.setSyncStatus(ImageRepository.TYPE_Unsynced);
1✔
1170
                ImageRepository imageRepo = Utils.context().imageRepository();
1✔
1171
                imageRepo.add(profileImage);
1✔
1172
            }
1173
        } catch (FileNotFoundException e) {
×
1174
            Timber.e(e, "ChildJsonFormUtils --> Failed to save static image to disk");
×
1175
        } finally {
1176
            if (os != null) {
1✔
1177
                try {
1178
                    os.close();
1✔
1179
                } catch (IOException e) {
×
1180
                    Timber.e(e, "ChildJsonFormUtils --> Failed to close static images output stream after attempting to write image");
×
1181
                }
1✔
1182
            }
1183
        }
1184
    }
1✔
1185

1186
    /**
1187
     * Get JSON form string of the form populated with child's details
1188
     *
1189
     * @param context      Form context
1190
     * @param childDetails Map of child details to populate form
1191
     * @return JSON string of the form metadata
1192
     */
1193
    public static String getMetadataForEditForm(Context context, Map<String, String> childDetails) {
1194
        return getMetadataForEditForm(context, childDetails, new ArrayList<String>());
1✔
1195
    }
1196

1197
    /**
1198
     * Get JSON form string of the form populated with child's details
1199
     *
1200
     * @param context           Form context
1201
     * @param childDetails      Map of child details to populate form
1202
     * @param nonEditableFields List of fields not editable on the form
1203
     * @return JSON string of the form metadata
1204
     */
1205
    public static String getMetadataForEditForm(Context context, Map<String, String> childDetails, List<String> nonEditableFields) {
1206
        try {
1207
            JSONObject form = new FormUtils(context).getFormJson(Utils.metadata().childRegister.formName);
1✔
1208

1209
            if (form != null) {
1✔
1210
                ChildJsonFormUtils.addRegistrationFormLocationHierarchyQuestions(form);
1✔
1211

1212
                Timber.d("Form is %s", form.toString());
1✔
1213

1214
                form.put(ChildJsonFormUtils.ENTITY_ID, childDetails.get(Constants.KEY.BASE_ENTITY_ID));
1✔
1215
                form.put(ChildJsonFormUtils.ENCOUNTER_TYPE, Utils.metadata().childRegister.updateEventType);
1✔
1216
                form.put(ChildJsonFormUtils.RELATIONAL_ID, childDetails.get(RELATIONAL_ID));
1✔
1217
                form.put(ChildJsonFormUtils.CURRENT_ZEIR_ID,
1✔
1218
                        Utils.getValue(childDetails, Constants.KEY.ZEIR_ID, true).replace("-", ""));
1✔
1219
                form.put(ChildJsonFormUtils.CURRENT_OPENSRP_ID,
1✔
1220
                        Utils.getValue(childDetails, Constants.JSON_FORM_KEY.UNIQUE_ID, false));
1✔
1221

1222
                JSONObject metadata = form.getJSONObject(ChildJsonFormUtils.METADATA);
1✔
1223

1224
                metadata.put(ChildJsonFormUtils.ENCOUNTER_LOCATION, ChildJsonFormUtils.getProviderLocationId(context));
1✔
1225

1226
                prePopulateJsonFormFields(form, childDetails, nonEditableFields);
1✔
1227

1228
                return form.toString();
1✔
1229
            }
1230
        } catch (Exception e) {
1✔
1231
            Timber.e(e, "ChildJsonFormUtils --> getMetadataForEditForm");
1✔
1232
        }
×
1233

1234
        return "";
1✔
1235
    }
1236

1237
    /**
1238
     * Populate JSON form object fields with values passed in the childDetails map
1239
     *
1240
     * @param form              JSON form
1241
     * @param childDetails      Map of values to be pre-populated
1242
     * @param nonEditableFields List of fields that should not be editable
1243
     * @throws JSONException
1244
     */
1245
    public static void prePopulateJsonFormFields(JSONObject form, Map<String, String> childDetails, List<String> nonEditableFields) throws JSONException {
1246
        JSONObject stepOne = form.getJSONObject(ChildJsonFormUtils.STEP1);
1✔
1247
        JSONArray jsonArray = stepOne.getJSONArray(ChildJsonFormUtils.FIELDS);
1✔
1248

1249
        for (int i = 0; i < jsonArray.length(); i++) {
1✔
1250
            JSONObject jsonObject = jsonArray.getJSONObject(i);
1✔
1251
            setFormFieldValues(childDetails, nonEditableFields, jsonObject);
1✔
1252
        }
1253
    }
1✔
1254

1255
    private static void setFormFieldValues(Map<String, String> childDetails, List<String> nonEditableFields, JSONObject jsonObject)
1256
            throws JSONException {
1257

1258
        String prefix = getEntityPrefix(jsonObject);
1✔
1259

1260
        String dobUnknownField = prefix.startsWith(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_DATE_BIRTH_UNKNOWN : Constants.JSON_FORM_KEY.DATE_BIRTH_UNKNOWN;
1✔
1261
        String dobAgeField = prefix.startsWith(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_AGE : Constants.JSON_FORM_KEY.AGE;
1✔
1262

1263
        setFormFieldInitDataCleanUp(childDetails, prefix);
1✔
1264

1265
        if (jsonObject.getString(ChildJsonFormUtils.KEY).equalsIgnoreCase(Constants.KEY.PHOTO)) {
1✔
1266
            processPhoto(childDetails.get(Constants.KEY.BASE_ENTITY_ID), jsonObject);
1✔
1267
        } else if (jsonObject.getString(ChildJsonFormUtils.KEY).equalsIgnoreCase(dobUnknownField)) {
1✔
1268
            JSONObject optionsObject = jsonObject.getJSONArray(Constants.JSON_FORM_KEY.OPTIONS).getJSONObject(0);
1✔
1269
            optionsObject.put(ChildJsonFormUtils.VALUE, Utils.getValue(childDetails, prefix + Constants.KEY.DOB_UNKNOWN, false));
1✔
1270
        } else if (jsonObject.getString(ChildJsonFormUtils.KEY).equalsIgnoreCase(dobAgeField)) {
1✔
1271
            processAge(Utils.getValue(childDetails, prefix + Constants.KEY.DOB, false), jsonObject);
1✔
1272
        } else if (jsonObject.getString(JsonFormConstants.TYPE).equalsIgnoreCase(JsonFormConstants.DATE_PICKER)) {
1✔
1273
            processDate(childDetails, prefix, jsonObject);
1✔
1274
        } else if (jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY).equalsIgnoreCase(ChildJsonFormUtils.PERSON_INDENTIFIER)) {
1✔
1275
            jsonObject.put(ChildJsonFormUtils.VALUE, getMappedValue(jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY_ID), childDetails).replace("-", ""));
1✔
1276
        } else if (jsonObject.has(JsonFormConstants.TREE)) {
1✔
1277
            processTree(jsonObject, Utils.getValue(childDetails, jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY).equalsIgnoreCase(ChildJsonFormUtils.PERSON_ADDRESS) ? prefix + jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY_ID) : jsonObject.getString(ChildJsonFormUtils.KEY), false));
1✔
1278
        } else if (jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY).equalsIgnoreCase(ChildJsonFormUtils.CONCEPT)) {
1✔
1279
            jsonObject.put(ChildJsonFormUtils.VALUE, getMappedValue(jsonObject.getString(ChildJsonFormUtils.KEY), childDetails));
1✔
1280
        } else if (jsonObject.has(Constants.JSON_FORM_KEY.SUB_TYPE) && jsonObject.getString(Constants.JSON_FORM_KEY.SUB_TYPE).equalsIgnoreCase(Constants.JSON_FORM_KEY.LOCATION_SUB_TYPE)) {
1✔
1281
            setSubTypeFieldValue(childDetails, jsonObject);
×
1282
        } else if (jsonObject.has(JsonFormConstants.OPTIONS_FIELD_NAME)) {
1✔
1283
            setOptionFieldValue(childDetails, jsonObject, prefix);
1✔
1284
        } else {
1285
            jsonObject.put(ChildJsonFormUtils.VALUE, getMappedValue(prefix + jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY_ID), childDetails));
1✔
1286
        }
1287

1288
        jsonObject.put(ChildJsonFormUtils.READ_ONLY, nonEditableFields.contains(jsonObject.getString(ChildJsonFormUtils.KEY)));
1✔
1289
    }
1✔
1290

1291
    @NotNull
1292
    public static String getEntityPrefix(JSONObject jsonObject) throws JSONException {
1293
        String prefix = "";
1✔
1294
        if (jsonObject.has(JsonFormUtils.ENTITY_ID)) {
1✔
1295
            String entityId = jsonObject.getString(JsonFormUtils.ENTITY_ID);
1✔
1296
            if (entityId.equalsIgnoreCase(Constants.KEY.MOTHER)) {
1✔
1297
                prefix = "mother_";
1✔
1298
            } else if (entityId.equalsIgnoreCase(Constants.KEY.FATHER)) {
×
1299
                prefix = "father_";
×
1300
            }
1301
        }
1302
        return prefix;
1✔
1303
    }
1304

1305
    public static void setSubTypeFieldValue(Map<String, String> childDetails, JSONObject jsonObject) throws JSONException {
1306
        if (!jsonObject.has(Constants.JSON_FORM_KEY.VALUE_FIELD) || jsonObject.getString(Constants.JSON_FORM_KEY.VALUE_FIELD).equalsIgnoreCase(jsonObject.getString(ChildJsonFormUtils.KEY))) {
×
1307
            jsonObject.put(JsonFormConstants.VALUE, getMappedValue(jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY_ID), childDetails));
×
1308
        } else {
1309
            jsonObject.put(JsonFormConstants.VALUE, getMappedValue(jsonObject.getString(Constants.JSON_FORM_KEY.VALUE_FIELD), childDetails));
×
1310
        }
1311
    }
×
1312

1313
    private static void setOptionFieldValue(Map<String, String> childDetails, JSONObject jsonObject, String prefix) throws JSONException {
1314
        String val = getMappedValue(prefix + jsonObject.getString(ChildJsonFormUtils.KEY), childDetails);
1✔
1315
        String key = prefix + jsonObject.getString(ChildJsonFormUtils.KEY);
1✔
1316

1317
        if (!TextUtils.isEmpty(val)) {
1✔
1318
            JSONArray array = new JSONArray(val.charAt(0) == '[' ? val : "[" + key + "]");
×
1319
            jsonObject.put(JsonFormConstants.VALUE, array);
×
1320
        }
1321
    }
1✔
1322

1323
    private static void setFormFieldInitDataCleanUp(Map<String, String> childDetails, String prefix) {
1324
        //Inject if missing for entity age processing
1325
        String dobUnknownField = prefix.startsWith(Constants.KEY.MOTHER) ? Constants.JSON_FORM_KEY.MOTHER_GUARDIAN_DATE_BIRTH_UNKNOWN : Constants.JSON_FORM_KEY.DATE_BIRTH_UNKNOWN;
1✔
1326
        String dobUnknownKey = prefix + "dob_unknown";
1✔
1327

1328
        if (childDetails.containsKey(dobUnknownField) && !childDetails.containsKey(dobUnknownKey)) {
1✔
1329
            childDetails.put(dobUnknownKey, childDetails.get(dobUnknownField));
×
1330
        }
1331
    }
1✔
1332

1333
    private static void processTree(JSONObject jsonObject, String entity) throws JSONException {
1334
        List<String> entityHierarchy = null;
1✔
1335

1336
        if (entity != null) {
1✔
1337
            if (entity.equalsIgnoreCase("other")) {
1✔
1338
                entityHierarchy = new ArrayList<>();
×
1339
                entityHierarchy.add(entity);
×
1340
            } else {
1341
                entityHierarchy = LocationHelper.getInstance().getOpenMrsLocationHierarchy(entity, false);
1✔
1342
            }
1343
        }
1344

1345
        String birthFacilityHierarchyString = AssetHandler.javaToJsonString(entityHierarchy, new TypeToken<List<String>>() {
1✔
1346
        }.getType());
1✔
1347
        jsonObject.put(ChildJsonFormUtils.VALUE, birthFacilityHierarchyString);
1✔
1348
    }
1✔
1349

1350
    protected static void processPhoto(String baseEntityId, JSONObject jsonObject) throws JSONException {
1351
        if (StringUtils.isNotBlank(baseEntityId)) {
1✔
1352
            Photo photo = ImageUtils.profilePhotoByClientID(baseEntityId, Utils.getProfileImageResourceIDentifier());
×
1353
            if (StringUtils.isNotBlank(photo.getFilePath())) {
×
1354
                jsonObject.put(ChildJsonFormUtils.VALUE, photo.getFilePath());
×
1355
            }
1356
        }
1357
    }
1✔
1358

1359
    protected static void processAge(String dobString, JSONObject jsonObject) throws JSONException {
1360
        if (StringUtils.isNotBlank(dobString)) {
1✔
1361
            jsonObject.put(ChildJsonFormUtils.VALUE, Utils.getAgeFromDate(dobString));
1✔
1362
        }
1363
    }
1✔
1364

1365
    protected static void processDate(Map<String, String> childDetails, String prefix, JSONObject jsonObject) throws JSONException {
1366
        String key = jsonObject.getString(ChildJsonFormUtils.OPENMRS_ENTITY_ID).equalsIgnoreCase(FormEntityConstants.Person.birthdate.toString()) ? prefix + Constants.KEY.DOB : jsonObject.getString(ChildJsonFormUtils.KEY);
1✔
1367
        String dateString = Utils.getValue(childDetails, key, false);
1✔
1368
        dateString = StringUtils.isBlank(dateString) ? Utils.getValue(childDetails, key.toLowerCase(Locale.ENGLISH), false) : dateString;
1✔
1369
        String isDOBUnknown = childDetails.get(prefix + Constants.KEY.DOB_UNKNOWN);
1✔
1370
        if (isDOBUnknown == null || !Boolean.parseBoolean(isDOBUnknown)) {
1✔
1371
            Date date = Utils.dobStringToDate(dateString);
1✔
1372
            if (StringUtils.isNotBlank(dateString) && date != null) {
1✔
1373
                jsonObject.put(ChildJsonFormUtils.VALUE, DATE_FORMAT.format(date));
1✔
1374
            }
1375
        }
1376
    }
1✔
1377

1378
    protected static String getMappedValue(String key, Map<String, String> childDetails) {
1379
        String value = Utils.getValue(childDetails, key.toUpperCase(Locale.ENGLISH), false);
1✔
1380

1381
        return !TextUtils.isEmpty(value) ? value : Utils.getValue(childDetails, key.toLowerCase(Locale.ENGLISH), false);
1✔
1382
    }
1383

1384
    protected static Triple<Boolean, JSONObject, JSONArray> validateParameters(String jsonString, String step) {
1385
        JSONObject jsonForm = toJSONObject(jsonString);
×
1386
        JSONArray fields = fields(jsonForm, step);
×
1387

1388
        return Triple.of(jsonForm != null && fields != null, jsonForm, fields);
×
1389
    }
1390

1391
    public static JSONArray fields(JSONObject jsonForm, String step) {
1392
        try {
1393
            JSONObject step1 = jsonForm.has(step) ? jsonForm.getJSONObject(step) : null;
1✔
1394

1395
            if (step1 == null) {
1✔
1396
                return null;
1✔
1397
            }
1398

1399
            return step1.has(FIELDS) ? step1.getJSONArray(FIELDS) : null;
1✔
1400
        } catch (JSONException e) {
×
1401
            Timber.e(e, "ChildJsonFormUtils --> fields");
×
1402
        }
1403
        return null;
×
1404
    }
1405

1406
    public static FormTag formTag(AllSharedPreferences allSharedPreferences) {
1407
        FormTag formTag = new FormTag();
1✔
1408
        formTag.providerId = allSharedPreferences.fetchRegisteredANM();
1✔
1409
        formTag.team = allSharedPreferences.fetchDefaultTeam(allSharedPreferences.fetchRegisteredANM());
1✔
1410
        formTag.teamId = allSharedPreferences.fetchDefaultTeamId(allSharedPreferences.fetchRegisteredANM());
1✔
1411
        formTag.appVersion = ChildLibrary.getInstance().getApplicationVersion();
1✔
1412
        formTag.appVersionName = ChildLibrary.getInstance().getApplicationVersionName();
1✔
1413
        formTag.databaseVersion = ChildLibrary.getInstance().getDatabaseVersion();
1✔
1414
        return formTag;
1✔
1415
    }
1416

1417
    public static String getFieldValue(String jsonString, String step, String key) {
1418
        JSONObject jsonForm = toJSONObject(jsonString);
1✔
1419
        if (jsonForm == null) {
1✔
1420
            return null;
1✔
1421
        }
1422

1423
        JSONArray fields = fields(jsonForm, step);
1✔
1424
        if (fields == null) {
1✔
1425
            return null;
1✔
1426
        }
1427

1428
        return getFieldValue(fields, key);
1✔
1429
    }
1430

1431
    public static ChildEventClient processMotherRegistrationForm(String jsonString, String relationalId, ChildEventClient base, boolean isEditMode) {
1432
        try {
1433
            return processParentEventForm(jsonString, relationalId, base, Constants.KEY.MOTHER, isEditMode);
1✔
1434
        } catch (Exception e) {
×
1435
            Timber.e(e, "ChildJsonFormUtils --> processMotherRegistrationForm");
×
1436
            return null;
×
1437
        }
1438
    }
1439

1440
    public static ChildEventClient processFatherRegistrationForm(String jsonString, String relationalId, ChildEventClient base, boolean isEditMode) {
1441
        try {
1442
            return processParentEventForm(jsonString, relationalId, base, Constants.KEY.FATHER, isEditMode);
1✔
1443
        } catch (Exception e) {
×
1444
            Timber.e(e, "ChildJsonFormUtils --> processFatherRegistrationForm");
×
1445
            return null;
×
1446
        }
1447
    }
1448

1449
    @Nullable
1450
    private static ChildEventClient processParentEventForm(String jsonString, String relationalId, ChildEventClient childEventClient, String bindType, boolean isEditMode)
1451
            throws JSONException {
1452

1453
        Triple<Boolean, JSONObject, JSONArray> registrationFormParams = validateParameters(jsonString);
1✔
1454

1455
        if (bindType.equals(Constants.KEY.FATHER)) {
1✔
1456
            boolean isFatherDetailsValid = validateFatherDetails(jsonString);
1✔
1457
            if (!isFatherDetailsValid) {
1✔
1458
                return null;
1✔
1459
            }
1460
        }
1461

1462
        if (!registrationFormParams.getLeft()) {
1✔
1463
            return null;
×
1464
        } else {
1465

1466
            Client baseClient = childEventClient.getClient();
1✔
1467
            Event baseEvent = childEventClient.getEvent();
1✔
1468

1469
            JSONObject jsonForm = registrationFormParams.getMiddle();
1✔
1470
            JSONArray fields = registrationFormParams.getRight();
1✔
1471

1472
            JSONObject metadata = getJSONObject(jsonForm, METADATA);
1✔
1473

1474
            JSONObject lookUpJSONObject = getJSONObject(metadata, Constants.KEY.LOOK_UP);
1✔
1475

1476
            //Currently lookup works only for mothers - do not create new events for existing mothers.
1477
            if (lookUpJSONObject != null && bindType.equalsIgnoreCase(Constants.KEY.MOTHER) &&
1✔
1478
                    StringUtils.isNotBlank(getString(lookUpJSONObject, JsonFormConstants.VALUE))) {
1✔
1479
                return null;
×
1480
            } else {
1481

1482
                processLocationFields(fields);
1✔
1483

1484
                dobUnknownUpdateFromAge(fields, Constants.KEY.MOTHER);
1✔
1485

1486
                Event subFormEvent = null;
1✔
1487

1488
                Client subformClient = createSubFormClient(fields, baseClient, bindType, relationalId, isEditMode);
1✔
1489

1490
                //only set default gender if not explicitly set in the registration form
1491
                if (StringUtils.isBlank(subformClient.getGender()) && bindType.equalsIgnoreCase(Constants.KEY.MOTHER)) {
1✔
1492
                    subformClient.setGender(Constants.GENDER.FEMALE);
1✔
1493
                } else if (StringUtils.isBlank(subformClient.getGender()) && bindType.equalsIgnoreCase(Constants.KEY.FATHER)) {
×
1494
                    subformClient.setGender(Constants.GENDER.MALE);
×
1495
                }
1496

1497
                if (baseEvent != null) {
1✔
1498
                    JSONObject subBindTypeJson = getJSONObject(jsonForm, bindType);
1✔
1499
                    if (subBindTypeJson != null) {
1✔
1500
                        String subBindTypeEncounter = getString(subBindTypeJson, ENCOUNTER_TYPE);
1✔
1501
                        if (StringUtils.isNotBlank(subBindTypeEncounter)) {
1✔
1502
                            subFormEvent = ChildJsonFormUtils.createSubFormEvent(getEntityFields(fields, bindType), metadata, baseEvent, subformClient.getBaseEntityId(), subBindTypeEncounter, bindType);
1✔
1503
                        }
1504
                    }
1505
                }
1506

1507
                lastInteractedWith(fields);
1✔
1508
                ChildJsonFormUtils.tagSyncMetadata(subFormEvent);
1✔
1509
                tagClientLocation(subformClient, subFormEvent);
1✔
1510
                return new ChildEventClient(subformClient, subFormEvent);
1✔
1511
            }
1512
        }
1513
    }
1514

1515
    private static void tagClientLocation(Client baseClient, Event baseEvent) {
1516
        //Tag client with event's location and team
1517
        baseClient.setLocationId(baseEvent.getLocationId());
1✔
1518
        baseClient.setTeamId(baseEvent.getTeamId());
1✔
1519
    }
1✔
1520

1521
    public static boolean validateFatherDetails(String jsonString) {
1522
        JSONObject jsonForm = toJSONObject(jsonString);
1✔
1523
        JSONArray fields = fields(jsonForm);
1✔
1524
        boolean isFormValid = false;
1✔
1525

1526
        // Further validate father details field since they are optional
1527
        if (jsonForm.has(Constants.KEY.FATHER) && fields != null) {
1✔
1528
            for (int fieldIndex = 0; fieldIndex < fields.length(); fieldIndex++) {
×
1529
                try {
1530
                    JSONObject field = fields.getJSONObject(fieldIndex);
×
1531
                    if (field.has(ENTITY_ID) && field.getString(ENTITY_ID).equalsIgnoreCase(Constants.KEY.FATHER) &&
×
1532
                            field.has(JsonFormConstants.VALUE)) {
×
1533
                        String value = field.getString(JsonFormConstants.VALUE);
×
1534
                        isFormValid = StringUtils.isNotBlank(value);
×
1535
                        if (isFormValid) {
×
1536
                            //TODO Fix bug in spinner setting value as the hint/label when nothing is selected - Native Form issue
1537
                            if (field.getString(JsonFormConstants.TYPE).equalsIgnoreCase(JsonFormConstants.SPINNER)
×
1538
                                    && value.equalsIgnoreCase(field.getString(JsonFormConstants.HINT))) {
×
1539
                                isFormValid = false;
×
1540
                                continue;
×
1541
                            }
1542
                            break;
×
1543
                        }
1544
                    }
1545
                } catch (JSONException e) {
×
1546
                    Timber.e(e);
×
1547
                }
×
1548
            }
1549
        }
1550
        return isFormValid;
1✔
1551
    }
1552

1553
    /**
1554
     * Adds relationship as defined in the  ec_client_relationship.json file.
1555
     * <p>
1556
     * create ec_client_relationship.json file in your assets directory that is a json array in the format
1557
     * [
1558
     * {
1559
     * "client_relationship": "mother",
1560
     * "field": "entity_id",
1561
     * "comment": "Mother relational id"
1562
     * },
1563
     * {
1564
     * "client_relationship": "father",
1565
     * "field": "entity_id",
1566
     * "comment": "Father relational id"
1567
     * }
1568
     * ]
1569
     *
1570
     * @param childClient childClient client object
1571
     * @param jsonString  form json
1572
     */
1573
    private static void addRelationships(Client childClient, String jsonString) {
1574
        try {
1575
            JSONObject jsonForm = toJSONObject(jsonString);
1✔
1576
            JSONObject metadata = getJSONObject(jsonForm, METADATA);
1✔
1577
            JSONObject lookUpJSONObject = getJSONObject(metadata, Constants.KEY.LOOK_UP);
1✔
1578

1579
            String existingMotherRelationalId = null;
1✔
1580
            if (lookUpJSONObject != null) {
1✔
1581
                existingMotherRelationalId = getString(lookUpJSONObject, JsonFormConstants.VALUE);
1✔
1582
            }
1583

1584
            Context context = ChildLibrary.getInstance().context().applicationContext();
1✔
1585
            JSONArray relationships = getArrayFromFile(context, FormUtils.ecClientRelationships);
×
1586
            JSONObject client = ChildLibrary.getInstance().eventClientRepository().getClientByBaseEntityId(childClient.getBaseEntityId());
×
1587
            if (client != null && client.has(Constants.JSON_FORM_KEY.RELATIONSHIPS)) {
×
1588
                JSONObject relationshipsJson = client.getJSONObject(Constants.JSON_FORM_KEY.RELATIONSHIPS);
×
1589
                for (int i = 0; i < relationships.length(); i++) {
×
1590
                    JSONObject relationship = relationships.getJSONObject(i);
×
1591
                    if (relationship.has(Constants.CLIENT_RELATIONSHIP)) {
×
1592
                        String relationshipType = relationship.getString(Constants.CLIENT_RELATIONSHIP);
×
1593
                        if (relationshipsJson.has(relationshipType)) {
×
1594
                            childClient.addRelationship(relationshipType, String.valueOf(relationshipsJson.getJSONArray(relationshipType).get(0)));
×
1595
                        }
1596
                    }
1597
                }
1598
                return;
×
1599
            }
1600

1601
            //Special case - add relationship for existing mothers when creating this child as a sibling
1602
            if (StringUtils.isNotBlank(existingMotherRelationalId)) {
×
1603
                childClient.addRelationship(Constants.KEY.MOTHER, existingMotherRelationalId);
×
1604
            }
1605
        } catch (Exception e) {
1✔
1606
            Timber.e(e, "ChildJsonFormUtils --> addRelationship");
1✔
1607
        }
×
1608
    }
1✔
1609

1610
    /**
1611
     * Get Relations for the child with the provided entity id
1612
     *
1613
     * @param baseEntityId child base entity id
1614
     * @param bindType     type of relationship e.g father, mother
1615
     * @return First relational id of the given relation type
1616
     * @throws JSONException when it fails to retrieve the relationships
1617
     */
1618
    public static String getRelationalIdByType(String baseEntityId, String bindType) throws JSONException {
1619
        JSONObject client = ChildLibrary.getInstance().eventClientRepository().getClientByBaseEntityId(baseEntityId);
1✔
1620
        if (client != null && client.has(Constants.JSON_FORM_KEY.RELATIONSHIPS)) {
1✔
1621
            JSONObject relationships = client.getJSONObject(Constants.JSON_FORM_KEY.RELATIONSHIPS);
1✔
1622
            if (relationships.has(bindType)) {
1✔
1623
                return String.valueOf(relationships.getJSONArray(bindType).get(0));
1✔
1624
            }
1625
        }
1626
        return null;
1✔
1627
    }
1628

1629
    private static Client createSubFormClient(JSONArray fields, Client parent, String bindType, String entityRelationId, boolean isEditMode) {
1630
        if (StringUtils.isBlank(bindType)) {
1✔
1631
            return null;
×
1632
        }
1633
        String stringBirthDate = getSubFormFieldValue(fields, FormEntityConstants.Person.birthdate, bindType);
1✔
1634
        Map<String, String> identifierMap = !isEditMode ? getSubFormIdentifierMap(bindType) : new HashMap<>();
1✔
1635
        Date birthDate = formatDate(stringBirthDate, true);
1✔
1636
        birthDate = cleanBirthDateForSave(birthDate);//Fix weird bug day decrements on save
1✔
1637
        String stringDeathDate = getSubFormFieldValue(fields, FormEntityConstants.Person.deathdate, bindType);
1✔
1638
        Date deathDate = formatDate(stringDeathDate, true);
1✔
1639
        deathDate = cleanBirthDateForSave(deathDate);
1✔
1640
        String approxBirthDate = getSubFormFieldValue(fields, FormEntityConstants.Person.birthdate_estimated, bindType);
1✔
1641
        boolean birthDateApprox = isDateApprox(approxBirthDate);
1✔
1642
        String approxDeathDate = getSubFormFieldValue(fields, FormEntityConstants.Person.deathdate_estimated, bindType);
1✔
1643
        boolean deathDateApprox = isDateApprox(approxDeathDate);
1✔
1644

1645
        List<Address> addresses = new ArrayList<>(extractAddresses(fields, bindType).values());
1✔
1646

1647
        Map<String, String> clientMap = getClientAttributes(fields, bindType, entityRelationId);
1✔
1648

1649
        Client client = getClient(clientMap, birthDate, deathDate, birthDateApprox, deathDateApprox, bindType);
1✔
1650
        client.withAddresses(addresses).withAttributes(extractAttributes(fields, clientMap.get(Constants.BIND_TYPE))).withIdentifiers(identifierMap);
1✔
1651

1652
        if (addresses.isEmpty()) {
1✔
1653
            client.withAddresses(parent.getAddresses());
1✔
1654
        }
1655

1656
        tagSyncMetadata(client);
1✔
1657
        return client;
1✔
1658
    }
1659

1660
    /**
1661
     * Fixes weird bug where day decrements on save
1662
     *
1663
     * @param birthDate birth date to process
1664
     */
1665
    @NotNull
1666
    private static Date cleanBirthDateForSave(Date birthDate) {
1667
        if (birthDate != null) {
1✔
1668
            return new LocalDateTime(birthDate.getTime()).plusHours(12).toDate();
×
1669
        } else {
1670
            return null;
1✔
1671
        }
1672
    }
1673

1674
    @NotNull
1675
    private static Client getClient(Map<String, String> clientMap, Date birthDate, Date deathDate, boolean birthDateApprox, boolean deathDateApprox, String bindType) {
1676
        return (Client) new Client(clientMap.get(Constants.ENTITY_ID), clientMap.get(Constants.FIRST_NAME), clientMap.get(Constants.MIDDLE_NAME), clientMap.get(Constants.LAST_NAME), birthDate, deathDate, birthDateApprox, deathDateApprox, clientMap.get(GENDER), bindType)
1✔
1677
                .withDateCreated(new Date());
1✔
1678
    }
1679

1680
    private static Map<String, String> getClientAttributes(JSONArray fields, String bindType, String relationalId) {
1681

1682
        String entityId = TextUtils.isEmpty(relationalId) ? generateRandomUUIDString() : relationalId;
1✔
1683
        String firstName = getSubFormFieldValue(fields, FormEntityConstants.Person.first_name, bindType);
1✔
1684
        String middleName = getSubFormFieldValue(fields, FormEntityConstants.Person.middle_name, bindType);
1✔
1685
        String lastName = getSubFormFieldValue(fields, FormEntityConstants.Person.last_name, bindType);
1✔
1686
        String gender = getSubFormFieldValue(fields, FormEntityConstants.Person.gender, bindType);
1✔
1687

1688
        Map<String, String> attributes = new HashMap<>();
1✔
1689
        attributes.put(Constants.ENTITY_ID, entityId);
1✔
1690
        attributes.put(Constants.FIRST_NAME, firstName);
1✔
1691
        attributes.put(Constants.MIDDLE_NAME, middleName);
1✔
1692
        attributes.put(Constants.LAST_NAME, lastName);
1✔
1693
        attributes.put(GENDER, gender);
1✔
1694
        attributes.put(Constants.BIND_TYPE, bindType);
1✔
1695
        return attributes;
1✔
1696
    }
1697

1698
    @NotNull
1699
    private static Map<String, String> getSubFormIdentifierMap(String bindType) {
1700
        Map<String, String> identifiers = new HashMap<>();
1✔
1701
        String parentZEIRId = Utils.getNextOpenMrsId();
1✔
1702
        if (StringUtils.isBlank(parentZEIRId)) {
1✔
1703
            return identifiers;
×
1704
        }
1705
        if (bindType.equalsIgnoreCase(Constants.KEY.MOTHER)) {
1✔
1706
            identifiers.put(M_ZEIR_ID, parentZEIRId);
1✔
1707
        } else if (bindType.equalsIgnoreCase(Constants.KEY.FATHER)) {
×
1708
            identifiers.put(F_ZEIR_ID, parentZEIRId);
×
1709
        }
1710
        return identifiers;
1✔
1711
    }
1712

1713
    private static boolean isDateApprox(String approxDate) {
1714
        boolean dateApprox = false;
1✔
1715
        if (!StringUtils.isEmpty(approxDate) && NumberUtils.isCreatable(approxDate)) {
1✔
1716
            int date = 0;
1✔
1717
            try {
1718
                date = Integer.parseInt(approxDate);
1✔
1719
            } catch (Exception e) {
1✔
1720
                Timber.e(e);
1✔
1721
            }
1✔
1722
            dateApprox = date > 0;
1✔
1723
        }
1724
        return dateApprox;
1✔
1725
    }
1726

1727
    private static Event createSubFormEvent(JSONArray fields, JSONObject metadata, Event parent,
1728
                                            String entityId, String encounterType, String bindType) {
1729

1730
        List<EventClient> eventClients = ChildLibrary.getInstance().eventClientRepository()
1✔
1731
                .getEventsByBaseEntityIdsAndSyncStatus(BaseRepository.TYPE_Unsynced, Collections.singletonList(entityId));
1✔
1732

1733
        Set<String> eligibleBindTypeEvents = eventTypeMap.get(bindType);
1✔
1734
        EventClient existingEventClient = null;
1✔
1735
        if (eligibleBindTypeEvents != null) {
1✔
1736
            for (EventClient eventClient : eventClients) {
1✔
1737
                if (eligibleBindTypeEvents.contains(eventClient.getEvent().getEventType())) {
×
1738
                    existingEventClient = eventClient;
×
1739
                    break;
×
1740
                }
1741
            }
×
1742
        }
1743
        boolean alreadyExists = eventClients.size() > 0;
1✔
1744

1745
        org.smartregister.domain.Event existingEvent = existingEventClient != null ? existingEventClient.getEvent() : null;
1✔
1746

1747
        Event event = getSubFormEvent(parent, entityId, encounterType, bindType, alreadyExists, existingEvent);
1✔
1748
        addSubFormEventObservations(fields, event);
1✔
1749
        updateMetadata(metadata, event);
1✔
1750

1751
        return event;
1✔
1752
    }
1753

1754
    private static void addSubFormEventObservations(JSONArray fields, Event event) {
1755
        if (fields != null && fields.length() != 0)
1✔
1756
            addSaveReportDeceasedObservations(fields, event);
1✔
1757
    }
1✔
1758

1759
    private static Event getSubFormEvent(Event parent, String entityId, String encounterType, String bindType, boolean alreadyExists, org.smartregister.domain.Event existingEvent) {
1760

1761
        Event event = (Event) new Event().withBaseEntityId(alreadyExists ? existingEvent.getBaseEntityId() : entityId)
1✔
1762
                .withEventDate(parent.getEventDate())
1✔
1763
                .withEventType(alreadyExists ? existingEvent.getEventType() : encounterType)
1✔
1764
                .withEntityType(bindType)
1✔
1765
                .withFormSubmissionId(alreadyExists ? existingEvent.getFormSubmissionId() : generateRandomUUIDString())
1✔
1766
                .withDateCreated(new Date());
1✔
1767

1768
        tagSyncMetadata(event);
1✔
1769

1770
        return event;
1✔
1771
    }
1772

1773
    private static JSONArray getEntityFields(JSONArray fields, String mother) throws JSONException {
1774
        JSONArray array = new JSONArray();
1✔
1775

1776
        for (int i = 0; i < fields.length(); i++) {
1✔
1777
            if (fields.getJSONObject(i).has(ENTITY_ID) && fields.getJSONObject(i).getString(ENTITY_ID).equals(mother)) {
1✔
1778
                array.put(fields.getJSONObject(i));
1✔
1779
            }
1780
        }
1781
        return array;
1✔
1782
    }
1783

1784
    public static boolean processMoveToCatchment(org.smartregister.Context openSRPContext, MoveToCatchmentEvent moveToCatchmentEvent) {
1785
        try {
1786
            JSONObject jsonObject = moveToCatchmentEvent.getJsonObject();
1✔
1787
            int eventsCount = jsonObject.has(Constants.NO_OF_EVENTS) ? jsonObject.getInt(Constants.NO_OF_EVENTS) : 0;
1✔
1788
            if (eventsCount == 0) {
1✔
1789
                return false;
1✔
1790
            }
1791

1792
            JSONArray events = getOutOFCatchmentJsonArray(jsonObject, Constants.EVENTS);
1✔
1793
            JSONArray clients = getOutOFCatchmentJsonArray(jsonObject, Constants.CLIENTS);
1✔
1794

1795
            // TODO: Mark clients as unsynced, update teamId & locationId
1796
            AllSharedPreferences allSharedPreferences = CoreLibrary.getInstance().context().allSharedPreferences();
1✔
1797
            String providerId = allSharedPreferences.fetchRegisteredANM();
1✔
1798
            String teamId = allSharedPreferences.fetchDefaultTeamId(providerId);
1✔
1799
            String locationId = allSharedPreferences.fetchUserLocalityId(providerId);
1✔
1800

1801
            for (int i = 0; i < clients.length(); i++) {
1✔
1802
                JSONObject client = clients.getJSONObject(i);
1✔
1803

1804
                if (moveToCatchmentEvent.isPermanent()) {
1✔
1805
                    client.put("syncStatus", BaseRepository.TYPE_Unsynced);
1✔
1806
                } else {
1807
                    client.put("syncStatus", BaseRepository.TYPE_Synced);
1✔
1808
                }
1809

1810
                client.put("teamId", teamId);
1✔
1811
                client.put("locationId", locationId);
1✔
1812
            }
1813

1814
            if (!moveToCatchmentEvent.isPermanent()) {
1✔
1815
                tagClients(clients);
1✔
1816
            }
1817

1818
            ChildLibrary.getInstance().getEcSyncHelper().batchSave(events, clients);
1✔
1819

1820
            List<Pair<Event, JSONObject>> eventPairList = MoveToMyCatchmentUtils.createEventList(ChildLibrary.getInstance().getEcSyncHelper(), events);
1✔
1821

1822
            if (moveToCatchmentEvent.isPermanent()) {
1✔
1823
                processMoveToCatchmentPermanent(openSRPContext.applicationContext(), openSRPContext.allSharedPreferences(), eventPairList);
1✔
1824
                processTriggerClientProcessorAndUpdateFTS(openSRPContext, clients);
1✔
1825
            } else {
1826
                processMoveToCatchmentTemporary(openSRPContext, events, clients, moveToCatchmentEvent.isCreateEvent());
1✔
1827
            }
1828

1829
            return true;
1✔
1830
        } catch (Exception e) {
1✔
1831
            Timber.e(e, "ChildJsonFormUtils --> processMoveToCatchment");
1✔
1832
        }
1833

1834
        return false;
1✔
1835
    }
1836

1837
    private static void tagClients(JSONArray clientList) throws JSONException {
1838
        for (int i = 0; i < clientList.length(); i++) {
1✔
1839
            clientList.getJSONObject(i).getJSONObject(Constants.Client.ATTRIBUTES).put(Constants.Client.IS_OUT_OF_CATCHMENT, true);
1✔
1840
        }
1841
    }
1✔
1842

1843
    private static void processTriggerClientProcessorAndUpdateFTS(org.smartregister.Context openSRPContext, JSONArray clients) throws Exception {
1844
        processClients(openSRPContext.allSharedPreferences(), ChildLibrary.getInstance().getEcSyncHelper());
1✔
1845

1846
        List<String> clientIds = getClientIdsFromClientsJsonArray(clients);
1✔
1847

1848
        Timber.i("Moved %s  client(s) to new catchment area.", clientIds.size());
1✔
1849
    }
1✔
1850

1851
    public static void processMoveToCatchmentTemporary(org.smartregister.Context opensrpContext, JSONArray events, JSONArray clients, boolean createEvent) throws Exception {
1852
        if (createEvent) {
1✔
1853
            Event moveToCatchmentSyncEvent = createMoveToCatchmentSyncEvent(opensrpContext, clients);
1✔
1854

1855
            convertAndPersistEvent(moveToCatchmentSyncEvent);
1✔
1856
        }
1857

1858
        List<String> formSubmissionIds = new ArrayList<>();
1✔
1859

1860
        for (int i = 0; i < events.length(); i++) {
1✔
1861
            formSubmissionIds.add(events.getJSONObject(i).getString("formSubmissionId"));
1✔
1862
        }
1863

1864
        List<EventClient> eventList = new ArrayList<>();
1✔
1865
        eventList.addAll(ChildLibrary.getInstance().getEcSyncHelper().getEvents(formSubmissionIds));
1✔
1866

1867
        ChildLibrary.getInstance().getClientProcessorForJava().processClient(eventList);
1✔
1868
        getClientIdsFromClientsJsonArray(clients);
1✔
1869
    }
1✔
1870

1871
    private static List<String> getClientIdsFromClientsJsonArray(JSONArray clients) throws JSONException {
1872
        List<String> clientBaseEntityIds = new ArrayList<>();
1✔
1873

1874
        for (int i = 0; i < clients.length(); i++) {
1✔
1875
            if (!clients.getJSONObject(i).getJSONObject(IDENTIFIERS).has(M_ZEIR_ID)) {
1✔
1876

1877
                clientBaseEntityIds.add(clients.getJSONObject(i).getString(Constants.Client.BASE_ENTITY_ID));
1✔
1878

1879
                ContentValues contentValues = new ContentValues();
1✔
1880
                contentValues.put(Constants.KEY.LAST_INTERACTED_WITH, Calendar.getInstance().getTimeInMillis());
1✔
1881
                updateChildFTSTables(contentValues, clients.getJSONObject(i).getString(Constants.Client.BASE_ENTITY_ID));
1✔
1882
            }
1883
        }
1884

1885
        return clientBaseEntityIds;
1✔
1886
    }
1887

1888
    private static JSONArray getOutOFCatchmentJsonArray(JSONObject jsonObject, String clients) throws JSONException {
1889
        return jsonObject.has(clients) ? jsonObject.getJSONArray(clients) : new JSONArray();
1✔
1890
    }
1891

1892
    private static void processMoveToCatchmentPermanent(Context context, AllSharedPreferences allSharedPreferences, List<Pair<Event, JSONObject>> eventList) {
1893
        String providerId = allSharedPreferences.fetchRegisteredANM();
1✔
1894
        String locationId = getProviderLocationId(context);
1✔
1895

1896
        //The identifiers for provider we are transferring TO
1897
        Identifiers localProviderIdentifiers = new Identifiers();
1✔
1898
        localProviderIdentifiers.setProviderId(allSharedPreferences.fetchRegisteredANM());
1✔
1899
        localProviderIdentifiers.setLocationId(locationId);
1✔
1900
        localProviderIdentifiers.setChildLocationId(ChildJsonFormUtils.getChildLocationId(allSharedPreferences.fetchDefaultLocalityId(allSharedPreferences.fetchRegisteredANM()), allSharedPreferences));
1✔
1901
        localProviderIdentifiers.setTeam(allSharedPreferences.fetchDefaultTeam(providerId));
1✔
1902
        localProviderIdentifiers.setTeamId(allSharedPreferences.fetchDefaultTeamId(providerId));
1✔
1903

1904
        for (Pair<Event, JSONObject> pair : eventList) {
1✔
1905
            Event event = pair.first;
1✔
1906
            JSONObject jsonEvent = pair.second;
1✔
1907

1908
            if (Utils.metadata().childRegister.registerEventType.equals(event.getEventType())) {
1✔
1909
                updateHomeFacility(locationId, event);
1✔
1910
            }
1911

1912
            if (Constants.EventType.BITRH_REGISTRATION.equals(event.getEventType())
1✔
1913
                    || Constants.EventType.NEW_WOMAN_REGISTRATION.equals(event.getEventType())
×
1914
                    || Constants.EventType.FATHER_REGISTRATION.equals(event.getEventType())) {
×
1915

1916
                //Create move to catchment event;
1917
                Event moveToCatchmentEvent = ChildJsonFormUtils.createMoveToCatchmentEvent(context, localProviderIdentifiers, event);
1✔
1918
                convertAndPersistEvent(moveToCatchmentEvent);
1✔
1919
            }
1920

1921
            /*
1922
            //To do uncomment to handle reports refresh
1923

1924
            if (Constants.EventType.VACCINATION.equals(event.getEventType())) {
1925
                for (Obs obs : event.getObs()) {
1926
                    if (obs.getFieldCode().equals(Constants.CONCEPT.VACCINE_DATE)) {
1927

1928
                        String vaccineName = obs.getFormSubmissionField();
1929
                        setVaccineAsInvalid(event.getBaseEntityId(), vaccineName);
1930
                    }
1931
                }
1932
            }
1933
            */
1934

1935
            // Update tags and Save unsynced event
1936
            ChildJsonFormUtils.tagSyncMetadata(event);
1✔
1937
            event.setVersion(System.currentTimeMillis());
1✔
1938
            JSONObject updatedJsonEvent = ChildLibrary.getInstance().getEcSyncHelper().convertToJson(event);
1✔
1939
            jsonEvent = ChildJsonFormUtils.merge(jsonEvent, updatedJsonEvent);
1✔
1940

1941
            ChildLibrary.getInstance().getEcSyncHelper().addEvent(event.getBaseEntityId(), jsonEvent);
1✔
1942
        }
1✔
1943
    }
1✔
1944

1945
    public static void convertAndPersistEvent(Event event) {
1946
        if (event != null) {
1✔
1947
            JSONObject jsonEvent = ChildLibrary.getInstance().getEcSyncHelper().convertToJson(event);
1✔
1948
            if (jsonEvent != null) {
1✔
1949
                ChildLibrary.getInstance().getEcSyncHelper().addEvent(event.getBaseEntityId(), jsonEvent);
1✔
1950
            }
1951
        }
1952
    }
1✔
1953

1954
    private static void updateHomeFacility(String toLocationId, Event event) {
1955
        // Update home facility
1956
        for (Obs obs : event.getObs()) {
1✔
1957
            if (obs.getFormSubmissionField().equals(Constants.HOME_FACILITY)) {
1✔
1958
                List<Object> values = new ArrayList<>();
×
1959
                values.add(toLocationId);
×
1960
                obs.setValues(values);
×
1961
                break;
×
1962
            }
1963
        }
1✔
1964
    }
1✔
1965

1966
    public static Event createMoveToCatchmentEvent(Context context, Identifiers toIdentifiers, Event referenceEvent) {
1967
        try {
1968
            //From Identifiers
1969
            String fromLocationId = referenceEvent.getLocationId();
1✔
1970

1971
            //To identifiers
1972
            String toProviderId = toIdentifiers.getProviderId();
1✔
1973
            String toLocationId = toIdentifiers.getLocationId();
1✔
1974
            String toChildLocationId = toIdentifiers.getChildLocationId();
1✔
1975
            String toTeam = toIdentifiers.getTeam();
1✔
1976
            String toTeamId = toIdentifiers.getTeamId();
1✔
1977

1978
            //Same location/provider, no need to move
1979
            if (toLocationId.equals(fromLocationId) || referenceEvent.getProviderId().equals(toProviderId)) {
1✔
1980
                return null;
×
1981
            }
1982

1983
            final String DATA_TYPE = "text";
1✔
1984

1985
            Event event = getEventAndTag(referenceEvent.getBaseEntityId(), MoveToMyCatchmentUtils.MOVE_TO_CATCHMENT_EVENT, new Date(), Constants.CHILD_TYPE);
1✔
1986

1987
            String formSubmissionField = "From_ProviderId";
1✔
1988
            List<Object> vall = new ArrayList<>();
1✔
1989
            vall.add(referenceEvent.getProviderId());
1✔
1990
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
1991
                    formSubmissionField));
1992

1993
            formSubmissionField = "From_LocationId";
1✔
1994
            vall = new ArrayList<>();
1✔
1995
            vall.add(referenceEvent.getLocationId());
1✔
1996
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
1997
                    formSubmissionField));
1998

1999

2000
            formSubmissionField = "From_Child_LocationId";
1✔
2001
            vall = new ArrayList<>();
1✔
2002
            vall.add(referenceEvent.getChildLocationId());
1✔
2003
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2004
                    formSubmissionField));
2005

2006
            formSubmissionField = "From_Team";
1✔
2007
            vall = new ArrayList<>();
1✔
2008
            vall.add(referenceEvent.getTeam());
1✔
2009
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2010
                    formSubmissionField));
2011

2012
            formSubmissionField = "From_TeamId";
1✔
2013
            vall = new ArrayList<>();
1✔
2014
            vall.add(referenceEvent.getTeamId());
1✔
2015
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2016
                    formSubmissionField));
2017

2018
            formSubmissionField = "To_ProviderId";
1✔
2019
            vall = new ArrayList<>();
1✔
2020
            vall.add(toProviderId);
1✔
2021
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2022
                    formSubmissionField));
2023

2024
            formSubmissionField = "To_LocationId";
1✔
2025
            vall = new ArrayList<>();
1✔
2026
            vall.add(toLocationId);
1✔
2027
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2028
                    formSubmissionField));
2029

2030

2031
            formSubmissionField = "To_Child_LocationId";
1✔
2032
            vall = new ArrayList<>();
1✔
2033
            vall.add(toChildLocationId);
1✔
2034
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2035
                    formSubmissionField));
2036

2037
            formSubmissionField = "To_Team";
1✔
2038
            vall = new ArrayList<>();
1✔
2039
            vall.add(toTeam);
1✔
2040
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2041
                    formSubmissionField));
2042

2043
            formSubmissionField = "To_TeamId";
1✔
2044
            vall = new ArrayList<>();
1✔
2045
            vall.add(toTeamId);
1✔
2046
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, formSubmissionField, "", vall, new ArrayList<>(), null,
1✔
2047
                    formSubmissionField));
2048

2049
            addMetaData(context, event, new Date());
1✔
2050

2051
            //This event type should be synced to the former location NOT the new one
2052
            //Reset required fields, client processor should then remove the moved events/clients from the database
2053
            event.setLocationId(fromLocationId);
1✔
2054
            event.setChildLocationId(referenceEvent.getChildLocationId());
1✔
2055
            event.setTeam(referenceEvent.getTeam());
1✔
2056
            event.setTeamId(referenceEvent.getTeamId());
1✔
2057
            event.setProviderId(referenceEvent.getProviderId());
1✔
2058

2059
            return event;
1✔
2060
        } catch (Exception e) {
×
2061
            Timber.e(e, "ChildJsonFormUtils --> createMoveToCatchmentEvent");
×
2062
            return null;
×
2063
        }
2064
    }
2065

2066
    public static Event createMoveToCatchmentSyncEvent(org.smartregister.Context opensrpContext, JSONArray clientList) {
2067
        try {
2068

2069
            if (clientList == null) {
1✔
2070
                return null;
×
2071
            }
2072

2073
            final String DATA_TYPE = "text";
1✔
2074

2075
            Event event = getEvent(opensrpContext.allSharedPreferences().fetchRegisteredANM(), getProviderLocationId(opensrpContext.applicationContext()), "", MoveToMyCatchmentUtils.MOVE_TO_CATCHMENT_SYNC_EVENT, new Date(), Constants.CHILD_TYPE);
1✔
2076

2077
            List<Object> val = new ArrayList<>();
1✔
2078

2079
            String clientBaseEntityId = "";
1✔
2080

2081
            for (int i = 0; i < clientList.length(); i++) {
1✔
2082

2083
                val.add(clientList.getJSONObject(i).optString(Constants.Client.BASE_ENTITY_ID));
1✔
2084

2085
                clientBaseEntityId = clientList.getJSONObject(i).getJSONObject(ChildJsonFormUtils.IDENTIFIERS).has(Constants.KEY.ZEIR_ID.toUpperCase(Locale.ENGLISH)) ? clientList.getJSONObject(i).optString(Constants.Client.BASE_ENTITY_ID) : clientBaseEntityId;
1✔
2086
            }
2087

2088
            event.addObs(new Obs(FORM_SUBMISSION_FIELD, DATA_TYPE, MoveToMyCatchmentUtils.MOVE_TO_CATCHMENT_IDENTIFIERS_FORM_FIELD, "", val, new ArrayList<>(), null, MoveToMyCatchmentUtils.MOVE_TO_CATCHMENT_IDENTIFIERS_FORM_FIELD));
1✔
2089
            event.setBaseEntityId(clientBaseEntityId);
1✔
2090

2091
            addMetaData(opensrpContext.applicationContext(), event, new Date());
1✔
2092

2093
            return event;
1✔
2094
        } catch (Exception e) {
×
2095
            Timber.e(e, "ChildJsonFormUtils --> createMoveToCatchmentSyncEvent");
×
2096
            return null;
×
2097
        }
2098
    }
2099

2100
    /**
2101
     * Starts an instance of JsonFormActivity with the provided form details
2102
     *
2103
     * @param context                     The activity form is being launched from
2104
     * @param jsonFormActivityRequestCode The request code to be used to launch {@link BaseChildFormActivity}
2105
     * @param formName                    The name of the form to launch
2106
     * @param uniqueId                    The unique entity id for the form (e.g child's ZEIR id)
2107
     * @param currentLocationId           OpenMRS id for the current device's location
2108
     * @throws Exception
2109
     */
2110
    public static void startForm(Activity context, int jsonFormActivityRequestCode, String formName,
2111
                                 String uniqueId, String currentLocationId) throws Exception {
2112

2113
        String entityId = uniqueId;
×
2114
        JSONObject form = new FormUtils(context).getFormJson(formName);
×
2115
        if (form != null) {
×
2116
            form.getJSONObject(METADATA).put(ENCOUNTER_LOCATION, currentLocationId);
×
2117
            if (Utils.metadata().childRegister.formName.equals(formName)) {
×
2118
                if (CoreLibrary.getInstance().context().getUniqueIdRepository().countUnUsedIds() < 2) {
×
2119
                    Utils.showShortToast(context, context.getString(R.string.no_openmrs_id));
×
2120
                    Timber.d( "ChildJsonFormUtils --> startForm: Unique ids are less than 2 required to register mother and child");
×
2121
                    return;
×
2122
                }
2123
                if (StringUtils.isBlank(entityId)) {
×
2124
                    UniqueIdRepository uniqueIdRepo = CoreLibrary.getInstance().context().getUniqueIdRepository();
×
2125
                    entityId = uniqueIdRepo.getNextUniqueId() != null ? uniqueIdRepo.getNextUniqueId().getOpenmrsId() : "";
×
2126
                    if (entityId.isEmpty()) {
×
2127
                        Utils.showShortToast(context, context.getString(R.string.no_openmrs_id));
×
2128
                        return;
×
2129
                    }
2130
                }
2131

2132
                addRegistrationFormLocationHierarchyQuestions(form);
×
2133
            } else if (Constants.JsonForm.OUT_OF_CATCHMENT_SERVICE.equals(formName)) {
×
2134
                addAvailableVaccines(context, form);
×
2135
            }
2136

2137
            // Inject opensrp id into the form
2138
            injectOpenSrpId(entityId, form);
×
2139

2140
            Form formParam = new Form();
×
2141
            formParam.setWizard(true);
×
2142
            formParam.setHideSaveLabel(true);
×
2143
            formParam.setNextLabel("");
×
2144

2145
            Intent intent = new Intent(context, Utils.metadata().childFormActivity);
×
2146
            intent.putExtra("json", form.toString());
×
2147
            intent.putExtra(JsonFormConstants.JSON_FORM_KEY.FORM, formParam);
×
2148
            if (Boolean.parseBoolean(ChildLibrary.getInstance().getProperties()
×
2149
                    .getProperty(ChildAppProperties.KEY.MULTI_LANGUAGE_SUPPORT, "false"))) {
×
2150
                intent.putExtra(JsonFormConstants.PERFORM_FORM_TRANSLATION, true);
×
2151
            }
2152
            Timber.d("ChildJsonFormUtils --> form is %s", form.toString());
×
2153
            context.startActivityForResult(intent, jsonFormActivityRequestCode);
×
2154
        }
2155
    }
×
2156

2157
    private static void injectOpenSrpId(String entityId, JSONObject form) throws JSONException {
2158
        if (StringUtils.isNoneBlank(entityId)) {
×
2159
            JSONArray fields = form.getJSONObject(JsonFormConstants.STEP1).getJSONArray(JsonFormConstants.FIELDS);
×
2160
            for (int i = 0; i < fields.length(); i++) {
×
2161
                JSONObject field = fields.getJSONObject(i);
×
2162
                if (field.getString(JsonFormConstants.KEY).equalsIgnoreCase(ZEIR_ID) ||
×
2163
                        field.getString(JsonFormUtils.KEY).equalsIgnoreCase(OPENSRP_ID)) {
×
2164
                    field.remove(JsonFormUtils.VALUE);
×
2165
                    field.put(JsonFormUtils.VALUE, entityId.replace("-", ""));
×
2166
                    field.put(READ_ONLY, true);
×
2167
                    break;
×
2168
                }
2169
            }
2170
        }
2171
    }
×
2172

2173
    /**
2174
     * This method does ...
2175
     *
2176
     * @deprecated because provider and location id will be set by the getEventAndTag method use
2177
     * {@link #createBCGScarEvent(Context context, String baseEntityId)} instead.
2178
     */
2179
    @Deprecated
2180
    public static void createBCGScarEvent(Context context, String baseEntityId, String providerId, String locationId) {
2181
        createBCGScarEvent(context, baseEntityId);
1✔
2182
    }
1✔
2183

2184
    public static void createBCGScarEvent(Context context, String baseEntityId) {
2185
        try {
2186
            Event event = getEventAndTag(baseEntityId, BCG_SCAR_EVENT, new Date(), Constants.CHILD_TYPE);
1✔
2187

2188
            final String BCG_SCAR_CONCEPT = "160265AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1✔
2189
            final String YES_CONCEPT = "1065AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
1✔
2190

2191
            List<Object> values = new ArrayList<>();
1✔
2192
            values.add(YES_CONCEPT);
1✔
2193

2194
            List<Object> humanReadableValues = new ArrayList<>();
1✔
2195
            humanReadableValues.add("Yes");
1✔
2196

2197
            event.addObs(
1✔
2198
                    new Obs(CONCEPT, "select one", BCG_SCAR_CONCEPT, "", values, humanReadableValues, null, "bcg_scar"));
2199

2200
            JSONObject eventJson = new JSONObject(gson.toJson(event));
1✔
2201
            if (eventJson != null) {
1✔
2202
                ECSyncHelper.getInstance(context).addEvent(baseEntityId, eventJson);
1✔
2203
            }
2204
        } catch (Exception e) {
×
2205
            Timber.e(e, "ChildJsonFormUtils --> createBCGScarEvent");
×
2206
        }
1✔
2207
    }
1✔
2208

2209
    /**
2210
     * This method does ...
2211
     *
2212
     * @deprecated because provider and location id will be set by the getEventAndTag method use
2213
     * {@link #updateClientAttribute(org.smartregister.Context openSRPContext, CommonPersonObjectClient childDetails, String attributeName, Object attributeValue)} instead.
2214
     */
2215
    @Deprecated
2216
    public static Map<String, String> updateClientAttribute(org.smartregister.Context openSRPContext, CommonPersonObjectClient childDetails, LocationHelper locationHelper, String attributeName, Object attributeValue) throws Exception {
2217

2218
        return updateClientAttribute(openSRPContext, childDetails, attributeName, attributeValue);
1✔
2219
    }
2220

2221
    /**
2222
     * This method updates the Client document attributes to add the attribute name and attribute value parameters passed
2223
     *
2224
     * @param openSRPContext The OpenSRP context
2225
     * @param childDetails   The data object holding the child client details
2226
     * @param attributeName  The key of the attribute to add
2227
     * @param attributeValue The value of the attribute
2228
     * @return the updated child client details map
2229
     */
2230
    public static Map<String, String> updateClientAttribute(org.smartregister.Context openSRPContext, CommonPersonObjectClient childDetails, String attributeName, Object attributeValue) throws Exception {
2231
        return updateClientAttribute(openSRPContext, childDetails, EasyMap.mapOf(attributeName, attributeValue));
1✔
2232
    }
2233

2234
    /**
2235
     * This method updates the Client document attributes to add the attribute name and attribute value parameters passed.
2236
     * It creates and updates the Update Birth Registration Event to include the child statuses as Obs
2237
     *
2238
     * @param openSRPContext The OpenSRP context
2239
     * @param childDetails   The data object holding the child client details
2240
     * @param attributesMap  The map holding key - value entries of the attribute to add
2241
     * @return the updated child client details map
2242
     */
2243
    public static Map<String, String> updateClientAttribute(org.smartregister.Context openSRPContext, CommonPersonObjectClient childDetails, Map<String, Object> attributesMap) throws Exception {
2244
        Date date = new Date();
1✔
2245
        EventClientRepository db = openSRPContext.getEventClientRepository();
1✔
2246
        JSONObject client = db.getClientByBaseEntityId(childDetails.entityId());
1✔
2247
        JSONObject attributes = client.getJSONObject(ChildJsonFormUtils.attributes);
1✔
2248
        ContentValues contentValues = new ContentValues();
1✔
2249

2250
        Event event = getEventAndTag(childDetails.entityId(), ChildJsonFormUtils.updateBirthRegistrationDetailsEncounter, new Date(), Constants.CHILD_TYPE);
1✔
2251

2252
        //update details
2253
        Map<String, String> detailsMap = ChildDbUtils.fetchChildDetails(childDetails.entityId());
1✔
2254

2255
        Iterator<Map.Entry<String, Object>> attributeValueIterator = attributesMap.entrySet().iterator();
1✔
2256
        String attributeName;
2257
        Object attributeValue;
2258

2259
        while (attributeValueIterator.hasNext()) {
1✔
2260

2261
            Map.Entry<String, Object> attributeValuePair = attributeValueIterator.next();
1✔
2262

2263
            attributeName = attributeValuePair.getKey();
1✔
2264
            attributeValue = attributeValuePair.getValue();
1✔
2265

2266
            attributes.put(attributeName, attributeValue);
1✔
2267

2268
            //Add the base_entity_id
2269
            contentValues.put(attributeName.toLowerCase(), attributeValue.toString());
1✔
2270

2271
            ChildDbUtils.updateChildDetailsValue(attributeName.toLowerCase(), String.valueOf(attributeValue), childDetails.entityId());
1✔
2272

2273
            ChildJsonFormUtils.addObservation(attributeName, String.valueOf(attributeValue), Observation.TYPE.TEXT, event);
1✔
2274

2275

2276
            if (detailsMap != null && childDetails.getColumnmaps().containsKey(attributeName)) {
1✔
2277
                childDetails.getColumnmaps().put(attributeName, attributeValue.toString());
1✔
2278
            }
2279
        }
1✔
2280

2281
        client.remove(ChildJsonFormUtils.attributes);
1✔
2282
        client.put(ChildJsonFormUtils.attributes, attributes);
1✔
2283

2284
        db.addorUpdateClient(childDetails.entityId(), client);
1✔
2285

2286
        ChildJsonFormUtils.addMetaData(openSRPContext.applicationContext(), event, date);
1✔
2287
        JSONObject eventJson = new JSONObject(ChildJsonFormUtils.gson.toJson(event));
1✔
2288
        db.addEvent(childDetails.entityId(), eventJson);
1✔
2289
        processClients(openSRPContext.allSharedPreferences(), ChildLibrary.getInstance().getEcSyncHelper());
1✔
2290

2291
        if (detailsMap != null) {
1✔
2292
            Utils.putAll(detailsMap, childDetails.getColumnmaps());
1✔
2293
        }
2294

2295
        return detailsMap;
1✔
2296
    }
2297

2298
    /**
2299
     * This method is used to process the result returned by advance search using the new approach.
2300
     * To provide more context. The new advance search method returns a list of clients including their relationships
2301
     * in one result. This processing is done to map the client to their relationships for instance map a child to their mother and or their father
2302
     *
2303
     * @param clientSearchResponse JSON string retrieved from the server
2304
     * @return a list of client detail models
2305
     */
2306
    public static List<ChildMotherDetailModel> processReturnedAdvanceSearchResults(Response<String> clientSearchResponse) {
2307
        List<ChildMotherDetailModel> childMotherDetailModels = new ArrayList<>();
1✔
2308
        Set<String> processedClients = new HashSet<>();
1✔
2309
        try {
2310
            if (clientSearchResponse.status().equals(ResponseStatus.success)) {
1✔
2311
                JSONArray searchResults = new JSONArray(clientSearchResponse.payload());
1✔
2312
                for (int index = 0; index < searchResults.length(); index++) {
1✔
2313
                    JSONObject searchResult = searchResults.getJSONObject(index);
1✔
2314
                    String baseEntityId = searchResult.getString(Constants.Client.BASE_ENTITY_ID);
1✔
2315

2316
                    if (!searchResult.has(Constants.Client.RELATIONSHIPS) || processedClients.contains(baseEntityId)) {
1✔
2317
                        continue;
×
2318
                    }
2319

2320
                    JSONObject relationships = searchResult.getJSONObject(Constants.Client.RELATIONSHIPS);
1✔
2321
                    if (relationships != null && relationships.has(Constants.KEY.MOTHER)) {
1✔
2322
                        JSONObject motherJson = getRelationshipJson(searchResults, relationships.getJSONArray(Constants.KEY.MOTHER).getString(0));
1✔
2323
                        if (motherJson != null) {
1✔
2324
                            childMotherDetailModels.add(new ChildMotherDetailModel(searchResult, motherJson));
1✔
2325
                        }
2326
                    }
2327
                    processedClients.add(baseEntityId);
1✔
2328
                }
2329
                Collections.sort(childMotherDetailModels, Collections.reverseOrder());
1✔
2330
            }
2331

2332
        } catch (JSONException e) {
×
2333
            Timber.e(e);
×
2334
        }
1✔
2335
        return childMotherDetailModels;
1✔
2336
    }
2337

2338
    /**
2339
     * Return Json for provided relational id
2340
     *
2341
     * @param searchResults List of returned clients
2342
     * @param relationalId  base entity id of the relation e.g mother base entity id
2343
     * @return Json for the given relational id
2344
     */
2345
    public static JSONObject getRelationshipJson(JSONArray searchResults, String relationalId) throws JSONException {
2346
        for (int index = 0; index < searchResults.length(); index++) {
1✔
2347
            JSONObject searchResult = searchResults.getJSONObject(index);
1✔
2348
            if (searchResult.has(Constants.Client.BASE_ENTITY_ID) &&
1✔
2349
                    relationalId.equalsIgnoreCase(searchResult.getString(Constants.Client.BASE_ENTITY_ID))) {
1✔
2350
                return searchResult;
1✔
2351
            }
2352
        }
2353
        return null;
×
2354
    }
2355

2356
    /**
2357
     * Creates the Next Appointment event
2358
     *
2359
     * @param baseEntityId
2360
     * @param observations     A list of obs value to send as part of the event
2361
     * @param formSubmissionId A formSubmissionId to update an unsynced next appointment Event, can be null, if null a new one will be created in the db
2362
     */
2363
    public static Event createNextAppointmentEvent(String baseEntityId, List<Observation> observations, @Nullable String formSubmissionId) throws JSONException {
2364

2365
        return createEvent(Constants.EventType.NEXT_APPOINTMENT, Constants.CHILD_TYPE, baseEntityId, observations, formSubmissionId);
1✔
2366
    }
2367

2368
    /**
2369
     * @param eventType        The name of the event
2370
     * @param baseEntityId     the unique entity identifier
2371
     * @param entityType       the entity type e.g. child, mother, father
2372
     * @param observations     the list of observations to send as part of the event. Can be null if no observations
2373
     * @param formSubmissionId the value of the submission id, can be null. If null a new one will be created in the db
2374
     */
2375
    public static Event createEvent(@NonNull String eventType, @NonNull String entityType, @NonNull String baseEntityId, @Nullable List<Observation> observations, @Nullable String formSubmissionId) throws JSONException {
2376

2377
        Event event = getEventAndTag(baseEntityId, eventType, new Date(), entityType).withFormSubmissionId(StringUtils.isNotBlank(formSubmissionId) ? formSubmissionId : generateRandomUUIDString());
1✔
2378

2379
        if (observations != null) {
1✔
2380
            for (Observation ob : observations) {
1✔
2381

2382
                addObservation(ob.getKey(), ob.getValue(), ob.getType(), event);
1✔
2383

2384
            }
1✔
2385

2386
        }
2387
        return event;
1✔
2388
    }
2389

2390
    /**
2391
     * This helper method creates and adds an Observation to the supplied parameter of type Event
2392
     *
2393
     * @param key   The form field key
2394
     * @param value The form field value
2395
     * @param type  The Enum type of the Observation {@link Observation.TYPE}
2396
     * @param event The Event to add the Observation to
2397
     */
2398
    protected static void addObservation(String key, String value, Observation.TYPE type, Event event) throws JSONException {
2399
        //In case it is an unsynced Event and we are updating, we need to remove the previous Observation with the same form field tag
2400
        //Form fields should always be unique per submission
2401
        List<Obs> obsList = event.getObs();
1✔
2402
        if (obsList != null && obsList.size() > 0) {
1✔
2403
            obsList.removeIf(obs -> key.equals(obs.getFormSubmissionField()));
1✔
2404
        }
2405

2406
        // Process new observation
2407
        JSONObject jsonObject = new JSONObject();
1✔
2408
        jsonObject.put(KEY, key);
1✔
2409
        jsonObject.put(VALUE, value);
1✔
2410
        jsonObject.put(OPENMRS_DATA_TYPE, type != null ? type : AllConstants.TEXT);
1✔
2411
        addObservation(event, jsonObject);
1✔
2412
    }
1✔
2413

2414
    protected JSONObject getJsonObject(JSONObject jsonObject, String field) {
2415
        try {
2416
            if (jsonObject != null && jsonObject.has(field)) {
×
2417
                return jsonObject.getJSONObject(field);
×
2418
            }
2419
        } catch (JSONException e) {
×
2420
            Timber.e(e);
×
2421
        }
×
2422
        return null;
×
2423

2424
    }
2425

2426
    protected JSONObject getJsonObject(JSONArray jsonArray, int position) {
2427
        try {
2428
            if (jsonArray != null && jsonArray.length() > 0) {
×
2429
                return jsonArray.getJSONObject(position);
×
2430
            }
2431
        } catch (JSONException e) {
×
2432
            Timber.e(e);
×
2433
        }
×
2434
        return null;
×
2435

2436
    }
2437
}
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