def test_notification_organisation_pid(
        org_martigny, notification_availability_martigny):
    """Test organisation pid has been added during the indexing."""
    search = NotificationsSearch()
    pid = notification_availability_martigny.get('pid')
    notification = next(search.filter('term', pid=pid).scan())
    assert notification.organisation.pid == org_martigny.pid

    # test notification can_delete
    assert notification_availability_martigny.get_links_to_me() == {}
    assert notification_availability_martigny.can_delete
Exemple #2
0
def get_notifications(notification_type, processed=False, not_sent=False):
    """Returns specific notifications pids.

    :param notification_type: filter on the notification type.
    :param processed: filter on already processed notifications.
    :param not_sent: filter on not yet send notifications.
    :return a notification pid generator.
    """
    query = NotificationsSearch()\
        .filter('term', notification_type=notification_type) \
        .source('pid')
    if not not_sent:
        query = query.filter('bool',
                             must_not=[
                                 Q('exists', field='notification_sent'),
                                 Q('term', notification_sent=False)
                             ])
    if processed:
        query = query.filter('exists', field='process_date')
    else:
        query = query.filter('bool',
                             must_not=[Q('exists', field='process_date')])

    for hit in query.scan():
        yield hit.pid
Exemple #3
0
def test_notification_es_mapping(dummy_notification, loan_validated_martigny):
    """Test notification elasticsearch mapping."""

    search = NotificationsSearch()
    mapping = get_mapping(search.Meta.index)
    assert mapping

    notif = deepcopy(dummy_notification)
    validated_pid = loan_validated_martigny.get('pid')
    loan_ref = f'https://bib.rero.ch/api/loans/{validated_pid}'
    notif['context']['loan']['$ref'] = loan_ref
    Notification.create(notif, dbcommit=True, delete_pid=True, reindex=True)
    assert mapping == get_mapping(search.Meta.index)
Exemple #4
0
def number_of_notifications_sent(loan,
                                 notification_type=NotificationType.OVERDUE):
    """Get the number of notifications sent for the given loan.

    :param loan: the parent loan.
    :param notification_type: the type of notification to find.
    :return notification counter.
    """
    trans_date = ciso8601.parse_datetime(loan.get('transaction_date'))
    return NotificationsSearch()\
        .filter('term', context__loan__pid=loan.pid)\
        .filter('term', notification_type=notification_type) \
        .filter('term', notification_sent=True) \
        .filter('range', creation_date={'gt': trans_date}) \
        .source().count()
Exemple #5
0
def test_notification_es_mapping(dummy_notification, loan_validated_martigny):
    """Test notification elasticsearch mapping."""

    search = NotificationsSearch()
    mapping = get_mapping(search.Meta.index)
    assert mapping

    notif = deepcopy(dummy_notification)
    notif_data = {
        'loan_url': 'https://ils.rero.ch/api/loans/',
        'pid': loan_validated_martigny.get('pid')
    }
    loan_ref = '{loan_url}{pid}'.format(**notif_data)
    notif['loan'] = {"$ref": loan_ref}

    Notification.create(notif, dbcommit=True, delete_pid=True, reindex=True)

    assert mapping == get_mapping(search.Meta.index)
Exemple #6
0
def get_notification(loan, notification_type):
    """Returns specific notification from loan.

    :param loan: the parent loan.
    :param notification_type: the type of notification sent.
    """
    from .api import Notification
    results = NotificationsSearch()\
        .filter('term', context__loan__pid=loan.pid)\
        .filter('term', notification_type=notification_type) \
        .params(preserve_order=True) \
        .sort({'creation_date': {"order": "desc"}}) \
        .source().scan()
    try:
        pid = next(results).pid
        return Notification.get_record_by_pid(pid)
    except StopIteration:
        return None
Exemple #7
0
def test_reminder_notifications_after_extend(
    item_lib_martigny, patron_martigny, loc_public_martigny,
    librarian_martigny, circulation_policies, mailbox, client
):
    """Test any reminder notification could be resend after loan extension."""

    # STEP 1 - CREATE BASIC RESOURCES FOR THE TEST
    #   * Create a loan and update it to be considerate as "due soon".
    #   * Run the `notification-creation` task to create a DUE_SOON
    #     notification
    params = {
        'patron_pid': patron_martigny.pid,
        'transaction_location_pid': loc_public_martigny.pid,
        'transaction_user_pid': librarian_martigny.pid,
        'pickup_location_pid': loc_public_martigny.pid
    }
    item, loan = item_record_to_a_specific_loan_state(
        item=item_lib_martigny,
        loan_state=LoanState.ITEM_ON_LOAN,
        params=params, copy_item=True)

    # get the related cipo and check than an due_soon reminder exists
    cipo = get_circ_policy(loan)
    due_soon_reminder = cipo.get_reminder(DUE_SOON_REMINDER_TYPE)
    assert due_soon_reminder

    # Update the loan
    delay = due_soon_reminder.get('days_delay') - 1
    due_soon_date = datetime.now() - timedelta(days=delay)
    end_date = datetime.now() + timedelta(days=1)
    loan['due_soon_date'] = due_soon_date.astimezone(pytz.utc).isoformat()
    loan['end_date'] = end_date.astimezone(pytz.utc).isoformat()
    loan = loan.update(loan, dbcommit=True, reindex=True)
    assert loan.is_loan_due_soon()

    # run the create notification task and process notification.
    mailbox.clear()
    create_notifications(types=[NotificationType.DUE_SOON])
    process_notifications(NotificationType.DUE_SOON)

    first_notification = get_notification(loan, NotificationType.DUE_SOON)
    assert first_notification \
           and first_notification['status'] == NotificationStatus.DONE
    assert len(mailbox) == 1
    counter = NotificationsSearch()\
        .filter('term', context__loan__pid=loan.pid)\
        .filter('term', notification_type=NotificationType.DUE_SOON)\
        .count()
    assert counter == 1

    # STEP 2 - CHECK NOTIFICATIONS CREATION
    #   Run the `create_notification` task for DUE_SOON notification type.
    #   As a notification already exists, no new DUE_SOON#1 notifications
    #   should be created
    create_notifications(types=[NotificationType.DUE_SOON])
    query = NotificationsSearch() \
        .filter('term', context__loan__pid=loan.pid) \
        .filter('term', notification_type=NotificationType.DUE_SOON) \
        .source('pid').scan()
    notification_pids = [hit.pid for hit in query]
    assert len(notification_pids) == 1
    assert notification_pids[0] == first_notification.pid

    # STEP 3 - EXTEND THE LOAN
    #   * User has received the DUE_SOON message and extend the loan.
    #   * Get the new 'due_soon_date' it will be used later to create
    #     notifications
    login_user_via_session(client, librarian_martigny.user)
    params = dict(
        item_pid=item.pid,
        transaction_user_pid=librarian_martigny.pid,
        transaction_location_pid=loc_public_martigny.pid
    )
    res, _ = postdata(client, 'api_item.extend_loan', params)
    assert res.status_code == 200
    loan = Loan.get_record_by_pid(loan.pid)
    due_soon_date = ciso8601.parse_datetime(loan.get('due_soon_date'))

    # STEP 4 - CHECK NOTIFICATIONS CREATION
    #    Run again the `create_notification` task, again for DUE_SOON
    #    notification type. As the loan is extended, a new DUE_SOON
    #    notification should be created about this loan.
    #    Process the notification, check that this new notification isn't
    #    cancelled and well processed.
    process_date = due_soon_date + timedelta(days=1)
    create_notifications(
        types=[NotificationType.DUE_SOON],
        tstamp=process_date
    )
    counter = NotificationsSearch() \
        .filter('term', context__loan__pid=loan.pid) \
        .filter('term', notification_type=NotificationType.DUE_SOON) \
        .count()
    assert counter == 2
    process_notifications(NotificationType.DUE_SOON)
    assert len(mailbox) == 2
    second_notification = get_notification(loan, NotificationType.DUE_SOON)
    assert second_notification \
           and second_notification['status'] == NotificationStatus.DONE
    assert second_notification.pid != first_notification