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

OpenSRP / opensrp-client-immunization / #898

pending completion
#898

push

github-actions

web-flow
Merge pull request #195 from opensrp/check-vaccine-duplicates

Add Duplicate Vaccines & Recurring Service Record Checks

5076 of 6673 relevant lines covered (76.07%)

0.76 hits per line

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

60.84
opensrp-immunization/src/main/java/org/smartregister/immunization/util/VaccinatorUtils.java
1
/*
2
 * Copyright (C) 2012 The Android Open Source Project
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package org.smartregister.immunization.util;
18

19
import static org.smartregister.immunization.R.id.vaccine;
20
import static org.smartregister.util.Utils.addToList;
21
import static org.smartregister.util.Utils.addToRow;
22
import static org.smartregister.util.Utils.convertDateFormat;
23
import static org.smartregister.util.Utils.getValue;
24

25
import android.app.Activity;
26
import android.content.Context;
27
import android.content.res.AssetManager;
28
import android.content.res.Resources;
29
import android.graphics.Color;
30
import android.text.Html;
31
import android.text.TextUtils;
32
import android.util.Pair;
33
import android.util.TypedValue;
34
import android.view.Gravity;
35
import android.view.View;
36
import android.widget.Button;
37
import android.widget.FrameLayout;
38
import android.widget.LinearLayout;
39
import android.widget.RelativeLayout;
40
import android.widget.TableLayout;
41
import android.widget.TableRow;
42
import android.widget.TextView;
43

44
import androidx.annotation.NonNull;
45
import androidx.annotation.Nullable;
46
import androidx.fragment.app.Fragment;
47
import androidx.fragment.app.FragmentActivity;
48
import androidx.fragment.app.FragmentTransaction;
49

50
import com.google.gson.reflect.TypeToken;
51

52
import org.apache.commons.lang3.StringUtils;
53
import org.joda.time.DateTime;
54
import org.joda.time.Months;
55
import org.json.JSONException;
56
import org.json.JSONObject;
57
import org.smartregister.commonregistry.CommonPersonObject;
58
import org.smartregister.domain.Alert;
59
import org.smartregister.domain.AlertStatus;
60
import org.smartregister.domain.jsonmapping.Location;
61
import org.smartregister.domain.jsonmapping.util.LocationTree;
62
import org.smartregister.domain.jsonmapping.util.TreeNode;
63
import org.smartregister.immunization.ImmunizationLibrary;
64
import org.smartregister.immunization.R;
65
import org.smartregister.immunization.db.VaccineRepo;
66
import org.smartregister.immunization.db.VaccineRepo.Vaccine;
67
import org.smartregister.immunization.domain.ServiceRecord;
68
import org.smartregister.immunization.domain.ServiceSchedule;
69
import org.smartregister.immunization.domain.ServiceTrigger;
70
import org.smartregister.immunization.domain.ServiceType;
71
import org.smartregister.immunization.domain.State;
72
import org.smartregister.immunization.domain.VaccineSchedule;
73
import org.smartregister.immunization.domain.VaccineWrapper;
74
import org.smartregister.immunization.domain.jsonmapping.VaccineGroup;
75
import org.smartregister.immunization.fragment.UndoVaccinationDialogFragment;
76
import org.smartregister.immunization.fragment.VaccinationDialogFragment;
77
import org.smartregister.immunization.repository.RecurringServiceRecordRepository;
78
import org.smartregister.util.AssetHandler;
79
import org.smartregister.util.IntegerUtil;
80

81
import java.io.IOException;
82
import java.lang.reflect.Type;
83
import java.util.ArrayList;
84
import java.util.Arrays;
85
import java.util.Calendar;
86
import java.util.Date;
87
import java.util.HashMap;
88
import java.util.LinkedHashMap;
89
import java.util.List;
90
import java.util.Locale;
91
import java.util.Map;
92
import java.util.regex.Matcher;
93
import java.util.regex.Pattern;
94

95
import timber.log.Timber;
96

97
/**
98
 * Class containing some static utility methods.
99
 */
100
public class VaccinatorUtils {
1✔
101
    public static final String vaccines_file = "vaccines.json";
102
    public static final String mother_vaccines_file = "mother_vaccines.json";
103
    public static final String special_vaccines_file = "special_vaccines.json";
104
    public static final String recurring_service_types_file = "recurring_service_types.json";
105
    public static final String vaccines_folder = "vaccines";
106
    private static final String TAG = "VaccinatorUtils";
107

108
    private static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> specialVaccines;
109

110
    public static HashMap<String, String> providerDetails() {
111
        org.smartregister.Context context = ImmunizationLibrary.getInstance().context();
1✔
112
        Timber.d("ANM DETAILS %s", context.anmController().get());
1✔
113
        Timber.d("USER DETAILS %s", context.allSettings().fetchUserInformation());
1✔
114
        Timber.d("TEAM DETAILS %s", context.allSharedPreferences().getPreference("team"));
1✔
115

116
        String locationJson = context.anmLocationController().get();
1✔
117
        LocationTree locationTree = AssetHandler.jsonStringToJava(locationJson, LocationTree.class);
1✔
118

119
        HashMap<String, String> map = new HashMap<>();
1✔
120

121
        if (locationTree != null) {
1✔
122
            Map<String, TreeNode<String, Location>> locationMap = locationTree.getLocationsHierarchy();
1✔
123
            Map<String, String> locations = new HashMap<>();
1✔
124
            addToList(locations, locationMap, "country");
1✔
125
            addToList(locations, locationMap, "province");
1✔
126
            addToList(locations, locationMap, "city");
1✔
127
            addToList(locations, locationMap, "town");
1✔
128
            addToList(locations, locationMap, "uc");
1✔
129
            addToList(locations, locationMap, "vaccination center");
1✔
130

131
            map.put("provider_uc", locations.get("uc"));
1✔
132
            map.put("provider_town", locations.get("town"));
1✔
133
            map.put("provider_city", locations.get("city"));
1✔
134
            map.put("provider_province", locations.get("province"));
1✔
135
            map.put("provider_location_id", locations.get("vaccination center"));
1✔
136
            map.put("provider_location_name", locations.get("vaccination center"));
1✔
137
            map.put("provider_id", context.anmService().fetchDetails().name());
1✔
138
        }
139

140
        try {
141
            JSONObject tm = new JSONObject(context.allSharedPreferences().getPreference("team"));
1✔
142
            map.put("provider_name", tm.getJSONObject("person").getString("display"));
1✔
143
            map.put("provider_identifier", tm.getString("identifier"));
1✔
144
            map.put("provider_team", tm.getJSONObject("team").getString("teamName"));
1✔
145
        } catch (JSONException e) {
×
146
            Timber.e(e);
×
147
        }
1✔
148

149
        return map;
1✔
150
    }
151

152
    public static ArrayList<HashMap<String, String>> getWasted(String startDate, String endDate, String type) {
153
        String sqlWasted = "select sum (total_wasted)as total_wasted from stock where `report` ='" + type + "' and `date` between '" + startDate + "' and '" + endDate + "'";
1✔
154
        return ImmunizationLibrary.getInstance().context().commonrepository("stock").rawQuery(sqlWasted, new String[]{});
1✔
155
    }
156

157
    public static int getWasted(String startDate, String endDate, String type, String... variables) {
158
        List<CommonPersonObject> cl = ImmunizationLibrary.getInstance().context().commonrepository("stock")
1✔
159
                .customQueryForCompleteRow(
1✔
160
                        "SELECT * FROM stock WHERE `report` ='" + type + "' and `date` between '" + startDate + "' and '" + endDate + "'",
161
                        null, "stock");
162
        int total = 0;
1✔
163
        for (CommonPersonObject c : cl) {
1✔
164
            for (String v : variables) {
×
165
                String val = getValue(c.getDetails(), v, "0", false);
×
166
                total += IntegerUtil.tryParse(val, 0);
×
167
            }
168
        }
×
169
        return total;
1✔
170
    }
171

172
    public static int getTotalUsed(String startDate, String endDate, String table, String... vaccines) {
173
        int totalUsed = 0;
×
174

175
        for (HashMap<String, String> v : getUsed(startDate, endDate, table, vaccines)) {
×
176
            for (String k : v.keySet()) {
×
177
                totalUsed += Integer.parseInt(v.get(k) == null ? "0" : v.get(k));
×
178
            }
×
179
        }
×
180
        Timber.i("TOTAL USED: %s", totalUsed);
×
181

182
        return totalUsed;
×
183
    }
184

185
    public static ArrayList<HashMap<String, String>> getUsed(String startDate, String endDate, String table,
186
                                                             String... vaccines) {
187
        String q = "SELECT * FROM (";
1✔
188
        for (String v : vaccines) {
1✔
189
            q += " (select count(*) " + v + " from " + table + " where " + v + " between '" + startDate + "' and '" + endDate + "') " + v + " , ";
1✔
190
        }
191
        q = q.trim().substring(0, q.trim().lastIndexOf(","));
1✔
192
        q += " ) e ";
1✔
193

194
        Timber.i("DD %s", q);
1✔
195
        return ImmunizationLibrary.getInstance().context().commonrepository(table).rawQuery(q, new String[]{});
1✔
196
    }
197

198
    public static void addStatusTag(Context context, TableLayout table, String tag, boolean hrLine) {
199
        TableRow tr = new TableRow(context);
×
200
        if (hrLine) {
×
201
            tr.setBackgroundColor(Color.LTGRAY);
×
202
            tr.setPadding(1, 1, 1, 1);
×
203
            table.addView(tr);
×
204
        }
205
        tr = addToRow(context, Html.fromHtml("<b>" + tag + "</b>"), new TableRow(context), true, 1);
×
206
        tr.setPadding(15, 5, 0, 0);
×
207
        table.addView(tr);
×
208
    }
×
209

210

211
    public static void addVaccineDetail(final Context context, TableLayout table, final VaccineWrapper vaccineWrapper) {
212
        TableRow tr = (TableRow) ((Activity) context).getLayoutInflater().inflate(R.layout.vaccinate_row_view, null);
1✔
213
        tr.setGravity(Gravity.CENTER_VERTICAL);
1✔
214
        tr.setTag(vaccineWrapper.getId());
1✔
215

216
        RelativeLayout relativeLayout = tr.findViewById(R.id.vacc_status_layout);
1✔
217
        if (vaccineWrapper.isCompact()) {
1✔
218
            relativeLayout
×
219
                    .setPadding(dpToPx(context, 0f), dpToPx(context, 7.5f), dpToPx(context, 0f), dpToPx(context, 7.5f));
×
220
        } else {
221
            relativeLayout.setPadding(dpToPx(context, 0f), dpToPx(context, 10f), dpToPx(context, 0f), dpToPx(context, 10f));
1✔
222
        }
223

224

225
        TextView label = tr.findViewById(vaccine);
1✔
226
        label.setText(vaccineWrapper.getVaccine().display());
1✔
227

228
        String vaccineDate = "";
1✔
229
        String color = "#ffffff";
1✔
230
        if (vaccineWrapper.getStatus().equalsIgnoreCase("due")) {
1✔
231
            if (vaccineWrapper.getAlert() != null) {
1✔
232
                color = getColorValue(context, vaccineWrapper.getAlert().status());
1✔
233
                vaccineDate = "due: " + convertDateFormat(vaccineWrapper.getVaccineDateAsString(), true) + "";
1✔
234
                addVaccinationDialogHook(context, tr, vaccineWrapper, color, vaccineDate);
1✔
235
            } else if (StringUtils.isNotBlank(vaccineWrapper.getVaccineDateAsString())) {
1✔
236
                color = getColorValue(context, AlertStatus.inProcess);
1✔
237
                vaccineDate = "due: " + convertDateFormat(vaccineWrapper.getVaccineDateAsString(), true) + "";
1✔
238
                addVaccinationDialogHook(context, tr, vaccineWrapper, color, vaccineDate);
1✔
239
            }
240
        } else if (vaccineWrapper.getStatus().equalsIgnoreCase("done")) {
1✔
241
            color = "#31B404";
1✔
242
            vaccineDate = convertDateFormat(vaccineWrapper.getVaccineDateAsString(), true);
1✔
243
        } else if (vaccineWrapper.getStatus().equalsIgnoreCase("expired")) {
1✔
244
            color = getColorValue(context, AlertStatus.inProcess);
1✔
245
            vaccineDate = "exp: " + convertDateFormat(vaccineWrapper.getVaccineDateAsString(), true) + "";
1✔
246
            addVaccinationDialogHook(context, tr, vaccineWrapper, color, vaccineDate);
1✔
247
        }
248

249
        LinearLayout l = new LinearLayout(context);
1✔
250
        l.setOrientation(LinearLayout.HORIZONTAL);
1✔
251
        l.setVerticalGravity(Gravity.CENTER_VERTICAL);
1✔
252
        l.setGravity(Gravity.CENTER_VERTICAL);
1✔
253

254
        Button s = tr.findViewById(R.id.status);
1✔
255
        s.setBackgroundColor(StringUtils.isBlank(color) ? Color.WHITE : Color.parseColor(color));
1✔
256

257
        TextView v = tr.findViewById(R.id.date);
1✔
258
        v.setText(vaccineDate);
1✔
259

260
        Button u = tr.findViewById(R.id.undo);
1✔
261
        FrameLayout.LayoutParams ulp = (FrameLayout.LayoutParams) u.getLayoutParams();
1✔
262
        if (vaccineWrapper.isCompact()) {
1✔
263
            ulp.width = dpToPx(context, 70f);
×
264
            ulp.height = dpToPx(context, 35f);
×
265
            u.setLayoutParams(ulp);
×
266
        } else {
267
            ulp.width = dpToPx(context, 65f);
1✔
268
            ulp.height = dpToPx(context, 40f);
1✔
269
            u.setLayoutParams(ulp);
1✔
270
        }
271

272
        u.setOnClickListener(new View.OnClickListener() {
1✔
273
            @Override
274
            public void onClick(View view) {
275
                FragmentTransaction ft = ((FragmentActivity) context).getSupportFragmentManager().beginTransaction();
1✔
276
                Fragment prev = ((FragmentActivity) context).getSupportFragmentManager()
1✔
277
                        .findFragmentByTag(UndoVaccinationDialogFragment.DIALOG_TAG);
1✔
278
                if (prev != null) {
1✔
279
                    ft.remove(prev);
×
280
                }
281
                ft.addToBackStack(null);
1✔
282
                UndoVaccinationDialogFragment undoVaccinationDialogFragment = UndoVaccinationDialogFragment
1✔
283
                        .newInstance(vaccineWrapper);
1✔
284
                undoVaccinationDialogFragment.show(ft, UndoVaccinationDialogFragment.DIALOG_TAG);
1✔
285
            }
1✔
286
        });
287

288
        if (table.getChildCount() > 0 && StringUtils.isNotBlank(vaccineWrapper.getId()) && StringUtils
1✔
289
                .isNotBlank(vaccineWrapper.getPreviousVaccineId()) && !vaccineWrapper.getId()
×
290
                .equals(vaccineWrapper.getId())) {
×
291
            View view = new View(context);
×
292
            view.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, dpToPx(context, 10f)));
×
293

294
            table.addView(view);
×
295
        }
296

297
        table.addView(tr);
1✔
298
    }
1✔
299

300
    public static int dpToPx(Context context, float dpValue) {
301
        Resources r = context.getResources();
1✔
302
        float val = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, r.getDisplayMetrics());
1✔
303
        return new Float(val).intValue();
1✔
304
    }
305

306
    public static String getColorValue(Context cxt, AlertStatus alertStatus) {
307
        if (alertStatus.equals(AlertStatus.upcoming)) {
1✔
308
            return "#" + Integer
1✔
309
                    .toHexString(cxt.getResources().getColor(org.smartregister.immunization.R.color.alert_upcoming))
1✔
310
                    .substring(2);
1✔
311
        }
312
        if (alertStatus.equals(AlertStatus.normal)) {
1✔
313
            return "#" + Integer
1✔
314
                    .toHexString(cxt.getResources().getColor(org.smartregister.immunization.R.color.alert_normal))
1✔
315
                    .substring(2);
1✔
316
        }
317
        if (alertStatus.equals(AlertStatus.urgent)) {
1✔
318
            return "#" + Integer
1✔
319
                    .toHexString(cxt.getResources().getColor(org.smartregister.immunization.R.color.alert_urgent))
1✔
320
                    .substring(2);
1✔
321
        } else {
322
            return "#" + Integer.toHexString(cxt.getResources().getColor(org.smartregister.immunization.R.color.alert_na))
1✔
323
                    .substring(2);
1✔
324
        }
325
    }
326

327
    private static void addVaccinationDialogHook(final Context context, TableRow tr, final VaccineWrapper vaccineWrapper,
328
                                                 String color, String formattedDate) {
329

330
        if (VaccinateActionUtils.addDialogHookCustomFilter(vaccineWrapper)) {
1✔
331
            vaccineWrapper.setColor(color);
1✔
332
            vaccineWrapper.setFormattedVaccineDate(formattedDate);
1✔
333

334
            tr.setOnClickListener(new TableRow.OnClickListener() {
1✔
335
                @Override
336
                public void onClick(View view) {
337
                    FragmentTransaction ft = ((FragmentActivity) context).getSupportFragmentManager().beginTransaction();
×
338
                    Fragment prev =
×
339
                            ((FragmentActivity) context).getSupportFragmentManager()
×
340
                                    .findFragmentByTag(VaccinationDialogFragment.DIALOG_TAG);
×
341
                    if (prev != null) {
×
342
                        ft.remove(prev);
×
343
                    }
344
                    ft.addToBackStack(null);
×
345
                    ArrayList<VaccineWrapper> list = new ArrayList<VaccineWrapper>();
×
346
                    list.add(vaccineWrapper);
×
347
                    VaccinationDialogFragment vaccinationDialogFragment = VaccinationDialogFragment
×
348
                            .newInstance(null, null, list);
×
349
                    vaccinationDialogFragment.show(ft, VaccinationDialogFragment.DIALOG_TAG);
×
350

351
                }
×
352
            });
353
        }
354
    }
1✔
355

356
    public static List<Map<String, Object>> generateScheduleList(String category, DateTime milestoneDate,
357
                                                                 Map<String, Date> received, List<Alert> alerts) {
358
        return generateScheduleList(category, milestoneDate, received, alerts, false);
1✔
359
    }
360

361
    /**
362
     * To use generateSchedule() method just use this method and set showExpired to true
363
     *
364
     * @param category
365
     * @param milestoneDate
366
     * @param received
367
     * @param alerts
368
     * @param showExpired
369
     * @return
370
     */
371
    public static List<Map<String, Object>> generateScheduleList(String category, DateTime milestoneDate,
372
                                                                 Map<String, Date> received, List<Alert> alerts,
373
                                                                 boolean showExpired) {
374
        List<Map<String, Object>> schedule = new ArrayList<>();
1✔
375
        boolean m1Given = false;
1✔
376
        boolean m2Given = false;
1✔
377
        boolean oGiven = false;
1✔
378
        try {
379
            List<Vaccine> vl = VaccineRepo.getVaccines(category);
×
380
            for (Vaccine v : vl) {
×
381
                Map<String, Object> m = new HashMap<>();
×
382
                Date recDate = received.get(v.display().toLowerCase(Locale.ENGLISH));
×
383
                if (recDate != null) {
×
384
                    m = createVaccineMap("done", null, new DateTime(recDate), v);
×
385
                    // Check for vaccines where either can be given - mealses/mr opv0/opv4
386
                    if (VaccineRepo.Vaccine.measles1.equals(v) || VaccineRepo.Vaccine.mr1.equals(v)) {
×
387
                        m1Given = true;
×
388
                    } else if (VaccineRepo.Vaccine.measles2.equals(v) || VaccineRepo.Vaccine.mr2.equals(v)) {
×
389
                        m2Given = true;
×
390
                    } else if (VaccineRepo.Vaccine.opv0.equals(v) || VaccineRepo.Vaccine.opv4.equals(v)) {
×
391
                        oGiven = true;
×
392
                    }
393
                } else if (showExpired && milestoneDate != null && v.expiryDays() > 0 && milestoneDate
×
394
                        .plusDays(v.expiryDays()).isBefore(DateTime.now())) {
×
395
                    m = createVaccineMap("expired", null, milestoneDate.plusDays(v.expiryDays()), v);
×
396
                } else if (alerts.size() > 0) {
×
397
                    for (Alert a : alerts) {
×
398
                        if (a.scheduleName().replaceAll(" ", "").equalsIgnoreCase(v.name())
×
399
                                || a.visitCode().replaceAll(" ", "").equalsIgnoreCase(v.name())) {
×
400
                            m = createVaccineMap("due", a, new DateTime(a.startDate()), v);
×
401
                        }
402
                    }
×
403
                }
404

405
                // Remove status to avoid vaccine entry, if it is expired
406
                // and its pre-requisite isn't given yet
407
                if (!m.isEmpty() && v.prerequisite() != null
×
408
                        && ((String) m.get("status")).equalsIgnoreCase("expired")
×
409
                        && received.get(v.prerequisite().display().toLowerCase(Locale.ENGLISH)) == null) {
×
410
                    m.clear();
×
411
                }
412

413
                if (m.isEmpty()) {
×
414
                    if (v.prerequisite() != null) {
×
415
                        Date prereq = received.get(v.prerequisite().display().toLowerCase(Locale.ENGLISH));
×
416
                        if (prereq != null) {
×
417
                            DateTime prereqDateTime = new DateTime(prereq);
×
418
                            prereqDateTime = prereqDateTime.plusDays(v.prerequisiteGapDays());
×
419
                            m = createVaccineMap("due", null, prereqDateTime, v);
×
420
                        } else {
×
421
                            m = createVaccineMap("due", null, null, v);
×
422
                        }
423
                    } else if (milestoneDate != null) {
×
424
                        m = createVaccineMap("due", null, milestoneDate.plusDays(v.milestoneGapDays()), v);
×
425
                    } else {
426
                        m = createVaccineMap("na", null, null, v);
×
427
                    }
428
                }
429

430
                schedule.add(m);
×
431
            }
×
432

433
            // Check for vaccines where either can be given - mealses/mr opv0/opv4
434
            List<Map<String, Object>> toRemove = retrieveNotDoneSchedule(schedule, m1Given, m2Given, oGiven);
×
435
            if (toRemove != null && !toRemove.isEmpty()) {
×
436
                schedule.removeAll(toRemove);
×
437
            }
438

439
        } catch (Exception e) {
1✔
440
            Timber.e(e);
1✔
441
        }
×
442
        return schedule;
1✔
443
    }
444

445
    private static Map<String, Object> createVaccineMap(String status, Alert a, DateTime date, Vaccine v) {
446

447
        Map<String, Object> m = new HashMap<>();
×
448
        m.put("status", a != null && !TextUtils.isEmpty(a.status().name()) && a.status().name().equals("expired") ? a.status().name() : status);
×
449
        m.put("alert", a);
×
450
        m.put("date", date);
×
451
        m.put("vaccine", v);
×
452

453
        return m;
×
454
    }
455

456
    private static List<Map<String, Object>> retrieveNotDoneSchedule(List<Map<String, Object>> schedule, boolean m1Given,
457
                                                                     boolean m2Given, boolean oGiven) {
458
        if (schedule == null || schedule.isEmpty() || (!m1Given && !m2Given && !oGiven)) {
×
459
            return new ArrayList<>();
×
460
        }
461

462
        String STATUS = "status";
×
463
        String VACCINE = "vaccine";
×
464
        String DONE = "done";
×
465
        List<Map<String, Object>> toRemove = new ArrayList<>();
×
466

467
        for (Map<String, Object> m : schedule) {
×
468
            if (m == null ||
×
469
                    m.get(STATUS) == null ||
×
470
                    m.get(VACCINE) == null ||
×
471
                    !(m.get(VACCINE) instanceof Vaccine) ||
×
472
                    DONE.equalsIgnoreCase(m.get(STATUS).toString())) {
×
473
                continue;
×
474
            }
475

476
            Vaccine v = (Vaccine) m.get(VACCINE);
×
477

478
            if (m1Given && (VaccineRepo.Vaccine.measles1.equals(v) || VaccineRepo.Vaccine.mr1.equals(v))) {
×
479
                toRemove.add(m);
×
480
            } else if (m2Given && (VaccineRepo.Vaccine.measles2.equals(v) || VaccineRepo.Vaccine.mr2.equals(v))) {
×
481
                toRemove.add(m);
×
482
            } else if (oGiven && (VaccineRepo.Vaccine.opv0.equals(v) || VaccineRepo.Vaccine.opv4.equals(v))) {
×
483
                toRemove.add(m);
×
484
            }
485
        }
×
486

487
        return toRemove;
×
488
    }
489

490
    public static List<Map<String, Object>> generateScheduleList(List<ServiceType> serviceTypes, DateTime milestoneDate,
491
                                                                 Map<String, Date> received, List<Alert> alerts) {
492
        List<Map<String, Object>> schedule = new ArrayList();
1✔
493

494
        try {
495
            for (ServiceType s : serviceTypes) {
1✔
496
                String VIT_A_IFC_2 = "Vit A IFC 2";
1✔
497
                if (VIT_A_IFC_2.equals(s.getName())) {
1✔
498
                    int months = Months.monthsBetween(milestoneDate, DateTime.now()).getMonths();
×
499
                    if (months >= 6) {
×
500
                        continue;
×
501
                    }
502

503
                }
504
                Map<String, Object> m = new HashMap<>();
1✔
505
                Date recDate = received.get(s.getName());
1✔
506
                if (recDate != null) {
1✔
507
                    m = createServiceMap("done", null, new DateTime(recDate), s);
×
508
                } /*else if (milestoneDate != null && StringUtils.isNotBlank(s.getExpiryOffset()) && ServiceSchedule.addOffsetToDateTime(milestoneDate, s.getExpiryOffset()).isBefore(DateTime.now())) {
509
                m = createServiceMap("expired", null, ServiceSchedule.addOffsetToDateTime(milestoneDate, s.getExpiryOffset()), s);
510
            }*/ else if (alerts.size() > 0) {
1✔
511
                    for (Alert a : alerts) {
1✔
512
                        if (a.scheduleName().equalsIgnoreCase(s.getName())
1✔
513
                                || a.visitCode().equalsIgnoreCase(s.getName())) {
1✔
514
                            m = createServiceMap("due", a, new DateTime(a.startDate()), s);
×
515
                        }
516
                    }
1✔
517
                }
518

519
                if (m.isEmpty()) {
1✔
520
                    DateTime referenceDate = milestoneDate;
1✔
521
                    if (!schedule.isEmpty()) {
1✔
522
                        Map<String, Object> leadingService = (Map<String, Object>) schedule.get(schedule.size() - 1);
×
523
                        referenceDate = (DateTime) leadingService.get("date");
×
524
                    }
525
                    DateTime dueDateTime = getServiceDueDate(s, referenceDate, received, referenceDate.equals(milestoneDate));
1✔
526
                    m = createServiceMap("due", null, dueDateTime, s);
1✔
527
                }
528

529
                // check prerequisite has been met
530
                // prerequisite has to be in received list
531
                String prerequisite = s.getPrerequisite();
1✔
532
                if (!prerequisite.equalsIgnoreCase(ServiceTrigger.Reference.DOB.name())) {
1✔
533
                    String[] preArray = prerequisite.split("\\|");
1✔
534
                    if (preArray.length >= 2) {
1✔
535
                        if (preArray[0].equalsIgnoreCase(ServiceTrigger.Reference.PREREQUISITE.name())) {
×
536
                            String preService = preArray[1];
×
537
                            Date prereq = received.get(preService);
×
538
                            if (prereq == null) {
×
539
                                m.put("status", State.NOT_DUE);
×
540
                            }
541
                        }
542
                    }
543
                }
544

545
                schedule.add(m);
1✔
546
            }
1✔
547

548
        } catch (Exception e) {
1✔
549
            Timber.e(e);
1✔
550
        }
1✔
551
        return schedule;
1✔
552
    }
553

554
    private static Map<String, Object> createServiceMap(String status, Alert a, DateTime
555
            date, ServiceType s) {
556
        Map<String, Object> m = new HashMap<>();
1✔
557
        m.put("status", status);
1✔
558
        m.put("alert", a);
1✔
559
        m.put("date", date);
1✔
560
        m.put("service", s);
1✔
561

562
        return m;
1✔
563
    }
564

565
    public static DateTime getServiceDueDate(ServiceType serviceType, DateTime milestoneDate,
566
                                             Map<String, Date> received, boolean isMilestoneDateDOB) {
567
        try {
568
            if (serviceType == null || milestoneDate == null || received == null) {
1✔
569
                return null;
×
570
            }
571
            boolean hasPrerequisite = false;
1✔
572
            Date prereq = null;
1✔
573
            if (StringUtils.isNotBlank(serviceType.getPrerequisite())) {
1✔
574
                String prerequisite = serviceType.getPrerequisite();
1✔
575
                if (!prerequisite.equalsIgnoreCase(ServiceTrigger.Reference.DOB.name())) {
1✔
576
                    String[] preArray = prerequisite.split("\\|");
1✔
577
                    if (preArray.length >= 2) {
1✔
578
                        if (preArray[0].equalsIgnoreCase(ServiceTrigger.Reference.PREREQUISITE.name())) {
×
579
                            String preService = preArray[1];
×
580
                            prereq = received.get(preService);
×
581
                            if (prereq != null) {
×
582
                                hasPrerequisite = true;
×
583
                            }
584
                            // Calculate recurring vaccine date based on its pre-requisite date
585
                            else if (!isMilestoneDateDOB) {
×
586
                                prereq = milestoneDate.toDate();
×
587
                                hasPrerequisite = true;
×
588
                            }
589
                        } else if (preArray[0].equalsIgnoreCase(ServiceTrigger.Reference.MULTIPLE.name())) {
×
590
                            String condition = preArray[1];
×
591
                            if (condition.equalsIgnoreCase("or") && preArray.length == 3) {
×
592
                                String arrayString = preArray[2];
×
593
                                String[] preqs = convertToArray(arrayString);
×
594
                                if (preqs != null) {
×
595
                                    for (String preService : preqs) {
×
596
                                        if (preService.equalsIgnoreCase(ServiceTrigger.Reference.DOB.name())) {
×
597
                                            continue;
×
598
                                        }
599
                                        prereq = received.get(preService);
×
600
                                        if (prereq != null) {
×
601
                                            hasPrerequisite = true;
×
602
                                            break;
×
603
                                        }
604
                                    }
605
                                }
606
                            }
607
                        }
608
                    }
609
                }
610
            }
611

612
            return getSchedules(hasPrerequisite, serviceType, milestoneDate, prereq);
1✔
613
        } catch (Exception e) {
×
614
            Timber.e(e);
×
615
        }
616
        return null;
×
617
    }
618

619
    private static DateTime getSchedules(boolean hasPrerequisite, ServiceType serviceType, DateTime milestoneDate, Date prereq) {
620
        if (hasPrerequisite && StringUtils.isNotBlank(serviceType.getPreOffset())) {
1✔
621
            DateTime prereqDateTime = new DateTime(prereq);
×
622
            return ServiceSchedule.addOffsetToDateTime(prereqDateTime, serviceType.getPreOffset());
×
623
        } else if (StringUtils.isNotBlank(serviceType.getMilestoneOffset())) {
1✔
624
            String[] milestones = convertToArray(serviceType.getMilestoneOffset());
1✔
625
            if (milestones != null) {
1✔
626
                List<String> milestoneList = Arrays.asList(milestones);
1✔
627
                return ServiceSchedule.addOffsetToDateTime(milestoneDate, milestoneList);
1✔
628
            }
629
        }
630
        return null;
×
631
    }
632

633
    /**
634
     * Converts string [a,b,c] to string array
635
     *
636
     * @param s_
637
     * @return
638
     */
639
    private static String[] convertToArray(String s_) {
640
        try {
641
            String s = s_;
1✔
642
            if (StringUtils.isBlank(s)) {
1✔
643
                return null;
×
644
            }
645

646
            if (s.contains("[")) {
1✔
647
                s = s.replace("[", "");
×
648
            }
649

650
            if (s.contains("]")) {
1✔
651
                s = s.replace("]", "");
×
652
            }
653

654
            if (StringUtils.isBlank(s)) {
1✔
655
                return null;
×
656
            } else if (s.contains(",")) {
1✔
657
                return StringUtils.stripAll(s.split(","));
×
658
            } else if (StringUtils.isNotBlank(s)) {
1✔
659
                return new String[]{s};
1✔
660
            }
661

662
        } catch (Exception e) {
×
663
            Timber.e(e);
×
664
        }
×
665
        return null;
×
666
    }
667

668
    public static DateTime getServiceDueDate(ServiceType serviceType, DateTime milestoneDate,
669
                                             List<ServiceRecord> serviceRecordList) {
670
        return getServiceDueDate(serviceType, milestoneDate, receivedServices(serviceRecordList), true);
1✔
671
    }
672

673
    public static Map<String, Date> receivedServices(List<ServiceRecord> serviceRecordList) {
674
        Map<String, Date> map = new LinkedHashMap<>();
1✔
675
        if (serviceRecordList != null) {
1✔
676
            for (org.smartregister.immunization.domain.ServiceRecord serviceRecord : serviceRecordList) {
1✔
677
                if (serviceRecord.getDate() != null) {
1✔
678
                    map.put(serviceRecord.getName(), serviceRecord.getDate());
1✔
679
                }
680
            }
1✔
681
        }
682
        return map;
1✔
683

684
    }
685

686
    public static DateTime getServiceExpiryDate(ServiceType serviceType, DateTime milestoneDate) {
687
        if (serviceType == null || milestoneDate == null) {
1✔
688
            return null;
1✔
689
        }
690
        return ServiceSchedule.addOffsetToDateTime(milestoneDate, serviceType.getExpiryOffset());
1✔
691
    }
692

693
    public static Map<String, Object> nextVaccineDue(List<Map<String, Object>> schedule, Date lastVisit) {
694
        Map<String, Object> v = null;
1✔
695
        try {
696
            for (Map<String, Object> m : schedule) {
1✔
697
                if (m != null && m.get("status") != null && m.get("status").toString().equalsIgnoreCase("due")) {
1✔
698
                    if (m.get("vaccine") != null && (m.get("vaccine").equals(Vaccine.bcg2) || m
1✔
699
                            .get("vaccine").equals(Vaccine.ipv))) {
1✔
700
                        // bcg2 is a special alert and should not be considered as the next vaccine
701
                        continue;
×
702
                    }
703

704
                    if (v == null) {
1✔
705
                        v = m;
1✔
706
                    } else if (m.get("date") != null && v.get("date") != null
1✔
707
                            && ((DateTime) m.get("date")).isBefore((DateTime) v.get("date"))
1✔
708
                            && (lastVisit == null
709
                            || lastVisit.before(((DateTime) m.get("date")).toDate()))) {
1✔
710
                        v = m;
1✔
711
                    }
712
                }
713
            }
1✔
714
        } catch (Exception e) {
×
715
            Timber.e(e);
×
716
        }
1✔
717
        return v;
1✔
718
    }
719

720
    public static Map<String, Object> nextVaccineDue(List<Map<String, Object>> schedule, List<Vaccine> vaccineList) {
721
        Map<String, Object> v = null;
×
722
        try {
723
            for (Map<String, Object> m : schedule) {
×
724
                if (m != null && m.get("status") != null && m.get("status").toString().equalsIgnoreCase("due")) {
×
725
                    if (m.get("vaccine") != null && (m.get("vaccine").equals(Vaccine.bcg2) || m
×
726
                            .get("vaccine").equals(Vaccine.ipv))) {
×
727
                        // bcg2 is a special alert and should not be considered as the next vaccine
728
                        continue;
×
729
                    }
730

731
                    if (v == null && m.get("vaccine") != null && vaccineList.contains(m.get("vaccine"))) {
×
732
                        v = m;
×
733
                    } else if ((v.get("alert") == null && m.get("alert") != null) && (m.get("vaccine") != null && vaccineList
×
734
                            .contains(m.get("vaccine")))) {
×
735
                        v = m;
×
736
                    } else if (v.get("alert") != null && m.get("alert") != null && m.get("vaccine") != null && vaccineList
×
737
                            .contains(m.get("vaccine"))) {
×
738
                        Alert vAlert = (Alert) v.get("alert");
×
739
                        Alert mAlert = (Alert) m.get("alert");
×
740
                        if ((!vAlert.status().equals(AlertStatus.urgent) && (vAlert.status()
×
741
                                .equals(AlertStatus.upcoming)) && (mAlert.status().equals(AlertStatus.normal) || mAlert
×
742
                                .status().equals(AlertStatus.urgent)))) {
×
743
                            v = m;
×
744

745
                        } else if (vAlert.status().equals(AlertStatus.normal) && mAlert.status()
×
746
                                .equals(AlertStatus.urgent)) {
×
747
                            v = m;
×
748

749
                        }
750
                    }
751
                }
752
            }
×
753
        } catch (Exception e) {
×
754
            Timber.e(e, e.toString());
×
755
        }
×
756
        return v;
×
757
    }
758

759
    public static Map<String, Object> nextServiceDue(List<Map<String, Object>> schedule, Date lastVisit) {
760
        Map<String, Object> v = null;
1✔
761
        try {
762
            for (Map<String, Object> m : schedule) {
1✔
763
                if (m != null && m.get("status") != null && m.get("status").toString().equalsIgnoreCase("due")) {
1✔
764

765
                    if (v == null) {
1✔
766
                        v = m;
1✔
767
                    } else if (m.get("date") != null && v.get("date") != null
1✔
768
                            && ((DateTime) m.get("date")).isBefore((DateTime) v.get("date"))
1✔
769
                            && (lastVisit == null
770
                            || lastVisit.before(((DateTime) m.get("date")).toDate()))) {
1✔
771
                        v = m;
×
772
                    }
773
                }
774
            }
1✔
775
        } catch (Exception e) {
×
776
            Timber.e(e, e.toString());
×
777
        }
1✔
778
        return v;
1✔
779
    }
780

781
    public static Map<String, Object> nextServiceDue(List<Map<String, Object>> schedule, List<ServiceType> serviceTypeList) {
782
        Map<String, Object> v = null;
1✔
783
        try {
784
            for (Map<String, Object> m : schedule) {
1✔
785
                if (m != null && m.get("status") != null && m.get("status").toString().equalsIgnoreCase("due")) {
×
786

787
                    if (v == null && m.get("service") != null && serviceTypeList.contains(m.get("service"))) {
×
788
                        v = m;
×
789

790
                    } else if (v.get("alert") == null && m.get("alert") != null && m
×
791
                            .get("service") != null && serviceTypeList.contains(m.get("service"))) {
×
792
                        v = m;
×
793

794
                    } else if (v.get("alert") != null && m.get("alert") != null && m
×
795
                            .get("service") != null && serviceTypeList.contains(m.get("service"))) {
×
796
                        Alert vAlert = (Alert) v.get("alert");
×
797
                        Alert mAlert = (Alert) m.get("alert");
×
798
                        if (!vAlert.status().equals(AlertStatus.urgent)) {
×
799
                            if (vAlert.status().equals(AlertStatus.upcoming) && (mAlert.status()
×
800
                                    .equals(AlertStatus.normal) || mAlert.status().equals(AlertStatus.urgent))) {
×
801
                                v = m;
×
802
                            } else if (vAlert.status().equals(AlertStatus.normal) && mAlert.status()
×
803
                                    .equals(AlertStatus.urgent)) {
×
804
                                v = m;
×
805
                            }
806
                        }
807
                    }
808
                }
809
            }
×
810
        } catch (Exception e) {
×
811
            Timber.e(e, e.toString());
×
812
        }
1✔
813

814
        return v;
1✔
815
    }
816

817
    public static Map<String, Object> nextServiceDue(List<Map<String, Object>> schedule, ServiceRecord lastServiceRecord) {
818
        if (lastServiceRecord == null || StringUtils.isBlank(lastServiceRecord.getType()) || StringUtils
1✔
819
                .isBlank(lastServiceRecord.getName())) {
1✔
820
            return null;
1✔
821
        }
822

823
        if (!lastServiceRecord.getSyncStatus().equalsIgnoreCase(RecurringServiceRecordRepository.TYPE_Unsynced)) {
1✔
824
            return null;
×
825
        }
826
        Map<String, Object> v = null;
1✔
827
        for (Map<String, Object> m : schedule) {
1✔
828
            if (m != null && m.get("service") != null) {
1✔
829
                ServiceType mServiceType = (ServiceType) m.get("service");
1✔
830
                if (mServiceType.getName().equalsIgnoreCase(lastServiceRecord.getName()) && mServiceType.getType()
1✔
831
                        .equalsIgnoreCase(lastServiceRecord.getType())) {
1✔
832
                    v = m;
1✔
833
                }
834
            }
835
        }
1✔
836
        return v;
1✔
837
    }
838

839
    /**
840
     * Returns a list of VaccineGroup containing a list of supported woman vaccines
841
     *
842
     * @param context Current valid context to be used
843
     * @return list of VaccineGroup with the supported vaccines
844
     */
845
    public static List<VaccineGroup> getSupportedWomanVaccines(@Nullable Context context) {
846
        return getSupportedWomanVaccines(context, null);
1✔
847
    }
848

849
    /**
850
     * Returns a list of VaccineGroup containing a list of supported woman vaccines
851
     *
852
     * @param context Current valid context to be used
853
     * @param prefix  vaccine config file prefix
854
     * @return list of VaccineGroup with the supported vaccines
855
     */
856
    public static List<VaccineGroup> getSupportedWomanVaccines(@Nullable Context context, String prefix) {
857

858
        return getVaccineGroupsFromVaccineConfigFile(context, getFileName(mother_vaccines_file, prefix));
1✔
859
    }
860

861
    public static String getFileName(String fileName, String prefix) {
862
        if (prefix != null) {
1✔
863
            return prefix + "_" + fileName;
1✔
864
        } else {
865
            return fileName;
1✔
866
        }
867
    }
868

869
    public static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> getSpecialVaccines(@Nullable Context context) {
870
        return getSpecialVaccines(context, null);
1✔
871
    }
872

873
    public static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> getSpecialVaccines(@Nullable Context context, String prefix) {
874

875
        return getVaccineFromVaccineConfigFile(context, getFileName(special_vaccines_file, prefix));
1✔
876
    }
877

878
    public static List<VaccineGroup> getSpecialVaccineGroups(@Nullable Context context) {
879

880
        return getVaccineGroupsFromVaccineConfigFile(context, special_vaccines_file);
×
881
    }
882

883

884
    public static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> getJsonVaccineGroup(
885
            @NonNull String filename) {
886

887
        return getVaccineFromVaccineConfigFile(ImmunizationLibrary.getInstance().context().applicationContext(), filename);
×
888
    }
889

890
    public static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> getJsonVaccineGroup(Context context, @NonNull String filename) {
891
        return getVaccineFromVaccineConfigFile(context, filename);
×
892
    }
893

894

895
    public static List<org.smartregister.immunization.domain.jsonmapping.Vaccine> getVaccineFromVaccineConfigFile(@Nullable android.content.Context context, String vaccines_file) {
896
        Class<List<org.smartregister.immunization.domain.jsonmapping.Vaccine>> classType = (Class) List.class;
1✔
897
        Type listType = new TypeToken<List<org.smartregister.immunization.domain.jsonmapping.Vaccine>>() {
1✔
898
        }.getType();
1✔
899

900
        if (specialVaccines == null) {
1✔
901
            specialVaccines = ImmunizationLibrary.assetJsonToJava(ImmunizationLibrary.getInstance().getVaccinesConfigJsonMap(), context, vaccines_file, classType, listType);
1✔
902
        }
903

904
        return specialVaccines;
1✔
905
    }
906

907
    /**
908
     * Returns a JSON String containing a list of supported services
909
     *
910
     * @param context Current valid context to be used
911
     * @return JSON String with the supported vaccines or NULL if unable to obtain the list
912
     */
913
    public static String getSupportedRecurringServices(Context context) {
914
        return getSupportedRecurringServices(context, null);
1✔
915
    }
916

917
    /**
918
     * Returns a JSON String containing a list of supported services
919
     *
920
     * @param context Current valid context to be used
921
     * @return JSON String with the supported vaccines or NULL if unable to obtain the list
922
     */
923
    public static String getSupportedRecurringServices(Context context, String prefix) {
924
        String supportedServicesString = org.smartregister.util.Utils
1✔
925
                .readAssetContents(context, getFileName(recurring_service_types_file, prefix));
1✔
926
        return supportedServicesString;
1✔
927
    }
928

929
    public static int getVaccineCalculation(Context context, String vaccineName) {
930
        List<VaccineGroup> supportedVaccines = getSupportedVaccines(context);
1✔
931
        for (VaccineGroup vaccineGroup : supportedVaccines) {
1✔
932
            for (org.smartregister.immunization.domain.jsonmapping.Vaccine vaccine : vaccineGroup.vaccines) {
1✔
933
                if (vaccine.name.equalsIgnoreCase(vaccineName))
1✔
934
                    return vaccine.openmrs_calculate.calculation;
1✔
935
            }
1✔
936
        }
1✔
937
        return -1;
1✔
938
    }
939

940
    /**
941
     * Returns a list of VaccineGroup containing a list of supported vaccines
942
     *
943
     * @param context Current valid context to be used
944
     * @return list of VaccineGroup with the supported vaccines
945
     */
946
    public static List<VaccineGroup> getSupportedVaccines(@Nullable Context context) {
947
        return getSupportedVaccines(context, null);
1✔
948
    }
949

950
    /**
951
     * Returns a list of VaccineGroup containing a list of supported vaccines
952
     *
953
     * @param context Current valid context to be used
954
     * @param prefix  Country prefix
955
     * @return list of VaccineGroup with the supported vaccines
956
     */
957
    public static List<VaccineGroup> getSupportedVaccines(@Nullable Context context, String prefix) {
958
        ImmunizationLibrary immunizationLibrary = ImmunizationLibrary.getInstance();
1✔
959
        Map<String, String> conditionalVaccinesMap = immunizationLibrary.getConditionalVaccinesMap();
1✔
960
        if (!conditionalVaccinesMap.isEmpty() && immunizationLibrary.getCurrentConditionalVaccine() != null) {
1✔
961
            return getVaccineGroupsFromVaccineConfigFile(context, getFileName(conditionalVaccinesMap.get(immunizationLibrary.getCurrentConditionalVaccine()), prefix));
×
962
        }
963
        return getVaccineGroupsFromVaccineConfigFile(context, getFileName(vaccines_file, prefix));
1✔
964
    }
965

966
    public static Map<String, Date> receivedVaccines(List<org.smartregister.immunization.domain.Vaccine> vaccines) {
967
        Map<String, Date> map = new LinkedHashMap<>();
1✔
968
        if (vaccines != null) {
1✔
969
            for (org.smartregister.immunization.domain.Vaccine vaccine : vaccines) {
1✔
970
                if (vaccine.getDate() != null) {
1✔
971
                    map.put(vaccine.getName(), vaccine.getDate());
1✔
972
                }
973
            }
1✔
974
        }
975
        return map;
1✔
976

977
    }
978

979
    /**
980
     * This method retrieves the human readable name corresponding to the vaccine name from {@code Vaccine.getName()}
981
     *
982
     * @param vaccineDbName
983
     * @return
984
     */
985
    public static String getVaccineDisplayName(Context context, String vaccineDbName) {
986
        List<VaccineGroup> availableVaccines = getSupportedVaccines(context);
1✔
987

988
        for (VaccineGroup vaccineGroup : availableVaccines) {
1✔
989
            for (org.smartregister.immunization.domain.jsonmapping.Vaccine vaccine : vaccineGroup.vaccines) {
1✔
990
                if (vaccine.name.equalsIgnoreCase(vaccineDbName))
1✔
991
                    return vaccine.name;
1✔
992
            }
1✔
993
        }
1✔
994

995
        return vaccineDbName;
1✔
996
    }
997

998
    /**
999
     * @param context Context
1000
     * @param name_   vaccine name to translate
1001
     * @return translated value
1002
     */
1003
    public static String getTranslatedVaccineName(Context context, String name_) {
1004
        String name = name_;
1✔
1005
        String[] vcn = name.contains("/") ? name.split("/") : null;
1✔
1006

1007
        if (vcn != null && vcn.length > 1) {
1✔
1008

1009
            name = translate(context, vcn[0]) + " / " + translate(context, vcn[1]);
1✔
1010

1011
        } else {
1012
            name = translate(context, name);
1✔
1013
        }
1014

1015

1016
        return name;
1✔
1017
    }
1018

1019
    /**
1020
     * @param context     Context
1021
     * @param vaccineName vaccine name which is converted to a string key/identifier in strings xml of string to translate
1022
     * @return translated value
1023
     */
1024
    public static String translate(Context context, String vaccineName) {
1025
        String resourceIdentifierKey = vaccineName;
1✔
1026

1027
        int identifier = context.getResources().getIdentifier(createIdentifier(vaccineName), "string", context.getPackageName());
1✔
1028
        if (identifier > 0) {
1✔
1029
            resourceIdentifierKey = context.getResources().getString(identifier);
1✔
1030

1031
        }
1032
        return resourceIdentifierKey;
1✔
1033
    }
1034

1035
    /**
1036
     * Creates identifier from text by doing clean up on the passed name/text
1037
     *
1038
     * @param text key to be used for reverse look up
1039
     * @return string.xml key to be used in string look ups
1040
     **/
1041
    public static String createIdentifier(String text) {
1042

1043
        String prefix = text.matches("^\\d.*\\n*") ? "_" : "";
1✔
1044
        return prefix + text.trim().toLowerCase(Locale.ENGLISH).replaceAll(" ", "_");
1✔
1045

1046
    }
1047

1048
    public static String cleanVaccineName(String vaccineName) {
1049

1050
        return StringUtils.isNotBlank(vaccineName) ? vaccineName.trim().replaceAll("[-,\\s]+", "").toLowerCase(Locale.ENGLISH) : null;
1✔
1051
    }
1052

1053
    public static Vaccine getPrerequisiteVaccine(org.smartregister.immunization.domain.jsonmapping.Vaccine vaccine) {
1054

1055
        return vaccine.schedule != null && vaccine.schedule.due != null && vaccine.schedule.due.size() > 0 && !TextUtils.isEmpty(vaccine.schedule.due.get(0).prerequisite) ? VaccineRepo.getVaccineEnumFromValue(vaccine.schedule.due.get(0).prerequisite) : null;
1✔
1056

1057
    }
1058

1059
    public static int getPrerequisiteGapDays(org.smartregister.immunization.domain.jsonmapping.Vaccine vaccine) {
1060

1061
        String prerequisteGapOffset = vaccine.schedule != null && vaccine.schedule.due != null && vaccine.schedule.due.size() > 0 && !TextUtils.isEmpty(vaccine.schedule.due.get(0).offset) ? vaccine.schedule.due.get(0).offset : null;
1✔
1062

1063
        return processOffsetValueInDays(prerequisteGapOffset);
1✔
1064
    }
1065

1066
    public static int getExpiryDays(org.smartregister.immunization.domain.jsonmapping.Vaccine vaccine) {
1067

1068
        String expiryOffset = vaccine.schedule != null && vaccine.schedule.expiry != null && vaccine.schedule.expiry.size() > 0 && !TextUtils.isEmpty(vaccine.schedule.expiry.get(0).offset) ? vaccine.schedule.expiry.get(0).offset : null;
1✔
1069

1070
        return processOffsetValueInDays(expiryOffset);
1✔
1071
    }
1072

1073
    /*
1074
     * Right now we only have child and woman type vaccines
1075
     * To do extend for automatically supporting any vaccine type , enforce naming conventional with categories for auto-loading e.g. child_vaccines.json, mother_vaccines.json, father_vaccines.json e.t.c
1076
     *
1077
     */
1078
    public static List<VaccineGroup> getSupportedVaccinesByCategory(Context context, String category) {
1079

1080
        return IMConstants.VACCINE_TYPE.CHILD.equals(category) ? getSupportedVaccines(context) : getSupportedWomanVaccines(context);
1✔
1081

1082
    }
1083

1084
    public static List<VaccineGroup> getVaccineGroupsFromVaccineConfigFile(@Nullable android.content.Context context, String vaccines_file) {
1085
        Map<String, Object> jsonMap = new HashMap<>();
1✔
1086
        Class<List<VaccineGroup>> clazz = (Class) List.class;
1✔
1087
        Type listType = new TypeToken<List<VaccineGroup>>() {
1✔
1088
        }.getType();
1✔
1089
        return ImmunizationLibrary.assetJsonToJava(jsonMap, context, vaccines_file, clazz, listType);
1✔
1090
    }
1091

1092
    /***
1093
     * Get list of vaccine files from
1094
     * @param context android context
1095
     */
1096
    public static List<String> getVaccineFiles(Context context) throws IOException {
1097
        AssetManager assetManager = context.getAssets();
1✔
1098
        String[] files = assetManager.list(vaccines_folder);
1✔
1099
        return Arrays.asList(files);
1✔
1100
    }
1101

1102
    public static void processConfigCalendarOffset(Calendar calendar, String offset) {
1103

1104
        String[] offsetTokens = offset.split(",");
1✔
1105

1106
        for (int i = 0; i < offsetTokens.length; i++) {
1✔
1107

1108
            Matcher m2 = getSuffixSymbolMatcher(offsetTokens[i]);
1✔
1109
            if (m2.find()) {
1✔
1110
                int curValue = getOperator(offsetTokens[i]) * Integer.parseInt(m2.group(1));
1✔
1111
                String fieldString = m2.group(2);
1✔
1112
                int field = Calendar.DATE;
1✔
1113
                if ("d".equals(fieldString)) {
1✔
1114
                    field = Calendar.DATE;
1✔
1115
                } else if ("m".equals(fieldString)) {
1✔
1116
                    field = Calendar.MONTH;
1✔
1117
                } else if ("y".equals(fieldString)) {
1✔
1118
                    field = Calendar.YEAR;
1✔
1119
                }
1120

1121
                calendar.add(field, curValue);
1✔
1122
            }
1123
        }
1124

1125
    }
1✔
1126

1127
    public static DateTime processConfigDateTimeOffset(DateTime afterOffset, String offset) {
1128

1129
        String[] offsetTokens = offset.split(",");
1✔
1130

1131
        for (int i = 0; i < offsetTokens.length; i++) {
1✔
1132

1133
            Matcher m2 = getSuffixSymbolMatcher(offsetTokens[i]);
1✔
1134
            if (m2.find()) {
1✔
1135
                int curValue = getOperator(offsetTokens[i]) * Integer.parseInt(m2.group(1));
1✔
1136
                String fieldString = m2.group(2);
1✔
1137
                if ("d".endsWith(fieldString)) {
1✔
1138
                    afterOffset = afterOffset.plusDays(curValue);
1✔
1139
                } else if ("m".equals(fieldString)) {
1✔
1140
                    afterOffset = afterOffset.plusMonths(curValue);
1✔
1141
                } else if ("y".equals(fieldString)) {
1✔
1142
                    afterOffset = afterOffset.plusYears(curValue);
1✔
1143
                }
1144

1145
            }
1146
        }
1147
        return afterOffset;
1✔
1148

1149
    }
1150

1151
    public static int processOffsetValueInDays(String offset) {
1152
        if (offset == null) return -1;
1✔
1153
        int days = 0;
1✔
1154
        String[] offsetTokens = offset.split(",");
1✔
1155

1156
        for (int i = 0; i < offsetTokens.length; i++) {
1✔
1157

1158
            Matcher m2 = getSuffixSymbolMatcher(offsetTokens[i]);
1✔
1159
            if (m2.find()) {
1✔
1160
                int curValue = getOperator(offsetTokens[i]) * Integer.parseInt(m2.group(1));
1✔
1161
                String fieldString = m2.group(2);
1✔
1162
                if ("d".endsWith(fieldString)) {
1✔
1163
                    days += curValue;
1✔
1164
                } else if ("m".equals(fieldString)) {
1✔
1165
                    days += (int) Math.round(30.44 * curValue);
1✔
1166
                } else if ("y".equals(fieldString)) {
1✔
1167
                    days += 366 * curValue;
1✔
1168
                }
1169
            }
1170
        }
1171

1172
        return days;
1✔
1173

1174
    }
1175

1176
    private static int getOperator(String offsetToken) {
1177
        int operator = 1;
1✔
1178
        Matcher m1 = getPrefixSymbolMatcher(offsetToken);
1✔
1179
        if (m1.find()) {
1✔
1180
            String operatorString = m1.group(1);
1✔
1181

1182
            if ("-".equals(operatorString)) {
1✔
1183
                operator = -1;
1✔
1184
            }
1185
        }
1186
        return operator;
1✔
1187
    }
1188

1189
    private static Matcher getSuffixSymbolMatcher(String value) {
1190
        Pattern p2 = Pattern.compile("(\\d+)([dwmy]{1})");
1✔
1191
        return p2.matcher(value);
1✔
1192
    }
1193

1194
    private static Matcher getPrefixSymbolMatcher(String offset) {
1195
        String offsetAfterReplace = offset.replace(" ", "").toLowerCase(Locale.ENGLISH);
1✔
1196
        Pattern p1 = Pattern.compile("([-+]{1})(.*)");
1✔
1197
        return p1.matcher(offsetAfterReplace);
1✔
1198
    }
1199

1200
    /**
1201
     * This method is used to return minimum and maximum date as a pair for a vaccine that has a
1202
     * prerequisite. Example if you have IPV2 vaccine that depends on IPV1. We want to set the minimum
1203
     * date for IPV2 to be the date IPV1 was administered.
1204
     *
1205
     * @param vaccineWrappers Current vaccine(s) to be administered
1206
     * @param issuedVaccines  Requisite vaccine(s) that were administered earlier
1207
     * @return a pair of minimum and maximum date respectively
1208
     */
1209
    public static Pair<Calendar, Calendar> getVaccineMinimumAndMaximumDate(List<VaccineWrapper> vaccineWrappers, List<org.smartregister.immunization.domain.Vaccine> issuedVaccines) {
1210
        boolean requisiteDateConstraintEnabled = Boolean.parseBoolean(ImmunizationLibrary.getInstance().getProperties()
1✔
1211
                .getProperty(IMConstants.APP_PROPERTIES.VACCINE_REQUISITE_DATE_CONSTRAINT_ENABLED, String.valueOf(false)));
1✔
1212

1213
        Calendar maxDate = null;
1✔
1214
        Calendar minDate = null;
1✔
1215
        if (requisiteDateConstraintEnabled && vaccineWrappers.size() == 1) {
1✔
1216

1217
            VaccineWrapper vaccineWrapper = vaccineWrappers.get(0);
×
1218

1219
            VaccineSchedule curVaccineSchedule = VaccineSchedule.getVaccineSchedule(IMConstants.VACCINE_TYPE.CHILD, vaccineWrapper.getName());
×
1220
            if (curVaccineSchedule == null) {
×
1221
                curVaccineSchedule = VaccineSchedule.getVaccineSchedule(IMConstants.VACCINE_TYPE.WOMAN, vaccineWrapper.getName());
×
1222
            }
1223
            if (curVaccineSchedule != null) {
×
1224
                VaccineRepo.Vaccine prerequisite = curVaccineSchedule.getVaccine().prerequisite();
×
1225
                if (prerequisite != null)
×
1226
                    for (org.smartregister.immunization.domain.Vaccine vaccine : issuedVaccines)
×
1227
                        if (vaccine.getName().equalsIgnoreCase(prerequisite.display())) {
×
1228
                            minDate = Calendar.getInstance();
×
1229
                            minDate.setTime(vaccine.getDate());
×
1230
                            maxDate = Calendar.getInstance();
×
1231
                            break;
×
1232
                        }
1233
            }
1234
        }
1235
        return Pair.create(minDate, maxDate);
1✔
1236
    }
1237

1238
    public static boolean isSkippableVaccine(String vaccine) {
1239

1240
        if (ImmunizationLibrary.getInstance().getSkippableVaccines() == null || ImmunizationLibrary.getInstance().getSkippableVaccines().size() == 0) {
1✔
1241
            return false;
1✔
1242
        }
1243

1244
        String[] vaccineNames = vaccine.replaceAll("\\s", "").split("/");
1✔
1245
        for (String vaccineName : vaccineNames) {
1✔
1246
            try {
1247
                if (ImmunizationLibrary.getInstance().getSkippableVaccines().contains(VaccineRepo.Vaccine.valueOf(VaccinatorUtils.cleanVaccineName(vaccineName)))) {
1✔
1248
                    return true;
1✔
1249
                }
1250
            } catch (IllegalArgumentException e) {
×
1251
                Timber.d(e.getMessage());
×
1252
            }
×
1253
        }
1254

1255
        return false;
×
1256
    }
1257
}
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

© 2025 Coveralls, Inc