示例#1
0
def test_checkout_temporary_item_type(client, librarian_martigny, lib_martigny,
                                      loc_public_martigny, patron_martigny,
                                      item_lib_martigny,
                                      item_type_on_site_martigny,
                                      circ_policy_short_martigny,
                                      circ_policy_default_martigny):
    """Test checkout or item with temporary item_types"""
    login_user_via_session(client, librarian_martigny.user)
    item = item_lib_martigny
    assert item.status == ItemStatus.ON_SHELF

    # test basic behavior
    cipo_used = CircPolicy.provide_circ_policy(
        lib_martigny.organisation_pid, lib_martigny.pid,
        patron_martigny.patron_type_pid,
        item.item_type_circulation_category_pid)
    assert cipo_used == circ_policy_short_martigny

    # add a temporary_item_type on item
    #   due to this change, the cipo used during circulation operation should
    #   be different from the first cipo found.
    item['temporary_item_type'] = {
        '$ref': get_ref_for_pid('itty', item_type_on_site_martigny.pid)
    }
    item = item.update(data=item, dbcommit=True, reindex=True)
    cipo_tmp_used = CircPolicy.provide_circ_policy(
        lib_martigny.organisation_pid, lib_martigny.pid,
        patron_martigny.patron_type_pid,
        item.item_type_circulation_category_pid)
    assert cipo_tmp_used == circ_policy_default_martigny

    delta = timedelta(cipo_tmp_used.get('checkout_duration'))
    expected_date = datetime.now() + delta
    expected_dates = [expected_date, lib_martigny.next_open(expected_date)]
    expected_dates = [d.strftime('%Y-%m-%d') for d in expected_dates]

    # try a checkout and check the transaction end_date is related to the cipo
    # corresponding to the temporary item_type
    params = dict(item_pid=item.pid,
                  patron_pid=patron_martigny.pid,
                  transaction_user_pid=librarian_martigny.pid,
                  transaction_location_pid=loc_public_martigny.pid)
    res, data = postdata(client, 'api_item.checkout', params)
    assert res.status_code == 200
    transaction_end_date = data['action_applied']['checkout']['end_date']
    transaction_end_date = ciso8601.parse_datetime(transaction_end_date).date()
    transaction_end_date = transaction_end_date.strftime('%Y-%m-%d')
    assert transaction_end_date in expected_dates

    # reset the item to original value
    del item['temporary_item_type']
    item.update(data=item, dbcommit=True, reindex=True)
示例#2
0
def test_checkout_default_policy(client, lib_martigny,
                                 librarian_martigny_no_email,
                                 patron_martigny_no_email, loc_public_martigny,
                                 item_type_standard_martigny,
                                 item_lib_martigny, json_header,
                                 circulation_policies):
    """Test circ policy parameters"""
    login_user_via_session(client, librarian_martigny_no_email.user)
    item = item_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny_no_email.pid

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1',
                                                 'itty1')

    # checkout
    res, data = postdata(client, 'api_item.checkout',
                         dict(item_pid=item_pid, patron_pid=patron_pid))
    assert res.status_code == 200

    actions = data.get('action_applied')
    loan = actions[LoanAction.CHECKOUT]
    end_date = loan.get('end_date')
    start_date = loan.get('start_date')
    checkout_duration = (ciso8601.parse_datetime(end_date) -
                         ciso8601.parse_datetime(start_date)).days

    assert checkout_duration >= circ_policy.get('checkout_duration')

    # checkin
    res, _ = postdata(client, 'api_item.checkin',
                      dict(item_pid=item_pid, pid=loan.get('pid')))
    assert res.status_code == 200
def test_circ_policy_search(app, circulation_policies):
    """Test finding a circulation policy."""
    data = [{
        'library_pid': 'lib1',
        'patron_type_pid': 'ptty1',
        'item_type_pid': 'itty1',
        'cipo': 'cipo2'
    }, {
        'library_pid': 'lib1',
        'patron_type_pid': 'ptty2',
        'item_type_pid': 'itty2',
        'cipo': 'cipo3'
    }, {
        'library_pid': 'lib2',
        'patron_type_pid': 'ptty2',
        'item_type_pid': 'itty2',
        'cipo': 'cipo1'
    }, {
        'library_pid': 'lib1',
        'patron_type_pid': 'ptty3',
        'item_type_pid': 'itty2',
        'cipo': 'cipo1'
    }, {
        'library_pid': 'lib1',
        'patron_type_pid': 'ptty1',
        'item_type_pid': 'itty2',
        'cipo': 'cipo1'
    }]
    for row in data:
        cipo = CircPolicy.provide_circ_policy(row['library_pid'],
                                              row['patron_type_pid'],
                                              row['item_type_pid'])
        assert cipo.pid == row['cipo']
示例#4
0
def test_item_possible_actions(client, item_on_shelf, user_librarian_no_email,
                               user_patron_no_email):
    """Possible action changes according to params of cipo"""
    login_user_via_session(client, user_librarian_no_email.user)
    item = item_on_shelf
    patron_pid = user_patron_no_email.pid
    res = client.get(
        url_for('api_item.item',
                item_barcode=item.get('barcode'),
                patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)

    actions = data.get('metadata').get('item').get('actions')
    assert 'checkout' in actions

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1',
                                                 'itty1')

    circ_policy['allow_checkout'] = False
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    res = client.get(
        url_for('api_item.item',
                item_barcode=item.get('barcode'),
                patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)

    actions = data.get('metadata').get('item').get('actions')
    assert 'checkout' not in actions

    circ_policy['allow_checkout'] = True
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    assert circ_policy['allow_checkout']
def test_due_soon_loans(client, librarian_martigny_no_email,
                        patron_martigny_no_email, loc_public_martigny,
                        item_type_standard_martigny, item_lib_martigny,
                        json_header, circ_policy_short_martigny):
    """Test overdue loans."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    item = item_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny_no_email.pid

    assert not item.is_loaned_to_patron(
        patron_martigny_no_email.get('barcode'))
    assert item.can_delete
    assert item.available

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(
        item.library_pid, patron_martigny_no_email.patron_type_pid,
        item.item_type_pid)
    circ_policy['number_of_days_before_due_date'] = 7
    circ_policy['checkout_duration'] = 3
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)

    # checkout
    res = client.post(
        url_for('api_item.checkout'),
        data=json.dumps(dict(item_pid=item_pid, patron_pid=patron_pid)),
        content_type='application/json',
    )
    assert res.status_code == 200
    data = get_json(res)
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')
    due_soon_loans = get_due_soon_loans()
    assert due_soon_loans[0].get('pid') == loan_pid

    # test due date hour
    checkout_loan = Loan.get_record_by_pid(loan_pid)

    end_date = ciso8601.parse_datetime(checkout_loan.get('end_date'))
    assert end_date.minute == 59 and end_date.hour == 23

    new_timezone = pytz.timezone('US/Pacific')
    end_date = ciso8601.parse_datetime(
        checkout_loan.get('end_date')).astimezone(new_timezone)
    assert end_date.minute == 59 and end_date.hour != 23

    new_timezone = pytz.timezone('Europe/Amsterdam')
    end_date = ciso8601.parse_datetime(
        checkout_loan.get('end_date')).astimezone(new_timezone)
    assert end_date.minute == 59 and end_date.hour != 23

    # checkin the item to put it back to it's original state
    res = client.post(
        url_for('api_item.checkin'),
        data=json.dumps(dict(item_pid=item_pid, pid=loan_pid)),
        content_type='application/json',
    )
    assert res.status_code == 200
示例#6
0
def test_extend_possible_actions(client, item_lib_martigny,
                                 loc_public_martigny,
                                 librarian_martigny_no_email,
                                 patron_martigny_no_email,
                                 circ_policy_short_martigny):
    """Extend action changes according to params of cipo."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    item = item_lib_martigny
    patron_pid = patron_martigny_no_email.pid
    res, _ = postdata(
        client, 'api_item.checkout',
        dict(item_pid=item.pid,
             patron_pid=patron_pid,
             transaction_user_pid=librarian_martigny_no_email.pid,
             transaction_location_pid=loc_public_martigny.pid))

    # check the item is now in patron loaned item
    res = client.get(url_for('api_item.loans', patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)
    assert data['hits']['total']['value'] == 1
    hit = data.get('hits').get('hits')[0].get('item')
    assert hit.get('barcode') == item.get('barcode')

    # check the item can be checked-in
    res = client.get(url_for('api_item.item',
                             item_barcode=item.get('barcode')))
    assert res.status_code == 200
    data = get_json(res)
    actions = data.get('metadata').get('item').get('actions', [])
    assert 'checkin' in actions

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1',
                                                 'itty1')
    circ_policy['number_renewals'] = 0
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    res = client.get(url_for('api_item.item',
                             item_barcode=item.get('barcode')))
    assert res.status_code == 200
    data = get_json(res)
    actions = data.get('metadata').get('item').get('actions', [])
    assert 'extend_loan' not in actions
    assert 'checkin' in actions

    # reset used objects
    loan_pid = data.get('metadata').get('loan').get('pid')
    res, _ = postdata(
        client, 'api_item.checkin',
        dict(item_pid=item.pid,
             pid=loan_pid,
             transaction_user_pid=librarian_martigny_no_email.pid,
             transaction_location_pid=loc_public_martigny.pid))
    assert res.status_code == 200
    circ_policy['number_renewals'] = 1
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    assert circ_policy['number_renewals'] == 1
示例#7
0
def test_due_soon_loans(client, librarian_martigny, patron_martigny,
                        loc_public_martigny, item_type_standard_martigny,
                        item_lib_martigny, circ_policy_short_martigny):
    """Test overdue loans."""
    login_user_via_session(client, librarian_martigny.user)
    item = item_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny.pid

    assert not get_last_transaction_loc_for_item(item_pid)

    assert not item.patron_has_an_active_loan_on_item(patron_martigny)
    assert item.can_delete
    assert item.available

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(
        item.organisation_pid, item.library_pid,
        patron_martigny.patron_type_pid, item.item_type_pid)
    circ_policy['reminders'][0]['days_delay'] = 7
    circ_policy['checkout_duration'] = 3
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)

    # checkout
    res, data = postdata(
        client, 'api_item.checkout',
        dict(
            item_pid=item_pid,
            patron_pid=patron_pid,
            transaction_location_pid=loc_public_martigny.pid,
            transaction_user_pid=librarian_martigny.pid,
        ))
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')
    due_soon_loans = get_due_soon_loans()
    assert due_soon_loans[0].get('pid') == loan_pid

    # test due date regarding multiple timezones
    checkout_loan = Loan.get_record_by_pid(loan_pid)
    loan_date = ciso8601.parse_datetime(checkout_loan.get('end_date'))

    # as instance timezone is Europe/Zurich, it should be either 21 or 22
    check_timezone_date(pytz.utc, loan_date, [21, 22])

    # should be 14:59/15:59 in US/Pacific (because of daylight saving time)

    check_timezone_date(pytz.timezone('US/Pacific'), loan_date, [14, 15])
    check_timezone_date(pytz.timezone('Europe/Amsterdam'), loan_date)

    # checkin the item to put it back to it's original state
    res, _ = postdata(
        client, 'api_item.checkin',
        dict(item_pid=item_pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_martigny.pid,
             transaction_user_pid=librarian_martigny.pid))
    assert res.status_code == 200
def test_circ_policy_search(
    app,
    circ_policy,
    circ_policy_short,
    circ_policy_short_library
):
    """Test Find circ policy"""
    data = [
        {
            'library_pid': 'lib1',
            'patron_type_pid': 'ptty1',
            'item_type_pid': 'itty1',
            'cipo': 'cipo2'

        },
        {
            'library_pid': 'lib1',
            'patron_type_pid': 'ptty2',
            'item_type_pid': 'itty2',
            'cipo': 'cipo3'

        },
        {
            'library_pid': 'lib2',
            'patron_type_pid': 'ptty2',
            'item_type_pid': 'itty2',
            'cipo': 'cipo1'
        },
        {
            'library_pid': 'lib1',
            'patron_type_pid': 'ptty3',
            'item_type_pid': 'itty2',
            'cipo': 'cipo1'

        },
        {
            'library_pid': 'lib1',
            'patron_type_pid': 'ptty1',
            'item_type_pid': 'itty2',
            'cipo': 'cipo1'

        }
    ]
    for row in data:
        cipo = CircPolicy.provide_circ_policy(
            row['library_pid'],
            row['patron_type_pid'],
            row['item_type_pid']
        )
        assert cipo.pid == row['cipo']
示例#9
0
def test_extend_possible_actions(client, item_lib_martigny,
                                 librarian_martigny_no_email,
                                 patron_martigny_no_email,
                                 circ_policy_short_martigny):
    """Extend action changes according to params of cipo."""
    login_user_via_session(client, librarian_martigny_no_email.user)
    circ_policy = circ_policy_short_martigny
    item = item_lib_martigny
    patron_pid = patron_martigny_no_email.pid
    res = client.post(
        url_for('api_item.checkout'),
        data=json.dumps(dict(item_pid=item.pid, patron_pid=patron_pid)),
        content_type='application/json',
    )

    res = client.get(url_for('api_item.loans', patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)
    assert data.get('hits').get('total') == 1
    actions = data.get('hits').get('hits')[0].get('item').get('actions')
    assert 'checkin' in actions

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(item.library_pid, 'ptty1',
                                                 'itty1')

    circ_policy['number_renewals'] = 0
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    res = client.get(url_for('api_item.loans', patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)
    assert data.get('hits').get('total') == 1
    actions = data.get('hits').get('hits')[0].get('item').get('actions')
    assert 'extend_loan' not in actions
    assert 'checkin' in actions
    loan_pid = data.get('hits').get('hits')[0].get('loan').get('pid')
    # reset used objects
    res = client.post(
        url_for('api_item.checkin'),
        data=json.dumps(dict(item_pid=item.pid, pid=loan_pid)),
        content_type='application/json',
    )
    assert res.status_code == 200

    circ_policy['number_renewals'] = 1
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    assert circ_policy['number_renewals'] == 1
示例#10
0
def test_item_possible_actions(client, item_lib_martigny, librarian_martigny,
                               patron_martigny, circulation_policies):
    """Possible action changes according to params of cipo."""
    login_user_via_session(client, librarian_martigny.user)
    item = item_lib_martigny
    patron_pid = patron_martigny.pid
    res = client.get(
        url_for('api_item.item',
                item_barcode=item.get('barcode'),
                patron_pid=patron_pid))
    data = get_json(res)
    assert res.status_code == 200

    actions = data.get('metadata').get('item').get('actions')
    assert 'checkout' in actions

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(item.organisation_pid,
                                                 item.library_pid, 'ptty1',
                                                 'itty1')

    original_checkout_duration = circ_policy.get('checkout_duration')
    if original_checkout_duration is not None:
        del circ_policy['checkout_duration']
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    res = client.get(
        url_for('api_item.item',
                item_barcode=item.get('barcode'),
                patron_pid=patron_pid))
    assert res.status_code == 200
    data = get_json(res)

    actions = data.get('metadata').get('item').get('actions')
    assert 'checkout' not in actions

    if original_checkout_duration is not None:
        circ_policy['checkout_duration'] = original_checkout_duration
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)
    assert circ_policy.can_checkout
示例#11
0
文件: api.py 项目: zannkukai/rero-ils
 def can_extend(cls, item, **kwargs):
     """Loan can extend."""
     from rero_ils.modules.loans.utils import extend_loan_data_is_valid
     if 'loan' not in kwargs:  # this method is not relevant
         return True, []
     loan = kwargs['loan']
     if loan.get('state') != LoanState.ITEM_ON_LOAN:
         return False, [_('The loan cannot be extended')]
     patron = Patron.get_record_by_pid(loan.get('patron_pid'))
     cipo = CircPolicy.provide_circ_policy(
         item.organisation_pid, item.library_pid, patron.patron_type_pid,
         item.item_type_circulation_category_pid)
     extension_count = loan.get('extension_count', 0)
     if not (cipo.get('number_renewals', 0) > 0
             and extension_count < cipo.get('number_renewals', 0)
             and extend_loan_data_is_valid(loan.get('end_date'),
                                           cipo.get('renewal_duration'),
                                           item.library_pid)):
         return False, [_('Circulation policies disallows the operation.')]
     if item.number_of_requests():
         return False, [_('A pending request exists on this item.')]
     return True, []
示例#12
0
def item(item_barcode):
    """HTTP GET request for requested loans for a library item and patron."""
    item = Item.get_item_by_barcode(item_barcode,
                                    current_librarian.organisation_pid)
    if not item:
        abort(404)
    loan = get_loan_for_item(item_pid_to_object(item.pid))
    if loan:
        loan = Loan.get_record_by_pid(loan.get('pid')).dumps_for_circulation()
    item_dumps = item.dumps_for_circulation()
    patron_pid = flask_request.args.get('patron_pid')

    if patron_pid:
        patron = Patron.get_record_by_pid(patron_pid)
        organisation_pid = item.organisation_pid
        library_pid = item.library_pid
        patron_type_pid = patron.patron_type_pid
        item_type_pid = item.item_type_circulation_category_pid
        circ_policy = CircPolicy.provide_circ_policy(
            organisation_pid=organisation_pid,
            library_pid=library_pid,
            patron_type_pid=patron_type_pid,
            item_type_pid=item_type_pid)
        new_actions = []
        # If circulation policy doesn't allow checkout operation no need to
        # perform special check describe below.
        if circ_policy.can_checkout:
            for action in item_dumps.get('actions', []):
                if action == 'checkout':
                    if (item.number_of_requests() > 0
                            and item.patron_request_rank(patron) == 1
                            or item.number_of_requests() <= 0):
                        new_actions.append(action)
                elif action == 'receive' and item.number_of_requests() == 0:
                    new_actions.append('checkout')
        item_dumps['actions'] = new_actions
    return jsonify({'metadata': {'item': item_dumps, 'loan': loan}})
示例#13
0
def calculate_notification_amount(notification):
    """Return amount due for a notification.

    :param notification: the notification for which to compute the amount. At
                         this time, this is not yet a `Notification`, only a
                         dict of structured data.
    :return the amount due for this notification. 0 if no amount could be
            compute.
    """
    # Find the reminder type to use based on the notification that we would
    # sent. If no reminder type is found, then no amount could be calculated
    # and we can't return '0'
    notif_type = notification.get('notification_type')
    reminder_type_mapping = {
        NotificationType.DUE_SOON: DUE_SOON_REMINDER_TYPE,
        NotificationType.OVERDUE: OVERDUE_REMINDER_TYPE
    }
    reminder_type = reminder_type_mapping.get(notif_type)
    if not notif_type or not reminder_type:
        return 0

    # to find the notification due amount, we firstly need to get the
    # circulation policy linked to the parent loan.
    location_pid = notification.transaction_location_pid
    location = Location.get_record_by_pid(location_pid)
    cipo = CircPolicy.provide_circ_policy(
        location.organisation_pid, location.library_pid,
        notification.patron.patron_type_pid,
        notification.item.holding_circulation_category_pid)

    # now we get the circulation policy, search the correct reminder depending
    # of the reminder_counter from the notification context.
    reminder = cipo.get_reminder(reminder_type=reminder_type,
                                 idx=notification.get('context', {}).get(
                                     'reminder_counter', 0))
    return reminder.get('fee_amount', 0) if reminder else 0
示例#14
0
def test_timezone_due_date(client, librarian_martigny_no_email,
                           patron_martigny_no_email, loc_public_martigny,
                           item_type_standard_martigny,
                           item3_lib_martigny,
                           circ_policy_short_martigny,
                           lib_martigny):
    """Test that timezone affects due date regarding library location."""
    # Login to perform action
    login_user_via_session(client, librarian_martigny_no_email.user)

    # Close the library all days. Except Monday.
    del lib_martigny['opening_hours']
    del lib_martigny['exception_dates']
    lib_martigny['opening_hours'] = [
        {
            "day": "monday",
            "is_open": True,
            "times": [
                {
                    "start_time": "07:00",
                    "end_time": "19:00"
                }
            ]
        },
        {
            "day": "tuesday",
            "is_open": False,
            "times": []
        },
        {
            "day": "wednesday",
            "is_open": False,
            "times": []
        },
        {
            "day": "thursday",
            "is_open": False,
            "times": []
        },
        {
            "day": "friday",
            "is_open": False,
            "times": []
        },
        {
            "day": "saturday",
            "is_open": False,
            "times": []
        },
        {
            "day": "sunday",
            "is_open": False,
            "times": []
        }
    ]
    lib_martigny.update(lib_martigny, dbcommit=True, reindex=True)

    # Change circulation policy
    checkout_duration = 3
    item = item3_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny_no_email.pid
    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(
        item.library_pid,
        patron_martigny_no_email.patron_type_pid,
        item.item_type_pid
    )
    circ_policy['number_of_days_before_due_date'] = 7
    circ_policy['checkout_duration'] = checkout_duration
    circ_policy.update(
        circ_policy,
        dbcommit=True,
        reindex=True
    )

    # Checkout the item
    res, data = postdata(
        client,
        'api_item.checkout',
        dict(
            item_pid=item_pid,
            patron_pid=patron_pid,
            transaction_location_pid=loc_public_martigny.pid,
            transaction_user_pid=librarian_martigny_no_email.pid,
        )
    )
    assert res.status_code == 200

    # Get Loan date (should be in UTC)
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')
    loan = Loan.get_record_by_pid(loan_pid)
    loan_end_date = loan.get('end_date')

    # Get next library open date (should be next monday after X-1 days) where
    # X is checkout_duration
    soon = datetime.now(pytz.utc) + timedelta(days=(checkout_duration-1))
    lib = Library.get_record_by_pid(item.library_pid)
    lib_datetime = lib.next_open(soon)

    # Loan date should be in UTC (as lib_datetime).
    loan_datetime = ciso8601.parse_datetime(loan_end_date)

    # Compare year, month and date for Loan due date: should be the same!
    fail_msg = "Check timezone for Loan and Library. \
It should be the same date, even if timezone changed."
    assert loan_datetime.year == lib_datetime.year, fail_msg
    assert loan_datetime.month == lib_datetime.month, fail_msg
    assert loan_datetime.day == lib_datetime.day, fail_msg
    # Loan date differs regarding timezone, and day of the year (GMT+1/2).
    check_timezone_date(pytz.utc, loan_datetime, [21, 22])
示例#15
0
def test_due_soon_loans(client, librarian_martigny, lib_martigny_data,
                        lib_martigny, patron_martigny, loc_public_martigny,
                        item_type_standard_martigny, item_lib_martigny,
                        circ_policy_short_martigny, yesterday):
    """Test overdue loans."""
    login_user_via_session(client, librarian_martigny.user)
    item = item_lib_martigny
    item_pid = item.pid
    patron_pid = patron_martigny.pid
    can, reasons = item.can_delete
    assert can
    assert reasons == {}
    assert item.available
    assert not get_last_transaction_loc_for_item(item_pid)
    assert not item.patron_has_an_active_loan_on_item(patron_martigny)

    from rero_ils.modules.circ_policies.api import CircPolicy
    circ_policy = CircPolicy.provide_circ_policy(
        item.organisation_pid, item.library_pid,
        patron_martigny.patron_type_pid, item.item_type_pid)
    circ_policy['reminders'][0]['days_delay'] = 7
    circ_policy['checkout_duration'] = 3
    circ_policy.update(circ_policy, dbcommit=True, reindex=True)

    # Remove library exception date to ensure to not been annoyed by
    # closed dates.
    custom_lib_data = deepcopy(lib_martigny_data)
    custom_lib_data['exception_dates'] = []
    lib_martigny.update(custom_lib_data, dbcommit=True, reindex=True)
    flush_index(LibrariesSearch.Meta.index)

    # checkout
    res, data = postdata(
        client, 'api_item.checkout',
        dict(
            item_pid=item_pid,
            patron_pid=patron_pid,
            transaction_location_pid=loc_public_martigny.pid,
            transaction_user_pid=librarian_martigny.pid,
        ))
    assert res.status_code == 200
    loan_pid = data.get('action_applied')[LoanAction.CHECKOUT].get('pid')
    # To be considerate as 'due_soon', we need to update the loan start date
    # to figure than start_date occurs before due_date.
    loan = Loan.get_record_by_pid(loan_pid)
    start_date = ciso8601.parse_datetime(loan.get('start_date'))
    loan['start_date'] = (start_date - timedelta(days=30)).isoformat()
    loan.update(loan, dbcommit=True, reindex=True)

    due_soon_loans = list(get_due_soon_loans())
    assert due_soon_loans[0].get('pid') == loan_pid

    # test due date regarding multiple timezones
    checkout_loan = Loan.get_record_by_pid(loan_pid)
    loan_date = ciso8601.parse_datetime(checkout_loan.get('end_date'))

    # as instance timezone is Europe/Zurich, it should be either 21 or 22
    check_timezone_date(pytz.utc, loan_date, [21, 22])

    # should be 14:59/15:59 in US/Pacific (because of daylight saving time)
    check_timezone_date(pytz.timezone('US/Pacific'), loan_date, [14, 15])
    check_timezone_date(pytz.timezone('Europe/Amsterdam'), loan_date)

    # checkin the item to put it back to it's original state
    res, _ = postdata(
        client, 'api_item.checkin',
        dict(item_pid=item_pid,
             pid=loan_pid,
             transaction_location_pid=loc_public_martigny.pid,
             transaction_user_pid=librarian_martigny.pid))
    assert res.status_code == 200

    # reset lib
    lib_martigny.update(lib_martigny_data, dbcommit=True, reindex=True)