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_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)
Beispiel #4
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_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 == {}
Beispiel #6
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
Beispiel #7
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'
Beispiel #8
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
Beispiel #9
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
Beispiel #10
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
Beispiel #11
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
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()
Beispiel #13
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
Beispiel #14
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
def test_circ_policy_can_delete(app, circ_policy_data_tmp):
    """Test can delete"""
    circ_policy_data_tmp['is_default'] = False
    cipo = CircPolicy.create(circ_policy_data_tmp, delete_pid=True)
    assert cipo.get_links_to_me() == {}
    assert cipo.can_delete
def test_circ_policy_create(
        circ_policy_martigny_data_tmp, circ_policy_short_martigny_data,
        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_data = deepcopy(circ_policy_short_martigny_data)
    del circ_policy_data['$schema']
    cipo = CircPolicy.create(circ_policy_data, delete_pid=True)
    assert cipo.get('$schema')
    assert cipo.get('pid') == '2'

    cipo_data = {
        '$schema':
        'https://bib.rero.ch/schemas/'
        'circ_policies/circ_policy-v0.0.1.json',
        'pid':
        'cipo_test',
        'name':
        'test',
        'organisation': {
            '$ref': 'https://bib.rero.ch/api/organisations/org1'
        },
        'is_default':
        False,
        'allow_requests':
        True,
        'policy_library_level':
        False,
        'settings': [{
            'patron_type': {
                '$ref': 'https://bib.rero.ch/api/patron_types/ptty3'
            },
            'item_type': {
                '$ref': 'https://bib.rero.ch/api/item_types/itty1'
            }
        }, {
            'patron_type': {
                '$ref': 'https://bib.rero.ch/api/patron_types/ptty2'
            },
            'item_type': {
                '$ref': 'https://bib.rero.ch/api/item_types/itty4'
            }
        }]
    }
    with pytest.raises(ValidationError):
        cipo = CircPolicy.create(cipo_data, delete_pid=False)

    # TEST #2 : create a second defaut policy
    #   The first created policy (pid=1) is the default policy.
    #   Creation of a second default policy should raise a ValidationError
    default_cipo = CircPolicy.get_record_by_pid('1')
    assert default_cipo.get('is_default')
    with pytest.raises(ValidationError) as excinfo:
        CircPolicy.create(circ_policy_martigny_data_tmp, delete_pid=True)
    assert 'CircPolicy: already a default policy for this org' \
           in str(excinfo.value)
Beispiel #17
0
def test_fees_after_extend(item_on_loan_martigny_patron_and_loan_on_loan,
                           loc_public_martigny, loc_public_saxon,
                           librarian_martigny, circulation_policies):
    """Test fees calculation after extend on different location."""

    # STEP#1 :: CREATE A SPECIAL CIPO FOR NEXT EXTEND OPERATION
    item, patron, loan = item_on_loan_martigny_patron_and_loan_on_loan
    checkout_cipo = get_circ_policy(loan)
    extend_cipo = deepcopy(checkout_cipo)
    extend_cipo['policy_library_level'] = True
    extend_cipo.update({
        'libraries': [{
            '$ref':
            get_ref_for_pid(Library, loc_public_saxon.library_pid)
        }],
        'overdue_fees': {
            'intervals': [{
                'from': 1,
                'fee_amount': 0.01
            }]
        }
    })
    del extend_cipo['pid']
    extend_cipo = CircPolicy.create(extend_cipo)
    assert extend_cipo

    # Update checkout cipo to set some intervals
    checkout_cipo_ori = get_circ_policy(loan, checkout_location=True)
    checkout_cipo = deepcopy(checkout_cipo_ori)
    checkout_fee_amount = 10
    checkout_cipo['overdue_fees'] = {
        'intervals': [{
            'from': 1,
            'fee_amount': checkout_fee_amount
        }]
    }
    checkout_cipo = checkout_cipo.update(checkout_cipo,
                                         dbcommit=True,
                                         reindex=True)

    # UPDATE LOAN TO BE OVERDUE
    interval = 10
    while not loan.is_loan_overdue():
        new_end_date = datetime.now(timezone.utc) - timedelta(days=interval)
        loan['end_date'] = new_end_date.isoformat()
        interval += 1
    loan.update(loan, dbcommit=True, reindex=True)

    # STEP#2 :: EXTEND THE LOAN FOR SAXON LIBRARY.
    #   The loan should use the new created circulation policy
    #   Update loan `end_date` to play with "extend" function without problem
    params = {
        'transaction_location_pid': loc_public_saxon.pid,
        'transaction_user_pid': librarian_martigny.pid
    }
    item, actions = item.extend_loan(**params)
    loan = actions[LoanAction.EXTEND]
    assert item.status == ItemStatus.ON_LOAN
    assert get_circ_policy(loan).pid == extend_cipo.pid
    assert loan.get('checkout_location_pid') == loc_public_martigny.pid
    assert loan.get('transaction_location_pid') == loc_public_saxon.pid

    # The patron should have fees.
    flush_index(PatronTransactionsSearch.Meta.index)
    pttr = get_last_transaction_by_loan_pid(loan.pid)
    assert pttr.total_amount >= checkout_fee_amount

    # UPDATE LOAN TO BE OVERDUE
    interval = 10
    while not loan.is_loan_overdue():
        new_end_date = datetime.now(timezone.utc) - timedelta(days=interval)
        loan['end_date'] = new_end_date.isoformat()
        interval += 1
    loan.update(loan, dbcommit=True, reindex=True)

    # STEP#3 :: CHECK-IN THE LOAN
    #   Execute the check-in circulation operation
    #   Check that a fee has been created and this fees is related to the
    #   checkout circulation.
    params = {
        'transaction_location_pid': loc_public_saxon.pid,
        'transaction_user_pid': librarian_martigny.pid
    }
    _, actions = item.checkin(**params)
    loan = actions[LoanAction.CHECKIN]
    assert loan.state == LoanState.ITEM_IN_TRANSIT_TO_HOUSE
    params['transaction_location_pid'] = loc_public_martigny.pid
    _, actions = item.checkin(**params)
    loan = actions[LoanAction.RECEIVE]
    assert loan.state == LoanState.ITEM_RETURNED

    pttr = get_last_transaction_by_loan_pid(loan.pid)
    assert pttr.total_amount >= checkout_fee_amount

    # STEP#X :: RESET DATA
    checkout_cipo.update(checkout_cipo_ori, dbcommit=True, reindex=True)
    extend_cipo.delete()