Skip to content

Commit

Permalink
#2009 - Raise InvalidPhoneNumberException on invalid (landline, etc) …
Browse files Browse the repository at this point in the history
…telephones (#2023)
  • Loading branch information
AdamKing0126 authored Oct 2, 2024
1 parent af32073 commit f0d151d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 18 deletions.
4 changes: 4 additions & 0 deletions app/va/va_profile/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class NoContactInfoException(VAProfileNonRetryableException):
failure_reason = 'No contact info found from VA Profile'


class InvalidPhoneNumberException(VAProfileNonRetryableException):
failure_reason = 'Phone number is invalid'


class VAProfileIDNotFoundException(VAProfileNonRetryableException):
failure_reason = 'No VA Profile account found'

Expand Down
45 changes: 30 additions & 15 deletions app/va/va_profile/va_profile_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@

from app.feature_flags import FeatureFlag, is_feature_enabled
from app.va.identifier import OIDS, IdentifierType, transform_to_fhir_format
from app.va.va_profile import NoContactInfoException, VAProfileNonRetryableException, VAProfileRetryableException
from app.va.va_profile import (
NoContactInfoException,
VAProfileNonRetryableException,
VAProfileRetryableException,
)
from app.va.va_profile.exceptions import (
CommunicationItemNotFoundException,
InvalidPhoneNumberException,
VAProfileIDNotFoundException,
)

Expand Down Expand Up @@ -165,35 +170,38 @@ def get_email(self, va_profile_id: RecipientIdentifier) -> str:
self.statsd_client.incr('clients.va-profile.get-email.failure')
self._raise_no_contact_info_exception(self.EMAIL_BIO_TYPE, va_profile_id, contact_info.get(self.TX_AUDIT_ID))

def has_valid_mobile_telephone_classification(self, telephone: Telephone) -> bool:
def has_valid_mobile_telephone_classification(self, telephone: Telephone, contact_info: ContactInformation) -> bool:
"""
Args:
telephone (Telephone): telephone entry from ContactInformation object retrieved from Vet360 API endpoint
Returns:
bool - if AWS-classified telephone is a valid sms recipient (if nonexistent, return True)
Raises:
InvalidPhoneNumberException - if AWS-classified telephone is not a valid sms recipient
"""
classification = telephone.get('classification', {})
classification_code = classification.get('classificationCode', None)
if classification_code is not None:
if classification_code not in VALID_PHONE_TYPES_FOR_SMS_DELIVERY:
self.logger.debug(
'V3 Profile -- Phone classification code of %s is not a valid SMS recipient (VA Profile ID: %s)',
classification_code,
telephone['vaProfileId'],
)
return False
if classification_code is None:
# fall back, if no phone number classification is present
self.logger.debug(
'V3 Profile -- No telephone classification present, assuming the number is a valid SMS recipient (VA Profile ID: %s)',
telephone['vaProfileId'],
)
return True

if classification_code not in VALID_PHONE_TYPES_FOR_SMS_DELIVERY:
self.logger.debug(
'V3 Profile -- Phone classification code of %s is a valid SMS recipient (VA Profile ID: %s)',
'V3 Profile -- Phone classification code of %s is not a valid SMS recipient (VA Profile ID: %s)',
classification_code,
telephone['vaProfileId'],
)
return True
self._raise_invalid_phone_number_exception(contact_info)

# fall back, if no phone number classification is present
self.logger.debug(
'V3 Profile -- No telephone classification present, assuming the number is a valid SMS recipient (VA Profile ID: %s)',
'V3 Profile -- Phone classification code of %s is a valid SMS recipient (VA Profile ID: %s)',
classification_code,
telephone['vaProfileId'],
)
return True
Expand Down Expand Up @@ -222,7 +230,7 @@ def get_mobile_telephone_from_contact_info(self, contact_info: ContactInformatio
self.logger.debug(
'V3 Profile -- VA_PROFILE_V3_IDENTIFY_MOBILE_TELEPHONE_NUMBERS enabled. Checking telephone classification info.'
)
is_mobile = self.has_valid_mobile_telephone_classification(sorted_telephones[0])
is_mobile = self.has_valid_mobile_telephone_classification(sorted_telephones[0], contact_info)
else:
self.logger.debug(
'V3 Profile -- VA_PROFILE_V3_IDENTIFY_MOBILE_TELEPHONE_NUMBERS is not enabled. Will not check classification info.'
Expand Down Expand Up @@ -485,6 +493,13 @@ def _raise_no_contact_info_exception(
f'No {bio_type} in response for VA Profile ID {va_profile_id} ' f'with AuditId {tx_audit_id}'
)

def _raise_invalid_phone_number_exception(self, contact_info: ContactInformation):
self.statsd_client.incr(f'clients.va-profile.get-{self.PHONE_BIO_TYPE}.no-{self.PHONE_BIO_TYPE}')
raise InvalidPhoneNumberException(
f'No valid {self.PHONE_BIO_TYPE} in response for VA Profile ID {contact_info.get("vaProfileId")} '
f'with AuditId {contact_info.get("txAuditId")}'
)

def send_va_profile_email_status(self, notification_data: dict) -> None:
"""
This method sends notification status data to VA Profile. This is part of our integration to help VA Profile
Expand Down
14 changes: 11 additions & 3 deletions tests/app/va/va_profile/test_va_profile_client_for_profile_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from app.va.identifier import IdentifierType, OIDS, transform_to_fhir_format
from app.va.va_profile.exceptions import (
NoContactInfoException,
InvalidPhoneNumberException,
VAProfileIDNotFoundException,
VAProfileNonRetryableException,
VAProfileRetryableException,
Expand Down Expand Up @@ -233,7 +234,14 @@ def test_has_valid_telephone_classification(self, mock_va_profile_client, classi
if classification_code is None:
telephone_instance.pop('classification')

assert mock_va_profile_client.has_valid_mobile_telephone_classification(telephone_instance) is expected
mock_contact_info = {'vaProfileId': 'test', 'txAuditId': '1234'}
if expected:
assert mock_va_profile_client.has_valid_mobile_telephone_classification(
telephone_instance, mock_contact_info
)
else:
with pytest.raises(InvalidPhoneNumberException):
mock_va_profile_client.has_valid_mobile_telephone_classification(telephone_instance, mock_contact_info)


class TestVAProfileClientExceptionHandling:
Expand Down Expand Up @@ -271,7 +279,7 @@ def test_get_telephone_raises_NoContactInfoException_if_no_mobile_telephones_exi
with pytest.raises(NoContactInfoException):
mock_va_profile_client.get_telephone_with_permission(recipient_identifier, sample_notification())

def test_get_telephone_raises_NoContactInfoException_if_number_classified_as_not_mobile(
def test_get_telephone_raises_InvalidPhoneNumberException_if_number_classified_as_not_mobile(
self, rmock, mock_va_profile_client, mock_response, recipient_identifier, url, mocker, sample_notification
):
mock_feature_flag(mocker, FeatureFlag.VA_PROFILE_V3_IDENTIFY_MOBILE_TELEPHONE_NUMBERS, 'True')
Expand All @@ -282,7 +290,7 @@ def test_get_telephone_raises_NoContactInfoException_if_number_classified_as_not
mock_response['profile']['contactInformation']['telephones'] = telephones
rmock.post(url, json=mock_response, status_code=200)

with pytest.raises(NoContactInfoException):
with pytest.raises(InvalidPhoneNumberException):
mock_va_profile_client.get_telephone_with_permission(recipient_identifier, sample_notification())

def test_get_telephone_with_permission_prefers_user_specified_mobile_phone(
Expand Down

0 comments on commit f0d151d

Please sign in to comment.