def test_update_company_export_countries_with_pre_existing_company_fields_sync( self, ): """ Test sync when company export_countries update, of a company with currently_exporting_to and future_interest_countries preset. """ initial_countries = list(CountryModel.objects.order_by('id')[:5]) initial_export_to_countries = initial_countries[:3] initial_future_interest_countries = initial_countries[3:] company = CompanyFactory( export_to_countries=initial_export_to_countries, future_interest_countries=initial_future_interest_countries, ) countries_set = list(CountryModel.objects.order_by('name')[:10]) data_items = [{ 'country': { 'id': str(country.id), 'name': country.name, }, 'status': self._get_export_interest_status(), } for country in countries_set] data = { 'export_countries': data_items, } status_wise_items = { outer['status']: [ inner['country']['id'] for inner in data_items if inner['status'] == outer['status'] ] for outer in data_items } current_countries_request = status_wise_items.get( CompanyExportCountry.Status.CURRENTLY_EXPORTING, [], ) future_countries_request = status_wise_items.get( CompanyExportCountry.Status.FUTURE_INTEREST, [], ) url = reverse('api-v4:company:update-export-detail', kwargs={'pk': company.pk}) response = self.api_client.patch(url, data=data) assert response.status_code == status.HTTP_204_NO_CONTENT company.refresh_from_db() current_countries_response = [ str(c.id) for c in company.export_to_countries.all() ] future_countries_response = [ str(c.id) for c in company.future_interest_countries.all() ] assert current_countries_request == current_countries_response assert future_countries_request == future_countries_response
def test_update_company_from_dnb_data_partial_fields(dnb_response_uk, base_company_dict): """ Test the update_company_from_dnb_data command when a subset of DNB fields are updated. """ company = CompanyFactory(duns_number='123456789') original_company = Company.objects.get(id=company.id) task_result = update_company_from_dnb_data.apply_async( args=[dnb_response_uk['results'][0]], kwargs={'fields_to_update': ['global_ultimate_duns_number']}, ) assert task_result.successful() company.refresh_from_db() assert model_to_dict(company) == { **base_company_dict, 'address_1': original_company.address_1, 'address_2': original_company.address_2, 'address_country': original_company.address_country_id, 'address_county': original_company.address_county, 'address_postcode': original_company.address_postcode, 'address_area': original_company.address_area, 'address_town': original_company.address_town, 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'created_by': original_company.created_by_id, 'duns_number': original_company.duns_number, 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': original_company.is_number_of_employees_estimated, 'is_turnover_estimated': original_company.is_turnover_estimated, 'modified_by': original_company.modified_by_id, 'name': original_company.name, 'number_of_employees': original_company.number_of_employees, 'registered_address_1': original_company.registered_address_1, 'registered_address_2': original_company.registered_address_2, 'registered_address_country': original_company.registered_address_country_id, 'registered_address_county': original_company.registered_address_county, 'registered_address_area': original_company.registered_address_area, 'registered_address_postcode': original_company.registered_address_postcode, 'registered_address_town': original_company.registered_address_town, 'sector': original_company.sector_id, 'export_segment': original_company.export_segment, 'export_sub_segment': original_company.export_sub_segment, 'trading_names': original_company.trading_names, 'turnover': original_company.turnover, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'website': original_company.website, 'dnb_modified_on': now(), }
def test_sync_company_with_dnb_all_fields( requests_mock, dnb_response_uk, base_company_dict, update_descriptor, ): """ Test the sync_company_with_dnb task when all fields should be synced. """ requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company = CompanyFactory(duns_number='123456789') original_company = Company.objects.get(id=company.id) task_result = sync_company_with_dnb.apply_async( args=[company.id], kwargs={'update_descriptor': update_descriptor}, ) assert task_result.successful() company.refresh_from_db() uk_country = Country.objects.get(iso_alpha2_code='GB') assert model_to_dict_company(company) == { **base_company_dict, 'address_1': 'Unit 10, Ockham Drive', 'address_2': '', 'address_country': uk_country.id, 'address_county': '', 'address_postcode': 'UB6 0F2', 'address_town': 'GREENFORD', 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'company_number': '01261539', 'created_by': original_company.created_by_id, 'duns_number': '123456789', 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': True, 'modified_by': original_company.modified_by_id, 'name': 'FOO BICYCLE LIMITED', 'number_of_employees': 260, 'sector': original_company.sector_id, 'turnover': 50651895, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'dnb_modified_on': now(), } versions = list(Version.objects.get_for_object(company)) assert len(versions) == 1 version = versions[0] expected_update_descriptor = f'celery:sync_company_with_dnb:{task_result.id}' if update_descriptor: expected_update_descriptor = update_descriptor assert version.revision.comment == f'Updated from D&B [{expected_update_descriptor}]' assert version.revision.user is None
def test_update(self, wb_record, expected_fields, commit): """ Test that update_company_from_wb_record updates the company with the data from wb_record. """ factory_data = { 'duns_number': None, 'name': 'Previous name', 'trading_names': ['Previous trading name'], 'company_number': '87654321', 'number_of_employees': 999, 'is_number_of_employees_estimated': False, 'employee_range': random_obj_for_model(EmployeeRange), 'turnover': 888, 'is_turnover_estimated': False, 'turnover_range': random_obj_for_model(TurnoverRange), 'address_1': '999', 'address_2': 'Street Main', 'address_town': 'Manchester', 'address_county': 'Manchester', 'address_country_id': UNITED_KINGDOM_COUNTRY_UUID, 'address_postcode': 'M90 1QX', 'registered_address_1': '999', 'registered_address_2': 'Street Main', 'registered_address_town': 'Manchester', 'registered_address_county': 'Manchester', 'registered_address_country_id': UNITED_KINGDOM_COUNTRY_UUID, 'registered_address_postcode': 'M90 1QX', 'trading_address_1': '999', 'trading_address_2': 'Street Main', 'trading_address_town': 'Manchester', 'trading_address_county': 'Manchester', 'trading_address_country_id': UNITED_KINGDOM_COUNTRY_UUID, 'trading_address_postcode': 'M90 1QX', 'archived': False, 'archived_on': None, 'archived_reason': '', } company = CompanyFactory(**factory_data) updated_fields = update_company_from_wb_record(company, wb_record, commit=commit) company.refresh_from_db() if commit: actual_fields = { field_name: getattr(company, field_name) for field_name in expected_fields } assert actual_fields == expected_fields else: actual_fields = { field_name: getattr(company, field_name) for field_name in factory_data } assert actual_fields == factory_data assert set(updated_fields) == set(expected_fields)
def test_sync_company_with_dnb_partial_fields( requests_mock, dnb_response_uk, base_company_dict, ): """ Test the sync_company_with_dnb task when only a subset of fields should be synced. """ requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company = CompanyFactory(duns_number='123456789') original_company = Company.objects.get(id=company.id) task_result = sync_company_with_dnb.apply_async( args=[company.id], kwargs={'fields_to_update': ['global_ultimate_duns_number']}, ) assert task_result.successful() company.refresh_from_db() assert model_to_dict(company) == { **base_company_dict, 'address_1': original_company.address_1, 'address_2': original_company.address_2, 'address_country': original_company.address_country_id, 'address_county': original_company.address_county, 'address_postcode': original_company.address_postcode, 'address_town': original_company.address_town, 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'created_by': original_company.created_by_id, 'duns_number': original_company.duns_number, 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': original_company.is_number_of_employees_estimated, 'is_turnover_estimated': original_company.is_turnover_estimated, 'modified_by': original_company.modified_by_id, 'name': original_company.name, 'number_of_employees': original_company.number_of_employees, 'registered_address_1': original_company.registered_address_1, 'registered_address_2': original_company.registered_address_2, 'registered_address_country': original_company.registered_address_country_id, 'registered_address_county': original_company.registered_address_county, 'registered_address_postcode': original_company.registered_address_postcode, 'registered_address_town': original_company.registered_address_town, 'sector': original_company.sector_id, 'trading_names': original_company.trading_names, 'turnover': original_company.turnover, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'website': original_company.website, 'dnb_modified_on': now(), }
def test_link_company_with_dnb_success( requests_mock, dnb_response_uk, base_company_dict, ): """ Test the link_company_with_dnb utility. """ requests_mock.post( DNB_V2_SEARCH_URL, json=dnb_response_uk, ) company = CompanyFactory() original_company = Company.objects.get(id=company.id) modifying_adviser = AdviserFactory() link_company_with_dnb(company.id, '123456789', modifying_adviser) company.refresh_from_db() uk_country = Country.objects.get(iso_alpha2_code='GB') assert model_to_dict_company(company) == { **base_company_dict, 'address_1': 'Unit 10, Ockham Drive', 'address_2': '', 'address_country': uk_country.id, 'address_county': '', 'address_postcode': 'UB6 0F2', 'address_area': None, 'address_town': 'GREENFORD', 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'company_number': '01261539', 'created_by': original_company.created_by_id, 'duns_number': '123456789', 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'modified_by': modifying_adviser.id, 'name': 'FOO BICYCLE LIMITED', 'is_number_of_employees_estimated': True, 'number_of_employees': 260, 'pending_dnb_investigation': False, 'reference_code': '', 'registered_address_area': None, 'sector': original_company.sector_id, 'export_segment': original_company.export_segment, 'export_sub_segment': original_company.export_sub_segment, 'turnover': 50651895, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'dnb_modified_on': now(), }
def test_update_company_from_dnb_data(dnb_response_uk, base_company_dict): """ Test the update_company_from_dnb_data command when all DNB fields are updated. """ company = CompanyFactory(duns_number='123456789') original_company = Company.objects.get(id=company.id) update_descriptor = 'foobar' task_result = update_company_from_dnb_data.apply_async( args=[dnb_response_uk['results'][0]], kwargs={'update_descriptor': update_descriptor}, ) assert task_result.successful() company.refresh_from_db() uk_country = Country.objects.get(iso_alpha2_code='GB') assert model_to_dict_company(company) == { **base_company_dict, 'address_1': 'Unit 10, Ockham Drive', 'address_2': '', 'address_country': uk_country.id, 'address_county': '', 'address_postcode': 'UB6 0F2', 'address_area': None, 'address_town': 'GREENFORD', 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'company_number': '01261539', 'created_by': original_company.created_by_id, 'duns_number': '123456789', 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': True, 'modified_by': original_company.modified_by_id, 'name': 'FOO BICYCLE LIMITED', 'number_of_employees': 260, 'sector': original_company.sector_id, 'export_segment': original_company.export_segment, 'export_sub_segment': original_company.export_sub_segment, 'turnover': 50651895, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'dnb_modified_on': now(), } versions = list(Version.objects.get_for_object(company)) assert len(versions) == 1 version = versions[0] assert version.revision.comment == f'Updated from D&B [{update_descriptor}]'
def test_orders( self, automatic_company_archive_feature_flag, ): """ Test that a company with OMIS orders is not archived. """ gt_3m_ago = timezone.now() - relativedelta(months=3, days=1) with freeze_time(gt_3m_ago): company = CompanyFactory() OrderFactory(company=company) task_result = automatic_company_archive.apply_async(kwargs={'simulate': False}) assert task_result.successful() company.refresh_from_db() assert not company.archived
def test_updates_with_update_company_from_dnb_data_with_failure( self, mocked_log_to_sentry, mocked_send_realtime_message, monkeypatch, dnb_company_updates_response_uk, ): """ Test full integration for the `get_company_updates` task with the `update_company_from_dnb_data` task when all fields are updated and one company in the dnb-service result does not exist in Data Hub. """ company = CompanyFactory(duns_number='123456789') missing_dnb_company = { **dnb_company_updates_response_uk['results'][0], 'duns_number': '999999999', } dnb_company_updates_response_uk['results'].append(missing_dnb_company) mock_get_company_update_page = mock.Mock( return_value=dnb_company_updates_response_uk, ) monkeypatch.setattr( 'datahub.dnb_api.tasks.update.get_company_update_page', mock_get_company_update_page, ) task_result = get_company_updates.apply() company.refresh_from_db() dnb_company = dnb_company_updates_response_uk['results'][0] assert company.name == dnb_company['primary_name'] expected_gu_number = dnb_company['global_ultimate_duns_number'] assert company.global_ultimate_duns_number == expected_gu_number mocked_log_to_sentry.assert_called_with( 'get_company_updates task completed.', extra={ 'success_count': 1, 'failure_count': 1, 'updated_company_ids': [str(company.pk)], 'producer_task_id': task_result.id, 'start_time': '2019-01-02T02:00:00+00:00', 'end_time': '2019-01-02T02:00:00+00:00', }, ) expected_message = ( 'datahub.dnb_api.tasks.update.get_company_updates ' 'updated: 1; failed to update: 1' ) mocked_send_realtime_message.assert_called_once_with(expected_message)
def test_delete_company_export_countries_check_history_tracks_correct_user( self): """ Check that history correctly tracks the user who deletes the export country """ company = CompanyFactory() country = CountryModel.objects.order_by('name')[0] adviser = AdviserFactory() export_country = CompanyExportCountryFactory( company=company, country=country, status=CompanyExportCountry.Status.FUTURE_INTEREST, created_by=adviser, ) CompanyExportCountryHistoryFactory( id=export_country.id, company=export_country.company, country=export_country.country, status=export_country.status, history_type=CompanyExportCountryHistory.HistoryType.INSERT, history_user=export_country.created_by, ) new_user = create_test_user(permission_codenames=( 'change_company', 'change_companyexportcountry', ), ) api_client = self.create_api_client(user=new_user) url = reverse('api-v4:company:update-export-detail', kwargs={'pk': company.pk}) response = api_client.patch( url, data={ 'export_countries': [], }, ) assert response.status_code == status.HTTP_204_NO_CONTENT company.refresh_from_db() assert company.export_countries.count() == 0 delete_history = CompanyExportCountryHistory.objects.filter( company=company, history_type=CompanyExportCountryHistory.HistoryType.DELETE, ) assert delete_history.count() == 1 assert delete_history[0].country == country assert delete_history[0].history_user == new_user
def test_sync_outdated_companies_limit_most_recently_interacted_updated( requests_mock, dnb_response_uk, ): """ Test that running sync_outdated_companies_with_dnb with a limit will update the most recently interacted company. """ requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company_most_recent_interaction = CompanyFactory( duns_number='123456789', dnb_modified_on=now() - timedelta(days=1), ) CompanyInteractionFactory(company=company_most_recent_interaction, date=now()) company_least_recent_interaction = CompanyFactory( duns_number='123456788', dnb_modified_on=now() - timedelta(days=1), ) CompanyInteractionFactory( company=company_least_recent_interaction, date=now() - timedelta(days=1), ) task_result = sync_outdated_companies_with_dnb.apply_async(kwargs={ 'fields_to_update': ['global_ultimate_duns_number'], 'dnb_modified_on_before': now() + timedelta(days=1), 'simulate': False, 'limit': 1, }, ) company_least_recent_interaction.refresh_from_db() company_most_recent_interaction.refresh_from_db() assert task_result.successful() # We expect the least recently interacted company to be unmodified assert company_least_recent_interaction.dnb_modified_on == now( ) - timedelta(days=1) # We expect most recently interacted company to be modified assert company_most_recent_interaction.dnb_modified_on == now()
def test_dnb_company_serializer_partial_save(db): """ Test DNBCompanySerializer.partial_save() method. """ dh_company = CompanyFactory() original_company = Company.objects.get(id=dh_company.id) serializer = DNBCompanySerializer( dh_company, data={'name': 'foobar'}, partial=True, ) serializer.is_valid() serializer.partial_save(duns_number='123456789') dh_company.refresh_from_db() assert dh_company.name == 'foobar' assert dh_company.duns_number == '123456789' assert dh_company.modified_on == original_company.modified_on
def test_updates_with_update_company_from_dnb_data( self, mocked_log_to_sentry, mocked_send_realtime_message, caplog, monkeypatch, dnb_company_updates_response_uk, ): """ Test full integration for the `get_company_updates` task with the `update_company_from_dnb_data` task when all fields are updated. """ caplog.set_level('INFO') company = CompanyFactory(duns_number='123456789') mock_get_company_update_page = mock.Mock( return_value=dnb_company_updates_response_uk, ) monkeypatch.setattr( 'datahub.dnb_api.tasks.update.get_company_update_page', mock_get_company_update_page, ) task_result = get_company_updates.apply_async() company.refresh_from_db() dnb_company = dnb_company_updates_response_uk['results'][0] assert company.name == dnb_company['primary_name'] expected_gu_number = dnb_company['global_ultimate_duns_number'] assert company.global_ultimate_duns_number == expected_gu_number mocked_log_to_sentry.assert_called_with( 'get_company_updates task completed.', extra={ 'success_count': 1, 'failure_count': 0, 'updated_company_ids': [str(company.pk)], 'producer_task_id': task_result.id, 'start_time': '2019-01-02T02:00:00+00:00', 'end_time': '2019-01-02T02:00:00+00:00', }, ) expected_message = ( 'datahub.dnb_api.tasks.update.get_company_updates ' 'updated: 1; failed to update: 0' ) mocked_send_realtime_message.assert_called_once_with(expected_message) assert 'get_company_updates total update count: 1' in caplog.text
def test_investment_projects( self, automatic_company_archive_feature_flag, investment_projects_status, expected_archived, ): """ Test that a company with active investment projects is not archived. """ gt_3m_ago = timezone.now() - relativedelta(months=3, days=1) with freeze_time(gt_3m_ago): company = CompanyFactory() for status in investment_projects_status: InvestmentProjectFactory(investor_company=company, status=status) task_result = automatic_company_archive.apply_async(kwargs={'simulate': False}) assert task_result.successful() company.refresh_from_db() assert company.archived == expected_archived
def test_update_company_export_countries_with_new_list_deletes_old_ones( self, ): """ Test when updating company export countries with a new list and make sure old ones are removed. """ company = CompanyFactory() new_countries = list(CountryModel.objects.order_by('id')[:3]) CompanyExportCountryFactory( country=new_countries.pop(0), company=company, ) input_data_items = [{ 'country': { 'id': str(country.id), 'name': country.name, }, 'status': self._get_export_interest_status(), } for country in new_countries] input_export_countries = { 'export_countries': input_data_items, } url = reverse('api-v4:company:update-export-detail', kwargs={'pk': company.pk}) response = self.api_client.patch(url, data=input_export_countries) assert response.status_code == status.HTTP_204_NO_CONTENT company.refresh_from_db() company_data_items = [{ 'country': { 'id': str(export_country.country.id), 'name': export_country.country.name, }, 'status': export_country.status, } for export_country in company.export_countries.all().order_by( 'country__id')] company_export_countries = { 'export_countries': company_data_items, } assert company_export_countries == input_export_countries
def test_update_company_with_something_check_export_countries(self, ): """ Test when updating company with something else other than export countries will not affect export countries. """ company = CompanyFactory() export_country_one, export_country_two = CompanyExportCountryFactory.create_batch( 2) company.export_countries.set([export_country_one, export_country_two]) input_data = { 'website': 'www.google.com', } url = reverse('api-v4:company:item', kwargs={'pk': company.pk}) response = self.api_client.patch(url, data=input_data) assert response.status_code == status.HTTP_200_OK company.refresh_from_db() assert len(company.export_countries.all()) == 2
def test_created_on( self, automatic_company_archive_feature_flag, created_on_delta, expected_archived, ): """ Test that a company created_on dates around the 3m boundary are archived or not as expected. """ created_on = timezone.now() - created_on_delta with freeze_time(created_on): company = CompanyFactory() CompanyInteractionFactory( company=company, date=timezone.now() - relativedelta(years=8, days=1), ) task_result = automatic_company_archive.apply_async(kwargs={'simulate': False}) assert task_result.successful() company.refresh_from_db() assert company.archived == expected_archived
def test_interactions( self, automatic_company_archive_feature_flag, interaction_date_delta, expected_archived, ): """ Test that a company with interactions on various dates around the 8y boundary are archived or not as expected. """ gt_3m_ago = timezone.now() - relativedelta(months=3, days=1) with freeze_time(gt_3m_ago): company = CompanyFactory() CompanyInteractionFactory( company=company, date=timezone.now() - interaction_date_delta, ) task_result = automatic_company_archive.apply_async( kwargs={'simulate': False}, ) assert task_result.successful() company.refresh_from_db() assert company.archived == expected_archived
def test_sync_outdated_companies_limit_least_recently_synced_is_updated( requests_mock, dnb_response_uk, ): """ Test that running sync_outdated_companies_with_dnb with a limit will update the least recently synced company. """ requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company_1 = CompanyFactory( duns_number='123456788', dnb_modified_on=now() - timedelta(days=1), ) original_company_1 = Company.objects.get(id=company_1.id) company_2 = CompanyFactory( duns_number='123456789', dnb_modified_on=now() - timedelta(days=2), ) task_result = sync_outdated_companies_with_dnb.apply_async(kwargs={ 'fields_to_update': ['global_ultimate_duns_number'], 'dnb_modified_on_before': now() + timedelta(days=1), 'simulate': False, 'limit': 1, }, ) assert task_result.successful() company_1.refresh_from_db() company_2.refresh_from_db() # We expect company_1 to be unmodified assert company_1.dnb_modified_on == original_company_1.dnb_modified_on # We expect company_2 to be modified, as it was least recently synced with D&B assert company_2.dnb_modified_on == now()
def test_audit_log(s3_stubber): """Test that reversion revisions are created.""" company_without_change = CompanyFactory( great_profile_status=Company.GREAT_PROFILE_STATUSES.published, ) company_with_change = CompanyFactory( great_profile_status=Company.GREAT_PROFILE_STATUSES.unpublished, ) bucket = 'test_bucket' object_key = 'test_key' csv_content = f"""datahub_company_id,is_published_find_a_supplier,has_find_a_supplier_profile {company_without_change.pk},t,t {company_with_change.pk},t,t """ s3_stubber.add_response( 'get_object', { 'Body': BytesIO(csv_content.encode(encoding='utf-8')), }, expected_params={ 'Bucket': bucket, 'Key': object_key, }, ) call_command('update_company_great_profile_status', bucket, object_key) company_without_change.refresh_from_db() assert company_without_change.great_profile_status == Company.GREAT_PROFILE_STATUSES.published versions = Version.objects.get_for_object(company_without_change) assert versions.count() == 0 company_with_change.refresh_from_db() assert company_with_change.great_profile_status == Company.GREAT_PROFILE_STATUSES.published versions = Version.objects.get_for_object(company_with_change) assert versions.count() == 1 assert versions[0].revision.get_comment() == 'GREAT profile status updated.'
def test_sync_outdated_companies_simulation(caplog): """ Test that using simulation mode does not modify companies and logs correctly. """ caplog.set_level('INFO') company = CompanyFactory( duns_number='123456789', dnb_modified_on=now() - timedelta(days=5), ) original_company = Company.objects.get(id=company.id) task_result = sync_outdated_companies_with_dnb.apply_async(kwargs={ 'fields_to_update': ['global_ultimate_duns_number'], 'dnb_modified_on_before': now() - timedelta(days=1), }, ) assert task_result.successful() company.refresh_from_db() # We expect the company to be unmodified assert company.dnb_modified_on == original_company.dnb_modified_on expected_message = f'[SIMULATION] Syncing dnb-linked company "{company.id}" Succeeded' assert expected_message in caplog.text
def test_link_company_with_dnb_sync_task_failure( requests_mock, dnb_response_uk, ): """ Test link_company_with_dnb when the sync_company_with_dnb task encounters a failure - expect the exception to bubble up. """ malformed_response = dnb_response_uk.copy() del malformed_response['results'] requests_mock.post( DNB_V2_SEARCH_URL, json=malformed_response, ) company = CompanyFactory() original_company = Company.objects.get(id=company.id) modifying_adviser = AdviserFactory() with pytest.raises(DNBServiceInvalidRequestError): link_company_with_dnb(company.id, '123456789', modifying_adviser) company.refresh_from_db() # Ensure that any changes to the record were rolled back due to the task failure assert company.duns_number is None assert company.modified_by == original_company.modified_by
def test_audit_log(s3_stubber): """Test that reversion revisions are created.""" company_without_change = CompanyFactory( export_potential=Company.EXPORT_POTENTIAL_SCORES.high, ) company_with_change = CompanyFactory( export_potential=Company.EXPORT_POTENTIAL_SCORES.medium, ) bucket = 'test_bucket' object_key = 'test_key' csv_content = f"""datahub_company_id,export_propensity {company_without_change.pk},High {company_with_change.pk},Very high """ s3_stubber.add_response( 'get_object', { 'Body': BytesIO(csv_content.encode(encoding='utf-8')), }, expected_params={ 'Bucket': bucket, 'Key': object_key, }, ) call_command('update_company_export_potential', bucket, object_key) company_without_change.refresh_from_db() assert company_without_change.export_potential == Company.EXPORT_POTENTIAL_SCORES.high versions = Version.objects.get_for_object(company_without_change) assert versions.count() == 0 company_with_change.refresh_from_db() assert company_with_change.export_potential == Company.EXPORT_POTENTIAL_SCORES.very_high versions = Version.objects.get_for_object(company_with_change) assert versions.count() == 1 assert versions[0].revision.get_comment() == 'Export potential updated.'
def test_updates_with_update_company_from_dnb_data_partial_fields( self, mocked_log_to_sentry, monkeypatch, dnb_company_updates_response_uk, ): """ Test full integration for the `get_company_updates` task with the `update_company_from_dnb_data` task when the fields are only partially updated. """ company = CompanyFactory(duns_number='123456789') mock_get_company_update_page = mock.Mock( return_value=dnb_company_updates_response_uk, ) monkeypatch.setattr( 'datahub.dnb_api.tasks.get_company_update_page', mock_get_company_update_page, ) task_result = get_company_updates.apply(kwargs={'fields_to_update': ['name']}) company.refresh_from_db() dnb_company = dnb_company_updates_response_uk['results'][0] assert company.name == dnb_company['primary_name'] assert company.global_ultimate_duns_number == '' mocked_log_to_sentry.assert_called_with( 'get_company_updates task completed.', extra={ 'success_count': 1, 'failure_count': 0, 'updated_company_ids': [str(company.pk)], 'producer_task_id': task_result.id, 'start_time': '2019-01-02T02:00:00+00:00', 'end_time': '2019-01-02T02:00:00+00:00', }, )
def test_sync_outdated_companies_with_dnb_partial_fields( requests_mock, dnb_response_uk, base_company_dict, existing_company_dnb_modified_on, caplog, ): """ Test the sync_outdated_companies_with_dnb task when only a subset of fields should be synced. """ caplog.set_level('INFO') if callable(existing_company_dnb_modified_on): existing_company_dnb_modified_on = existing_company_dnb_modified_on() requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company = CompanyFactory( duns_number='123456789', dnb_modified_on=existing_company_dnb_modified_on, ) original_company = Company.objects.get(id=company.id) task_result = sync_outdated_companies_with_dnb.apply_async(kwargs={ 'fields_to_update': ['global_ultimate_duns_number'], 'dnb_modified_on_before': now() + timedelta(days=1), 'simulate': False, }, ) assert task_result.successful() company.refresh_from_db() assert model_to_dict(company) == { **base_company_dict, 'address_1': original_company.address_1, 'address_2': original_company.address_2, 'address_country': original_company.address_country_id, 'address_county': original_company.address_county, 'address_postcode': original_company.address_postcode, 'address_town': original_company.address_town, 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'company_number': original_company.company_number, 'created_by': original_company.created_by_id, 'duns_number': original_company.duns_number, 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': original_company.is_number_of_employees_estimated, 'is_turnover_estimated': original_company.is_turnover_estimated, 'modified_by': original_company.modified_by_id, 'name': original_company.name, 'number_of_employees': original_company.number_of_employees, 'registered_address_1': original_company.registered_address_1, 'registered_address_2': original_company.registered_address_2, 'registered_address_country': original_company.registered_address_country_id, 'registered_address_county': original_company.registered_address_county, 'registered_address_postcode': original_company.registered_address_postcode, 'registered_address_town': original_company.registered_address_town, 'sector': original_company.sector_id, 'trading_names': original_company.trading_names, 'turnover': original_company.turnover, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'website': original_company.website, 'dnb_modified_on': now(), } expected_message = f'Syncing dnb-linked company "{company.id}" Succeeded' assert expected_message in caplog.text
def test_sync_outdated_companies_with_dnb_all_fields( requests_mock, dnb_response_uk, base_company_dict, existing_company_dnb_modified_on, caplog, ): """ Test the sync_outdated_companies_with_dnb task when all fields should be synced. """ caplog.set_level('INFO') if callable(existing_company_dnb_modified_on): existing_company_dnb_modified_on = existing_company_dnb_modified_on() requests_mock.post( DNB_SEARCH_URL, json=dnb_response_uk, ) company = CompanyFactory( duns_number='123456789', dnb_modified_on=existing_company_dnb_modified_on, ) original_company = Company.objects.get(id=company.id) task_result = sync_outdated_companies_with_dnb.apply_async(kwargs={ 'dnb_modified_on_before': now() + timedelta(days=1), 'simulate': False, }, ) assert task_result.successful() company.refresh_from_db() uk_country = Country.objects.get(iso_alpha2_code='GB') assert model_to_dict_company(company) == { **base_company_dict, 'address_1': 'Unit 10, Ockham Drive', 'address_2': '', 'address_country': uk_country.id, 'address_county': '', 'address_postcode': 'UB6 0F2', 'address_town': 'GREENFORD', 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type_id, 'company_number': '01261539', 'created_by': original_company.created_by_id, 'duns_number': '123456789', 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': True, 'modified_by': original_company.modified_by_id, 'name': 'FOO BICYCLE LIMITED', 'number_of_employees': 260, 'sector': original_company.sector_id, 'turnover': 50651895, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'dnb_modified_on': now(), } expected_message = f'Syncing dnb-linked company "{company.id}" Succeeded' assert expected_message in caplog.text
class TestUpdateFromDNB(AdminTestMixin): """ Tests GET requests to 'Update from DNB'. """ def _create_company(self, **kwargs): self.company = CompanyFactory(**kwargs) change_url = reverse( admin_urlname(Company._meta, 'change'), args=(self.company.pk, ), ) update_url = reverse( admin_urlname(Company._meta, 'update-from-dnb'), args=(self.company.pk, ), ) return (change_url, update_url) def test_get(self, requests_mock, dnb_response): """ Test that the link exists for a company with duns_number and a user with the change company permission. """ change_url, update_url = self._create_company(duns_number='123456789') requests_mock.post( DNB_SEARCH_URL, json=dnb_response, ) response = self.client.get(change_url) assert update_url in response.rendered_content response = self.client.get(update_url) response.status_code == status.HTTP_200_OK def test_get_view_permission_only(self): """ Test that the link does not exist for a company with duns_number but a user with only the view company permission. """ change_url, update_url = self._create_company(duns_number='123456789') user = create_test_user( permission_codenames=(CompanyPermission.view_company, ), is_staff=True, password=self.PASSWORD, ) client = self.create_client(user=user) response = client.get(change_url) assert update_url not in response.rendered_content response = client.get(update_url) assert response.status_code == status.HTTP_403_FORBIDDEN def test_get_no_duns_number(self): """ Test that the link does not exist when the company does not have a duns_number. """ change_url, update_url = self._create_company() response = self.client.get(change_url) assert update_url not in response.rendered_content response = self.client.get(update_url) assert response.status_code == status.HTTP_400_BAD_REQUEST def test_post(self, requests_mock, dnb_response): """ Test that a post request to 'upddate-from-dnb' updates the company. """ _, update_url = self._create_company( duns_number='123456789', pending_dnb_investigation=True, ) requests_mock.post( DNB_SEARCH_URL, json=dnb_response, ) response = self.client.post(update_url) assert response.status_code == status.HTTP_302_FOUND self.company.refresh_from_db() dnb_company = dnb_response['results'][0] assert self.company.name == dnb_company['primary_name'] assert self.company.address_1 == dnb_company['address_line_1'] assert self.company.address_2 == dnb_company['address_line_2'] assert self.company.address_town == dnb_company['address_town'] assert self.company.address_county == dnb_company['address_county'] assert self.company.address_country.iso_alpha2_code == dnb_company[ 'address_country'] assert not self.company.pending_dnb_investigation assert (self.company.global_ultimate_duns_number == dnb_company['global_ultimate_duns_number']) versions = list(Version.objects.get_for_object(self.company)) assert len(versions) == 1 assert versions[0].revision.comment == 'Updated from D&B' @pytest.mark.parametrize( 'dnb_response_code', ( status.HTTP_400_BAD_REQUEST, status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN, status.HTTP_404_NOT_FOUND, status.HTTP_500_INTERNAL_SERVER_ERROR, ), ) def test_post_dnb_error(self, requests_mock, dnb_response_code): """ Tests that the users get an error message if the dnb-service doesn't return with a 200 status code. """ _, update_url = self._create_company(duns_number='123456789') requests_mock.post( DNB_SEARCH_URL, status_code=dnb_response_code, ) response = self.client.post(update_url) assert response.status_code == status.HTTP_302_FOUND messages = list(get_messages(response.wsgi_request)) assert len(messages) == 1 assert str( messages[0]) == 'Something went wrong in an upstream service.' @pytest.mark.parametrize( 'search_results, expected_message', ( ( [], 'No matching company found in D&B database.', ), ( ['foo', 'bar'], 'Something went wrong in an upstream service.', ), ( [{ 'duns_number': '012345678' }], 'Something went wrong in an upstream service.', ), ), ) def test_post_dnb_response_invalid( self, requests_mock, search_results, expected_message, ): """ Test if we get anything other than a single company from dnb-service, we return an error message to the user. """ _, update_url = self._create_company(duns_number='123456789') requests_mock.post( DNB_SEARCH_URL, json={'results': search_results}, ) response = self.client.post(update_url) assert response.status_code == status.HTTP_302_FOUND messages = list(get_messages(response.wsgi_request)) assert len(messages) == 1 assert str(messages[0]) == expected_message def test_post_dnb_data_invalid( self, requests_mock, dnb_response, ): """ Tests that if the data returned from DNB does not clear DataHub validation, we show an appropriate message to our users. """ _, update_url = self._create_company(duns_number='123456789') dnb_response['results'][0]['primary_name'] = None requests_mock.post( DNB_SEARCH_URL, json=dnb_response, ) response = self.client.post(update_url) assert response.status_code == status.HTTP_302_FOUND messages = list(get_messages(response.wsgi_request)) assert len(messages) == 1 assert str( messages[0] ) == 'Data from D&B did not pass the Data Hub validation checks.'
def test_update_company_from_dnb_all_fields( self, formatted_dnb_company, base_company_dict, adviser_callable, update_descriptor, ): """ Test that update_company_from_dnb will update all fields when the fields kwarg is not specified. """ duns_number = '123456789' company = CompanyFactory(duns_number=duns_number, pending_dnb_investigation=True) original_company = Company.objects.get(id=company.id) adviser = adviser_callable() update_company_from_dnb( company, formatted_dnb_company, user=adviser, update_descriptor=update_descriptor, ) company.refresh_from_db() uk_country = Country.objects.get(iso_alpha2_code='GB') assert model_to_dict_company(company) == { **base_company_dict, 'address_1': 'Unit 10, Ockham Drive', 'address_2': '', 'address_country': uk_country.id, 'address_county': '', 'address_postcode': 'UB6 0F2', 'address_town': 'GREENFORD', 'archived_documents_url_path': original_company.archived_documents_url_path, 'business_type': original_company.business_type.id, 'company_number': '01261539', 'created_by': original_company.created_by.id, 'duns_number': '123456789', 'employee_range': original_company.employee_range.id, 'export_experience_category': original_company.export_experience_category.id, 'global_ultimate_duns_number': '291332174', 'id': original_company.id, 'is_number_of_employees_estimated': True, 'modified_by': adviser.id if adviser else original_company.modified_by.id, 'name': 'FOO BICYCLE LIMITED', 'number_of_employees': 260, 'sector': original_company.sector.id, 'turnover': 50651895, 'turnover_range': original_company.turnover_range.id, 'uk_region': original_company.uk_region.id, 'dnb_modified_on': now(), } versions = list(Version.objects.get_for_object(company)) assert len(versions) == 1 version = versions[0] if update_descriptor: assert version.revision.comment == f'Updated from D&B [{update_descriptor}]' else: assert version.revision.comment == 'Updated from D&B' assert version.revision.user == adviser if not adviser: assert company.modified_on == original_company.modified_on
def test_update_company_from_dnb_data_partial_fields(dnb_response_uk): """ Test the update_company_from_dnb_data command when a subset of DNB fields are updated. """ company = CompanyFactory(duns_number='123456789') original_company = Company.objects.get(id=company.id) task_result = update_company_from_dnb_data.apply_async( args=[dnb_response_uk['results'][0]], kwargs={'fields_to_update': ['global_ultimate_duns_number']}, ) assert task_result.successful() company.refresh_from_db() assert model_to_dict(company) == { 'address_1': original_company.address_1, 'address_2': original_company.address_2, 'address_country': original_company.address_country_id, 'address_county': original_company.address_county, 'address_postcode': original_company.address_postcode, 'address_town': original_company.address_town, 'archived': original_company.archived, 'archived_by': original_company.archived_by, 'archived_documents_url_path': original_company.archived_documents_url_path, 'archived_on': original_company.archived_on, 'archived_reason': original_company.archived_reason, 'business_type': original_company.business_type_id, 'company_number': original_company.company_number, 'created_by': original_company.created_by_id, 'description': original_company.description, 'dnb_investigation_data': original_company.dnb_investigation_data, 'duns_number': original_company.duns_number, 'employee_range': original_company.employee_range_id, 'export_experience_category': original_company.export_experience_category_id, 'export_potential': original_company.export_potential, 'export_to_countries': [], 'future_interest_countries': [], 'global_headquarters': original_company.global_headquarters, 'global_ultimate_duns_number': '291332174', 'great_profile_status': original_company.great_profile_status, 'headquarter_type': original_company.headquarter_type, 'id': original_company.id, 'is_number_of_employees_estimated': original_company.is_number_of_employees_estimated, 'is_turnover_estimated': original_company.is_turnover_estimated, 'modified_by': original_company.modified_by_id, 'name': original_company.name, 'number_of_employees': original_company.number_of_employees, 'one_list_account_owner': original_company.one_list_account_owner, 'one_list_tier': original_company.one_list_tier, 'pending_dnb_investigation': original_company.pending_dnb_investigation, 'reference_code': original_company.reference_code, 'registered_address_1': original_company.registered_address_1, 'registered_address_2': original_company.registered_address_2, 'registered_address_country': original_company.registered_address_country_id, 'registered_address_county': original_company.registered_address_county, 'registered_address_postcode': original_company.registered_address_postcode, 'registered_address_town': original_company.registered_address_town, 'sector': original_company.sector_id, 'trading_names': original_company.trading_names, 'transfer_reason': original_company.transfer_reason, 'transferred_by': None, 'transferred_on': None, 'transferred_to': None, 'turnover': original_company.turnover, 'turnover_range': original_company.turnover_range_id, 'uk_region': original_company.uk_region_id, 'vat_number': original_company.vat_number, 'website': original_company.website, 'dnb_modified_on': now(), }
def test_merge_investment_projects_succeeds(self, fields): """ Tests that perform_merge() moves investment projects to the target company and marks the source company as archived and transferred. """ creation_time = datetime(2010, 12, 1, 15, 0, 10, tzinfo=utc) with freeze_time(creation_time): source_company = CompanyFactory() investment_project = InvestmentProjectFactory( **{field: source_company for field in fields}, ) target_company = CompanyFactory() user = AdviserFactory() merge_time = datetime(2011, 2, 1, 14, 0, 10, tzinfo=utc) with freeze_time(merge_time): result = merge_companies(source_company, target_company, user) other_fields = set(INVESTMENT_PROJECT_COMPANY_FIELDS) - set(fields) assert result == { # each interaction has a contact, that's why 4 contacts should be moved CompanyListItem: { 'company': 0 }, Contact: { 'company': 0 }, Interaction: { 'company': 0 }, InvestmentProject: { **{field: 1 for field in fields}, **{field: 0 for field in other_fields}, }, Order: { 'company': 0 }, } investment_project.refresh_from_db() assert all( getattr(investment_project, field) == target_company for field in fields) assert all( getattr(investment_project, field) != target_company for field in other_fields) assert all( getattr(investment_project, field) != source_company for field in other_fields) assert investment_project.modified_on == creation_time source_company.refresh_from_db() assert source_company.archived assert source_company.archived_by == user assert source_company.archived_on == merge_time assert source_company.archived_reason == ( f'This record is no longer in use and its data has been transferred ' f'to {target_company} for the following reason: Duplicate record.') assert source_company.modified_by == user assert source_company.modified_on == merge_time assert source_company.transfer_reason == Company.TRANSFER_REASONS.duplicate assert source_company.transferred_by == user assert source_company.transferred_on == merge_time assert source_company.transferred_to == target_company