示例#1
0
def test_investment_project_interaction_changed_sync_to_opensearch(
        opensearch_with_signals):
    """
    Test projects get synced to OpenSearch when an interaction's project is changed.

    When an interaction's project is switched to another project, both the old
    and new project should be updated in OpenSearch.
    """
    investment_project_a = InvestmentProjectFactory(name='alpha')
    investment_project_b = InvestmentProjectFactory(name='beta')

    with reversion.create_revision():
        interaction = InvestmentProjectInteractionFactory(
            investment_project=investment_project_a, )

    opensearch_with_signals.indices.refresh()

    for project_name, has_interaction in [('alpha', True), ('beta', False)]:
        assert_project_search_latest_interaction(
            has_interaction=has_interaction,
            name=project_name,
        )

    interaction.investment_project = investment_project_b
    with reversion.create_revision():
        interaction.save()

    opensearch_with_signals.indices.refresh()

    for project_name, has_interaction in [('alpha', False), ('beta', True)]:
        assert_project_search_latest_interaction(
            has_interaction=has_interaction,
            name=project_name,
        )
示例#2
0
    def test_sector_descends_filter_for_investment_project_interaction(
        self,
        hierarchical_sectors,
        setup_es,
        sector_level,
    ):
        """Test the sector_descends filter with investment project interactions."""
        num_sectors = len(hierarchical_sectors)
        sectors_ids = [sector.pk for sector in hierarchical_sectors]

        projects = ActiveInvestmentProjectFactory.create_batch(
            num_sectors,
            sector_id=factory.Iterator(sectors_ids),
        )
        investment_project_interactions = InvestmentProjectInteractionFactory.create_batch(
            3,
            investment_project=factory.Iterator(projects),
        )

        other_projects = ActiveInvestmentProjectFactory.create_batch(
            3,
            sector=factory.LazyFunction(lambda: random_obj_for_queryset(
                Sector.objects.exclude(pk__in=sectors_ids), )),
        )
        InvestmentProjectInteractionFactory.create_batch(
            3,
            investment_project=factory.Iterator(other_projects),
        )

        setup_es.indices.refresh()

        url = reverse('api-v3:search:interaction')
        body = {
            'sector_descends': hierarchical_sectors[sector_level].pk,
        }
        response = self.api_client.post(url, body)
        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()
        assert response_data['count'] == num_sectors - sector_level

        actual_ids = {
            UUID(interaction['id'])
            for interaction in response_data['results']
        }
        expected_ids = {
            interaction.pk
            for interaction in investment_project_interactions[sector_level:]
        }
        assert actual_ids == expected_ids
示例#3
0
def test_investment_project_interaction_deleted_sync_to_opensearch(
        opensearch_with_signals):
    """Test investment project gets synced to OpenSearch when an interaction is deleted."""
    investment_project = InvestmentProjectFactory()
    interaction = InvestmentProjectInteractionFactory(
        investment_project=investment_project, )
    opensearch_with_signals.indices.refresh()

    assert_project_search_latest_interaction(has_interaction=True)

    interaction.delete()
    opensearch_with_signals.indices.refresh()

    assert_project_search_latest_interaction(has_interaction=False)
示例#4
0
    def test_spi_fields_are_serialised(self, data_flow_api_client,
                                       ist_adviser):
        """Test that SPI fields are serialised."""
        pm_assigned_by = AdviserFactory()
        pm_assigned_on = now()
        investment_project = VerifyWinInvestmentProjectFactory(
            project_manager=ist_adviser,
            project_manager_first_assigned_on=pm_assigned_on,
            project_manager_first_assigned_by=pm_assigned_by,
        )
        spi1 = InvestmentProjectInteractionFactory(
            investment_project=investment_project,
            service_id=ServiceConstant.
            investment_enquiry_requested_more_information.value.id,
        )
        spi2 = InvestmentProjectInteractionFactory(
            investment_project=investment_project,
            service_id=ServiceConstant.investment_enquiry_assigned_to_ist_cmc.
            value.id,
        )
        with freeze_time('2017-01-01'):
            investment_project.stage_id = InvestmentProjectStageConstant.won.value.id
            investment_project.save()

        spi5 = InvestmentProjectInteractionFactory(
            investment_project=investment_project,
            service_id=ServiceConstant.investment_ist_aftercare_offered.value.
            id,
        )

        response = data_flow_api_client.get(self.view_url)
        assert response.status_code == status.HTTP_200_OK

        response_results = response.json()['results']
        assert response_results == [
            {
                'enquiry_processed': spi1.created_on.isoformat(),
                'enquiry_type': spi1.service.name,
                'enquiry_processed_by_id': str(spi1.created_by.id),
                'assigned_to_ist': spi2.created_on.isoformat(),
                'project_manager_assigned': pm_assigned_on.isoformat(),
                'project_manager_assigned_by_id': str(pm_assigned_by.id),
                'investment_project_id': str(investment_project.id),
                'project_moved_to_won': '2017-01-01T00:00:00+00:00',
                'aftercare_offered_on': spi5.created_on.isoformat(),
                'propositions': [],
            },
        ]
def test_earliest_interactions_are_being_selected(spi_report, ist_adviser):
    """Tests that report contains earliest interaction dates."""
    investment_project = InvestmentProjectFactory(
        project_manager=ist_adviser, )

    service_dates = (
        (Service.investment_enquiry_confirmed_prospect.value.id, '2016-01-02'),
        (Service.investment_enquiry_confirmed_prospect.value.id, '2016-01-03'),
        (Service.investment_enquiry_confirmed_prospect.value.id, '2016-01-01'),
        (Service.investment_enquiry_assigned_to_ist_sas.value.id,
         '2017-01-03'),
        (Service.investment_enquiry_assigned_to_ist_sas.value.id,
         '2017-01-01'),
        (Service.investment_enquiry_assigned_to_ist_sas.value.id,
         '2017-01-02'),
        (Service.investment_ist_aftercare_offered.value.id, '2017-03-04'),
        (Service.investment_ist_aftercare_offered.value.id, '2017-03-05'),
        (Service.investment_ist_aftercare_offered.value.id, '2017-03-06'),
    )
    for service_date in service_dates:
        with freeze_time(service_date[1]):
            InvestmentProjectInteractionFactory(
                investment_project=investment_project,
                service_id=service_date[0],
            )

    rows = list(spi_report.rows())

    assert len(rows) == 1
    assert rows[0]['Enquiry processed'] == '2016-01-01T00:00:00+00:00'
    assert rows[0]['Assigned to IST'] == '2017-01-01T00:00:00+00:00'
    assert rows[0]['Aftercare offered on'] == '2017-03-04T00:00:00+00:00'
示例#6
0
    def test_non_restricted_user_can_get_interaction_with_service_answers(
        self,
        permissions,
    ):
        """Test that a non-restricted user can get interaction with service answers."""
        requester = create_test_user(permission_codenames=permissions)

        extra_data = {
            'service_id':
            ServiceConstant.providing_investment_advice_and_information.value.
            id,
            'service_answers': {
                ServiceQuestionID.piai_what_did_you_give_advice_about.value: {
                    ServiceAnswerOptionID.piai_banking_and_funding.value: {},
                },
            },
        }
        interaction = InvestmentProjectInteractionFactory(**extra_data)
        api_client = self.create_api_client(user=requester)
        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()

        assert response_data['service'] == {
            'id':
            str(ServiceConstant.providing_investment_advice_and_information.
                value.id),
            'name':
            ServiceConstant.providing_investment_advice_and_information.value.
            name,
        }
        assert response_data['service_answers'] == extra_data[
            'service_answers']
示例#7
0
def test_investment_project_interaction_updated_sync_to_opensearch(
        opensearch_with_signals):
    """Test investment project gets synced to OpenSearch when an interaction is updated."""
    investment_project = InvestmentProjectFactory()
    interaction_date = '2018-05-05T00:00:00+00:00'
    interaction_subject = 'Did something interactive'
    new_interaction = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        date=datetime.fromisoformat(interaction_date),
        subject=interaction_subject,
    )
    opensearch_with_signals.indices.refresh()

    assert_project_search_latest_interaction(has_interaction=True)

    results = get_search_by_entities_query(
        [InvestmentProject],
        term='',
        filter_data={},
    ).execute()

    assert len(results) == 1
    result = results[0]

    assert result['latest_interaction'] == {
        'id': str(new_interaction.id),
        'subject': interaction_subject,
        'date': interaction_date,
    }
示例#8
0
def test_deleted_interaction_deleted_from_opensearch(opensearch_with_signals):
    """
    Test that when an interaction is deleted from db it is also
    deleted from OpenSearch.
    """
    interaction = InvestmentProjectInteractionFactory()
    opensearch_with_signals.indices.refresh()

    assert opensearch_with_signals.get(
        index=InteractionSearchApp.search_model.get_write_index(),
        id=interaction.pk,
    )

    interaction_id = interaction.pk
    interaction.delete()
    opensearch_with_signals.indices.refresh()

    with pytest.raises(NotFoundError):
        assert opensearch_with_signals.get(
            index=InteractionSearchApp.search_model.get_write_index(),
            id=interaction_id,
        ) is None
示例#9
0
def test_deleted_interaction_deleted_from_es(es_with_signals):
    """
    Test that when an interaction is deleted from db it is also
    deleted from ES.
    """
    interaction = InvestmentProjectInteractionFactory()
    es_with_signals.indices.refresh()

    assert es_with_signals.get(
        index=InteractionSearchApp.es_model.get_write_index(),
        doc_type=InteractionSearchApp.name,
        id=interaction.pk,
    )

    interaction_id = interaction.pk
    interaction.delete()
    es_with_signals.indices.refresh()

    with pytest.raises(NotFoundError):
        assert es_with_signals.get(
            index=InteractionSearchApp.es_model.get_write_index(),
            doc_type=InteractionSearchApp.name,
            id=interaction_id,
        ) is None
    def test_restricted_user_cannot_get_non_associated_investment_project_interaction(self):
        """
        Test that a restricted user cannot get a non-associated investment project
        interaction.
        """
        interaction = InvestmentProjectInteractionFactory()
        requester = create_test_user(
            permission_codenames=[InteractionPermission.view_associated_investmentproject],
            dit_team=TeamFactory(),
        )
        api_client = self.create_api_client(user=requester)
        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = api_client.get(url)

        assert response.status_code == status.HTTP_403_FORBIDDEN
示例#11
0
def test_updating_project_name_updates_interaction(opensearch_with_signals):
    """
    Test that when an investment project's name is updated, the project's interactions are
    synced to OpenSearch.
    """
    interaction = InvestmentProjectInteractionFactory()
    new_project_name = 'helios'
    interaction.investment_project.name = new_project_name
    interaction.investment_project.save()
    opensearch_with_signals.indices.refresh()

    result = opensearch_with_signals.get(
        index=InteractionSearchApp.search_model.get_write_index(),
        id=interaction.pk,
    )
    assert result['_source']['investment_project']['name'] == new_project_name
示例#12
0
def test_interaction_would_start_spi2_or_not(spi_report, ist_adviser,
                                             service_id, visible):
    """Checks if specified interaction starts spi2 or not."""
    investment_project = InvestmentProjectFactory(
        project_manager=ist_adviser, )
    interaction = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        service_id=service_id,
    )

    rows = list(spi_report.rows())

    assert len(rows) == 1
    if visible:
        assert rows[0]['Assigned to IST'] == interaction.created_on.isoformat()
    else:
        assert 'Assigned to IST' not in rows[0]
示例#13
0
def test_updating_project_name_updates_interaction(es_with_signals):
    """
    Test that when an investment project's name is updated, the project's interactions are
    synced to ES.
    """
    interaction = InvestmentProjectInteractionFactory()
    new_project_name = 'helios'
    interaction.investment_project.name = new_project_name
    interaction.investment_project.save()
    es_with_signals.indices.refresh()

    result = es_with_signals.get(
        index=InteractionSearchApp.es_model.get_write_index(),
        doc_type=DEFAULT_MAPPING_TYPE,
        id=interaction.pk,
    )
    assert result['_source']['investment_project']['name'] == new_project_name
示例#14
0
def test_interaction_would_end_spi1_or_not(spi_report, service_id, visible):
    """Checks if specified interaction ends spi1 or not."""
    investment_project = InvestmentProjectFactory()
    interaction = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        service_id=service_id,
    )

    rows = list(spi_report.rows())

    assert len(rows) == 1
    assert rows[0][
        'Project created on'] == investment_project.created_on.isoformat()
    if visible:
        assert rows[0][
            'Enquiry processed'] == interaction.created_on.isoformat()
    else:
        assert 'Enquiry processed' not in rows[0]
示例#15
0
def test_can_get_spi5_start_and_end(spi_report, ist_adviser):
    """Tests if we can see spi5 start and end dates."""
    investment_project = VerifyWinInvestmentProjectFactory(
        project_manager=ist_adviser, )

    with freeze_time('2017-01-01'):
        investment_project.stage_id = InvestmentProjectStage.won.value.id
        investment_project.save()

    with freeze_time('2017-01-15'):
        InvestmentProjectInteractionFactory(
            service_id=Service.investment_ist_aftercare_offered.value.id,
            investment_project=investment_project,
        )

    rows = list(spi_report.rows())
    assert len(rows) == 1
    assert rows[0]['Project moved to won'] == '2017-01-01T00:00:00+00:00'
    assert rows[0]['Aftercare offered on'] == '2017-01-15T00:00:00+00:00'
示例#16
0
def test_only_ist_interactions_are_being_selected(spi_report, ist_adviser):
    """Tests that report takes into account IST interactions only."""
    investment_project = InvestmentProjectFactory(
        project_manager=ist_adviser,
    )

    service_dates = (
        (ServiceConstant.account_management.value.id, '2015-01-23'),
        (
            random_obj_for_queryset(Service.objects.exclude(pk__in=ALL_SPI_SERVICE_IDS)).id,
            '2015-12-03',
        ),
        (ServiceConstant.investment_enquiry_confirmed_prospect.value.id, '2016-01-02'),
        (
            random_obj_for_queryset(Service.objects.exclude(pk__in=ALL_SPI_SERVICE_IDS)).id,
            '2016-01-02',
        ),
        (
            random_obj_for_queryset(Service.objects.exclude(pk__in=ALL_SPI_SERVICE_IDS)).id,
            '2016-01-03',
        ),
        (ServiceConstant.investment_enquiry_confirmed_prospect.value.id, '2016-01-01'),
        (
            random_obj_for_queryset(Service.objects.exclude(pk__in=ALL_SPI_SERVICE_IDS)).id,
            '2017-01-01',
        ),
        (ServiceConstant.investment_enquiry_assigned_to_ist_sas.value.id, '2017-01-03'),
        (ServiceConstant.investment_ist_aftercare_offered.value.id, '2017-03-04'),
    )
    for service_date in service_dates:
        with freeze_time(service_date[1]):
            InvestmentProjectInteractionFactory(
                investment_project=investment_project,
                service_id=service_date[0],
            )

    rows = list(spi_report.rows())

    assert len(rows) == 1
    assert rows[0]['Enquiry processed'] == '2016-01-01T00:00:00+00:00'
    assert rows[0]['Assigned to IST'] == '2017-01-03T00:00:00+00:00'
    assert rows[0]['Aftercare offered on'] == '2017-03-04T00:00:00+00:00'
    def test_restricted_user_cannot_update_non_associated_investment_project_interaction(self):
        """
        Test that a restricted user cannot update a non-associated investment project interaction.
        """
        interaction = InvestmentProjectInteractionFactory(
            subject='I am a subject',
        )
        requester = create_test_user(
            permission_codenames=[InteractionPermission.change_associated_investmentproject],
        )

        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_403_FORBIDDEN
示例#18
0
def test_cannot_get_spi5_start_and_end_for_non_new_investor(
    spi_report,
    ist_adviser,
):
    """Tests if we are not going to see spi5 start and end dates if investor is not new."""
    investment_project = VerifyWinInvestmentProjectFactory(
        project_manager=ist_adviser,
        investor_type_id=InvestorType.existing_investor.value.id,
    )

    with freeze_time('2017-01-01'):
        investment_project.stage_id = InvestmentProjectStage.won.value.id
        investment_project.save()

    with freeze_time('2017-01-15'):
        InvestmentProjectInteractionFactory(
            service_id=Service.investment_ist_aftercare_offered.value.id,
            investment_project=investment_project,
        )

    rows = list(spi_report.rows())
    assert len(rows) == 1
    assert 'Project moved to won' not in rows[0]
    assert 'Aftercare offered on' not in rows[0]
示例#19
0
def test_interaction_investment_project_activity(api_client):
    """
    Get a list of interactions and test the returned JSON is valid as per:
    https://www.w3.org/TR/activitystreams-core/
    """
    start = datetime.datetime(year=2012, month=7, day=12, hour=15, minute=6, second=3)
    with freeze_time(start) as frozen_datetime:
        interaction = InvestmentProjectInteractionFactory()
        project = interaction.investment_project
        frozen_datetime.tick(datetime.timedelta(seconds=1, microseconds=1))
        response = hawk.get(api_client, get_url('api-v3:activity-stream:interactions'))

    assert response.status_code == status.HTTP_200_OK
    assert response.json() == {
        '@context': 'https://www.w3.org/ns/activitystreams',
        'summary': 'Interaction Activities',
        'type': 'OrderedCollectionPage',
        'next': 'http://testserver/v3/activity-stream/interaction'
                + '?cursor=2012-07-12T15%3A06%3A03.000000%2B00%3A00'
                + f'&cursor={str(interaction.id)}',
        'orderedItems': [
            {
                'id': f'dit:DataHubInteraction:{interaction.id}:Announce',
                'type': 'Announce',
                'published': format_date_or_datetime(interaction.created_on),
                'generator': {'name': 'dit:dataHub', 'type': 'Application'},
                'object': {
                    'id': f'dit:DataHubInteraction:{interaction.id}',
                    'type': [
                        'dit:Event',
                        'dit:Interaction',
                        f'dit:datahub:theme:{interaction.theme}',
                    ],
                    'content': interaction.notes,
                    'startTime': format_date_or_datetime(interaction.date),
                    'dit:status': interaction.status,
                    'dit:archived': interaction.archived,
                    'dit:communicationChannel': {'name': interaction.communication_channel.name},
                    'dit:subject': interaction.subject,
                    'dit:service': {'name': interaction.service.name},
                    'attributedTo': [
                        *[
                            {
                                'id': f'dit:DataHubCompany:{company.pk}',
                                'dit:dunsNumber': company.duns_number,
                                'dit:companiesHouseNumber': company.company_number,
                                'type': ['Organization', 'dit:Company'],
                                'name': company.name,
                            }
                            for company in interaction.companies.order_by('pk')
                        ],
                        *[
                            {
                                'id': f'dit:DataHubAdviser:{participant.adviser.pk}',
                                'type': ['Person', 'dit:Adviser'],
                                'dit:emailAddress':
                                    participant.adviser.contact_email or participant.adviser.email,
                                'name': participant.adviser.name,
                                'dit:team': {
                                    'id': f'dit:DataHubTeam:{participant.team.pk}',
                                    'type': ['Group', 'dit:Team'],
                                    'name': participant.team.name,
                                },
                            }
                            for participant in interaction.dit_participants.order_by('pk')
                        ],
                        *[
                            {
                                'id': f'dit:DataHubContact:{contact.pk}',
                                'type': ['Person', 'dit:Contact'],
                                'url': contact.get_absolute_url(),
                                'dit:emailAddress': contact.email,
                                'dit:jobTitle': contact.job_title,
                                'name': contact.name,
                            }
                            for contact in interaction.contacts.order_by('pk')
                        ],
                    ],
                    'url': interaction.get_absolute_url(),
                    'context': [
                        {
                            'id': f'dit:DataHubInvestmentProject:{project.pk}',
                            'name': project.name,
                            'type': 'dit:InvestmentProject',
                            'url': project.get_absolute_url(),
                        },
                    ],
                },
            },
        ],
    }
示例#20
0
def test_write_report(ist_adviser):
    """Test that SPI report CSV is generated correctly."""
    pm_assigned_by = AdviserFactory()
    pm_assigned_on = now()
    investment_project = VerifyWinInvestmentProjectFactory(
        project_manager=ist_adviser,
        project_manager_first_assigned_on=pm_assigned_on,
        project_manager_first_assigned_by=pm_assigned_by,
    )
    spi1 = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        service_id=ServiceConstant.investment_enquiry_requested_more_information.value.id,
    )
    spi2 = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        service_id=ServiceConstant.investment_enquiry_assigned_to_ist_cmc.value.id,
    )

    proposition = PropositionFactory(
        deadline='2017-01-05',
        status='ongoing',
        adviser=pm_assigned_by,
        investment_project=investment_project,
        created_by=ist_adviser,
    )

    investment_project.stage_id = InvestmentProjectStageConstant.won.value.id
    investment_project.save()

    spi5 = InvestmentProjectInteractionFactory(
        investment_project=investment_project,
        service_id=ServiceConstant.investment_ist_aftercare_offered.value.id,
    )

    lines = []
    file = Mock()
    file.write = lambda line: lines.append(line.decode('utf8'))
    write_report(file)

    headers = ','.join(SPIReport.field_titles.keys())
    assert lines[1] == f'{headers}\r\n'

    row = [
        str(investment_project.pk),
        investment_project.project_code,
        investment_project.name,
        investment_project.created_on.isoformat(),
        spi1.created_on.isoformat(),
        spi1.service.name,
        spi1.created_by.name,
        spi2.created_on.isoformat(),
        investment_project.project_manager_first_assigned_on.isoformat(),
        investment_project.project_manager_first_assigned_by.name,
        investment_project.stage_log.get(
            stage_id=InvestmentProjectStageConstant.won.value.id,
        ).created_on.isoformat(),
        spi5.created_on.isoformat(),
        f'{proposition.deadline};{proposition.status};;{proposition.adviser.name}',
    ]
    expected_line = ','.join(row)
    assert lines[2] == f'{expected_line}\r\n'
示例#21
0
    def test_interaction_export(
        self,
        setup_es,
        request_sortby,
        orm_ordering,
    ):
        """
        Test export of interaction search results with a policy feedback user.

        Checks that all interaction kinds except for policy feedback are included in the export.
        """
        # Faker generates job titles containing commas which complicates comparisons,
        # so all contact job titles are explicitly set
        company = CompanyFactory()
        CompanyInteractionFactory(
            company=company,
            contacts=[
                ContactFactory(company=company, job_title='Engineer'),
                ContactFactory(company=company, job_title=None),
                ContactFactory(company=company, job_title=''),
            ],
        )
        EventServiceDeliveryFactory(
            company=company,
            contacts=[
                ContactFactory(company=company, job_title='Managing director'),
            ],
        )
        InvestmentProjectInteractionFactory(
            company=company,
            contacts=[
                ContactFactory(company=company, job_title='Exports manager'),
            ],
        )
        ServiceDeliveryFactory(
            company=company,
            contacts=[
                ContactFactory(company=company, job_title='Sales director'),
            ],
        )
        CompanyInteractionFactoryWithPolicyFeedback(
            company=company,
            contacts=[
                ContactFactory(company=company,
                               job_title='Business development manager'),
            ],
            policy_areas=PolicyArea.objects.order_by('?')[:2],
            policy_issue_types=PolicyIssueType.objects.order_by('?')[:2],
        )

        setup_es.indices.refresh()

        data = {}
        if request_sortby:
            data['sortby'] = request_sortby

        url = reverse('api-v3:search:interaction-export')

        with freeze_time('2018-01-01 11:12:13'):
            response = self.api_client.post(url, data=data)

        assert response.status_code == status.HTTP_200_OK
        assert parse_header(response.get('Content-Type')) == ('text/csv', {
            'charset':
            'utf-8'
        })
        assert parse_header(response.get('Content-Disposition')) == (
            'attachment',
            {
                'filename': 'Data Hub - Interactions - 2018-01-01-11-12-13.csv'
            },
        )

        sorted_interactions = Interaction.objects.all().order_by(
            orm_ordering,
            'pk',
        )
        reader = DictReader(StringIO(response.getvalue().decode('utf-8-sig')))

        assert reader.fieldnames == list(
            SearchInteractionExportAPIView.field_titles.values())

        expected_row_data = [{
            'Date':
            interaction.date,
            'Type':
            interaction.get_kind_display(),
            'Service':
            get_attr_or_none(interaction, 'service.name'),
            'Subject':
            interaction.subject,
            'Link':
            f'{settings.DATAHUB_FRONTEND_URL_PREFIXES["interaction"]}'
            f'/{interaction.pk}',
            'Company':
            get_attr_or_none(interaction, 'company.name'),
            'Company link':
            f'{settings.DATAHUB_FRONTEND_URL_PREFIXES["company"]}'
            f'/{interaction.company.pk}',
            'Company country':
            get_attr_or_none(
                interaction,
                'company.address_country.name',
            ),
            'Company UK region':
            get_attr_or_none(interaction, 'company.uk_region.name'),
            'Company sector':
            get_attr_or_none(interaction, 'company.sector.name'),
            'Contacts':
            _format_expected_contacts(interaction),
            'Adviser':
            get_attr_or_none(interaction, 'dit_adviser.name'),
            'Service provider':
            get_attr_or_none(interaction, 'dit_team.name'),
            'Event':
            get_attr_or_none(interaction, 'event.name'),
            'Communication channel':
            get_attr_or_none(interaction, 'communication_channel.name'),
            'Service delivery status':
            get_attr_or_none(
                interaction,
                'service_delivery_status.name',
            ),
            'Net company receipt':
            interaction.net_company_receipt,
            'Policy issue types':
            join_attr_values(interaction.policy_issue_types.all()),
            'Policy areas':
            join_attr_values(interaction.policy_areas.all(), separator='; '),
            'Policy feedback notes':
            interaction.policy_feedback_notes,
        } for interaction in sorted_interactions]

        actual_row_data = [_format_actual_csv_row(row) for row in reader]
        assert actual_row_data == format_csv_data(expected_row_data)
示例#22
0
    def test_non_restricted_user_can_get_investment_project_interaction(self, permissions):
        """Test that a non-restricted user can get an investment project interaction."""
        requester = create_test_user(permission_codenames=permissions)
        interaction = InvestmentProjectInteractionFactory()
        api_client = self.create_api_client(user=requester)
        url = reverse('api-v3:interaction:item', kwargs={'pk': interaction.pk})
        response = api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data == {
            'id': response_data['id'],
            'kind': Interaction.KINDS.interaction,
            'is_event': None,
            'service_delivery_status': None,
            'grant_amount_offered': None,
            'net_company_receipt': None,
            'policy_areas': [],
            'policy_issue_type': None,
            'communication_channel': {
                'id': str(interaction.communication_channel.pk),
                'name': interaction.communication_channel.name,
            },
            'subject': interaction.subject,
            'date': interaction.date.date().isoformat(),
            'dit_adviser': {
                'id': str(interaction.dit_adviser.pk),
                'first_name': interaction.dit_adviser.first_name,
                'last_name': interaction.dit_adviser.last_name,
                'name': interaction.dit_adviser.name,
            },
            'notes': interaction.notes,
            'company': {
                'id': str(interaction.company.pk),
                'name': interaction.company.name,
            },
            'contact': {
                'id': str(interaction.contact.pk),
                'name': interaction.contact.name,
                'first_name': interaction.contact.first_name,
                'last_name': interaction.contact.last_name,
                'job_title': interaction.contact.job_title,
            },
            'event': None,
            'service': {
                'id': str(Service.trade_enquiry.value.id),
                'name': Service.trade_enquiry.value.name,
            },
            'dit_team': {
                'id': str(Team.healthcare_uk.value.id),
                'name': Team.healthcare_uk.value.name,
            },
            'investment_project': {
                'id': str(interaction.investment_project.pk),
                'name': interaction.investment_project.name,
                'project_code': interaction.investment_project.project_code,
            },
            'archived_documents_url_path': interaction.archived_documents_url_path,
            'created_by': {
                'id': str(interaction.created_by.pk),
                'first_name': interaction.created_by.first_name,
                'last_name': interaction.created_by.last_name,
                'name': interaction.created_by.name,
            },
            'modified_by': {
                'id': str(interaction.modified_by.pk),
                'first_name': interaction.modified_by.first_name,
                'last_name': interaction.modified_by.last_name,
                'name': interaction.modified_by.name,
            },
            'created_on': '2017-04-18T13:25:30.986208Z',
            'modified_on': '2017-04-18T13:25:30.986208Z',
        }
示例#23
0
def test_interaction_investment_project_activity(api_client):
    """
    Get a list of interactions and test the returned JSON is valid as per:
    https://www.w3.org/TR/activitystreams-core/
    """
    interaction = InvestmentProjectInteractionFactory()
    project = interaction.investment_project
    response = hawk.get(api_client, get_url('api-v3:activity-stream:interactions'))
    assert response.status_code == status.HTTP_200_OK

    assert response.json() == {
        '@context': 'https://www.w3.org/ns/activitystreams',
        'summary': 'Interaction Activities',
        'type': 'OrderedCollectionPage',
        'id': 'http://testserver/v3/activity-stream/interaction',
        'partOf': 'http://testserver/v3/activity-stream/interaction',
        'previous': None,
        'next': None,
        'orderedItems': [
            {
                'id': f'dit:DataHubInteraction:{interaction.id}:Announce',
                'type': 'Announce',
                'published': format_date_or_datetime(interaction.created_on),
                'generator': {'name': 'dit:dataHub', 'type': 'Application'},
                'object': {
                    'id': f'dit:DataHubInteraction:{interaction.id}',
                    'type': ['dit:Event', 'dit:Interaction'],
                    'startTime': format_date_or_datetime(interaction.date),
                    'dit:status': interaction.status,
                    'dit:archived': interaction.archived,
                    'dit:communicationChannel': {'name': interaction.communication_channel.name},
                    'dit:subject': interaction.subject,
                    'dit:service': {'name': interaction.service.name},
                    'attributedTo': [
                        {
                            'id': f'dit:DataHubCompany:{interaction.company.pk}',
                            'dit:dunsNumber': interaction.company.duns_number,
                            'dit:companiesHouseNumber': interaction.company.company_number,
                            'type': ['Organization', 'dit:Company'],
                            'name': interaction.company.name,
                        },
                        *[
                            {
                                'id': f'dit:DataHubAdviser:{participant.adviser.pk}',
                                'type': ['Person', 'dit:Adviser'],
                                'dit:emailAddress':
                                    participant.adviser.contact_email or participant.adviser.email,
                                'name': participant.adviser.name,
                                'dit:team': {
                                    'id': f'dit:DataHubTeam:{participant.team.pk}',
                                    'type': ['Group', 'dit:Team'],
                                    'name': participant.team.name,
                                },
                            }
                            for participant in interaction.dit_participants.order_by('pk')
                        ],
                        *[
                            {
                                'id': f'dit:DataHubContact:{contact.pk}',
                                'type': ['Person', 'dit:Contact'],
                                'url': contact.get_absolute_url(),
                                'dit:emailAddress': contact.email,
                                'dit:jobTitle': contact.job_title,
                                'name': contact.name,
                            }
                            for contact in interaction.contacts.order_by('pk')
                        ],
                    ],
                    'url': interaction.get_absolute_url(),
                    'context': [
                        {
                            'id': f'dit:DataHubInvestmentProject:{project.pk}',
                            'name': project.name,
                            'type': 'dit:InvestmentProject',
                            'url': project.get_absolute_url(),
                        },
                    ],
                },
            },
        ],
    }
    def test_restricted_user_can_get_associated_investment_project_interaction(self):
        """Test that a restricted user can get an associated investment project interaction."""
        project_creator = AdviserFactory()
        project = InvestmentProjectFactory(created_by=project_creator)
        interaction = InvestmentProjectInteractionFactory(investment_project=project)
        requester = create_test_user(
            permission_codenames=[InteractionPermission.view_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.get(url)

        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        response_data['contacts'].sort(key=itemgetter('id'))
        assert response_data == {
            'id': response_data['id'],
            'kind': Interaction.KINDS.interaction,
            # TODO: Change this once we give status a default
            'status': None,
            'theme': interaction.theme,
            'is_event': None,
            'service_delivery_status': None,
            'grant_amount_offered': None,
            'net_company_receipt': None,
            'policy_areas': [],
            'policy_feedback_notes': '',
            'policy_issue_types': [],
            'was_policy_feedback_provided': False,
            'communication_channel': {
                'id': str(interaction.communication_channel.pk),
                'name': interaction.communication_channel.name,
            },
            'subject': interaction.subject,
            'date': interaction.date.date().isoformat(),
            'dit_adviser': {
                'id': str(interaction.dit_adviser.pk),
                'first_name': interaction.dit_adviser.first_name,
                'last_name': interaction.dit_adviser.last_name,
                'name': interaction.dit_adviser.name,
            },
            'dit_participants': [
                {
                    'adviser': {
                        'id': str(interaction.dit_adviser.pk),
                        'first_name': interaction.dit_adviser.first_name,
                        'last_name': interaction.dit_adviser.last_name,
                        'name': interaction.dit_adviser.name,
                    },
                    'team': {
                        'id': str(interaction.dit_team.pk),
                        'name': interaction.dit_team.name,
                    },
                },
            ],
            'dit_team': {
                'id': str(interaction.dit_team.pk),
                'name': interaction.dit_team.name,
            },
            'notes': interaction.notes,
            'company': {
                'id': str(interaction.company.pk),
                'name': interaction.company.name,
            },
            'contacts': [
                {
                    'id': str(contact.pk),
                    'name': contact.name,
                    'first_name': contact.first_name,
                    'last_name': contact.last_name,
                    'job_title': contact.job_title,
                }
                for contact in interaction.contacts.order_by('pk')
            ],
            'event': None,
            'service': {
                'id': str(Service.trade_enquiry.value.id),
                'name': Service.trade_enquiry.value.name,
            },
            'investment_project': {
                'id': str(interaction.investment_project.pk),
                'name': interaction.investment_project.name,
                'project_code': interaction.investment_project.project_code,
            },
            'archived_documents_url_path': interaction.archived_documents_url_path,
            'created_by': {
                'id': str(interaction.created_by.pk),
                'first_name': interaction.created_by.first_name,
                'last_name': interaction.created_by.last_name,
                'name': interaction.created_by.name,
            },
            'modified_by': {
                'id': str(interaction.modified_by.pk),
                'first_name': interaction.modified_by.first_name,
                'last_name': interaction.modified_by.last_name,
                'name': interaction.modified_by.name,
            },
            'created_on': '2017-04-18T13:25:30.986208Z',
            'modified_on': '2017-04-18T13:25:30.986208Z',
            # TODO: change this once we enforce a default
            'location': None,
            # TODO: Change this once we enforce a default
            'archived': None,
            'archived_by': None,
            'archived_on': None,
            'archived_reason': None,
        }