Example #1
0
def calendar_data_fixture():
    """
    Create advisers, contacts and companies so that our email samples can be
    attributed to some DB entities.
    """
    advisers = [
        ('*****@*****.**', 'Adviser', '1'),
        ('*****@*****.**', 'Adviser', '2'),
    ]
    AdviserFactory.create_batch(
        len(advisers),
        email=factory.Iterator(advisers, getter=lambda a: a[0]),
        first_name=factory.Iterator(advisers, getter=lambda a: a[1]),
        last_name=factory.Iterator(advisers, getter=lambda a: a[2]),
        contact_email=factory.SelfAttribute('email'),
    )
    AdviserFactory(
        email='*****@*****.**',
        first_name='Adviser',
        last_name='3',
        contact_email='*****@*****.**',
    )
    company_1 = CompanyFactory(name='Company 1')
    company_2 = CompanyFactory(name='Company 2')
    contacts = [
        ('Bill Adama', company_1),
        ('Saul Tigh', company_1),
        ('Laura Roslin', company_2),
        ('Sharon Valerii', company_1),
        ('Sharon Valerii', company_2),
    ]
    for name, company in contacts:
        first_name, last_name = name.split(' ')
        email_prefix = name.lower().replace(' ', '.')
        email = f'{email_prefix}@example.net'
        ContactFactory(
            first_name=first_name,
            last_name=last_name,
            email=email,
            company=company,
        )
    # Ensure that our contact who appears on multiple companies
    # with a single email address has more interactions for the
    # contact attributed to 'Company 1'
    contact_with_interactions = Contact.objects.get(
        email='*****@*****.**',
        company=company_1,
    )
    CompanyInteractionFactory(contacts=[contact_with_interactions],
                              company=company_1)
    yield
    def test_invalid_adviser(self):
        """
        Test that calling PUT with an invalid adviser returns 400.
        """
        advisers = AdviserFactory.create_batch(2)
        order = OrderFactory()

        url = reverse(
            'api-v3:omis:order:subscriber-list',
            kwargs={'order_pk': order.id},
        )

        data = [{'id': adviser.id} for adviser in advisers]
        data.append({
            'id': '00000000-0000-0000-0000-000000000000',
        })

        response = self.api_client.put(url, data)

        assert response.status_code == status.HTTP_400_BAD_REQUEST
        assert response.json() == [
            {},
            {},
            {
                'id': [
                    '00000000-0000-0000-0000-000000000000 is not a valid adviser'
                ]
            },
        ]
Example #3
0
    def test_filter_by_dit_adviser_name(self, setup_es):
        """Tests filtering interaction by dit adviser name."""
        advisers = AdviserFactory.create_batch(10)
        CompanyInteractionFactory.create_batch(
            len(advisers),
            dit_adviser=factory.Iterator(advisers),
        )

        setup_es.indices.refresh()

        url = reverse('api-v3:search:interaction')
        request_data = {
            'dit_adviser_name': advisers[5].name,
        }
        response = self.api_client.post(url, request_data)

        assert response.status_code == status.HTTP_200_OK

        response_data = response.json()

        assert response_data['count'] > 0

        results = response_data['results']
        # multiple records can match our filter, let's make sure at least one is exact match
        assert any(result['dit_adviser']['id'] == str(advisers[5].id)
                   for result in results)
        assert any(result['dit_adviser']['name'] == advisers[5].name
                   for result in results)
    def test_non_empty(self):
        """
        Test that calling GET returns the list of advisers subscribed to the order.
        """
        advisers = AdviserFactory.create_batch(3)
        order = OrderFactory()
        for adviser in advisers[:2]:
            OrderSubscriberFactory(order=order, adviser=adviser)

        url = reverse(
            'api-v3:omis:order:subscriber-list',
            kwargs={'order_pk': order.id},
        )
        response = self.api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == [{
            'id': str(adviser.id),
            'first_name': adviser.first_name,
            'last_name': adviser.last_name,
            'name': adviser.name,
            'dit_team': {
                'id': str(adviser.dit_team.id),
                'name': adviser.dit_team.name,
                'uk_region': {
                    'id': str(adviser.dit_team.uk_region.pk),
                    'name': adviser.dit_team.uk_region.name,
                },
            },
        } for adviser in advisers[:2]]
Example #5
0
    def test_filter_by_dit_adviser_id(self, setup_es):
        """Tests filtering interaction by dit adviser id."""
        advisers = AdviserFactory.create_batch(10)
        CompanyInteractionFactory.create_batch(
            len(advisers),
            dit_adviser=factory.Iterator(advisers),
        )

        setup_es.indices.refresh()

        url = reverse('api-v3:search:interaction')
        request_data = {
            'dit_adviser': advisers[5].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 results[0]['dit_adviser']['id'] == str(advisers[5].id)
        assert results[0]['dit_adviser']['name'] == advisers[5].name
    def test_non_empty(self):
        """
        Test that calling GET returns the list of advisers assigned to the order.
        """
        advisers = AdviserFactory.create_batch(3)
        order = OrderFactory(assignees=[])
        for i, adviser in enumerate(advisers[:2]):
            OrderAssigneeFactory(
                order=order,
                adviser=adviser,
                estimated_time=(120 * i),
            )

        url = reverse(
            'api-v3:omis:order:assignee',
            kwargs={'order_pk': order.id},
        )
        response = self.api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == [{
            'adviser': {
                'id': str(adviser.id),
                'first_name': adviser.first_name,
                'last_name': adviser.last_name,
                'name': adviser.name,
            },
            'estimated_time': (120 * i),
            'actual_time': None,
            'is_lead': False,
        } for i, adviser in enumerate(advisers[:2])]
Example #7
0
    def test_change_existing_list(self, allowed_status):
        """
        Test that calling PUT with a different list of advisers completely changes
        the subscriber list:
        - advisers not in the list will be removed
        - new advisers will be added
        - existing advisers will be kept
        """
        previous_advisers = AdviserFactory.create_batch(2)
        order = OrderFactory(status=allowed_status)
        subscriptions = [
            OrderSubscriberFactory(order=order, adviser=adviser)
            for adviser in previous_advisers
        ]

        final_advisers = [
            AdviserFactory(),  # new
            previous_advisers[1],  # existing
        ]

        url = reverse(
            'api-v3:omis:order:subscriber-list',
            kwargs={'order_pk': order.id},
        )
        response = self.api_client.put(
            url,
            [{'id': adviser.id} for adviser in final_advisers],
        )

        assert response.status_code == status.HTTP_200_OK
        assert {adv['id'] for adv in response.json()} == {str(adv.id) for adv in final_advisers}

        # check that the id of the existing subscription didn't change
        assert order.subscribers.filter(id=subscriptions[1].id).exists()
Example #8
0
    def test_get_one_list_group_core_team(
        self,
        build_company,
        with_global_account_manager,
    ):
        """
        Test that `get_one_list_group_core_team` returns the Core Team of `self` if the company
        has no `global_headquarters` or the one of its `global_headquarters` otherwise.
        """
        team_member_advisers = AdviserFactory.create_batch(
            3,
            first_name=factory.Iterator(
                ('Adam', 'Barbara', 'Chris'),
            ),
        )
        global_account_manager = team_member_advisers[0] if with_global_account_manager else None

        company = build_company(global_account_manager)
        group_global_headquarters = company.global_headquarters or company

        OneListCoreTeamMemberFactory.create_batch(
            len(team_member_advisers),
            company=group_global_headquarters,
            adviser=factory.Iterator(team_member_advisers),
        )

        core_team = company.get_one_list_group_core_team()
        assert core_team == [
            {
                'adviser': adviser,
                'is_global_account_manager': adviser is global_account_manager,
            }
            for adviser in team_member_advisers
        ]
Example #9
0
    def test_adviser_report_download(self):
        """Test the download of a report."""
        AdviserFactory.create_batch(5)

        url = reverse('admin_report:download-report', kwargs={'report_id': 'all-advisers'})

        user = create_test_user(
            permission_codenames=('view_advisor',),
            is_staff=True,
            password=self.PASSWORD,
        )

        client = self.create_client(user=user)
        response = client.get(url)
        assert response.status_code == status.HTTP_200_OK
        # 7 = header + test user + the 5 test advisers
        assert len(response.getvalue().decode('utf-8').splitlines()) == 7
    def test_can_update_core_team_members(
        self,
        one_list_company,
        one_list_editor,
        existing_team_count,
        new_team_count,
    ):
        """Test that core team members can be updated."""
        api_client = self.create_api_client(user=one_list_editor)
        url = self._get_url(one_list_company)

        if existing_team_count:
            team_member_advisers = AdviserFactory.create_batch(
                existing_team_count)
            OneListCoreTeamMemberFactory.create_batch(
                len(team_member_advisers),
                company=one_list_company,
                adviser=factory.Iterator(team_member_advisers),
            )

        old_core_team_members = [
            core_team_member.adviser.id for core_team_member in
            one_list_company.one_list_core_team_members.all()
        ]

        new_core_team_members = [
            adviser.id for adviser in AdviserFactory.create_batch(2)
        ] if new_team_count else []

        response = api_client.patch(
            url,
            {
                'core_team_members': [{
                    'adviser': adviser_id,
                } for adviser_id in new_core_team_members],
            },
        )
        assert response.status_code == status.HTTP_204_NO_CONTENT

        core_team_members = [
            core_team_member.adviser.id for core_team_member in
            one_list_company.one_list_core_team_members.all()
        ]

        assert core_team_members != old_core_team_members
        assert core_team_members == new_core_team_members
Example #11
0
    def test_multiple_participating_advisers_can_be_specified(self):
        """Test that an interaction can be created with multiple DIT participants."""
        contact = ContactFactory()
        communication_channel = random_obj_for_model(CommunicationChannel)
        advisers = AdviserFactory.create_batch(5)
        advisers.sort(key=attrgetter('pk'))

        url = reverse('api-v3:interaction:collection')
        request_data = {
            'kind': Interaction.Kind.INTERACTION,
            'communication_channel': communication_channel.pk,
            'subject': 'whatever',
            'date': date.today().isoformat(),
            'dit_participants': [
                {
                    'adviser': {
                        'id': adviser.pk,
                    },
                }
                for adviser in advisers
            ],
            'company': {
                'id': contact.company.pk,
            },
            'contacts': [{
                'id': contact.pk,
            }],
            'service': {
                'id': random_service().pk,
            },
            'was_policy_feedback_provided': False,
        }

        api_client = self.create_api_client()
        response = api_client.post(url, request_data)
        assert response.status_code == status.HTTP_201_CREATED

        response_data = response.json()
        response_data['dit_participants'].sort(
            key=lambda dit_participant: dit_participant['adviser']['id'],
        )
        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(adviser.dit_team.pk),
                    'name': adviser.dit_team.name,
                },
            }
            for adviser in advisers
        ]
Example #12
0
    def test_can_filter_by_is_active(self, filter_value):
        """Test filtering by is_active."""
        AdviserFactory.create_batch(5, is_active=not filter_value)
        matching_advisers = AdviserFactory.create_batch(4,
                                                        is_active=filter_value)
        if filter_value:
            matching_advisers.append(self.user)

        url = reverse('api-v1:advisor-list')
        response = self.api_client.get(
            url,
            data={
                'is_active': filter_value,
            },
        )
        assert response.status_code == status.HTTP_200_OK
        response_data = response.json()
        assert response_data['count'] == len(matching_advisers)
        actual_ids = Counter(str(adviser.pk) for adviser in matching_advisers)
        expected_ids = Counter(result['id']
                               for result in response_data['results'])
        assert actual_ids == expected_ids
Example #13
0
    def test_with_core_team_members(self, build_company,
                                    with_global_account_manager):
        """
        Test that if there are Core Team members for a company's Global Headquarters,
        the endpoint returns a list with these advisers in it.
        """
        team_member_advisers = AdviserFactory.create_batch(
            3,
            first_name=factory.Iterator(('Adam', 'Barbara', 'Chris'), ),
        )
        global_account_manager = team_member_advisers[
            0] if with_global_account_manager else None

        company = build_company(global_account_manager)
        group_global_headquarters = company.global_headquarters or company
        OneListCoreTeamMemberFactory.create_batch(
            len(team_member_advisers),
            company=group_global_headquarters,
            adviser=factory.Iterator(team_member_advisers),
        )

        url = reverse(
            'api-v4:company:one-list-group-core-team',
            kwargs={'pk': company.pk},
        )
        response = self.api_client.get(url)

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == [{
            'adviser': {
                'id': str(adviser.pk),
                'name': adviser.name,
                'first_name': adviser.first_name,
                'last_name': adviser.last_name,
                'contact_email': adviser.contact_email,
                'dit_team': {
                    'id': str(adviser.dit_team.pk),
                    'name': adviser.dit_team.name,
                    'uk_region': {
                        'id': str(adviser.dit_team.uk_region.pk),
                        'name': adviser.dit_team.uk_region.name,
                    },
                    'country': {
                        'id': str(adviser.dit_team.country.pk),
                        'name': adviser.dit_team.country.name,
                    },
                },
            },
            'is_global_account_manager':
            adviser is global_account_manager,
        } for adviser in team_member_advisers]
Example #14
0
    def test_can_add_participants(self):
        """Test that participants can be added to an interaction without any being removed."""
        interaction = CompanyInteractionFactory(dit_participants=[])
        dit_participants = InteractionDITParticipantFactory.create_batch(
            3,
            interaction=interaction,
        )

        new_advisers = [
            *[dit_participant.adviser for dit_participant in dit_participants],
            *AdviserFactory.create_batch(2),
        ]
        new_advisers.sort(key=attrgetter('pk'))

        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 = [(adviser, adviser.dit_team) for adviser in new_advisers]

        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
        ]
    def test_remove_all(self, allowed_status):
        """
        Test that calling PUT with an empty list, removes all the subscribers.
        """
        advisers = AdviserFactory.create_batch(2)
        order = OrderFactory(status=allowed_status)
        for adviser in advisers:
            OrderSubscriberFactory(order=order, adviser=adviser)

        url = reverse(
            'api-v3:omis:order:subscriber-list',
            kwargs={'order_pk': order.id},
        )
        response = self.api_client.put(url, [])

        assert response.status_code == status.HTTP_200_OK
        assert response.json() == []
Example #16
0
    def test_add_to_empty_list(self):
        """
        Test that calling PUT with new advisers adds them to the subscriber list.
        """
        advisers = AdviserFactory.create_batch(2)
        order = OrderFactory()

        url = reverse(
            'api-v3:omis:order:subscriber-list',
            kwargs={'order_pk': order.id},
        )

        response = self.api_client.put(
            url,
            [{'id': adviser.id} for adviser in advisers],
        )

        assert response.status_code == status.HTTP_200_OK
        assert {adv['id'] for adv in response.json()} == {str(adv.id) for adv in advisers}
    def test_one_list_account_manager_filter(
        self,
        num_account_managers,
        opensearch_with_collector,
    ):
        """Test one list account manager filter."""
        account_managers = AdviserFactory.create_batch(3)

        selected_account_managers = random.sample(account_managers,
                                                  num_account_managers)

        CompanyFactory.create_batch(2)
        CompanyFactory.create_batch(
            3, one_list_account_owner=factory.Iterator(account_managers))

        opensearch_with_collector.flush_and_refresh()

        query = {
            'one_list_group_global_account_manager': [
                account_manager.id
                for account_manager in selected_account_managers
            ],
        }

        url = reverse('api-v4:search:company')
        response = self.api_client.post(url, query)

        assert response.status_code == status.HTTP_200_OK

        search_results = {
            company['one_list_group_global_account_manager']['id']
            for company in response.data['results']
        }
        expected_results = {
            str(account_manager.id)
            for account_manager in selected_account_managers
        }
        assert response.data['count'] == len(selected_account_managers)
        assert len(response.data['results']) == len(selected_account_managers)
        assert search_results == expected_results
Example #18
0
    def test_add(self):
        """Test that One List Core Team members can be added to a company."""
        team_member_advisers = AdviserFactory.create_batch(2)
        team_size = len(team_member_advisers)
        company = CompanyFactory()

        assert company.one_list_core_team_members.count() == 0

        url = reverse('admin:company_company_change', args=(company.id, ))

        data = {
            **get_required_company_form_data(company),
            'one_list_core_team_members-TOTAL_FORMS':
            team_size,
            'one_list_core_team_members-INITIAL_FORMS':
            0,
            'one_list_core_team_members-MIN_NUM_FORMS':
            0,
            'one_list_core_team_members-MAX_NUM_FORMS':
            1000,
        }

        for index, adviser in enumerate(team_member_advisers):
            team_member_id = uuid.uuid4()
            data.update({
                f'initial-one_list_core_team_members-{index}-id':
                team_member_id,
                f'one_list_core_team_members-{index}-id':
                team_member_id,
                f'one_list_core_team_members-{index}-company':
                company.pk,
                f'one_list_core_team_members-{index}-adviser':
                adviser.pk,
            })

        response = self.client.post(url, data, follow=True)

        assert response.status_code == status.HTTP_200_OK
        assert company.one_list_core_team_members.count() == team_size
Example #19
0
    def test_add_core_team_members(self):
        """Test that core team members can be added to a company."""
        team_member_advisers = AdviserFactory.create_batch(2)
        team_size = len(team_member_advisers)
        company = CompanyFactory()

        assert company.core_team_members.count() == 0

        url = reverse('admin:company_company_change', args=(company.id, ))

        data = {}

        # populate data with required field values
        admin_form = CompanyAdmin(Company, site).get_form(mock.Mock())
        for field_name, field in admin_form.base_fields.items():
            if field.required:
                field_value = getattr(company, field_name)
                data[field_name] = field.prepare_value(field_value)

        # add inline related field data
        data.update({
            'core_team_members-TOTAL_FORMS': team_size,
            'core_team_members-INITIAL_FORMS': 0,
            'core_team_members-MIN_NUM_FORMS': 0,
            'core_team_members-MAX_NUM_FORMS': 1000,
        })
        for index, adviser in enumerate(team_member_advisers):
            team_member_id = uuid.uuid4()
            data.update({
                f'initial-core_team_members-{index}-id': team_member_id,
                f'core_team_members-{index}-id': team_member_id,
                f'core_team_members-{index}-company': company.pk,
                f'core_team_members-{index}-adviser': adviser.pk,
            })

        response = self.client.post(url, data, follow=True)

        assert response.status_code == status.HTTP_200_OK
        assert company.core_team_members.count() == team_size
Example #20
0
class TestInteractionCSVRowForm:
    """Tests for InteractionCSVRowForm."""
    @pytest.mark.parametrize(
        'data,errors',
        (
            # kind blank
            (
                {
                    'kind': ''
                },
                {
                    'kind': ['This field is required.']
                },
            ),
            # kind invalid
            (
                {
                    'kind': 'invalid'
                },
                {
                    'kind': [
                        'Select a valid choice. invalid is not one of the available choices.'
                    ]
                },
            ),
            # date blank
            (
                {
                    'date': ''
                },
                {
                    'date': ['This field is required.']
                },
            ),
            # invalid date
            (
                {
                    'date': '08/31/2020'
                },
                {
                    'date': ['Enter a valid date.']
                },
            ),
            # invalid contact_email
            (
                {
                    'contact_email': 'invalid'
                },
                {
                    'contact_email': ['Enter a valid email address.']
                },
            ),
            # blank adviser_1
            (
                {
                    'adviser_1': ''
                },
                {
                    'adviser_1': ['This field is required.']
                },
            ),
            # adviser_1 doesn't exist
            (
                {
                    'adviser_1': 'Non-existent adviser'
                },
                {
                    'adviser_1': [ADVISER_NOT_FOUND_MESSAGE]
                },
            ),
            # multiple matching values for adviser_1
            (
                {
                    'adviser_1':
                    lambda: AdviserFactory.create_batch(
                        2,
                        first_name='Pluto',
                        last_name='Doris',
                    )[0].name,
                },
                {
                    'adviser_1': [MULTIPLE_ADVISERS_FOUND_MESSAGE]
                },
            ),
            # adviser_1 and team_1 mismatch
            (
                {
                    'adviser_1':
                    lambda: AdviserFactory(
                        first_name='Pluto',
                        last_name='Doris',
                        dit_team__name='Team Advantage',
                    ).name,
                    'team_1':
                    lambda: TeamFactory(name='Team Disadvantage', ).name,
                },
                {
                    'adviser_1': [ADVISER_WITH_TEAM_NOT_FOUND_MESSAGE]
                },
            ),
            # adviser_2 doesn't exist
            (
                {
                    'adviser_2': 'Non-existent adviser'
                },
                {
                    'adviser_2': [ADVISER_NOT_FOUND_MESSAGE]
                },
            ),
            # multiple matching values for adviser_2
            (
                {
                    'adviser_2':
                    lambda: AdviserFactory.create_batch(
                        2,
                        first_name='Pluto',
                        last_name='Doris',
                    )[0].name,
                },
                {
                    'adviser_2': [MULTIPLE_ADVISERS_FOUND_MESSAGE]
                },
            ),
            # adviser_2 and team_2 mismatch
            (
                {
                    'adviser_2':
                    lambda: AdviserFactory(
                        first_name='Pluto',
                        last_name='Doris',
                        dit_team__name='Team Advantage',
                    ).name,
                    'team_2':
                    lambda: TeamFactory(name='Team Disadvantage', ).name,
                },
                {
                    'adviser_2': [ADVISER_WITH_TEAM_NOT_FOUND_MESSAGE]
                },
            ),
            # service doesn't exist
            (
                {
                    'service': 'Non-existent service'
                },
                {
                    'service': [
                        'Select a valid choice. That choice is not one of the available choices.',
                    ],
                },
            ),
            # service is disabled
            (
                {
                    'service': lambda: _random_service(disabled=True).name,
                },
                {
                    'service': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # Multiple matching services
            (
                {
                    'service':
                    lambda: ServiceFactory.create_batch(2, name='Duplicate')[0]
                    .name,
                },
                {
                    'service': ['There is more than one matching service.'],
                },
            ),
            # communication_channel doesn't exist
            (
                {
                    'communication_channel':
                    'Non-existent communication channel'
                },
                {
                    'communication_channel': [
                        'Select a valid choice. That choice is not one of the available choices.',
                    ],
                },
            ),
            # Multiple matching communication channels
            (
                {
                    'communication_channel':
                    lambda: CommunicationChannelFactory.create_batch(
                        2,
                        name='Duplicate',
                    )[0].name,
                },
                {
                    'communication_channel': [
                        'There is more than one matching communication channel.',
                    ],
                },
            ),
            # communication_channel is disabled
            (
                {
                    'communication_channel':
                    lambda: _random_communication_channel(disabled=True, ).
                    name,
                },
                {
                    'communication_channel': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # event_id invalid
            (
                {
                    'event_id': 'non_existent_event_id'
                },
                {
                    'event_id': [
                        "'non_existent_event_id' is not a valid UUID.",
                    ],
                },
            ),
            # event_id is for a disabled event
            (
                {
                    'event_id': lambda: str(DisabledEventFactory().pk),
                },
                {
                    'event_id': [OBJECT_DISABLED_MESSAGE],
                },
            ),
            # event_id non-existent
            (
                {
                    'event_id': '00000000-0000-0000-0000-000000000000'
                },
                {
                    'event_id': [
                        'Select a valid choice. That choice is not one of the available '
                        'choices.',
                    ],
                },
            ),
            # cannot specify event_id for an interaction
            (
                {
                    'kind': Interaction.KINDS.interaction,
                    'event_id': lambda: str(EventFactory().pk),
                },
                {
                    'event_id': [INTERACTION_CANNOT_HAVE_AN_EVENT_MESSAGE],
                },
            ),
        ),
    )
    def test_validation_errors(self, data, errors):
        """Test validation for various fields."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            **_resolve_data(data),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert form.errors == errors

    @pytest.mark.parametrize(
        'field,input_value,expected_value',
        (
            # UK date format without leading zeroes
            (
                'date',
                '1/2/2013',
                date(2013, 2, 1),
            ),
            # UK date format with leading zeroes
            (
                'date',
                '03/04/2015',
                date(2015, 4, 3),
            ),
            # ISO date format
            (
                'date',
                '2016-05-04',
                date(2016, 5, 4),
            ),
            # Subject
            (
                'subject',
                'A subject',
                'A subject',
            ),
            # Notes (trailing blank lines are stripped)
            (
                'notes',
                'Notes with\nmultiple lines\n',
                'Notes with\nmultiple lines',
            ),
        ),
    )
    def test_simple_value_cleaning(self, field, input_value, expected_value):
        """Test the conversion and cleaning of various non-relationship fields."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_value,
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == expected_value

    @pytest.mark.parametrize(
        'kind',
        (Interaction.KINDS.interaction, Interaction.KINDS.service_delivery),
    )
    @pytest.mark.parametrize(
        'field,object_creator,input_transformer',
        (
            # adviser_1 look-up (same case)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name,
            ),
            # adviser_1 look-up (case-insensitive)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name.upper(),
            ),
            # adviser_2 look-up (same case)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name,
            ),
            # adviser_2 look-up (case-insensitive)
            (
                'adviser_1',
                lambda: AdviserFactory(
                    first_name='Pluto',
                    last_name='Doris',
                ),
                lambda obj: obj.name.upper(),
            ),
            # service look-up (same case)
            (
                'service',
                lambda: ServiceFactory(name='UNIQUE EXPORT DEAL'),
                lambda obj: obj.name,
            ),
            # service look-up (case-insensitive)
            (
                'service',
                lambda: ServiceFactory(name='UNIQUE EXPORT DEAL'),
                lambda obj: obj.name.lower(),
            ),
        ),
    )
    def test_common_relation_fields(self, kind, field, object_creator,
                                    input_transformer):
        """
        Test the looking up of values for relationship fields common to interactions and
        service deliveries.
        """
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': kind,
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == obj

    @pytest.mark.parametrize(
        'field,object_creator,input_transformer',
        (
            # communication channel look-up (same case)
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name,
            ),
            # communication channel look-up (case-insensitive)
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name.upper(),
            ),
        ),
    )
    def test_interaction_relation_fields(self, field, object_creator,
                                         input_transformer):
        """Test the looking up of values for relationship fields specific to interactions."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': 'interaction',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == obj

    @pytest.mark.parametrize(
        'field,object_creator,input_transformer,expected_value_transformer',
        (
            # communication channel should be ignored
            (
                'communication_channel',
                lambda: _random_communication_channel(),
                lambda obj: obj.name,
                lambda obj: None,
            ),
            # event look-up
            (
                'event_id',
                lambda: EventFactory(),
                lambda obj: str(obj.pk),
                lambda obj: obj,
            ),
        ),
    )
    def test_service_delivery_relation_fields(
        self,
        field,
        object_creator,
        input_transformer,
        expected_value_transformer,
    ):
        """Test the looking up of values for relationship fields specific to service deliveries."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()
        obj = object_creator()

        resolved_data = {
            'kind': 'service_delivery',
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
            field: input_transformer(obj),
        }

        form = InteractionCSVRowForm(data=resolved_data)
        assert not form.errors
        assert form.cleaned_data[field] == expected_value_transformer(obj)

    @pytest.mark.parametrize(
        'kind',
        (Interaction.KINDS.interaction, Interaction.KINDS.service_delivery),
    )
    def test_subject_falls_back_to_service(self, kind):
        """Test that if subject is not specified, the name of the service is used instead."""
        adviser = AdviserFactory(first_name='Neptune', last_name='Doris')
        service = _random_service()

        data = {
            'kind': kind,
            'date': '01/01/2018',
            'adviser_1': adviser.name,
            'contact_email': '*****@*****.**',
            'service': service.name,
        }

        form = InteractionCSVRowForm(data=data)
        assert not form.errors
        assert form.cleaned_data['subject'] == service.name
Example #21
0
def test_run(s3_stubber, caplog, reset_unmatched):
    """
    Test that the command updates the specified records (ignoring ones with errors).
    If `reset_unmatched` is False, the existing records not in the CSV are kept untouched,
    otherwise they are set to None.
    """
    caplog.set_level('ERROR')

    new_one_list_tier = random_obj_for_model(OneListTier)
    one_list_companies = CompanyFactory.create_batch(
        8,
        one_list_tier=factory.LazyFunction(
            lambda: random_obj_for_queryset(
                OneListTier.objects.exclude(pk=new_one_list_tier.pk), ), ),
        one_list_account_owner=factory.SubFactory(AdviserFactory),
    )
    non_one_list_companies = CompanyFactory.create_batch(
        3,
        one_list_tier=None,
        one_list_account_owner=None,
    )

    for company in chain(one_list_companies, non_one_list_companies):
        save_prev_fields(company, 'one_list_tier_id',
                         'one_list_account_owner_id')

    advisers = AdviserFactory.create_batch(4)

    bucket = 'test_bucket'
    object_key = 'test_key'
    csv_content = f"""id,one_list_tier_id,one_list_account_owner_id
00000000-0000-0000-0000-000000000000,test,test
{one_list_companies[0].pk},{one_list_companies[0].one_list_tier_id},{one_list_companies[0].one_list_account_owner_id}
{one_list_companies[1].pk},{one_list_companies[1].one_list_tier_id},{advisers[0].pk}
{one_list_companies[2].pk},{new_one_list_tier.pk},{one_list_companies[2].one_list_account_owner_id}
{one_list_companies[3].pk},null,null
{one_list_companies[4].pk},00000000-0000-0000-0000-000000000000,{advisers[1].pk}
{one_list_companies[5].pk},{new_one_list_tier.pk},00000000-0000-0000-0000-000000000000
{non_one_list_companies[0].pk},{new_one_list_tier.pk},{advisers[2].pk}
{non_one_list_companies[1].pk},00000000-0000-0000-0000-000000000000,{advisers[3].pk}
{non_one_list_companies[2].pk},{new_one_list_tier.pk},00000000-0000-0000-0000-000000000000
"""

    s3_stubber.add_response(
        'get_object',
        {'Body': BytesIO(csv_content.encode(encoding='utf-8'))},
        expected_params={
            'Bucket': bucket,
            'Key': object_key,
        },
    )

    call_command('update_one_list_fields',
                 bucket,
                 object_key,
                 reset_unmatched=reset_unmatched)

    for company in chain(one_list_companies, non_one_list_companies):
        company.refresh_from_db()

    # assert exceptions
    assert len(caplog.records) == 5
    assert 'Company matching query does not exist' in caplog.records[
        0].exc_text
    assert 'OneListTier matching query does not exist' in caplog.records[
        1].exc_text
    assert 'Advisor matching query does not exist' in caplog.records[
        2].exc_text
    assert 'OneListTier matching query does not exist' in caplog.records[
        3].exc_text
    assert 'Advisor matching query does not exist' in caplog.records[
        4].exc_text

    # one_list_companies[0]: nothing changed
    assert_did_not_change(one_list_companies[0], 'one_list_tier_id',
                          'one_list_account_owner_id')

    # one_list_companies[1]: only one_list_account_owner_id changed
    assert_changed(one_list_companies[1], 'one_list_account_owner_id')
    assert_did_not_change(one_list_companies[1], 'one_list_tier_id')
    assert one_list_companies[1].one_list_account_owner == advisers[0]

    # one_list_companies[2]: only one_list_tier_id changed
    assert_did_not_change(one_list_companies[2], 'one_list_account_owner_id')
    assert_changed(one_list_companies[2], 'one_list_tier_id')
    assert one_list_companies[2].one_list_tier == new_one_list_tier

    # one_list_companies[3]: all changed
    assert_changed(one_list_companies[3], 'one_list_tier_id',
                   'one_list_account_owner_id')
    assert one_list_companies[3].one_list_tier_id is None
    assert one_list_companies[3].one_list_account_owner_id is None

    # one_list_companies[4]: nothing changed
    assert_did_not_change(one_list_companies[4], 'one_list_tier_id',
                          'one_list_account_owner_id')

    # one_list_companies[5]: nothing changed
    assert_did_not_change(one_list_companies[5], 'one_list_tier_id',
                          'one_list_account_owner_id')

    # non_one_list_companies[0]: all changed
    assert_changed(non_one_list_companies[0], 'one_list_tier_id',
                   'one_list_account_owner_id')
    assert non_one_list_companies[0].one_list_account_owner == advisers[2]
    assert non_one_list_companies[0].one_list_tier == new_one_list_tier

    # non_one_list_companies[1]: nothing changed
    assert_did_not_change(
        non_one_list_companies[1],
        'one_list_tier_id',
        'one_list_account_owner_id',
    )

    # non_one_list_companies[2]: nothing changed
    assert_did_not_change(
        non_one_list_companies[2],
        'one_list_tier_id',
        'one_list_account_owner_id',
    )

    # one_list_companies[6] / [7]: if reset_unmatched == False => nothing changed else all changed
    if reset_unmatched:
        assert_changed(one_list_companies[6], 'one_list_tier_id',
                       'one_list_account_owner_id')
        assert_changed(one_list_companies[7], 'one_list_tier_id',
                       'one_list_account_owner_id')
        assert one_list_companies[6].one_list_tier is None
        assert one_list_companies[6].one_list_account_owner is None

        assert one_list_companies[7].one_list_tier is None
        assert one_list_companies[7].one_list_account_owner is None
    else:
        assert_did_not_change(
            one_list_companies[6],
            'one_list_tier_id',
            'one_list_account_owner_id',
        )
        assert_did_not_change(
            one_list_companies[7],
            'one_list_tier_id',
            'one_list_account_owner_id',
        )
Example #22
0
def test_simulate(s3_stubber, caplog, reset_unmatched):
    """Test that the command simulates updates if --simulate is passed in."""
    caplog.set_level('ERROR')

    new_one_list_tier = random_obj_for_model(OneListTier)
    one_list_companies = CompanyFactory.create_batch(
        8,
        one_list_tier=factory.LazyFunction(
            lambda: random_obj_for_queryset(
                OneListTier.objects.exclude(pk=new_one_list_tier.pk), ), ),
        one_list_account_owner=factory.SubFactory(AdviserFactory),
    )
    non_one_list_companies = CompanyFactory.create_batch(
        3,
        one_list_tier=None,
        one_list_account_owner=None,
    )

    for company in chain(one_list_companies, non_one_list_companies):
        save_prev_fields(company, 'one_list_tier_id',
                         'one_list_account_owner_id')

    advisers = AdviserFactory.create_batch(4)

    bucket = 'test_bucket'
    object_key = 'test_key'
    csv_content = f"""id,one_list_tier_id,one_list_account_owner_id
00000000-0000-0000-0000-000000000000,test,test
{one_list_companies[0].pk},{one_list_companies[0].one_list_tier_id},{one_list_companies[0].one_list_account_owner_id}
{one_list_companies[1].pk},{one_list_companies[1].one_list_tier_id},{advisers[0].pk}
{one_list_companies[2].pk},{new_one_list_tier.pk},{one_list_companies[2].one_list_account_owner_id}
{one_list_companies[3].pk},null,null
{one_list_companies[4].pk},00000000-0000-0000-0000-000000000000,{advisers[1].pk}
{one_list_companies[5].pk},{new_one_list_tier.pk},00000000-0000-0000-0000-000000000000
{non_one_list_companies[0].pk},{new_one_list_tier.pk},{advisers[2].pk}
{non_one_list_companies[1].pk},00000000-0000-0000-0000-000000000000,{advisers[3].pk}
{non_one_list_companies[2].pk},{new_one_list_tier.pk},00000000-0000-0000-0000-000000000000
"""

    s3_stubber.add_response(
        'get_object',
        {'Body': BytesIO(csv_content.encode(encoding='utf-8'))},
        expected_params={
            'Bucket': bucket,
            'Key': object_key,
        },
    )

    call_command(
        'update_one_list_fields',
        bucket,
        object_key,
        reset_unmatched=reset_unmatched,
        simulate=True,
    )

    for company in chain(one_list_companies, non_one_list_companies):
        company.refresh_from_db()

    # assert exceptions
    assert len(caplog.records) == 5
    assert 'Company matching query does not exist' in caplog.records[
        0].exc_text
    assert 'OneListTier matching query does not exist' in caplog.records[
        1].exc_text
    assert 'Advisor matching query does not exist' in caplog.records[
        2].exc_text
    assert 'OneListTier matching query does not exist' in caplog.records[
        3].exc_text
    assert 'Advisor matching query does not exist' in caplog.records[
        4].exc_text

    # assert that nothing really changed
    for company in chain(one_list_companies, non_one_list_companies):
        assert_did_not_change(company, 'one_list_tier_id',
                              'one_list_account_owner_id')