def test_can_perform_deprecation(self, *mocks): transition = Transition(domain=self.domain, location_type_code='city', operation=MoveOperation.type) transition.add(old_site_code=self.locations['Boston'].site_code, new_site_code='new_boston', new_location_details={ 'name': 'New Boston', 'parent_site_code': self.locations['Suffolk'].site_code, 'lgd_code': 'New Boston LGD Code', 'sub_district_name': 'New Boston Sub District' }, old_username="******", new_username="******") location = self.locations['Boston'] location.metadata[DEPRECATED_VIA] = MergeOperation.type location.save() with self.assertRaisesMessage( InvalidTransitionError, "Move operation: location Boston with site code boston cannot be deprecated again." ): transition.perform() location = self.locations['Boston'] location.metadata[DEPRECATED_VIA] = ExtractOperation.type location.save() location = self.locations['Boston'] location.metadata[DEPRECATED_VIA] = ExtractOperation.type location.save() transition.perform() self._validate_operation(transition.operation_obj, archived=True)
def email_other_cases_details(domain, transitions, uploaded_filename, user_email): try: transition_objs = [Transition(**transition) for transition in transitions] filestream = OtherCases(domain).dump(transition_objs) except Exception as e: notify_failure( e, subject=f"[{settings.SERVER_ENVIRONMENT}] - Location Reassignment Other Cases Dump Failed", email=user_email, uploaded_filename=uploaded_filename ) raise e else: body = f"The request has been successfully completed for file {uploaded_filename}. " if not filestream: body += "There were no cases found. " body += f"Please note that the cases are fetched only for " \ f"{', '.join(OtherCases.valid_operations)}." notify_success( subject=f"[{settings.SERVER_ENVIRONMENT}] - Location Reassignment Other Cases Dump Completed", body=body, email=user_email, filestream=filestream, filename=f"Other Cases - {uploaded_filename.split('.')[0]}.xlsx" )
def email_other_cases_details(domain, transitions, uploaded_filename, user_email): try: transition_objs = [ Transition(**transition) for transition in transitions ] filestream = OtherCases(domain).dump(transition_objs) except Exception as e: email = EmailMessage( subject= f"[{settings.SERVER_ENVIRONMENT}] - Location Reassignment Other Cases Dump Failed", body=linebreaksbr( f"The request could not be completed for file {uploaded_filename}. Something went wrong.\n" f"Error raised : {e}.\n" "Please report an issue if needed."), to=[user_email], from_email=settings.DEFAULT_FROM_EMAIL) email.content_subtype = "html" email.send() raise e else: email = EmailMessage( subject= f"[{settings.SERVER_ENVIRONMENT}] - Location Reassignment Other Cases Dump Completed", body= f"The request has been successfully completed for file {uploaded_filename}. ", to=[user_email], from_email=settings.DEFAULT_FROM_EMAIL) if filestream: email.attach(filename="Other Cases.zip", content=filestream.read()) else: email.body += "There were no cases found. " email.body += f"Please note that the cases are fetched only for " \ f"{', '.join(OtherCases.valid_operations)}." email.send()
def _consolidated_transition(self, location_type_code, operation, rows): transition = Transition(domain=self.domain, location_type_code=location_type_code, operation=operation) for row in rows: if row.new_site_code in transition.new_location_details: # new location is passed with different details if transition.new_location_details[row.new_site_code] != row.new_location_details: self.errors.append(f"New location {row.new_site_code} passed with different information") return None transition.add( old_site_code=row.old_site_code, new_site_code=row.new_site_code, new_location_details=row.new_location_details, old_username=row.old_username, new_username=row.new_username ) return transition
def deprecate_locations(domain, old_locations, new_locations, operation): """ add metadata on locations on old locations, add 1. DEPRECATED_TO: [list] would be a single location except in case of a split 2. DEPRECATION_OPERATION: this location was deprecated by a merge/split/extract/move operation 3. DEPRECATED_AT: [dict] new location id mapped to the timestamp of deprecation performed for new locations location 1. DEPRECATES: [list] append this location id on it. This would be more than one location in case of merge :param domain: domain name :param old_locations: the locations to deprecate :param new_locations: the location that deprecates these location :param operation: the operation being performed, split/merge/move/extract :return: errors in case of failure """ transition = Transition(domain, operation, old_locations, new_locations) if transition.valid(): transition.perform() for old_location in old_locations: deactivate_users_at_location(old_location.location_id) return transition.errors
def test_invalid_operation(self, deactivate_users_mock, update_usercase_mock): transition = Transition(domain=self.domain, location_type_code='city', operation=MoveOperation.type) transition.add(old_site_code='missing_old_location', new_site_code='new_boston', new_location_details={ 'name': 'New Boston', 'parent_site_code': self.locations['Suffolk'].site_code, 'lgd_code': 'New Boston LGD Code', 'sub_district_name': None }, old_username="******", new_username="******") self.assertEqual( SQLLocation.objects.filter(domain=self.domain, site_code='new_boston').count(), 0) with self.assertRaisesMessage( InvalidTransitionError, "Could not load location with following site codes: missing_old_location" ): transition.perform() self.assertEqual( SQLLocation.objects.filter(domain=self.domain, site_code='new_boston').count(), 0, "Unexpected new location created") deactivate_users_mock.assert_not_called() update_usercase_mock.assert_not_called()
def test_perform(self, deactivate_users_mock, update_usercase_mock): transition = Transition(domain=self.domain, location_type_code='city', operation=MoveOperation.type) transition.add(old_site_code=self.locations['Boston'].site_code, new_site_code='new_boston', new_location_details={ 'name': 'New Boston', 'parent_site_code': self.locations['Suffolk'].site_code, 'lgd_code': 'New Boston LGD Code', 'sub_district_name': 'New Boston Sub District' }, old_username="******", new_username="******") self.assertEqual( SQLLocation.objects.filter(domain=self.domain, site_code='new_boston').count(), 0, "New location already present") transition.perform() self._validate_operation(transition.operation_obj, archived=True) new_location = SQLLocation.active_objects.get_or_None( domain=self.domain, site_code='new_boston') self.assertIsNotNone(new_location, "New location not created successfully") self.assertEqual(new_location.metadata[LGD_CODE], 'New Boston LGD Code') self.assertEqual(new_location.metadata[MAP_LOCATION_NAME], 'New Boston Sub District') deactivate_users_mock.assert_called_with( self.locations['Boston'].location_id) update_usercase_mock.assert_called_with(self.domain, "ethan", "aquaman")
def process(self): # process each sheet, in order of hierarchy # so that newly created parent locations are present when needed for location_type_code in self.location_types_by_code: for transition in self.transitions[location_type_code]: Transition(**transition).perform()
def test_dump(self, get_location_mock, get_household_case_ids_mock, case_accessor_mock, child_cases_mock): location = Location(site_code='123', location_id='123654789') get_location_mock.return_value = location get_household_case_ids_mock.return_value = ['1', '2'] case_accessor_mock.return_value = CommCareCaseStub( '100', 'A House', {'hh_reg_date': '20/1/1988', 'hh_religion': 'Above All'}) child_cases_mock.return_value = [ CommCareCaseStub('101', 'A Person', {'age_at_reg': '4', 'sex': 'M'}), CommCareCaseStub('102', 'B Person', {'age_at_reg': '5', 'sex': 'F'}), ] transitions = [ Transition( domain=self.domain, location_type_code='awc', operation=MOVE_OPERATION, old_site_codes=['111'], new_site_codes=['112']), Transition( domain=self.domain, location_type_code='awc', operation=MERGE_OPERATION, old_site_codes=['113', '114'], new_site_codes=['115']), Transition( domain=self.domain, location_type_code='awc', operation=SPLIT_OPERATION, old_site_codes=['116'], new_site_codes=['117', '118']), Transition( domain=self.domain, location_type_code='awc', operation=EXTRACT_OPERATION, old_site_codes=['119'], new_site_codes=['120']) ] filestream = Households(self.domain).dump(transitions) get_location_mock.assert_has_calls([ call(domain='test', site_code='116'), call(domain='test', site_code='119') ]) get_household_case_ids_mock.assert_has_calls([ call(self.domain, location.location_id), call(self.domain, location.location_id) ]) case_accessor_mock.assert_has_calls([ call('1'), call('2') ]) child_cases_mock.assert_has_calls([ call(self.domain, '1', location.location_id, [PERSON_CASE_TYPE]), call(self.domain, '2', location.location_id, [PERSON_CASE_TYPE]) ]) workbook = get_workbook(filestream) self.assertEqual(len(workbook.worksheets), 2) expected_row = { AWC_NAME_COLUMN: '', AWC_CODE_COLUMN: '', 'Name of Household': 'A House', 'Date of Registration': '20/1/1988', 'Religion': 'Above All', 'Caste': '', 'APL/BPL': '', 'Number of Household Members': 2, HOUSEHOLD_MEMBER_DETAILS_COLUMN: 'A Person (4/M), B Person (5/F)', HOUSEHOLD_ID_COLUMN: '100' } worksheet1_rows = list(workbook.worksheets_by_title['116']) self.assertEqual( worksheet1_rows, [expected_row, expected_row] ) worksheet2_rows = list(workbook.worksheets_by_title['119']) self.assertEqual( worksheet2_rows, [expected_row, expected_row] )
def test_dump(self, mock_active_site_codes_search, mock_inactive_site_codes_search, mock_case_count, mock_location_ids): mock_case_count.return_value = [] transitions = { 'awc': [ Transition(domain=self.domain, location_type_code='awc', operation=MOVE_OPERATION, old_site_codes=['111'], new_site_codes=['112']), Transition(domain=self.domain, location_type_code='awc', operation=MERGE_OPERATION, old_site_codes=['113', '114'], new_site_codes=['115']), Transition(domain=self.domain, location_type_code='awc', operation=SPLIT_OPERATION, old_site_codes=['116'], new_site_codes=['117', '118']), Transition(domain=self.domain, location_type_code='awc', operation=EXTRACT_OPERATION, old_site_codes=['119'], new_site_codes=['120']) ], 'supervisor': [ Transition(domain=self.domain, location_type_code='awc', operation=MOVE_OPERATION, old_site_codes=['12'], new_site_codes=['13']), ], 'state': {} } mock_location_ids.return_value = { '111': 'locationid111', '113': 'locationid113', '114': 'locationid114', '116': 'locationid116', '119': 'locationid119', '12': 'locationid12' } mock_active_site_codes_search.return_value.values_list.return_value = [ '112', '115', '117' ] mock_inactive_site_codes_search.return_value.values_list.return_value = [ '120' ] filestream = Dumper(self.domain).dump(transitions) workbook = get_workbook(filestream) awc_worksheet_rows = list(workbook.get_worksheet('awc')) supervisor_worksheet_rows = list(workbook.get_worksheet('supervisor')) self.assertEqual(supervisor_worksheet_rows, [{ OLD_LOCATION_CODE_COLUMN: '12', TRANSITION_COLUMN: MOVE_OPERATION, NEW_LOCATION_CODE_COLUMN: '13', MISSING_COLUMN: True, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }]) self.assertEqual(awc_worksheet_rows, [{ OLD_LOCATION_CODE_COLUMN: '111', TRANSITION_COLUMN: MOVE_OPERATION, NEW_LOCATION_CODE_COLUMN: '112', MISSING_COLUMN: False, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }, { OLD_LOCATION_CODE_COLUMN: '113', TRANSITION_COLUMN: MERGE_OPERATION, NEW_LOCATION_CODE_COLUMN: '115', MISSING_COLUMN: False, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }, { OLD_LOCATION_CODE_COLUMN: '114', TRANSITION_COLUMN: MERGE_OPERATION, NEW_LOCATION_CODE_COLUMN: '115', MISSING_COLUMN: False, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }, { OLD_LOCATION_CODE_COLUMN: '116', TRANSITION_COLUMN: SPLIT_OPERATION, NEW_LOCATION_CODE_COLUMN: '117', MISSING_COLUMN: False, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }, { OLD_LOCATION_CODE_COLUMN: '116', TRANSITION_COLUMN: SPLIT_OPERATION, NEW_LOCATION_CODE_COLUMN: '118', MISSING_COLUMN: True, ARCHIVED_COLUMN: False, CASE_COUNT_COLUMN: 0 }, { OLD_LOCATION_CODE_COLUMN: '119', TRANSITION_COLUMN: EXTRACT_OPERATION, NEW_LOCATION_CODE_COLUMN: '120', MISSING_COLUMN: True, ARCHIVED_COLUMN: True, CASE_COUNT_COLUMN: 0 }])