def test_should_throw_error_when_invalid_type(self):
     recipient_identifier = RecipientIdentifier(notification_id="123456",
                                                id_type="unknown_type",
                                                id_value="123")
     with pytest.raises(UnsupportedIdentifierException) as e:
         transform_to_fhir_format(recipient_identifier)
     assert "No identifier of type" in str(e.value)
    def test_should_transform_recipient_identifier_to_mpi_acceptable_format(
            self, id_type, id_value, expected_fhir_format):
        recipient_identifier = RecipientIdentifier(notification_id="123456",
                                                   id_type=id_type.value,
                                                   id_value=id_value)
        actual_fhir_format = transform_to_fhir_format(recipient_identifier)

        assert actual_fhir_format == expected_fhir_format
def lookup_va_profile_id(self, notification_id):
    current_app.logger.info(
        f"Retrieving VA Profile ID from MPI for notification {notification_id}"
    )
    notification = notifications_dao.get_notification_by_id(notification_id)

    try:
        va_profile_id = mpi_client.get_va_profile_id(notification)
        notification.recipient_identifiers.set(
            RecipientIdentifier(notification_id=notification.id,
                                id_type=IdentifierType.VA_PROFILE_ID.value,
                                id_value=va_profile_id))
        notifications_dao.dao_update_notification(notification)
        current_app.logger.info(
            f"Successfully updated notification {notification_id} with VA PROFILE ID {va_profile_id}"
        )

    except MpiRetryableException as e:
        current_app.logger.warning(
            f"Received {str(e)} for notification {notification_id}.")
        try:
            self.retry(queue=QueueNames.RETRY)
        except self.MaxRetriesExceededError:
            message = "RETRY FAILED: Max retries reached. " \
                      f"The task lookup_va_profile_id failed for notification {notification_id}. " \
                      "Notification has been updated to technical-failure"

            notifications_dao.update_notification_status_by_id(
                notification_id,
                NOTIFICATION_TECHNICAL_FAILURE,
                status_reason=e.failure_reason)
            raise NotificationTechnicalFailureException(message) from e

    except (BeneficiaryDeceasedException, IdentifierNotFound,
            MultipleActiveVaProfileIdsException) as e:
        message = f"{e.__class__.__name__} - {str(e)}: " \
                  f"Can't proceed after querying MPI for VA Profile ID for {notification_id}. " \
                  "Stopping execution of following tasks. Notification has been updated to permanent-failure."
        current_app.logger.warning(message)
        self.request.chain = None
        notifications_dao.update_notification_status_by_id(
            notification_id,
            NOTIFICATION_PERMANENT_FAILURE,
            status_reason=e.failure_reason)

    except Exception as e:
        message = f"Failed to retrieve VA Profile ID from MPI for notification: {notification_id} " \
                  "Notification has been updated to technical-failure"
        current_app.logger.exception(message)

        status_reason = e.failure_reason if hasattr(
            e, 'failure_reason') else 'Unknown error from MPI'
        notifications_dao.update_notification_status_by_id(
            notification_id,
            NOTIFICATION_TECHNICAL_FAILURE,
            status_reason=status_reason)
        raise NotificationTechnicalFailureException(message) from e
def notification():
    recipient_identifier = RecipientIdentifier(
        notification_id=notification_id,
        id_type=IdentifierType.VA_PROFILE_ID.value,
        id_value=EXAMPLE_VA_PROFILE_ID
    )

    notification = Notification(id=notification_id)
    notification.recipient_identifiers.set(recipient_identifier)
    notification.notification_type = LETTER_TYPE

    return notification
Exemple #5
0
def sample_recipient_identifier(identifier_type=None, notification_id=None):
    if isinstance(identifier_type, IdentifierType):
        id_type = identifier_type.value
    elif identifier_type:
        id_type = identifier_type
    else:
        id_type = random.choice(IdentifierType.values())  # nosec
    id_value = get_random_alphanumeric_string()
    _notification_id = notification_id if notification_id else uuid4()
    return RecipientIdentifier(notification_id=_notification_id,
                               id_type=id_type,
                               id_value=id_value)
 def test_should_throw_error_when_no_mapping_for_type(self, mocker):
     mock_identifier = mocker.Mock(IdentifierType)
     mock_identifier.name = "MOCKED_IDENTIFIER"
     mock_identifier.value = "mocked_value"
     mocker.patch("app.va.identifier.IdentifierType",
                  return_value=mock_identifier)
     recipient_identifier = RecipientIdentifier(
         notification_id="123456",
         id_type=mock_identifier.name,
         id_value=mock_identifier.value)
     with pytest.raises(UnsupportedIdentifierException) as e:
         transform_to_fhir_format(recipient_identifier)
     assert "No mapping for identifier" in str(e.value)
def persist_notification(*,
                         template_id,
                         template_version,
                         recipient=None,
                         service,
                         personalisation,
                         notification_type,
                         api_key_id,
                         key_type,
                         created_at=None,
                         job_id=None,
                         job_row_number=None,
                         reference=None,
                         client_reference=None,
                         notification_id=None,
                         simulated=False,
                         created_by_id=None,
                         status=NOTIFICATION_CREATED,
                         reply_to_text=None,
                         billable_units=None,
                         postage=None,
                         template_postage=None,
                         recipient_identifier=None):
    notification_created_at = created_at or datetime.utcnow()
    if not notification_id:
        notification_id = uuid.uuid4()
    notification = Notification(id=notification_id,
                                template_id=template_id,
                                template_version=template_version,
                                to=recipient,
                                service_id=service.id,
                                service=service,
                                personalisation=personalisation,
                                notification_type=notification_type,
                                api_key_id=api_key_id,
                                key_type=key_type,
                                created_at=notification_created_at,
                                job_id=job_id,
                                job_row_number=job_row_number,
                                client_reference=client_reference,
                                reference=reference,
                                created_by_id=created_by_id,
                                status=status,
                                reply_to_text=reply_to_text,
                                billable_units=billable_units)
    if accept_recipient_identifiers_enabled() and recipient_identifier:
        _recipient_identifier = RecipientIdentifier(
            notification_id=notification_id,
            id_type=recipient_identifier['id_type'],
            id_value=recipient_identifier['id_value'])
        notification.recipient_identifiers.set(_recipient_identifier)

    if notification_type == SMS_TYPE and notification.to:
        formatted_recipient = validate_and_format_phone_number(
            recipient, international=True)
        recipient_info = get_international_phone_info(formatted_recipient)
        notification.normalised_to = formatted_recipient
        notification.international = recipient_info.international
        notification.phone_prefix = recipient_info.country_prefix
        notification.rate_multiplier = recipient_info.billable_units
    elif notification_type == EMAIL_TYPE and notification.to:
        notification.normalised_to = format_email_address(notification.to)
    elif notification_type == LETTER_TYPE:
        notification.postage = postage or template_postage

    # if simulated create a Notification model to return but do not persist the Notification to the dB
    if not simulated:
        dao_create_notification(notification)
        if key_type != KEY_TYPE_TEST:
            if redis_store.get(redis.daily_limit_cache_key(service.id)):
                redis_store.incr(redis.daily_limit_cache_key(service.id))

        current_app.logger.info("{} {} created at {}".format(
            notification_type, notification_id, notification_created_at))
    return notification
Exemple #8
0
def create_notification(
        template=None,
        job=None,
        job_row_number=None,
        to_field=None,
        status='created',
        reference=None,
        created_at=None,
        sent_at=None,
        updated_at=None,
        billable_units=1,
        personalisation=None,
        api_key=None,
        key_type=KEY_TYPE_NORMAL,
        sent_by=None,
        client_reference=None,
        rate_multiplier=None,
        international=False,
        phone_prefix=None,
        scheduled_for=None,
        normalised_to=None,
        one_off=False,
        reply_to_text=None,
        created_by_id=None,
        postage=None,
        recipient_identifiers=None
):
    assert job or template
    if job:
        template = job.template

    if created_at is None:
        created_at = datetime.utcnow()

    if to_field is None:
        to_field = '+16502532222' if template.template_type == SMS_TYPE else '*****@*****.**'

    if status != 'created':
        sent_at = sent_at or datetime.utcnow()
        updated_at = updated_at or datetime.utcnow()

    if not one_off and (job is None and api_key is None):
        # we didn't specify in test - lets create it
        api_key = ApiKey.query.filter(ApiKey.service == template.service, ApiKey.key_type == key_type).first()
        if not api_key:
            api_key = create_api_key(template.service, key_type=key_type)

    if template.template_type == 'letter' and postage is None:
        postage = 'second'

    data = {
        'id': uuid.uuid4(),
        'to': to_field,
        'job_id': job and job.id,
        'job': job,
        'service_id': template.service.id,
        'service': template.service,
        'template_id': template.id,
        'template_version': template.version,
        'status': status,
        'reference': reference,
        'created_at': created_at,
        'sent_at': sent_at,
        'billable_units': billable_units,
        'personalisation': personalisation,
        'notification_type': template.template_type,
        'api_key': api_key,
        'api_key_id': api_key and api_key.id,
        'key_type': api_key.key_type if api_key else key_type,
        'sent_by': sent_by,
        'updated_at': updated_at,
        'client_reference': client_reference,
        'job_row_number': job_row_number,
        'rate_multiplier': rate_multiplier,
        'international': international,
        'phone_prefix': phone_prefix,
        'normalised_to': normalised_to,
        'reply_to_text': reply_to_text,
        'created_by_id': created_by_id,
        'postage': postage
    }
    notification = Notification(**data)

    if recipient_identifiers:
        for recipient_identifier in recipient_identifiers:
            _recipient_identifier = RecipientIdentifier(
                notification_id=notification.id,
                id_type=recipient_identifier['id_type'],
                id_value=recipient_identifier['id_value']
            )
            notification.recipient_identifiers.set(_recipient_identifier)

    dao_create_notification(notification)
    if scheduled_for:
        scheduled_notification = ScheduledNotification(id=uuid.uuid4(),
                                                       notification_id=notification.id,
                                                       scheduled_for=datetime.strptime(scheduled_for,
                                                                                       "%Y-%m-%d %H:%M"))
        if status != 'created':
            scheduled_notification.pending = False
        dao_created_scheduled_notification(scheduled_notification)

    return notification