def test_migration(self): xform = self.get_xml("form") form_bad_tz = self.get_json("form") case_bad_tz = self.get_json("case") form_good_tz = self.get_json("form-tz") case_good_tz = self.get_json("case-tz") with override_settings(PHONE_TIMEZONES_HAVE_BEEN_PROCESSED=False, PHONE_TIMEZONES_SHOULD_BE_PROCESSED=False): submit_form_locally(xform, self.domain) # Form before xform_instance, = get_forms_by_type(self.domain, "XFormInstance", limit=10) xform_json = xform_instance.to_json() self._compare_forms(xform_json, form_bad_tz, "Form before migration does not match") # Case before case, = get_cases_in_domain(self.domain) self._compare_cases(case.to_json(), case_bad_tz, "Case before migration does not match") run_timezone_migration_for_domain(self.domain) # Form after xform_instance, = get_forms_by_type(self.domain, "XFormInstance", limit=10) xform_json = xform_instance.to_json() self._compare_forms(xform_json, form_good_tz, "Form after migration does not match") # Case after case, = get_cases_in_domain(self.domain) self._compare_cases(case.to_json(), case_good_tz, "Case after migration does not match")
def test_migration(self): xform = self.get_xml('form') form_bad_tz = self.get_json('form') case_bad_tz = self.get_json('case') form_good_tz = self.get_json('form-tz') case_good_tz = self.get_json('case-tz') with override_settings(PHONE_TIMEZONES_HAVE_BEEN_PROCESSED=False, PHONE_TIMEZONES_SHOULD_BE_PROCESSED=False): submit_form_locally(xform, self.domain) # Form before xform_instance, = get_forms_by_type(self.domain, 'XFormInstance', limit=10) xform_json = xform_instance.to_json() self._compare_forms(xform_json, form_bad_tz, "Form before migration does not match") # Case before case, = get_cases_in_domain(self.domain) self._compare_cases(case.to_json(), case_bad_tz, "Case before migration does not match") run_timezone_migration_for_domain(self.domain) # Form after xform_instance, = get_forms_by_type(self.domain, 'XFormInstance', limit=10) xform_json = xform_instance.to_json() self._compare_forms(xform_json, form_good_tz, "Form after migration does not match") # Case after case, = get_cases_in_domain(self.domain) self._compare_cases(case.to_json(), case_good_tz, "Case after migration does not match")
def testLocationOwner(self): # This is actually testing several different things, but I figure it's # worth it, as each of these tests takes a non-trivial amount of time. non_case_sharing = LocationType.objects.create( domain=self.domain, name='lt1', shares_cases=False ) case_sharing = LocationType.objects.create( domain=self.domain, name='lt2', shares_cases=True ) location = make_loc('loc-1', 'Loc 1', self.domain, case_sharing) make_loc('loc-2', 'Loc 2', self.domain, case_sharing) duplicate_loc = make_loc('loc-3', 'Loc 2', self.domain, case_sharing) improper_loc = make_loc('loc-4', 'Loc 4', self.domain, non_case_sharing) res = self.import_mock_file([ ['case_id', 'name', 'owner_id', 'owner_name'], ['', 'location-owner-id', location.group_id, ''], ['', 'location-owner-code', '', location.site_code], ['', 'location-owner-name', '', location.name], ['', 'duplicate-location-name', '', duplicate_loc.name], ['', 'non-case-owning-name', '', improper_loc.name], ]) cases = {c.name: c for c in list(get_cases_in_domain(self.domain))} self.assertEqual(cases['location-owner-id'].owner_id, location.group_id) self.assertEqual(cases['location-owner-code'].owner_id, location.group_id) self.assertEqual(cases['location-owner-name'].owner_id, location.group_id) error_message = ImportErrors.DuplicateLocationName self.assertIn(error_message, res['errors']) self.assertEqual(res['errors'][error_message]['rows'], [4]) error_message = ImportErrors.InvalidOwnerId self.assertIn(error_message, res['errors']) self.assertEqual(res['errors'][error_message]['rows'], [5])
def handle(self, *args, **options): domain = 'care-bihar' root_types = ('cc_bihar_pregnancy', 'cc_bihar_newborn') TASK_TYPE = 'task' # loop through all mother cases, then all child cases # for each case get all associated tasks # if any duplicates found, clean up / print them with open('bihar-duplicate-tasks.csv', 'wb') as f: writer = csv.writer(f, dialect=csv.excel) _dump_headings(writer) for case_type in root_types: for parent_case in get_cases_in_domain(domain, case_type): try: tasks = filter(lambda subcase: subcase.type == TASK_TYPE, parent_case.get_subcases()) if tasks: types = [_task_id(t) for t in tasks] unique_types = set(types) if len(unique_types) != len(tasks): for type_being_checked in unique_types: matching_cases = [t for t in tasks if _task_id(t) == type_being_checked] if len(matching_cases) > 1: for row, case in _get_rows(parent_case, matching_cases): keep = row[-1] writer.writerow(row) if options['cleanup'] and not keep: _purge(case) except Exception, e: print 'error with case %s (%s)' % (parent_case._id, e)
def handle(self, *args, **options): domain = 'care-bihar' # forward all cases that were last modified between these dates def should_forward_case(case): min_date = datetime(2013, 9, 10) max_date = datetime(2013, 11, 7) return (case.server_modified_on and min_date < case.server_modified_on < max_date) prod_repeater = CaseRepeater.get('a478a5a3d8964338cb3124de77e3ec58') success_count = 0 fail_count = 0 for case in get_cases_in_domain(domain): try: if should_forward_case(case): prod_repeater.register(case) success_count += 1 except Exception: fail_count += 1 logging.exception( 'problem creating repeater stub for case %s' % case._id) print 'successfully forwarded %s cases. %s were not processed' % ( success_count, fail_count)
def handle(self, *args, **options): domain = 'care-bihar' root_types = ('cc_bihar_pregnancy', 'cc_bihar_newborn') TASK_TYPE = 'task' # loop through all mother cases, then all child cases # for each case get all associated tasks # if any duplicates found, clean up / print them with open('bihar-duplicate-tasks.csv', 'wb') as f: writer = csv.writer(f, dialect=csv.excel) _dump_headings(writer) for case_type in root_types: for parent_case in get_cases_in_domain(domain, case_type): try: tasks = filter( lambda subcase: subcase.type == TASK_TYPE, parent_case.get_subcases()) if tasks: types = [_task_id(t) for t in tasks] unique_types = set(types) if len(unique_types) != len(tasks): for type_being_checked in unique_types: matching_cases = [ t for t in tasks if _task_id(t) == type_being_checked ] if len(matching_cases) > 1: for row, case in _get_rows( parent_case, matching_cases): keep = row[-1] writer.writerow(row) if options['cleanup'] and not keep: _purge(case) except Exception, e: print 'error with case %s (%s)' % (parent_case._id, e)
def test_get_cases_in_domain__type(self): self.assert_doc_list_equal( get_cases_in_domain(self.domain, type='type1'), [ case for case in self.cases if case.domain == self.domain and case.type == 'type1' ], )
def handle(self, *args, **options): if len(args) == 0: raise CommandError("Usage: python manage.py check_case_verified_numbers <domain1 domain2 ...>") make_fixes = options["fix"] for domain in args: print "*** Processing Domain %s ***" % domain for case in get_cases_in_domain(domain): contact_phone_number = case.get_case_property("contact_phone_number") contact_phone_number_is_verified = case.get_case_property("contact_phone_number_is_verified") contact_backend_id = case.get_case_property("contact_backend_id") contact_ivr_backend_id = case.get_case_property("contact_ivr_backend_id") contact = case verified_numbers = contact.get_verified_numbers(include_pending=True) should_have_entry = contact_phone_number_is_verified and contact_phone_number is not None and contact_phone_number != "" and str(contact_phone_number) != "0" and not case.closed has_entry = len(verified_numbers) > 0 if len(verified_numbers) > 1: print "skipping case %s, multiple verified number entries found" % case._id continue if has_entry: verified_number = sorted(verified_numbers.iteritems())[0][1] if not verified_number.verified: print "skipping case %s, unverified number found" % case._id continue if has_entry and should_have_entry: if verified_number.phone_number != contact_phone_number or verified_number.backend_id != contact_backend_id or verified_number.ivr_backend_id != contact_ivr_backend_id: print "DISCREPANCY: case %s case properties don't match the verified number entry" % case._id if make_fixes: try: contact.save_verified_number(contact.domain, contact_phone_number, True, contact_backend_id, ivr_backend_id=contact_ivr_backend_id, only_one_number_allowed=True) except (InvalidFormatException, PhoneNumberInUseException): contact.delete_verified_number() elif has_entry and not should_have_entry: print "DISCREPANCY: case %s has a verified number but should not" % case._id if make_fixes: contact.delete_verified_number() elif not has_entry and should_have_entry: try: contact.verify_unique_number(contact_phone_number) except InvalidFormatException: print "DISCREPANCY: case %s does not have a verified number because number format is invalid" % case._id except PhoneNumberInUseException: print "DISCREPANCY: case %s does not have a verified number because number is already in use" % case._id else: print "DISCREPANCY: case %s does not have a verified number but should" % case._id if make_fixes: contact.save_verified_number(contact.domain, contact_phone_number, True, contact_backend_id, ivr_backend_id=contact_ivr_backend_id, only_one_number_allowed=True) else: # Doesn't have an entry, and shouldn't have an entry pass
def get_participants(self): result = get_cases_in_domain(self.domain, 'participant') survey_report_date = parse(self.survey_report_date).date() def filter_function(case): registration_date = get_date(case, "start_date") if registration_date is None: return False first_tuesday = self.get_first_tuesday(registration_date) last_tuesday = first_tuesday + timedelta(days=49) return first_tuesday <= survey_report_date <= last_tuesday result = filter(filter_function, result) return result
def test_simple(self): caseblock = CaseBlock(create=True, case_id=uuid.uuid4().hex, user_id=self.user_id, owner_id=self.user_id, case_type='exploder-type', version=V2).as_string() submit_case_blocks([caseblock], self.domain.name) self.assertEqual(1, len(get_case_ids_in_domain(self.domain.name))) explode_cases(self.user_id, self.domain.name, 10) cases_back = list(get_cases_in_domain(self.domain.name)) self.assertEqual(10, len(cases_back)) for case in cases_back: self.assertEqual(self.user_id, case.owner_id)
def get_interactive_participants(domain): cases = get_cases_in_domain(domain, 'participant') result = [] timezone = get_timezone_for_user(None, domain) # Use project timezone only current_date = datetime.now(tz=timezone).date() for case in cases: study_arm = case.get_case_property("study_arm") if isinstance(study_arm, six.string_types) and study_arm.upper() == "A" and not case.closed: start_date = get_date(case, "start_date") if start_date is None: continue end_date = start_date + timedelta(days=55) if start_date <= current_date <= end_date: result.append(case) return result
def get_interactive_participants(domain): cases = get_cases_in_domain(domain, 'participant') result = [] timezone = get_timezone_for_user(None, domain) # Use project timezone only current_date = datetime.now(tz=timezone).date() for case in cases: study_arm = case.get_case_property("study_arm") if isinstance(study_arm, basestring) and study_arm.upper() == "A" and not case.closed: start_date = get_date(case, "start_date") if start_date is None: continue end_date = start_date + timedelta(days=55) if start_date <= current_date <= end_date: result.append(case) return result
def test_skip_user_case(self): caseblock = CaseBlock( create=True, case_id=uuid.uuid4().hex, user_id=self.user_id, owner_id=self.user_id, case_type='commcare-user', ).as_string() submit_case_blocks([caseblock], self.domain.name) self.assertEqual(1, len(get_case_ids_in_domain(self.domain.name))) explode_cases(self.user_id, self.domain.name, 10) cases_back = list(get_cases_in_domain(self.domain.name)) self.assertEqual(1, len(cases_back)) for case in cases_back: self.assertEqual(self.user_id, case.owner_id)
def indexed_facilities(): facility_index = {} for domain in DOMAINS: current_domain_index = {} facilities = get_cases_in_domain(domain, type="facility") for facility in facilities: case_sharing_group = GROUPS_BY_ID[domain].get(facility.owner_id, None) if case_sharing_group is None: continue cati_user = case_sharing_group.metadata.get('cati_user', None) fida_user = case_sharing_group.metadata.get('fida_user', None) current_domain_index[facility.facility_id] = { "cati": cati_user, "fida": fida_user } facility_index[domain] = current_domain_index return facility_index
def testImportBasic(self): config = self._config(self.default_headers) file = MockExcelFile(header_columns=self.default_headers, num_rows=5) res = do_import(file, config, self.domain) self.assertEqual(5, res['created_count']) self.assertEqual(0, res['match_count']) self.assertFalse(res['errors']) self.assertEqual(1, res['num_chunks']) cases = list(get_cases_in_domain(self.domain)) self.assertEqual(5, len(cases)) properties_seen = set() for case in cases: self.assertEqual(self.couch_user._id, case.user_id) self.assertEqual(self.couch_user._id, case.owner_id) self.assertEqual(self.default_case_type, case.type) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop)) self.assertFalse(case.get_case_property(prop) in properties_seen) properties_seen.add(case.get_case_property(prop))
def test_parent_child(self): parent_id = uuid.uuid4().hex parent_type = 'exploder-parent-type' parent_block = CaseBlock(create=True, case_id=parent_id, user_id=self.user_id, owner_id=self.user_id, case_type=parent_type, version=V2).as_string() child_id = uuid.uuid4().hex child_block = CaseBlock(create=True, case_id=child_id, user_id=self.user_id, owner_id=self.user_id, case_type='exploder-child-type', index={ 'parent': (parent_type, parent_id) }, version=V2).as_string() submit_case_blocks([parent_block, child_block], self.domain.name) self.assertEqual(2, len(get_case_ids_in_domain(self.domain.name))) explode_cases(self.user_id, self.domain.name, 5) cases_back = list(get_cases_in_domain(self.domain.name)) self.assertEqual(10, len(cases_back)) parent_cases = { p._id: p for p in filter(lambda case: case.type == parent_type, cases_back) } self.assertEqual(5, len(parent_cases)) child_cases = filter(lambda case: case.type == 'exploder-child-type', cases_back) self.assertEqual(5, len(child_cases)) child_indices = [ child.indices[0].referenced_id for child in child_cases ] # make sure they're different self.assertEqual(len(child_cases), len(set(child_indices))) for child in child_cases: self.assertEqual(1, len(child.indices)) self.assertTrue(child.indices[0].referenced_id in parent_cases)
def testImportBasic(self): config = self._config(self.default_headers) file = MockExcelFile(header_columns=self.default_headers, num_rows=5) res = do_import(file, config, self.domain) self.assertEqual(5, res['created_count']) self.assertEqual(0, res['match_count']) self.assertFalse(res['errors']) self.assertEqual(1, res['num_chunks']) cases = list(get_cases_in_domain(self.domain)) self.assertEqual(5, len(cases)) properties_seen = set() for case in cases: self.assertEqual(self.couch_user._id, case.user_id) self.assertEqual(self.couch_user._id, case.owner_id) self.assertEqual(self.default_case_type, case.type) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop)) self.assertFalse( case.get_case_property(prop) in properties_seen) properties_seen.add(case.get_case_property(prop))
def testExternalIdChunking(self): # bootstrap a stub case external_id = 'importer-test-external-id' headers = ['external_id', 'age', 'sex', 'location'] config = self._config(headers, search_field='external_id') file = MockExcelFile(header_columns=headers, num_rows=3, row_generator=id_match_generator(external_id)) # the first one should create the case, and the remaining two should update it res = do_import(file, config, self.domain) self.assertEqual(1, res['created_count']) self.assertEqual(2, res['match_count']) self.assertFalse(res['errors']) self.assertEqual(2, res['num_chunks']) # the lookup causes an extra chunk # should just create the one case self.assertEqual(1, len(get_case_ids_in_domain(self.domain))) [case] = get_cases_in_domain(self.domain) self.assertEqual(external_id, case.external_id) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop))
def testCaseIdMatching(self): # bootstrap a stub case case = CommCareCase(domain=self.domain, type=self.default_case_type) case.importer_test_prop = 'foo' case.save() self.assertEqual(1, len(get_case_ids_in_domain(self.domain))) config = self._config(self.default_headers) file = MockExcelFile(header_columns=self.default_headers, num_rows=3, row_generator=id_match_generator(case._id)) res = do_import(file, config, self.domain) self.assertEqual(0, res['created_count']) self.assertEqual(3, res['match_count']) self.assertFalse(res['errors']) # shouldn't create any more cases, just the one self.assertEqual(1, len(get_case_ids_in_domain(self.domain))) [case] = get_cases_in_domain(self.domain) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop)) # shouldn't touch existing properties self.assertEqual('foo', case.importer_test_prop)
def testLocationOwner(self): # This is actually testing several different things, but I figure it's # worth it, as each of these tests takes a non-trivial amount of time. non_case_sharing = LocationType.objects.create(domain=self.domain, name='lt1', shares_cases=False) case_sharing = LocationType.objects.create(domain=self.domain, name='lt2', shares_cases=True) location = make_loc('loc-1', 'Loc 1', self.domain, case_sharing) make_loc('loc-2', 'Loc 2', self.domain, case_sharing) duplicate_loc = make_loc('loc-3', 'Loc 2', self.domain, case_sharing) improper_loc = make_loc('loc-4', 'Loc 4', self.domain, non_case_sharing) res = self.import_mock_file([ ['case_id', 'name', 'owner_id', 'owner_name'], ['', 'location-owner-id', location.group_id, ''], ['', 'location-owner-code', '', location.site_code], ['', 'location-owner-name', '', location.name], ['', 'duplicate-location-name', '', duplicate_loc.name], ['', 'non-case-owning-name', '', improper_loc.name], ]) cases = {c.name: c for c in list(get_cases_in_domain(self.domain))} self.assertEqual(cases['location-owner-id'].owner_id, location.group_id) self.assertEqual(cases['location-owner-code'].owner_id, location.group_id) self.assertEqual(cases['location-owner-name'].owner_id, location.group_id) error_message = ImportErrors.DuplicateLocationName self.assertIn(error_message, res['errors']) self.assertEqual(res['errors'][error_message]['rows'], [4]) error_message = ImportErrors.InvalidOwnerId self.assertIn(error_message, res['errors']) self.assertEqual(res['errors'][error_message]['rows'], [5])
def test_parent_child(self): parent_id = uuid.uuid4().hex parent_type = 'exploder-parent-type' parent_block = CaseBlock( create=True, case_id=parent_id, user_id=self.user_id, owner_id=self.user_id, case_type=parent_type, version=V2 ).as_string() child_id = uuid.uuid4().hex child_block = CaseBlock( create=True, case_id=child_id, user_id=self.user_id, owner_id=self.user_id, case_type='exploder-child-type', index={'parent': (parent_type, parent_id)}, version=V2 ).as_string() submit_case_blocks([parent_block, child_block], self.domain.name) self.assertEqual(2, len(get_case_ids_in_domain(self.domain.name))) explode_cases(self.user_id, self.domain.name, 5) cases_back = list(get_cases_in_domain(self.domain.name)) self.assertEqual(10, len(cases_back)) parent_cases = {p._id: p for p in filter(lambda case: case.type == parent_type, cases_back)} self.assertEqual(5, len(parent_cases)) child_cases = filter(lambda case: case.type == 'exploder-child-type', cases_back) self.assertEqual(5, len(child_cases)) child_indices = [child.indices[0].referenced_id for child in child_cases] # make sure they're different self.assertEqual(len(child_cases), len(set(child_indices))) for child in child_cases: self.assertEqual(1, len(child.indices)) self.assertTrue(child.indices[0].referenced_id in parent_cases)
def handle(self, *args, **options): domain = 'care-bihar' # forward all cases that were last modified between these dates def should_forward_case(case): min_date = datetime(2013, 9, 10) max_date = datetime(2013, 11, 7) return (case.server_modified_on and min_date < case.server_modified_on < max_date) prod_repeater = CaseRepeater.get('a478a5a3d8964338cb3124de77e3ec58') success_count = 0 fail_count = 0 for case in get_cases_in_domain(domain): try: if should_forward_case(case): prod_repeater.register(case) success_count += 1 except Exception: fail_count += 1 logging.exception('problem creating repeater stub for case %s' % case._id) print 'successfully forwarded %s cases. %s were not processed' % (success_count, fail_count)
def rows(self): group_id = None if self.request.couch_user.is_commcare_user(): group_ids = self.request.couch_user.get_group_ids() if len(group_ids) > 0: group_id = group_ids[0] data = {} for case in get_cases_in_domain(self.domain, type='participant'): if case.closed: continue # If a site coordinator is viewing the report, only show participants from that site (group) if group_id is None or group_id == case.owner_id: timezone = pytz.timezone(case.get_case_property("time_zone")) data[case._id] = { "name": case.name, "time_zone": timezone, "dates": [None] * 14, } dates = self.get_past_two_weeks() date_strings = [json_format_date(date) for date in dates] start_date = dates[0] - timedelta(days=1) end_date = dates[-1] + timedelta(days=2) expected_callback_events = ExpectedCallback.by_domain( self.domain, start_date=datetime.combine(start_date, time(0, 0)), end_date=datetime.combine(end_date, time(0, 0)) ).order_by('date') for event in expected_callback_events: if event.couch_recipient in data: timezone = data[event.couch_recipient]["time_zone"] event_date = (ServerTime(event.date).user_time(timezone) .ui_string("%Y-%m-%d")) if event_date in date_strings: data[event.couch_recipient]["dates"][date_strings.index(event_date)] = event.status result = [] for case_id, data_dict in data.items(): row = [ self._fmt(data_dict["name"]), None, None, None, ] total_no_response = 0 total_indicated = 0 total_pending = 0 for date_status in data_dict["dates"]: if date_status == CALLBACK_PENDING: total_indicated += 1 total_pending += 1 row.append(self._fmt(_("pending"))) elif date_status == CALLBACK_RECEIVED: total_indicated += 1 row.append(self._fmt(_("OK"))) elif date_status == CALLBACK_MISSED: total_indicated += 1 total_no_response += 1 row.append(self._fmt_highlight(_("No Response"))) else: row.append(self._fmt(_("not indicated"))) if total_no_response > 0: row[1] = self._fmt_highlight(total_no_response) else: row[1] = self._fmt(total_no_response) row[2] = self._fmt(total_indicated) row[3] = self._fmt(total_pending) result.append(row) return result
def rows(self): group_id = None if self.request.couch_user.is_commcare_user(): group_ids = self.request.couch_user.get_group_ids() if len(group_ids) > 0: group_id = group_ids[0] data = {} for case in get_cases_in_domain(self.domain, type='participant'): if case.closed: continue # If a site coordinator is viewing the report, only show participants from that site (group) if group_id is None or group_id == case.owner_id: timezone = pytz.timezone(case.get_case_property("time_zone")) data[case._id] = { "name": case.name, "time_zone": timezone, "dates": [None] * 14, } dates = self.get_past_two_weeks() date_strings = [json_format_date(date) for date in dates] start_date = dates[0] - timedelta(days=1) end_date = dates[-1] + timedelta(days=2) expected_callback_events = ExpectedCallback.by_domain( self.domain, start_date=datetime.combine(start_date, time(0, 0)), end_date=datetime.combine(end_date, time(0, 0))).order_by('date') for event in expected_callback_events: if event.couch_recipient in data: timezone = data[event.couch_recipient]["time_zone"] event_date = (ServerTime( event.date).user_time(timezone).ui_string("%Y-%m-%d")) if event_date in date_strings: data[event.couch_recipient]["dates"][date_strings.index( event_date)] = event.status result = [] for case_id, data_dict in data.items(): row = [ self._fmt(data_dict["name"]), None, None, None, ] total_no_response = 0 total_indicated = 0 total_pending = 0 for date_status in data_dict["dates"]: if date_status == CALLBACK_PENDING: total_indicated += 1 total_pending += 1 row.append(self._fmt(_("pending"))) elif date_status == CALLBACK_RECEIVED: total_indicated += 1 row.append(self._fmt(_("OK"))) elif date_status == CALLBACK_MISSED: total_indicated += 1 total_no_response += 1 row.append(self._fmt_highlight(_("No Response"))) else: row.append(self._fmt(_("not indicated"))) if total_no_response > 0: row[1] = self._fmt_highlight(total_no_response) else: row[1] = self._fmt(total_no_response) row[2] = self._fmt(total_indicated) row[3] = self._fmt(total_pending) result.append(row) return result
def iter_cases_to_modify(): _domain = Domain.get_by_name(DOMAINS[0]) if _domain is None: return time_zone = _domain.get_default_timezone() past_21_date = past_x_date(time_zone, 21) past_42_date = past_x_date(time_zone, 42) setup_indices() for domain in DOMAINS: for case in chain(get_cases_in_domain(domain, type=BIRTH_TYPE), get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE)): if case.closed: continue if ( not get_none_or_value(case, "owner_id") or not get_none_or_value(case, "date_admission") or not get_none_or_value(case, "facility_id") ): continue curr_assignment = get_none_or_value(case, "current_assignment") next_assignment = get_none_or_value(case, "next_assignment") facility_id = get_none_or_value(case, "facility_id") fida_group = get_group_id(domain, "fida", facility_id) # get cati_owner_username from current owner-group assigned_owner_group = get_none_or_value(case, "owner_id") if assigned_owner_group not in GROUPS_BY_ID[domain]: continue cati_owner_username = GROUPS_BY_ID[domain][assigned_owner_group].metadata.get('main_user', None) # Assignment Directly from Registration ## # Assign Cases to Call Center if ( not curr_assignment and not next_assignment and past_21_date <= case.date_admission ): owner_id = get_group_id(domain, "cati", facility_id) if not owner_id: continue owner_group = GROUPS_BY_ID[domain].get(owner_id, None) cati_name = owner_group.metadata.get('name', None) if owner_group else None update = { "current_assignment": "cati", "cati_name": cati_name } yield { "case_id": case._id, "update": update, "close": False, "owner_id": owner_id, }, domain # Assign Cases Directly To Field elif ( not curr_assignment and not next_assignment and past_42_date <= case.date_admission < past_21_date ): if not fida_group: continue update = { "current_assignment": "fida", "cati_status": 'skipped', } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign Cases Directly to Lost to Follow Up elif ( not curr_assignment and not next_assignment and case.date_admission < past_42_date ): update = { "cati_status": 'skipped', "last_assignment": '', "closed_status": "timed_out_lost_to_follow_up", } yield { "case_id": case._id, "update": update, "close": True, }, domain ## Assignment from Call Center ## # Assign Cases to Field (manually by call center) elif ( next_assignment == "fida" and past_42_date <= case.date_admission ): if not cati_owner_username or not fida_group: continue update = { "last_cati_user": cati_owner_username, "current_assignment": "fida", "next_assignment": '', "cati_status": 'manually_assigned_to_field' } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign cases to field (automatically) elif ( curr_assignment in ("cati", "cati_tl") and past_42_date <= case.date_admission < past_21_date ): if not cati_owner_username or not fida_group: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "cati_status": 'timed_out', "current_assignment": "fida", "next_assignment": '', } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign Cases to Lost to Follow Up elif ( curr_assignment in ("cati", "cati_tl") and case.date_admission < past_42_date ): if not get_owner_username(domain, curr_assignment, facility_id) or not cati_owner_username: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "last_user": get_owner_username(domain, curr_assignment, facility_id), "cati_status": 'timed_out', "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '' } yield { "case_id": case._id, "update": update, "close": True, }, domain ## Assignment from Field ## # Assign Cases to Lost to Follow Up elif ( curr_assignment in ("fida", "fida_tl") and case.date_admission < past_42_date ): if not get_owner_username(domain, curr_assignment, facility_id): continue update = { "last_user": get_owner_username(domain, curr_assignment, facility_id), "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '', } yield { "case_id": case._id, "update": update, "close": True, }, domain
class ImporterTest(TestCase): def setUp(self): self.domain = create_domain("importer-test").name self.default_case_type = 'importer-test-casetype' self.default_headers = ['case_id', 'age', 'sex', 'location'] self.couch_user = WebUser.create(None, "test", "foobar") self.couch_user.add_domain_membership(self.domain, is_admin=True) self.couch_user.save() delete_all_cases() def tearDown(self): self.couch_user.delete() def _config(self, col_names=None, search_column=None, case_type=None, search_field='case_id', named_columns=False, create_new_cases=True): col_names = col_names or self.default_headers case_type = case_type or self.default_case_type search_column = search_column or col_names[0] return ImporterConfig( couch_user_id=self.couch_user._id, case_type=case_type, excel_fields=col_names, case_fields=[''] * len(col_names), custom_fields=col_names, type_fields=['plain'] * len(col_names), search_column=search_column, search_field=search_field, named_columns=named_columns, create_new_cases=create_new_cases, key_column='', value_column='', ) def testImportNone(self): res = do_import(None, self._config(), self.domain) self.assertEqual('EXPIRED', res['error']) self.assertEqual(0, len(get_case_ids_in_domain(self.domain))) def testImporterErrors(self): res = do_import(MockExcelFile(has_errors=True), self._config(), self.domain) self.assertEqual('HAS_ERRORS', res['error']) self.assertEqual(0, len(get_case_ids_in_domain(self.domain))) def testImportBasic(self): config = self._config(self.default_headers) file = MockExcelFile(header_columns=self.default_headers, num_rows=5) res = do_import(file, config, self.domain) self.assertEqual(5, res['created_count']) self.assertEqual(0, res['match_count']) self.assertFalse(res['errors']) self.assertEqual(1, res['num_chunks']) cases = list(get_cases_in_domain(self.domain)) self.assertEqual(5, len(cases)) properties_seen = set() for case in cases: self.assertEqual(self.couch_user._id, case.user_id) self.assertEqual(self.couch_user._id, case.owner_id) self.assertEqual(self.default_case_type, case.type) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop)) self.assertFalse( case.get_case_property(prop) in properties_seen) properties_seen.add(case.get_case_property(prop)) def testImportNamedColumns(self): config = self._config(self.default_headers, named_columns=True) file = MockExcelFile(header_columns=self.default_headers, num_rows=5) res = do_import(file, config, self.domain) # we create 1 less since we knock off the header column self.assertEqual(4, res['created_count']) self.assertEqual(4, len(get_case_ids_in_domain(self.domain))) def testImportTrailingWhitespace(self): cols = ['case_id', 'age', u'sex\xa0', 'location'] config = self._config(cols, named_columns=True) file = MockExcelFile(header_columns=cols, num_rows=2) res = do_import(file, config, self.domain) # we create 1 less since we knock off the header column self.assertEqual(1, res['created_count']) case_ids = get_case_ids_in_domain(self.domain) self.assertEqual(1, len(case_ids)) case = CommCareCase.get(case_ids[0]) self.assertTrue(bool( case.sex)) # make sure the value also got properly set def testCaseIdMatching(self): # bootstrap a stub case case = CommCareCase(domain=self.domain, type=self.default_case_type) case.importer_test_prop = 'foo' case.save() self.assertEqual(1, len(get_case_ids_in_domain(self.domain))) config = self._config(self.default_headers) file = MockExcelFile(header_columns=self.default_headers, num_rows=3, row_generator=id_match_generator(case._id)) res = do_import(file, config, self.domain) self.assertEqual(0, res['created_count']) self.assertEqual(3, res['match_count']) self.assertFalse(res['errors']) # shouldn't create any more cases, just the one self.assertEqual(1, len(get_case_ids_in_domain(self.domain))) [case] = get_cases_in_domain(self.domain) for prop in self.default_headers[1:]: self.assertTrue(prop in case.get_case_property(prop)) # shouldn't touch existing properties self.assertEqual('foo', case.importer_test_prop)
def test_create_fulfill_and_receive_requisition(self): amounts = [(p._id, 50.0 + float(i*10)) for i, p in enumerate(self.products)] # ---------------- # Create a request # ---------------- self.submit_xml_form(create_requisition_xml(amounts)) req_cases = list(get_cases_in_domain(self.domain.name, type=const.REQUISITION_CASE_TYPE)) self.assertEqual(1, len(req_cases)) req = RequisitionCase.get(req_cases[0]._id) [index] = req.indices self.assertEqual(req.requisition_status, 'requested') self.assertEqual(const.SUPPLY_POINT_CASE_TYPE, index.referenced_type) self.assertEqual(self.sp._id, index.referenced_id) self.assertEqual('parent_id', index.identifier) # TODO: these types of tests probably belong elsewhere self.assertEqual(req.get_next_action().keyword, 'fulfill') self.assertEqual(req.get_location()._id, self.sp.location._id) self.assertEqual(len(RequisitionCase.open_for_location( self.domain.name, self.sp.location._id )), 1) self.assertEqual( get_notification_message( req.get_next_action(), [req] ), self.expected_notification_message(req, amounts) ) for product, amt in amounts: self.check_stock_models(req, product, amt, 0, 'ct-requested') # ---------------- # Mark it fulfilled # ----------------- self.submit_xml_form(create_fulfillment_xml(req, amounts)) req = RequisitionCase.get(req._id) self.assertEqual(req.requisition_status, 'fulfilled') self.assertEqual(req.get_next_action().keyword, 'rec') self.assertEqual( get_notification_message( req.get_next_action(), [req] ), self.expected_notification_message(req, amounts) ) for product, amt in amounts: # we are expecting two separate blocks to have come with the same # values self.check_stock_models(req, product, amt, amt, 'stock') self.check_stock_models(req, product, amt, 0, 'ct-fulfilled') # ---------------- # Mark it received # ---------------- self.submit_xml_form(create_received_xml(req, amounts)) req = RequisitionCase.get(req._id) self.assertEqual(req.requisition_status, 'received') self.assertIsNone(req.get_next_action()) self.assertEqual(len(RequisitionCase.open_for_location( self.domain.name, self.sp.location._id )), 0) for product, amt in amounts: self.check_stock_models(req, product, 0, -amt, 'stock') self.check_stock_models(self.sp, product, amt, amt, 'stock')
def new_update_case_properties(): _domain = Domain.get_by_name(DOMAINS[0]) if _domain is None: return time_zone = _domain.get_default_timezone() past_21_date = past_x_date(time_zone, 21) past_42_date = past_x_date(time_zone, 42) setup_indices() for domain in DOMAINS: case_list = list(get_cases_in_domain(domain, type=BIRTH_TYPE)) case_list = case_list + list( get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE)) cases_to_modify = [] for case in case_list: if case.closed: continue if not get_none_or_value( case, "owner_id") or not get_none_or_value( case, "date_admission") or not get_none_or_value( case, "facility_id"): continue curr_assignment = get_none_or_value(case, "current_assignment") next_assignment = get_none_or_value(case, "next_assignment") facility_id = get_none_or_value(case, "facility_id") fida_group = get_group_id(domain, "fida", facility_id) # get cati_owner_username from current owner-group assigned_owner_group = get_none_or_value(case, "owner_id") if assigned_owner_group not in GROUPS_BY_ID[domain]: continue cati_owner_username = GROUPS_BY_ID[domain][ assigned_owner_group].metadata.get('main_user', None) # Assignment Directly from Registration ## # Assign Cases to Call Center if case.date_admission >= past_21_date and ( not curr_assignment) and (not next_assignment): owner_id = get_group_id(domain, "cati", facility_id) if not owner_id: continue owner_group = GROUPS_BY_ID[domain].get(owner_id, None) cati_name = owner_group.metadata.get( 'name', None) if owner_group else None update = {"current_assignment": "cati", "cati_name": cati_name} cases_to_modify.append({ "case_id": case._id, "update": update, "close": False, "owner_id": owner_id, }) # Assign Cases Directly To Field elif (case.date_admission >= past_42_date) and (case.date_admission < past_21_date) and ( not curr_assignment) and (not next_assignment): if not fida_group: continue update = { "current_assignment": "fida", "cati_status": 'skipped', } cases_to_modify.append({ "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, })
def test_get_cases_in_domain(self): self.assert_doc_list_equal( get_cases_in_domain(self.domain), [case for case in self.cases if case.domain == self.domain] )
def new_update_case_properties(): _domain = Domain.get_by_name(DOMAINS[0]) if _domain is None: return time_zone = _domain.get_default_timezone() past_21_date = past_x_date(time_zone, 21) past_42_date = past_x_date(time_zone, 42) setup_indices() for domain in DOMAINS: case_list = list(get_cases_in_domain(domain, type=BIRTH_TYPE)) case_list = case_list + list(get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE)) cases_to_modify = [] for case in case_list: if case.closed: continue if not get_none_or_value(case, "owner_id") or not get_none_or_value(case, "date_admission") or not get_none_or_value(case, "facility_id"): continue curr_assignment = get_none_or_value(case, "current_assignment") next_assignment = get_none_or_value(case, "next_assignment") facility_id = get_none_or_value(case, "facility_id") fida_group = get_group_id(domain, "fida", facility_id) # get cati_owner_username from current owner-group assigned_owner_group = get_none_or_value(case, "owner_id") if assigned_owner_group not in GROUPS_BY_ID[domain]: continue cati_owner_username = GROUPS_BY_ID[domain][assigned_owner_group].metadata.get('main_user', None) # Assignment Directly from Registration ## # Assign Cases to Call Center if case.date_admission >= past_21_date and (not curr_assignment) and (not next_assignment): owner_id = get_group_id(domain, "cati", facility_id) if not owner_id: continue owner_group = GROUPS_BY_ID[domain].get(owner_id, None) cati_name = owner_group.metadata.get('name', None) if owner_group else None update = { "current_assignment": "cati", "cati_name": cati_name } cases_to_modify.append({ "case_id": case._id, "update": update, "close": False, "owner_id": owner_id, }) # Assign Cases Directly To Field elif (case.date_admission >= past_42_date) and (case.date_admission < past_21_date) and (not curr_assignment) and (not next_assignment): if not fida_group: continue update = { "current_assignment": "fida", "cati_status": 'skipped', } cases_to_modify.append( { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, } ) # Assign Cases Directly to Lost to Follow Up elif case.date_admission < past_42_date and (not curr_assignment) and (not next_assignment): update = { "cati_status": 'skipped', "last_assignment": '', "closed_status": "timed_out_lost_to_follow_up", } cases_to_modify.append( { "case_id": case._id, "update": update, "close": True, } ) ## Assignment from Call Center ## # Assign Cases to Field (manually by call center) elif (case.date_admission >= past_42_date) and next_assignment == "fida": if not cati_owner_username or not fida_group: continue update = { "last_cati_user": cati_owner_username, "current_assignment": "fida", "next_assignment": '', "cati_status": 'manually_assigned_to_field' } cases_to_modify.append( { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, } ) # Assign cases to field (automatically) elif (case.date_admission >= past_42_date) and (case.date_admission < past_21_date) and (curr_assignment == "cati" or curr_assignment == "cati_tl"): if not cati_owner_username or not fida_group: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "cati_status": 'timed_out', "current_assignment": "fida", "next_assignment": '', } cases_to_modify.append( { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, } ) # Assign Cases to Lost to Follow Up elif case.date_admission < past_42_date and (curr_assignment == "cati" or curr_assignment == "cati_tl"): if not get_owner_username(domain, curr_assignment, facility_id) or not cati_owner_username: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "last_user": get_owner_username(domain, curr_assignment, facility_id), "cati_status": 'timed_out', "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '' } cases_to_modify.append( { "case_id": case._id, "update": update, "close": True, } ) ## Assignment from Field ## # Assign Cases to Lost to Follow Up elif case.date_admission < past_42_date and (curr_assignment == "fida" or curr_assignment == "fida_tl"): if not get_owner_username(domain, curr_assignment, facility_id): continue update = { "last_user": get_owner_username(domain, curr_assignment, facility_id), "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '', } cases_to_modify.append( { "case_id": case._id, "update": update, "close": True, } ) case_blocks = [] for case in cases_to_modify: kwargs = { "create": False, "case_id": case["case_id"], "update": case["update"], "close": case["close"], "version": V2, } if case.get("owner_id", None): kwargs["owner_id"] = case["owner_id"] case_blocks.append(ElementTree.tostring(CaseBlock(**kwargs).as_xml())) submit_case_blocks(case_blocks, domain)
def test_get_cases_in_domain__type(self): self.assert_doc_list_equal( get_cases_in_domain(self.domain, type='type1'), [case for case in self.cases if case.domain == self.domain and case.type == 'type1'], )
def iter_cases_to_modify(): _domain = Domain.get_by_name(DOMAINS[0]) if _domain is None: return time_zone = _domain.get_default_timezone() past_21_date = past_x_date(time_zone, 21) past_42_date = past_x_date(time_zone, 42) setup_indices() for domain in DOMAINS: for case in chain( get_cases_in_domain(domain, type=BIRTH_TYPE), get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE)): if case.closed: continue if (not get_none_or_value(case, "owner_id") or not get_none_or_value(case, "date_admission") or not get_none_or_value(case, "facility_id")): continue curr_assignment = get_none_or_value(case, "current_assignment") next_assignment = get_none_or_value(case, "next_assignment") facility_id = get_none_or_value(case, "facility_id") fida_group = get_group_id(domain, "fida", facility_id) # get cati_owner_username from current owner-group assigned_owner_group = get_none_or_value(case, "owner_id") if assigned_owner_group not in GROUPS_BY_ID[domain]: continue cati_owner_username = GROUPS_BY_ID[domain][ assigned_owner_group].metadata.get('main_user', None) # Assignment Directly from Registration ## # Assign Cases to Call Center if (not curr_assignment and not next_assignment and past_21_date <= case.date_admission): owner_id = get_group_id(domain, "cati", facility_id) if not owner_id: continue owner_group = GROUPS_BY_ID[domain].get(owner_id, None) cati_name = owner_group.metadata.get( 'name', None) if owner_group else None update = {"current_assignment": "cati", "cati_name": cati_name} yield { "case_id": case._id, "update": update, "close": False, "owner_id": owner_id, }, domain # Assign Cases Directly To Field elif (not curr_assignment and not next_assignment and past_42_date <= case.date_admission < past_21_date): if not fida_group: continue update = { "current_assignment": "fida", "cati_status": 'skipped', } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign Cases Directly to Lost to Follow Up elif (not curr_assignment and not next_assignment and case.date_admission < past_42_date): update = { "cati_status": 'skipped', "last_assignment": '', "closed_status": "timed_out_lost_to_follow_up", } yield { "case_id": case._id, "update": update, "close": True, }, domain ## Assignment from Call Center ## # Assign Cases to Field (manually by call center) elif (next_assignment == "fida" and past_42_date <= case.date_admission): if not cati_owner_username or not fida_group: continue update = { "last_cati_user": cati_owner_username, "current_assignment": "fida", "next_assignment": '', "cati_status": 'manually_assigned_to_field' } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign cases to field (automatically) elif (curr_assignment in ("cati", "cati_tl", "cati-tl") and past_42_date <= case.date_admission < past_21_date): if not cati_owner_username or not fida_group: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "cati_status": 'timed_out', "current_assignment": "fida", "next_assignment": '', } yield { "case_id": case._id, "update": update, "close": False, "owner_id": fida_group, }, domain # Assign Cases to Lost to Follow Up elif (curr_assignment in ("cati", "cati_tl", "cati-tl") and case.date_admission < past_42_date): if not get_owner_username( domain, curr_assignment, facility_id) or not cati_owner_username: continue update = { "last_cati_assignment": curr_assignment, "last_cati_user": cati_owner_username, "last_user": get_owner_username(domain, curr_assignment, facility_id), "cati_status": 'timed_out', "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '' } yield { "case_id": case._id, "update": update, "close": True, }, domain ## Assignment from Field ## # Assign Cases to Lost to Follow Up elif (curr_assignment in ("fida", "fida_tl") and case.date_admission < past_42_date): if not get_owner_username(domain, curr_assignment, facility_id): continue update = { "last_user": get_owner_username(domain, curr_assignment, facility_id), "last_assignment": curr_assignment, "current_assignment": '', "closed_status": "timed_out_lost_to_follow_up", "next_assignment": '', } yield { "case_id": case._id, "update": update, "close": True, }, domain
def test_get_cases_in_domain(self): self.assert_doc_list_equal( get_cases_in_domain(self.domain), [case for case in self.cases if case.domain == self.domain])