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)
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 == {}
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_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'
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
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 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
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()
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_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)
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()