Beispiel #1
0
def _company_factory(
        num_interactions=0,
        num_contacts=0,
        num_orders=0,
        num_referrals=0,
        num_company_list_items=0,
):
    """Factory for a company that has companies, interactions and OMIS orders."""
    company = CompanyFactory()
    ContactFactory.create_batch(num_contacts, company=company)
    CompanyInteractionFactory.create_batch(num_interactions, company=company)
    CompanyReferralFactory.create_batch(num_referrals, company=company, contact=None)
    OrderFactory.create_batch(num_orders, company=company)
    CompanyListItemFactory.create_batch(num_company_list_items, company=company)
    return company
    def test_ignores_interactions_without_adviser_and_team(
            self, monkeypatch, caplog):
        """Test that the task does not modify interactions without advisers and teams."""
        caplog.set_level('INFO', 'datahub')
        populate_interaction_dit_participant_mock = Mock(
            wraps=populate_interaction_dit_participant, )
        monkeypatch.setattr(
            'datahub.dbmaintenance.tasks.populate_interaction_dit_participant',
            populate_interaction_dit_participant_mock,
        )

        interactions = CompanyInteractionFactory.create_batch(
            10,
            dit_adviser=None,
            dit_team=None,
            dit_participants=[],
        )

        result = populate_interaction_dit_participant_mock.apply_async(
            kwargs={'batch_size': 100}, )

        assert result.successful()
        assert populate_interaction_dit_participant_mock.apply_async.call_count == 1

        for interaction in interactions:
            interaction.refresh_from_db()

        # These objects should not have been modified
        assert all([obj.dit_participants.count() == 0 for obj in interactions])
        assert len(caplog.records) == 1
        assert f'0 InteractionDITParticipant many-to-many objects created' in caplog.text
Beispiel #3
0
def _company_factory(num_interactions, num_contacts, num_investment_projects, num_orders):
    """
    Factory for a company that has companies, interactions, investment projects and OMIS orders.
    """
    company = CompanyFactory()
    ContactFactory.create_batch(num_contacts, company=company)
    CompanyInteractionFactory.create_batch(num_interactions, company=company)
    OrderFactory.create_batch(num_orders, company=company)

    fields_iter = cycle(INVESTMENT_PROJECT_COMPANY_FIELDS)
    fields = islice(fields_iter, 0, num_investment_projects)
    InvestmentProjectFactory.create_batch(
        num_investment_projects,
        **{field: company for field in fields},
    )
    return company
Beispiel #4
0
    def test_unarchive_interaction_non_restricted_user(self, permissions):
        """
        Tests un-archiving an interaction for a non-restricted user.
        """
        requester = create_test_user(permission_codenames=permissions)
        api_client = self.create_api_client(user=requester)

        interaction = CompanyInteractionFactory(
            archived=True,
            archived_by=requester,
            archived_reason='just cos',
            archived_on=now(),
        )
        url = reverse(
            'api-v3:interaction:unarchive-item',
            kwargs={'pk': interaction.pk},
        )
        response = api_client.post(url)

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['archived'] is False
        assert response_data['archived_by'] is None
        assert response_data['archived_reason'] == ''
        assert response_data['archived_on'] is None
Beispiel #5
0
 def test_realtime_messages_sent(
     self,
     monkeypatch,
     automatic_company_archive_feature_flag,
     created_on_delta,
     companies_to_create,
     expected_message,
 ):
     """
     Test that appropriate realtime messaging is sent which reflects the archiving
     actions.
     """
     created_on = timezone.now() - created_on_delta
     for _ in range(companies_to_create):
         with freeze_time(created_on):
             company = CompanyFactory()
         CompanyInteractionFactory(
             company=company,
             date=timezone.now() - relativedelta(years=8, days=1),
         )
     mock_send_realtime_message = mock.Mock()
     monkeypatch.setattr(
         'datahub.company.tasks.company.send_realtime_message',
         mock_send_realtime_message,
     )
     automatic_company_archive.apply_async(kwargs={'simulate': False})
     mock_send_realtime_message.assert_called_once_with(expected_message)
Beispiel #6
0
    def test_permissions(self, es_with_collector, permission, permission_entity, entity):
        """
        Tests model permissions enforcement in basic search.

        TODO: we should test permissions relevant to a specific search app in the tests for that
            search app, and remove this test.
        """
        user = create_test_user(permission_codenames=[permission], dit_team=TeamFactory())
        api_client = self.create_api_client(user=user)

        InvestmentProjectFactory(created_by=user)
        CompanyFactory()
        ContactFactory()
        EventFactory()
        CompanyInteractionFactory()
        OrderFactory()

        es_with_collector.flush_and_refresh()

        url = reverse('api-v3:search:basic')
        response = api_client.get(
            url,
            data={
                'term': '',
                'entity': entity,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert (response_data['count'] == 0) == (permission_entity != entity)

        assert len(response_data['aggregations']) == 1
        assert response_data['aggregations'][0]['entity'] == permission_entity
Beispiel #7
0
    def test_filter_by_was_policy_feedback_provided(
            self, setup_es, was_policy_feedback_provided):
        """Test filtering interactions by was_policy_feedback_provided."""
        interactions_without_policy_feedback = CompanyInteractionFactory.create_batch(
            5)
        interactions_with_policy_feedback = (
            CompanyInteractionFactoryWithPolicyFeedback.create_batch(5))

        setup_es.indices.refresh()

        url = reverse('api-v3:search:interaction')
        request_data = {
            'was_policy_feedback_provided': was_policy_feedback_provided,
        }
        response = self.api_client.post(url, data=request_data)
        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()
        expected_interactions = (interactions_with_policy_feedback
                                 if was_policy_feedback_provided else
                                 interactions_without_policy_feedback)
        assert response_data['count'] == len(expected_interactions)

        results = response_data['results']
        result_ids = {result['id'] for result in results}
        assert result_ids == {
            str(interaction.pk)
            for interaction in expected_interactions
        }
Beispiel #8
0
 def test_modified_on(
     self,
     automatic_company_archive_feature_flag,
     modified_on_delta,
     expected_archived,
 ):
     """
     Test that a company modified_on dates around the 3m 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() - relativedelta(years=8, days=1),
     )
     with freeze_time(timezone.now() - modified_on_delta):
         company.save()
     task_result = automatic_company_archive.apply_async(
         kwargs={'simulate': False})
     assert task_result.successful()
     archived_company = Company.objects.get(pk=company.id)
     assert archived_company.archived == expected_archived
     assert archived_company.modified_on == company.modified_on
Beispiel #9
0
def company_with_multiple_participant_interaction_factory():
    """Factory for a company with an interaction that has multiple participants."""
    company = CompanyFactory()
    interaction = CompanyInteractionFactory(company=company,
                                            dit_participants=[])
    InteractionDITParticipantFactory.create_batch(2, interaction=interaction)
    return company
Beispiel #10
0
    def test_archive_interaction_restricted_user_associated_project(self):
        """
        Tests archiving an interaction for a restricted user.
        """
        project_creator = AdviserFactory()
        project = InvestmentProjectFactory(created_by=project_creator)
        requester = create_test_user(
            permission_codenames=[InteractionPermission.change_associated_investmentproject],
            dit_team=project_creator.dit_team,  # same dit team as the project creator
        )
        api_client = self.create_api_client(user=requester)
        interaction = CompanyInteractionFactory(investment_project=project)
        url = reverse(
            'api-v3:interaction:archive-item',
            kwargs={'pk': interaction.pk},
        )
        response = api_client.post(
            url,
            data={
                'reason': 'archive reason',
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['archived'] is True
        assert response_data['archived_by']['id'] == str(requester.pk)
        assert response_data['archived_reason'] == 'archive reason'
Beispiel #11
0
def test_interaction_synced_when_dit_participant_added(
        opensearch_with_signals):
    """Test that interactions are synced to OpenSearch if their DIT participants change."""
    interaction = CompanyInteractionFactory(dit_participants=[])
    opensearch_with_signals.indices.refresh()

    doc = opensearch_with_signals.get(
        index=InteractionSearchApp.search_model.get_read_alias(),
        id=interaction.pk,
    )
    assert doc['_source']['dit_participants'] == []

    dit_participant = InteractionDITParticipantFactory(interaction=interaction)
    opensearch_with_signals.indices.refresh()

    updated_doc = opensearch_with_signals.get(
        index=InteractionSearchApp.search_model.get_read_alias(),
        id=interaction.pk,
    )
    actual_dit_participants = updated_doc['_source']['dit_participants']
    assert len(actual_dit_participants) == 1
    assert actual_dit_participants[0]['adviser']['id'] == str(
        dit_participant.adviser.pk)
    assert actual_dit_participants[0]['team']['id'] == str(
        dit_participant.team.pk)
Beispiel #12
0
    def test_cannot_update_read_only_fields(self):
        """Test updating read-only fields."""
        interaction = CompanyInteractionFactory(
            archived_documents_url_path='old_path',
            archived=False,
            archived_by=None,
            archived_on=None,
            archived_reason=None,
        )

        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        # TODO: also test `archived` field once we have made it read-only
        response = self.api_client.patch(
            url,
            data={
                'archived_documents_url_path': 'new_path',
                'archived': True,
                'archived_by': 123,
                'archived_on': date.today(),
                'archived_reason': 'test',
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['archived_documents_url_path'] == 'old_path'
        assert response.data['archived'] is False
        assert response.data['archived_by'] is None
        assert response.data['archived_on'] is None
        assert response.data['archived_reason'] is None
Beispiel #13
0
def test_find_active_contact_by_email_address(
    email,
    expected_matching_status,
    match_on_alternative,
    match_strategy,
):
    """Test finding a contact by email address for various scenarios."""
    for factory_kwargs in EMAIL_MATCHING_CONTACT_TEST_DATA:
        interaction_count = 0
        if factory_kwargs.get('interactions'):
            interaction_count = factory_kwargs.pop('interactions')
        created_contact = ContactFactory(**factory_kwargs)
        for _ in range(interaction_count):
            CompanyInteractionFactory(contacts=[created_contact])

    contact, actual_matching_status = find_active_contact_by_email_address(email, match_strategy)

    assert actual_matching_status == expected_matching_status

    if actual_matching_status == ContactMatchingStatus.matched:
        assert contact
        actual_email = contact.email_alternative if match_on_alternative else contact.email
        assert actual_email.lower() == email.lower()
    else:
        assert not contact
Beispiel #14
0
    def test_unarchive_interaction_restricted_user_non_associated_project(self):
        """
        Test that a restricted user cannot un-archive a non-associated interaction.
        """
        project_creator = AdviserFactory()
        project = InvestmentProjectFactory(created_by=project_creator)
        # Ensure the requester is created for a different DIT team
        requester = create_test_user(
            permission_codenames=[InteractionPermission.change_associated_investmentproject],
        )
        api_client = self.create_api_client(user=requester)
        interaction = CompanyInteractionFactory(
            investment_project=project,
            archived=True,
            archived_by=project_creator,
            archived_on=now(),
            archived_reason='why not',
        )
        url = reverse(
            'api-v3:interaction:unarchive-item',
            kwargs={'pk': interaction.pk},
        )
        response = api_client.post(
            url,
        )

        assert response.status_code == status.HTTP_403_FORBIDDEN
Beispiel #15
0
    def test_filter_by_dit_participant(self, setup_es, dit_participant_field):
        """Test filtering interaction by DIT participant adviser and team IDs."""
        interactions = CompanyInteractionFactory.create_batch(
            10, dit_participants=[])
        for interaction in interactions:
            InteractionDITParticipantFactory.create_batch(
                2, interaction=interaction)

        setup_es.indices.refresh()

        interaction = choice(interactions)
        dit_participant = interaction.dit_participants.order_by('?').first()

        url = reverse('api-v3:search:interaction')
        request_data = {
            f'dit_participants__{dit_participant_field}':
            getattr(dit_participant, dit_participant_field).id,
        }
        response = self.api_client.post(url, request_data)
        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()
        assert response_data['count'] == 1

        results = response_data['results']
        assert len(results) == 1
        assert results[0]['id'] == str(interaction.pk)
    def test_restricted_user_can_update_associated_investment_project_interaction(self):
        """
        Test that a restricted user can update an interaction for an associated investment project.
        """
        project_creator = AdviserFactory()
        project = InvestmentProjectFactory(created_by=project_creator)
        interaction = CompanyInteractionFactory(
            subject='I am a subject',
            investment_project=project,
        )
        requester = create_test_user(
            permission_codenames=[
                InteractionPermission.change_associated_investmentproject,
            ],
            dit_team=project_creator.dit_team,
        )

        api_client = self.create_api_client(user=requester)
        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = api_client.patch(
            url,
            data={
                'subject': 'I am another subject',
            },
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.data['subject'] == 'I am another subject'
Beispiel #17
0
def test_adding_interaction_updates_company(es_with_signals):
    """Test that when an interaction is added, the company is synced to ES."""
    test_name = 'very_hard_to_find_company'
    company = CompanyFactory(
        name=test_name,
    )

    es_with_signals.indices.refresh()

    doc = es_with_signals.get(
        index=CompanySearchApp.es_model.get_read_alias(),
        doc_type=DEFAULT_MAPPING_TYPE,
        id=company.pk,
    )
    assert doc['_source']['name'] == test_name
    assert doc['_source']['latest_interaction_date'] is None

    CompanyInteractionFactory(
        date=dateutil_parse('2018-04-05T00:00:00Z'),
        company=company,
    )

    es_with_signals.indices.refresh()

    updated_doc = es_with_signals.get(
        index=CompanySearchApp.es_model.get_read_alias(),
        doc_type=DEFAULT_MAPPING_TYPE,
        id=company.pk,
    )
    assert updated_doc['_source']['name'] == test_name
    assert updated_doc['_source']['latest_interaction_date'] == '2018-04-05T00:00:00+00:00'
Beispiel #18
0
    def test_basic_search_no_permissions(self, setup_es):
        """Tests model permissions enforcement in basic search for a user with no permissions."""
        user = create_test_user(permission_codenames=[], dit_team=TeamFactory())
        api_client = self.create_api_client(user=user)

        InvestmentProjectFactory(created_by=user)
        CompanyFactory()
        ContactFactory()
        EventFactory()
        CompanyInteractionFactory()
        OrderFactory()

        setup_es.indices.refresh()

        url = reverse('api-v3:search:basic')
        response = api_client.get(
            url,
            data={
                'term': '',
                'entity': 'company',
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['count'] == 0

        assert len(response_data['aggregations']) == 0
    def test_filtering_by_country_excludes_non_matches(self,
                                                       es_with_collector):
        """Test that filtering by country excludes non-matching objects."""
        countries = list(Country.objects.order_by('?')[:2])
        filter_country = countries[0]
        other_country = countries[1]

        # Non-export country interactions should be excluded
        CompanyInteractionFactory()

        # Unrelated countries should be excluded
        CompanyExportCountryHistoryFactory(country=other_country,
                                           history_type=HistoryType.INSERT)
        ExportCountriesInteractionFactory(
            export_countries__country=other_country)

        es_with_collector.flush_and_refresh()

        response = self.api_client.post(
            export_country_history_search_url,
            data={
                'country': filter_country.pk,
            },
        )
        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()
        assert response_data['count'] == 0
        assert response_data['results'] == []
Beispiel #20
0
def test_interactions_to_es_documents(setup_es):
    """Test converting 2 orders to Elasticsearch documents."""
    interactions = CompanyInteractionFactory.create_batch(2)

    result = Interaction.db_objects_to_es_documents(interactions)

    assert {item['_id'] for item in result} == {str(item.pk) for item in interactions}
Beispiel #21
0
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()
Beispiel #22
0
    def test_can_replace_some_participants(self):
        """Test that a subset of existing DIT participants can be replaced."""
        interaction = CompanyInteractionFactory(dit_participants=[])
        dit_participants = InteractionDITParticipantFactory.create_batch(
            3,
            interaction=interaction,
        )
        # Change the first adviser's team so that we can check that the participant's team is
        # unchanged after the update.
        dit_participants[0].adviser.dit_team = TeamFactory()
        dit_participants[0].adviser.save()

        new_advisers = [
            dit_participants[0].adviser,
            AdviserFactory(),
        ]

        request_data = {
            'dit_participants': [
                {
                    'adviser': {
                        'id': adviser.pk,
                    },
                }
                for adviser in new_advisers
            ],
        }

        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = self.api_client.patch(url, data=request_data)

        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()
        response_data['dit_participants'].sort(
            key=lambda dit_participant: dit_participant['adviser']['id'],
        )

        expected_advisers_and_teams = [
            (new_advisers[0], dit_participants[0].team),
            (new_advisers[1], new_advisers[1].dit_team),
        ]
        expected_advisers_and_teams.sort(key=lambda adviser_and_team: adviser_and_team[0].pk)

        assert response_data['dit_participants'] == [
            {
                'adviser': {
                    'id': str(adviser.pk),
                    'first_name': adviser.first_name,
                    'last_name': adviser.last_name,
                    'name': adviser.name,
                },
                'team': {
                    'id': str(team.pk),
                    'name': team.name,
                },
            }
            for adviser, team in expected_advisers_and_teams
        ]
Beispiel #23
0
 def test_fails_without_permissions(self):
     """Should return 403"""
     interaction = CompanyInteractionFactory()
     user = create_test_user(dit_team=TeamFactory())
     api_client = self.create_api_client(user=user)
     url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
     response = api_client.get(url)
     assert response.status_code == status.HTTP_403_FORBIDDEN
Beispiel #24
0
    def test_validation(self, data, errors):
        """Test validation when an invalid date is provided."""
        interaction = CompanyInteractionFactory()

        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = self.api_client.patch(url, data=data)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert response.json() == errors
Beispiel #25
0
def test_interactions_to_documents(opensearch):
    """Test converting 2 orders to OpenSearch documents."""
    interactions = CompanyInteractionFactory.create_batch(2)

    result = Interaction.db_objects_to_documents(interactions)

    assert {item['_id']
            for item in result} == {item.pk
                                    for item in interactions}
Beispiel #26
0
def test_new_interaction_synced(opensearch_with_signals):
    """Test that new interactions are synced to OpenSearch."""
    interaction = CompanyInteractionFactory()
    opensearch_with_signals.indices.refresh()

    assert opensearch_with_signals.get(
        index=InteractionSearchApp.search_model.get_write_index(),
        id=interaction.pk,
    )
Beispiel #27
0
    def test_intelligent_homepage_limit(self, setup_es):
        """Test the limit param."""
        CompanyInteractionFactory.create_batch(15, dit_adviser=self.user)
        ContactFactory.create_batch(15, created_by=self.user)

        setup_es.indices.refresh()

        url = reverse('dashboard:intelligent-homepage')
        response = self.api_client.get(
            url,
            data={
                'limit': 10,
            },
        )

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert len(response_data['contacts']) == 10
        assert len(response_data['interactions']) == 10
Beispiel #28
0
def test_new_interaction_synced(es_with_signals):
    """Test that new interactions are synced to ES."""
    interaction = CompanyInteractionFactory()
    es_with_signals.indices.refresh()

    assert es_with_signals.get(
        index=InteractionSearchApp.es_model.get_write_index(),
        doc_type=InteractionSearchApp.name,
        id=interaction.pk,
    )
Beispiel #29
0
 def test_get_contact_names(self, num_contacts, expected_display_value):
     """Test that contact names are formatted as expected."""
     interaction = CompanyInteractionFactory(
         contacts=ContactFactory.create_batch(num_contacts), )
     interaction_admin = InteractionAdmin(Interaction, site)
     first_contact = interaction.contacts.order_by('pk').first()
     formatted_expected_display_value = expected_display_value.format(
         first_contact_name=first_contact.name if first_contact else '', )
     assert interaction_admin.get_contact_names(
         interaction) == formatted_expected_display_value
Beispiel #30
0
    def test_filtered_by_event(self):
        """List of interactions filtered by event"""
        contact = ContactFactory()
        event = EventFactory()

        CompanyInteractionFactory.create_batch(3, contacts=[contact])
        EventServiceDeliveryFactory.create_batch(3)
        service_deliveries = EventServiceDeliveryFactory.create_batch(3, event=event)

        url = reverse('api-v3:interaction:collection')
        response = self.api_client.get(url, data={'event_id': event.id})

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['count'] == 3

        actual_ids = {result['id'] for result in response_data['results']}
        expected_ids = {str(service_delivery.id) for service_delivery in service_deliveries}
        assert actual_ids == expected_ids