def test_error_returned_if_contacts_dont_belong_to_company(self): """ Test that an error is returned if the contacts don't belong to the specified company. """ company = CompanyFactory() contacts = [ContactFactory(), ContactFactory(company=company)] communication_channel = random_obj_for_model(CommunicationChannel) 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': self.user.pk}, ], 'company': { 'id': company.pk, }, 'contacts': [{ 'id': contact.pk, } for contact in contacts], '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_400_BAD_REQUEST assert response.json() == { 'non_field_errors': ['The interaction contacts must belong to the specified company.'], }
def test_invalid_kind_is_rejected(self, kind): """Test that invalid kind values are rejected.""" adviser = self.user contact = ContactFactory() company = contact.company data = { 'kind': kind, 'company': { 'id': company.pk, }, 'contacts': [{ 'id': contact.pk, }], 'date': '2017-04-18', 'dit_participants': [ { 'adviser': { 'id': adviser.pk, }, }, ], 'service': { 'id': random_service().pk, }, 'subject': 'whatever', 'was_policy_feedback_provided': False, } url = reverse('api-v3:interaction:collection') response = self.api_client.post(url, data) assert response.status_code == status.HTTP_400_BAD_REQUEST assert response.json() == { 'kind': [f'"{kind}" is not a valid choice.'], }
def make_matched_rows(num_records): """Make multiple interaction CSV rows that should pass contact matching.""" adviser = AdviserFactory( first_name='Adviser for', last_name='Matched interaction', ) service = random_service() communication_channel = random_communication_channel() contacts = ContactFactory.create_batch( num_records, email=factory.Sequence(lambda i: f'unique{i}@matched.uk'), ) return [ { 'theme': Interaction.THEMES.export, 'kind': Interaction.KINDS.interaction, 'date': '01/01/2018', 'adviser_1': adviser.name, 'contact_email': contact.email, 'service': service.name, 'communication_channel': communication_channel.name, } for contact in contacts ]
def test_error_returned_if_duplicate_participating_advisers_specified(self): """ Test that an error is returned if an adviser is specified as a DIT participant multiple times. """ contact = ContactFactory() communication_channel = random_obj_for_model(CommunicationChannel) dit_adviser = AdviserFactory() 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': dit_adviser.pk, }, }, { 'adviser': { 'id': AdviserFactory().pk, }, }, { 'adviser': { 'id': dit_adviser.pk, }, }, ], '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_400_BAD_REQUEST # An error should be returned for each duplicated item in the dit_participants list in # the request assert response.json() == { 'dit_participants': [ {'adviser': ['You cannot add the same adviser more than once.']}, {}, {'adviser': ['You cannot add the same adviser more than once.']}, ], }
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 ]
def _sample_valid_request_data(referral): adviser = AdviserFactory() contact = ContactFactory(company=referral.company) communication_channel = random_obj_for_model(CommunicationChannel) service = random_service() return { 'kind': Interaction.Kind.INTERACTION, 'communication_channel': communication_channel.pk, 'subject': 'test subject', 'date': '2020-02-03', 'dit_participants': [ {'adviser': adviser.pk}, ], 'contacts': [contact.pk], 'service': service.pk, 'was_policy_feedback_provided': False, }
def test_displays_no_matches_message_if_no_matches(self): """ Test that if a valid file is uploaded but no records are matched to contacts, the import_no_matches.html template is used. """ adviser = AdviserFactory() service = random_service() communication_channel = random_communication_channel() file = make_csv_file( ( 'theme', 'kind', 'date', 'adviser_1', 'contact_email', 'service', 'communication_channel', ), ( Interaction.THEMES.export, Interaction.KINDS.interaction, '01/01/2018', adviser.name, '*****@*****.**', service.name, communication_channel.name, ), ) response = self.client.post( import_interactions_url, data={ 'csv_file': file, }, ) assert response.status_code == status.HTTP_200_OK assert response.template_name.endswith('/import_no_matches.html') assert response.context['num_matched'] == 0 assert response.context['num_unmatched'] == 1 assert response.context['num_multiple_matches'] == 0 assert response.context['matched_rows'] == [] assert response.context['num_matched_omitted'] == 0
def make_unmatched_rows(num_records): """Make multiple interaction CSV rows that should have no contact matches.""" adviser = AdviserFactory( first_name='Adviser for', last_name='Unmatched interaction', ) service = random_service() communication_channel = random_communication_channel() return [ { 'theme': Interaction.THEMES.export, 'kind': Interaction.KINDS.interaction, 'date': '01/01/2018', 'adviser_1': adviser.name, 'contact_email': f'unmatched{i}@unmatched.uk', 'service': service.name, 'communication_channel': communication_channel.name, } for i in range(num_records) ]
def make_multiple_matches_rows(num_records): """Make multiple interaction CSV rows that should have multiple contact matches.""" adviser = AdviserFactory( first_name='Adviser for', last_name='Multi-matched interaction', ) service = random_service() communication_channel = random_communication_channel() contact_email = '*****@*****.**' ContactFactory.create_batch(2, email=contact_email) return [ { 'theme': Interaction.THEMES.export, 'kind': Interaction.KINDS.interaction, 'date': '01/01/2018', 'adviser_1': adviser.name, 'contact_email': contact_email, 'service': service.name, 'communication_channel': communication_channel.name, } for _ in range(num_records) ]
def test_creates_an_interaction(self, extra_data): """Test that an interaction is created on success.""" referral = CompanyReferralFactory() url = _complete_url(referral.pk) contact = ContactFactory(company=referral.company) service = random_service() request_data = { 'kind': Interaction.Kind.INTERACTION, 'subject': 'test subject', 'date': '2020-02-03', 'dit_participants': [ { 'adviser': self.user }, ], 'contacts': [contact], 'service': service, 'was_policy_feedback_provided': False, **extra_data, } resolved_request_data = resolve_objects(request_data) with freeze_time(FROZEN_DATETIME): response = self.api_client.post(url, data=resolved_request_data) assert response.status_code == status.HTTP_201_CREATED referral.refresh_from_db() assert referral.interaction_id interaction_data = Interaction.objects.values().get( pk=referral.interaction_id) expected_interaction_data = { # Automatically set fields 'created_by_id': self.user.pk, 'created_on': FROZEN_DATETIME, 'id': referral.interaction_id, 'modified_by_id': self.user.pk, 'modified_on': FROZEN_DATETIME, # Fields specified in the request body 'communication_channel_id': resolved_request_data.get('communication_channel'), 'date': datetime(2020, 2, 3, tzinfo=utc), 'event_id': resolved_request_data.get('event'), 'grant_amount_offered': None, 'investment_project_id': None, 'kind': resolved_request_data['kind'], 'net_company_receipt': None, 'notes': '', 'policy_feedback_notes': '', 'service_answers': None, 'service_delivery_status_id': None, 'service_id': service.pk, 'source': None, 'status': Interaction.Status.COMPLETE, 'subject': resolved_request_data['subject'], 'theme': None, 'was_policy_feedback_provided': resolved_request_data['was_policy_feedback_provided'], 'were_countries_discussed': None, # Other fields 'archived': False, 'archived_by_id': None, 'archived_documents_url_path': '', 'archived_on': None, 'archived_reason': None, 'large_capital_opportunity_id': None, 'has_related_trade_agreements': None, # TODO: a legacy field, remove once interaction.company field is removed 'company_id': referral.company_id, } assert interaction_data == expected_interaction_data assert list(referral.interaction.contacts.all()) == [contact] assert list(referral.interaction.companies.all()) == [referral.company] participant = referral.interaction.dit_participants.get() assert participant.adviser == self.user assert participant.team == self.user.dit_team