def test_items_extend(client, librarian_martigny_no_email,
                      patron_martigny_no_email, loc_public_martigny,
                      item_type_standard_martigny, item_lib_martigny,
                      json_header, circulation_policies):
    """Test item renewal."""
    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
    location = loc_public_martigny
    # 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_pid = actions[LoanAction.CHECKOUT].get('pid')
    assert not item.get_extension_count()

    # extend loan
    res, data = postdata(client, 'api_item.extend_loan',
                         dict(item_pid=item_pid, pid=loan_pid))
    assert res.status_code == 200
    item_data = data.get('metadata')
    actions = data.get('action_applied')
    assert item_data.get('status') == ItemStatus.ON_LOAN
    assert actions.get(LoanAction.EXTEND)
    assert item.get_extension_count() == 1

    # Get library timezone
    lib = Library.get_record_by_pid(item.library_pid)
    lib_tz = lib.get_timezone()

    # test renewal due date hour
    extended_loan = Loan.get_record_by_pid(loan_pid)
    end_date = ciso8601.parse_datetime(extended_loan.get('end_date'))
    check_timezone_date(lib_tz, end_date)

    # second extenion
    res, _ = postdata(client, 'api_item.extend_loan',
                      dict(item_pid=item_pid, pid=loan_pid))
    assert res.status_code == 403

    # checkin
    res, _ = postdata(client, 'api_item.checkin',
                      dict(item_pid=item_pid, pid=loan_pid))
    assert res.status_code == 200
Exemple #2
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
Exemple #3
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])
Exemple #4
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)