def add_form_to_patient(line): change = Change(line) # check the global max seq in this process to avoid repeating ourselves. if change.seq < max_seq: return log_and_abort(logging.DEBUG, "ignoring item %s because it's seq is old") update_max_seq(change) form_id = change.id # don't bother with deleted or old documents if change.deleted or not change.is_current(db): return formdoc = CXFormInstance.get(form_id) pat_id = get_patient_id_from_form(formdoc) if pat_id is not None and get_classification(formdoc.namespace) == "clinic": try: # this is so we don't get conflicting updates. # resolve conflicts and bump version numbers before adding forms pat_data = get_db().get(pat_id, conflicts=True) if "_conflicts" in pat_data: return log_and_abort(logging.INFO, "ignoring patient %s because there are still conflicts that need to be resolved" % pat_id) else: pat = CPatient.wrap(pat_data) if pat.requires_upgrade(): return log_and_abort(logging.INFO, "ignoring patient %s, form %s because it is not yet upgraded to the latest version" % (pat_id, form_id)) found_ids = [enc.xform_id for enc in pat.encounters] if form_id in found_ids and not formdoc.requires_upgrade(): return log_and_abort(logging.DEBUG, "Already found appropriate version of form %s in patient %s, no need to do anything" % (form_id, pat_id)) else: print "Form %s not found in patient %s or was old. Rebuilding the patient now" % (form_id, pat_id) reprocess(pat_id) except ResourceNotFound, e: return log_and_abort(logging.WARNING, "tried to check form %s in patient %s but patient has been deleted. Ignoring" % (form_id, pat_id))
def testReprocessUpgradesVersion(self): patient = random_person() patient.app_version = MIN_VERSION patient.save() self.assertEqual(MIN_VERSION, patient.app_version) self.assertEqual(MIN_VERSION, patient.original_app_version) reprocess(patient.get_id) patback = CPatient.get(patient.get_id) self.assertEqual(settings.APP_VERSION, patback.app_version) # shouldn't upgrade the original version self.assertEqual(MIN_VERSION, patient.original_app_version)
def upgrade_patient(line): change = Change(line) # don't bother with deleted or old documents if change.deleted or not change.is_current(db): return patient_id = change.id try: if patient_id in problem_patients: return log_and_abort(logging.DEBUG, "skipping problem patient: %s" % patient_id) pat_data = get_db().get(patient_id, conflicts=True) # this is so we don't get conflicting updates. resolve conflicts before bumping version numbers. if "_conflicts" in pat_data: return log_and_abort(logging.INFO, "ignoring patient %s because there are still conflicts that need to be resolved" % patient_id) else: pat = CPatient.wrap(pat_data) if pat.requires_upgrade(): print "upgrading patient: %s" % patient_id logging.debug("upgrading patient: %s" % patient_id) if not reprocess(pat.get_id): log_and_abort(logging.ERROR, "problem upgrading patient %s!" % patient_id) problem_patients.append(patient_id) except Exception, e: logging.exception("problem upgrading patient (id: %s)" % patient_id) problem_patients.append(patient_id)
def handle(self, *args, **options): if not are_you_sure(WARNING_TEXT): print "Okay. Good call -- safety first! Goodbye." sys.exit() else: all_patients = get_db().view("patient/ids").all() successfully_processed = [] failed = [] NOTIFICATION_INCREMENT = 10 count = 0 total_pats = len(all_patients) for result in all_patients: if count % NOTIFICATION_INCREMENT == 0: print "processing patient %s of %s" % (count, total_pats) pat_id = result["key"] count = count + 1 if reprocess(pat_id): successfully_processed.append(pat_id) else: failed.append(pat_id) if failed: print "======= failed patients ========\n" + "\n".join(failed) print "Unable to process the above patients. Lookup these " \ "patient ids by visiting the urls like so: %s" % (reverse("single_patient", args=(failed[0],))) print "Successfully processed %s patients. There were problems with %s patients." % \ (len(successfully_processed), len(failed))
def testReturnToClinicSupercedes(self): folder_name = os.path.join(os.path.dirname(__file__), "testpatients", "ltfu_test2") patient = export.import_patient_json_file(os.path.join(folder_name, "patient.json")) updated_patient, form_doc1 = export.add_form_file_to_patient(patient.get_id, os.path.join(folder_name, "001_general.xml")) updated_patient, form_doc2 = export.add_form_file_to_patient(patient.get_id, os.path.join(folder_name, "002_general.xml")) updated_patient, form_doc3 = export.add_form_file_to_patient(patient.get_id, os.path.join(folder_name, "003_general.xml")) reprocess(updated_patient.get_id) updated_patient = CPatient.get(updated_patient.get_id) self.assertEqual(3, len(updated_patient.cases)) [c1, c2, c3] = sorted(updated_patient.cases, key=lambda case: case.opened_on) # after reprocessing the first case should be closed with returned to clinic, # but the second should be ltfu self.assertTrue(c1.closed) self.assertEqual(const.Outcome.RETURNED_TO_CLINIC, c1.outcome) self.assertTrue(c2.closed) self.assertEqual(const.Outcome.LOST_TO_FOLLOW_UP, c2.outcome)
def testRegeneratePatient(self): folder_name = os.path.join(os.path.dirname(__file__), "data", "chw") patient = export.import_patient_json_file(os.path.join(folder_name, "patient.json")) self.assertEqual(0, len(patient.encounters)) with open(os.path.join(folder_name, "non_life_threatening_referral.xml"), "r") as f: formbody = f.read() formdoc = post_xform_to_couch(formbody) new_form_workflow(formdoc, SENDER_PHONE, None) patient = CPatient.get(patient.get_id) self.assertEqual(1, len(patient.encounters)) self.assertTrue(reprocess(patient.get_id)) patient = CPatient.get(patient.get_id) self.assertEqual(1, len(patient.encounters))
def resolve_conflicts(patient_id): """ Resolve conflicts on a patient. Returns true if conflicts were found, otherwise false. """ pat_data = get_db().get(patient_id, conflicts=True) if "_conflicts" in pat_data: tries = 0 MAX_TRIES = 5 while tries < MAX_TRIES: try: # For now conflict resolution assumes that all you ever need # to do is reprocess the patient and delete the conflicts. reprocess(patient_id) conflict_docs = [get_db().get(patient_id, rev=conflict) for conflict in pat_data["_conflicts"]] get_db().bulk_delete(conflict_docs) return True except Exception, e: tries = tries + 1 if tries == MAX_TRIES: logging.exception("Couldn't resolve conflicts for document %s. Last error is %s" % (patient_id, e)) return True
def regenerate_data(request, patient_id): """ Regenerate all patient data, by reprocessing all forms. """ reprocess(patient_id) return HttpResponseRedirect(reverse("single_patient", args=(patient_id,)))