diff --git a/deployment.md b/app/docs/deployment.md similarity index 100% rename from deployment.md rename to app/docs/deployment.md diff --git a/app/docs/troubleshooting.md b/app/docs/troubleshooting.md new file mode 100644 index 00000000..d9c3315e --- /dev/null +++ b/app/docs/troubleshooting.md @@ -0,0 +1,70 @@ +# Local troubleshooting + +This document was created to provide solutions to common issues that occur when running Enquiry Management. The issues are categorised by the method used to bring up the application. + +When updating this document please use the following template: + +``` +### Issue title +[brief description of issue] + +Screenshot or text: + +![image-title](./Troubleshooting/[image-name].png) + +**Solution** If there is a single permanent fix for this issue enter it here. + +**Short-term fix** If there is a temporary workaround or some of 'sticky-tape' solution enter it here. + +**Long-term fix** If there is a permanent fix for the issue (or if one is being worked on) enter it here. +``` + +## Docker issues + +This section should include issues that occur when running Enquiry Management in Docker. + +### TypeError at /enquiries/14/company-search 'NoneType' object is not subscriptable + +This occurs when the connection to Data Hub is setup but the browser isn't logged in to the Django admin on http://localhost:8000/admin/. + +``` +TypeError at /enquiries/14/company-search +'NoneType' object is not subscriptable +solution: login to Django admin on http://localhost:8000/admin/ +Request Method: POST +Request URL: http://localhost:8001/enquiries/14/company-search +Django Version: 3.1.14 +Exception Type: TypeError +Exception Value: 'NoneType' object is not subscriptable +Exception Location: /usr/src/app/app/enquiries/common/datahub_utils.py, line 63, in dh_request +Python Executable: /usr/local/bin/python +Python Version: 3.8.14 +Python Path: ['/usr/src/app', + '/usr/src/app', + '/usr/local/lib/python38.zip', + '/usr/local/lib/python3.8', + '/usr/local/lib/python3.8/lib-dynload', + '/usr/local/lib/python3.8/site-packages'] +Server time: Thu, 22 Sep 2022 11:28:44 +0000 +``` + +**Solution** login to Django admin on http://localhost:8000/admin/ + + +## Native issues + +### TypeError at /enquiries/14/company-search 'NoneType' object is not subscriptable + +This occurs when the connection to Data Hub is setup but the browser isn't logged in to the Django admin on http://localhost:8000/admin/. + + +This section should be used for native issues that occur regardless of what API you are using. + +### There is a problem. Referral Advisor: Error validating your identity in DataHub + +``` +There is a problem. +Referral Advisor: Error validating your identity in DataHub +``` + +**Solution** Update/renew the MOCK_SSO_TOKEN from DataHub. (//[your-datahub-api]/admin/add-access-token/) diff --git a/app/enquiries/common/datahub_utils.py b/app/enquiries/common/datahub_utils.py index 663e0bdd..812ce02e 100644 --- a/app/enquiries/common/datahub_utils.py +++ b/app/enquiries/common/datahub_utils.py @@ -271,6 +271,28 @@ def dh_get_matching_company_contact(first_name, last_name, email, company_contac ) +def dh_get_matching_company_contact_by_email(email, company_contacts): + """ + Performs check identifying whether an enquirer's email exists in their company's contact + list in |data-hub-api|_. + + :param email: + :type email: str + + :param company_contacts: + :type company_contacts: list + + :returns: The first matching contact if any exist + :rtype: dict or None + """ + return next(( + company_contact for company_contact in company_contacts + if company_contact["email"].lower() == email.lower() + ), + None + ) + + def dh_contact_create(request, access_token, enquirer, company_id, primary=False): """ Create a |data-hub|_ `contact` and associate it with the given `company`. @@ -362,6 +384,21 @@ def dh_prepare_contact(request, access_token, enquirer, company_id): if matching_contact: enquiry_contact = matching_contact return enquiry_contact["datahub_id"], None + else: + matching_contact_email = dh_get_matching_company_contact_by_email( + enquirer.email, + existing_contacts, + ) + if matching_contact_email: + return None, { + "contact_details_mismatch": + f"a contact with the email " + f"{matching_contact_email['email']} already exists on Data Hub for this company. " + f"The name {enquirer.first_name} {enquirer.last_name} doesn't match the name " + f"{matching_contact_email['first_name']} {matching_contact_email['last_name']} on " + "Data Hub. Please ensure the names match accross both systems or use an " + "alternative email address." + } # If enquirer is a new contact, add them to DH enquiry_contact, error = dh_contact_create( diff --git a/app/enquiries/tests/test_dh_utils.py b/app/enquiries/tests/test_dh_utils.py index 5b9a054a..3f4716ba 100644 --- a/app/enquiries/tests/test_dh_utils.py +++ b/app/enquiries/tests/test_dh_utils.py @@ -8,6 +8,7 @@ from app.enquiries.models import Enquirer from app.enquiries.common.datahub_utils import ( dh_get_matching_company_contact, + dh_get_matching_company_contact_by_email, dh_prepare_contact, ) @@ -59,6 +60,15 @@ def setUp(self): phone=faker.phone_number(), request_for_call=ref_data.RequestForCall.YES_AFTERNOON.value, ) + self.partially_matching_on_email_enquirer = Enquirer.objects.create( + first_name=faker.name(), + last_name=faker.name(), + email=MATCHING_CONTACT_DETAILS["email"], + job_title='Manager', + phone_country_code='1', + phone=faker.phone_number(), + request_for_call=ref_data.RequestForCall.YES_AFTERNOON.value, + ) self.new_enquirer = Enquirer.objects.create( first_name=faker.name(), last_name=faker.name(), @@ -120,6 +130,33 @@ def test_dh_get_matching_company_contact_no_match(self): ) self.assertIsNone(contact) + def test_dh_get_matching_company_contact_by_email_match(self): + """Test company contact match by email function returns matching contact""" + + contact = dh_get_matching_company_contact_by_email( + self.matching_enquirer.email, + self.company_results + ) + self.assertEqual(contact["email"], MATCHING_CONTACT_DETAILS["email"]) + + def test_dh_get_matching_company_contact_by_email_partial_match(self): + """Test company contact match by email function does not return a partial match""" + + contact = dh_get_matching_company_contact_by_email( + self.partially_matching_enquirer.email, + self.company_results + ) + self.assertIsNone(contact) + + def test_dh_get_matching_company_contact_by_email_no_match(self): + """Test company contact match by email function returns None if no match""" + + contact = dh_get_matching_company_contact_by_email( + self.new_enquirer.email, + self.company_results + ) + self.assertIsNone(contact) + @mock.patch('app.enquiries.common.datahub_utils.dh_contact_create') @mock.patch('app.enquiries.common.datahub_utils.dh_get_matching_company_contact') @mock.patch('app.enquiries.common.datahub_utils.dh_get_company_contact_list') @@ -187,6 +224,47 @@ def test_dh_prepare_contact_new_contact_existing_contacts( self.assertEqual(contact_id, self.dh_contact_id) self.assertIsNone(error) + @mock.patch('app.enquiries.common.datahub_utils.dh_contact_create') + @mock.patch('app.enquiries.common.datahub_utils.dh_get_matching_company_contact_by_email') + @mock.patch('app.enquiries.common.datahub_utils.dh_get_company_contact_list') + def test_dh_prepare_contact_mismatch_contact_existing_contacts( + self, + mock_dh_contact_list, + mock_matching_company_contact_by_email, + mock_create_dh_contact, + ): + """Test contact prepare function in case of company having different existing """ + """contacts with mismatched name""" + mock_dh_contact_list.return_value = [self.company_results, None] + mock_create_dh_contact.return_value = [{"id": self.dh_contact_id}, None] + mock_matching_company_contact_by_email.return_value = { + 'datahub_id': self.dh_company_id, + 'first_name': self.matching_enquirer.first_name, + 'last_name': self.matching_enquirer.last_name, + 'job_title': self.matching_enquirer.job_title, + 'email': self.matching_enquirer.email, + 'phone': self.matching_enquirer.phone, + } + + contact_id, error = dh_prepare_contact( + self.request, + self.access_token, + self.partially_matching_on_email_enquirer, + self.dh_company_id + ) + + self.assertIsNotNone(error) + contact_details_mismatch_error = ( + f"a contact with the email " + f"{self.matching_enquirer.email} already exists on Data Hub for this company. " + f"The name {self.partially_matching_on_email_enquirer.first_name} " + f"{self.partially_matching_on_email_enquirer.last_name} doesn't match the name " + f"{MATCHING_CONTACT_DETAILS['first_name']} {MATCHING_CONTACT_DETAILS['last_name']} on " + "Data Hub. Please ensure the names match accross both systems or use an " + "alternative email address." + ) + self.assertEqual(error['contact_details_mismatch'], contact_details_mismatch_error) + @mock.patch('app.enquiries.common.datahub_utils.dh_contact_create') @mock.patch('app.enquiries.common.datahub_utils.dh_get_matching_company_contact') @mock.patch('app.enquiries.common.datahub_utils.dh_get_company_contact_list')