def test_circ_policy_exist_name_and_organisation_pid(circ_policy):
    """."""
    cipo = circ_policy.replace_refs()
    assert CircPolicy.exist_name_and_organisation_pid(
        cipo.get('name'), cipo.get('organisation', {}).get('pid'))
    assert not CircPolicy.exist_name_and_organisation_pid(
        'not exists yet', cipo.get('organisation', {}).get('pid'))
def test_circ_policy_create(
        circ_policy_martigny_data_tmp, org_martigny, lib_martigny, lib_saxon,
        patron_type_children_martigny, item_type_standard_martigny,
        patron_type_adults_martigny, item_type_specific_martigny,
        item_type_regular_sion, patron_type_youngsters_sion):
    """Test circulation policy creation."""
    cipo = CircPolicy.create(circ_policy_martigny_data_tmp, delete_pid=True)
    assert cipo == circ_policy_martigny_data_tmp
    assert cipo.get('pid') == '1'

    cipo = CircPolicy.get_record_by_pid('1')
    assert cipo == circ_policy_martigny_data_tmp

    fetched_pid = circ_policy_id_fetcher(cipo.id, cipo)
    assert fetched_pid.pid_value == '1'
    assert fetched_pid.pid_type == 'cipo'

    circ_policy = deepcopy(circ_policy_martigny_data_tmp)
    del circ_policy['$schema']
    cipo = CircPolicy.create(circ_policy, delete_pid=True)
    assert cipo.get('$schema')
    assert cipo.get('pid') == '2'

    cipo_data = {
        '$schema':
        'https://ils.rero.ch/schemas/'
        'circ_policies/circ_policy-v0.0.1.json',
        'pid':
        'cipo_test',
        'name':
        'test',
        'organisation': {
            '$ref': 'https://ils.rero.ch/api/organisations/org1'
        },
        'is_default':
        False,
        'allow_requests':
        True,
        'policy_library_level':
        False,
        'settings': [{
            'patron_type': {
                '$ref': 'https://ils.rero.ch/api/patron_types/ptty3'
            },
            'item_type': {
                '$ref': 'https://ils.rero.ch/api/item_types/itty1'
            }
        }, {
            'patron_type': {
                '$ref': 'https://ils.rero.ch/api/patron_types/ptty2'
            },
            'item_type': {
                '$ref': 'https://ils.rero.ch/api/item_types/itty4'
            }
        }]
    }
    with pytest.raises(RecordValidationError):
        cipo = CircPolicy.create(cipo_data, delete_pid=False)
def test_circ_policy_exist_name_and_organisation_pid(
        circ_policy_short_martigny):
    """Test policy name existence."""
    cipo = circ_policy_short_martigny.replace_refs()
    assert CircPolicy.exist_name_and_organisation_pid(
        cipo.get('name'),
        cipo.get('organisation', {}).get('pid'))
    assert not CircPolicy.exist_name_and_organisation_pid(
        'not exists yet',
        cipo.get('organisation', {}).get('pid'))
def test_circ_policy_es_mapping(es, db, org_martigny,
                                circ_policy_martigny_data_tmp):
    """Test circulation policy elasticsearch mapping."""
    search = CircPoliciesSearch()
    mapping = get_mapping(search.Meta.index)
    assert mapping
    CircPolicy.create(circ_policy_martigny_data_tmp,
                      dbcommit=True,
                      reindex=True,
                      delete_pid=True)
    assert mapping == get_mapping(search.Meta.index)
def test_circ_policy_es_mapping(es, db, organisation, circ_policy_data_tmp):
    """."""
    search = CircPoliciesSearch()
    mapping = get_mapping(search.Meta.index)
    assert mapping
    CircPolicy.create(
        circ_policy_data_tmp,
        dbcommit=True,
        reindex=True,
        delete_pid=True
    )
    assert mapping == get_mapping(search.Meta.index)
Exemple #6
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)
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']
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
Exemple #9
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']
Exemple #10
0
def circ_policy_default_sion(app, org_sion, circ_policy_default_sion_data):
    """Create default circ policy for organisation sion."""
    cipo = CircPolicy.create(data=circ_policy_default_sion_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
def test_circ_policy_can_delete(app, circ_policy_martigny_data_tmp):
    """Test can delete a policy."""
    circ_policy_martigny_data_tmp['is_default'] = False
    cipo = CircPolicy.create(circ_policy_martigny_data_tmp, delete_pid=True)

    can, reasons = cipo.can_delete
    assert can
    assert reasons == {}
Exemple #12
0
def circ_policy(app, organisation, circ_policy_data):
    """."""
    cipo = CircPolicy.create(data=circ_policy_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
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
Exemple #14
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
Exemple #15
0
def test_circ_policy_create(db, circ_policy_martigny_data_tmp):
    """Test circulation policy creation."""
    cipo = CircPolicy.create(circ_policy_martigny_data_tmp, delete_pid=True)
    assert cipo == circ_policy_martigny_data_tmp
    assert cipo.get('pid') == '1'

    cipo = CircPolicy.get_record_by_pid('1')
    assert cipo == circ_policy_martigny_data_tmp

    fetched_pid = circ_policy_id_fetcher(cipo.id, cipo)
    assert fetched_pid.pid_value == '1'
    assert fetched_pid.pid_type == 'cipo'

    circ_policy = deepcopy(circ_policy_martigny_data_tmp)
    del circ_policy['$schema']
    cipo = CircPolicy.create(circ_policy, delete_pid=True)
    assert cipo.get('$schema')
    assert cipo.get('pid') == '2'
Exemple #16
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 #17
0
def circ_policy_ebooks_sion(app, patron_type_youngsters_sion,
                            patron_type_grown_sion, item_type_online_sion,
                            circ_policy_ebooks_sion_data):
    """Create ebooks circ policy for organisation sion."""
    cipo = CircPolicy.create(data=circ_policy_ebooks_sion_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
Exemple #18
0
def circ_policy_less_than_one_day_martigny(
        app, patron_type_adults_martigny, item_type_standard_martigny,
        circ_policy_less_than_one_day_martigny_data):
    """Create short circ policy for organisation martigny."""
    cipo = CircPolicy.create(data=circ_policy_less_than_one_day_martigny_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
def test_circ_policy_can_not_delete(circ_policy_short_martigny):
    """Test can not delete a policy."""
    org_pid = circ_policy_short_martigny.organisation_pid
    defaut_cipo = CircPolicy.get_default_circ_policy(org_pid)
    can, reasons = defaut_cipo.can_delete
    assert not can
    assert reasons['others']['is_default']

    can, reasons = circ_policy_short_martigny.can_delete
    assert can
    assert reasons == {}
Exemple #20
0
def circ_policy_short(
        circ_policy_data_short, patron_type, patron_type_specific,
        item_type, item_type_specific, item_type_on_site):
    """."""
    cipo = CircPolicy.create(
        data=circ_policy_data_short,
        delete_pid=False,
        dbcommit=True,
        reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
Exemple #21
0
def circ_policy_ebooks_martigny(app, patron_type_adults_martigny,
                                patron_type_children_martigny,
                                item_type_online_martigny,
                                circ_policy_ebooks_martigny_data):
    """Create ebooks circ policy for organisation martigny."""
    cipo = CircPolicy.create(data=circ_policy_ebooks_martigny_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
Exemple #22
0
def upgrade():
    """Update circulation policy records."""
    query = CircPoliciesSearch() \
        .filter('term', allow_requests=True) \
        .source(['pid']).scan()
    for hit in query:
        cipo = CircPolicy.get_record_by_pid(hit.pid)
        cipo['pickup_hold_duration'] = 10  # default value is 10 days
        cipo.update(cipo, dbcommit=True, reindex=True)
        LOGGER.info(f'  * Updated cipo#{cipo.pid}')
    CircPoliciesSearch.flush_and_refresh()
    LOGGER.info(f'upgrade to {revision}')
Exemple #23
0
def downgrade():
    """Reset circulation policy records."""
    query = CircPoliciesSearch() \
        .filter('exists', field='pickup_hold_duration') \
        .source(['pid']).scan()
    for hit in query:
        cipo = CircPolicy.get_record_by_pid(hit.pid)
        del cipo['pickup_hold_duration']
        cipo.update(cipo, dbcommit=True, reindex=True)
        LOGGER.info(f'  * Updated cipo#{cipo.pid}')
    CircPoliciesSearch.flush_and_refresh()
    LOGGER.info(f'downgrade to revision {down_revision}')
def test_circ_policy_extended_validation(app, circ_policy_short_martigny,
                                         circ_policy_short_martigny_data):
    """Test extended validation for circ policy"""
    cipo_data = deepcopy(circ_policy_short_martigny_data)
    cipo_data['allow_requests'] = False
    cipo_data['pickup_hold_duration'] = 10
    del cipo_data['pid']

    cipo = CircPolicy.create(cipo_data)
    assert cipo
    assert 'pickup_hold_duration' not in cipo

    cipo.delete()
Exemple #25
0
def circ_policy_temp_martigny(app, lib_martigny, patron_type_adults_martigny,
                              item_type_on_site_martigny,
                              circ_policy_temp_martigny_data):
    """Create temporary circ policy for organisation martigny.

    library martigny.
    """
    cipo = CircPolicy.create(data=circ_policy_temp_martigny_data,
                             delete_pid=False,
                             dbcommit=True,
                             reindex=True)
    flush_index(CircPoliciesSearch.Meta.index)
    return cipo
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']
Exemple #27
0
def test_circ_policy_can_delete(app, circ_policy_martigny_data_tmp):
    """Test can delete a policy."""
    circ_policy_martigny_data_tmp['is_default'] = False
    cipo = CircPolicy.create(circ_policy_martigny_data_tmp, delete_pid=True)
    assert cipo.get_links_to_me() == {}
    assert cipo.can_delete

    reasons = cipo.reasons_not_to_delete()
    assert 'links' not in reasons

    with mock.patch(
            'rero_ils.modules.circ_policies.api.CircPolicy.get_links_to_me'
    ) as a:
        a.return_value = {'object': 1}
        reasons = cipo.reasons_not_to_delete()
        assert 'links' in reasons
Exemple #28
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
Exemple #29
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
Exemple #30
0
 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, []