def test_send_only_to_test_recipients(app, users, testdata, mocker): """Tests that send only to test recipients works.""" class TestMessage(BlockTemplatedMessage): def __init__(self, *args, **kwargs): template = "tests/subject_body_html.html" kwargs.pop("trigger", None) kwargs.pop("message_ctx", {}) kwargs.setdefault("sender", app.config["MAIL_NOTIFY_SENDER"]) super().__init__(template, **kwargs) app.config.update( dict(CELERY_TASK_ALWAYS_EAGER=True, ILS_MAIL_LOAN_MSG_LOADER=TestMessage, ILS_MAIL_ENABLE_TEST_RECIPIENTS=True)) patron = Patron(users["patron1"].id) mocker.patch( "invenio_app_ils.records.api.Patron.get_patron", return_value=patron, ) loan_data = testdata["loans"][-1] loan = Loan.get_record_by_pid(loan_data["pid"]) fake_recipients = app.config["ILS_MAIL_NOTIFY_TEST_RECIPIENTS"] with app.extensions["mail"].record_messages() as outbox: assert len(outbox) == 0 send_loan_mail("trigger", loan, subject="Test", body="Test") assert len(outbox) == 1 assert outbox[0].recipients == fake_recipients
def test_loan_patron_resolver_for_anonymous_patron_pid(app, testdata): """Test item resolving from loan.""" loan_pid = testdata["loans"][7]["pid"] loan = Loan.get_record_by_pid(loan_pid) loan = loan.replace_refs() assert loan["patron_pid"] == loan["patron"]["id"] assert loan["patron"]["name"] == "anonymous"
def test_loan_extend_permissions(app, client, json_headers, users, testdata, app_config, loan_params, user, expected_resp_code): """Test loan can be extended.""" # Create a Loan for patron with pid 1 login_user(users["librarian"]) loan_data = testdata["loans"][0] loan = Loan.get_record_by_pid(loan_data["pid"]) current_circulation.circulation.trigger( loan, **dict(loan_params, trigger="checkout")) user_login(client, "librarian", users) resp = client.get(url_for("invenio_records_rest.loanid_item", pid_value=loan["pid"]), headers=json_headers) loan = resp.get_json() # Remove payload params that break the request del loan_params["item_pid"] del loan_params["transaction_date"] extend_url = loan.get("links").get("actions").get("extend") user_login(client, user, users) extend_res = client.post(extend_url, headers=json_headers, data=json.dumps(loan_params)) assert extend_res.status_code == expected_resp_code
def test_search_loans_by_pid(indexed_loans): """Test retrieve loan list belonging to an item.""" item_pid = dict(type="itemid", value="item_pending_1") loans = list(search_by_pid(item_pid=item_pid).scan()) assert len(loans) == 1 loan = Loan.get_record_by_pid(loans[0]["pid"]) assert loan["item_pid"] == item_pid
def check_user_activity(app, user_pid, client, json_headers): """ Check if there are records related to the user. """ # wait ES refresh current_search.flush_and_refresh(index="*") AnonymousPatron = app.config["ILS_PATRON_ANONYMOUS_CLASS"] anonymous_patron_fields = AnonymousPatron().dumps_loader() loans = get_loans_by_patron_pid(user_pid).scan() for hit in loans: # test ES assert hit["patron"] == anonymous_patron_fields # test DB loan = Loan.get_record_by_pid(hit.pid) assert loan["patron"] == anonymous_patron_fields # test REST url = url_for("invenio_records_rest.loanid_item", pid_value=hit.pid) res = client.get(url, headers=json_headers) assert res.get_json()["metadata"]["patron"] == anonymous_patron_fields borrowing_requests = ( BorrowingRequestsSearch().search_by_patron_pid(user_pid).scan()) for hit in borrowing_requests: # test ES assert hit["patron"] == anonymous_patron_fields # test DB borrowing_request = BorrowingRequest.get_record_by_pid(hit.pid) assert borrowing_request["patron"] == anonymous_patron_fields # test REST url = url_for("invenio_records_rest.illbid_item", pid_value=hit.pid) res = client.get(url, headers=json_headers) assert res.get_json()["metadata"]["patron"] == anonymous_patron_fields document_requests = ( DocumentRequestSearch().search_by_patron_pid(user_pid).scan()) for hit in document_requests: # test ES assert hit["patron"] == anonymous_patron_fields # test DB document_request = DocumentRequest.get_record_by_pid(hit.pid) assert document_request["patron"] == anonymous_patron_fields # test REST url = url_for("invenio_records_rest.dreqid_item", pid_value=hit.pid) res = client.get(url, headers=json_headers) assert res.get_json()["metadata"]["patron"] == anonymous_patron_fields acquisitions = OrderSearch().search_by_patron_pid(user_pid).scan() for hit in acquisitions: # test ES assert hit["patron"] == anonymous_patron_fields # test DB acquisition = Order.get_record_by_pid(hit.pid) assert acquisition["patron"] == anonymous_patron_fields # test REST url = url_for("invenio_records_rest.acqoid_item", pid_value=hit.pid) res = client.get(url, headers=json_headers) assert res.get_json()["metadata"]["patron"] == anonymous_patron_fields
def test_loan_patron_resolver_for_non_existing_patron_pid(app, testdata): """Test item resolving from loan.""" AnonymousPatron = app.config["ILS_PATRON_ANONYMOUS_CLASS"] loan_pid = testdata["loans"][6]["pid"] loan = Loan.get_record_by_pid(loan_pid) loan = loan.replace_refs() assert loan["patron_pid"] == str(20) assert loan["patron"]["id"] == str(AnonymousPatron.id) assert loan["patron"]["name"] == "anonymous"
def index_loans_after_item_indexed(item_pid): """Index loan to refresh item reference.""" loan_search = search_by_pid(item_pid=item_pid) loan_ids = [] for loan in loan_search.scan(): record = Loan.get_record_by_pid(loan[Loan.pid_field]) if record: loan_ids.append(record.id) RecordIndexer().bulk_index(loan_ids)
def test_email_on_loan_checkout(client, app_with_mail, users, testdata, loan_params): """Test that an email is sent on loan checkout.""" loan_data = testdata["loans"][1] loan = Loan.get_record_by_pid(loan_data["pid"]) with app_with_mail.extensions["mail"].record_messages() as outbox: user_login(client, "admin", users) assert len(outbox) == 0 current_circulation.circulation.trigger( loan, **dict(loan_params, trigger="checkout")) assert len(outbox) == 1 msg = outbox[0] doc = Document.get_record_by_pid(loan_data["document_pid"]) expected_subject = ( """InvenioILS: your loan for "{0}" has started.""".format( doc["title"])) assert msg.subject == expected_subject edition_year = " ({edition} - {year})".format(edition=doc["edition"], year=doc["publication_year"]) full_title = "{title}, {author}{edition_year}".format( title=doc["title"], author=doc["authors"][0]["full_name"], edition_year=edition_year, ) literature_url = "{host}{path}".format( host=current_app.config["SPA_HOST"], path=current_app.config["SPA_PATHS"]["literature"] % {"pid": doc["pid"]}, ) profile_url = "{host}{path}".format( host=current_app.config["SPA_HOST"], path=current_app.config["SPA_PATHS"]["profile"], ) expected_body_plain = """Dear Patron One, your loan for "{doc_full_title}" <{literature_url}> has started. The due date is {loan_end_date}. You can see your ongoing and past loans in your profile page <{profile_url}>. Kind regards, InvenioILS""".format( doc_full_title=full_title, literature_url=literature_url, loan_end_date=loan_data["end_date"], profile_url=profile_url, ) assert msg.body == expected_body_plain
def test_email_on_loan_checkout(client, app_with_mail, users, testdata, loan_params): """Test that an email is sent when an admin performs a loan checkout.""" loan_data = testdata["loans"][1] loan = Loan.get_record_by_pid(loan_data["pid"]) with app_with_mail.extensions["mail"].record_messages() as outbox: user_login(client, "admin", users) assert len(outbox) == 0 current_circulation.circulation.trigger( loan, **dict(loan_params, trigger="checkout")) assert len(outbox) == 1
def test_email_on_overdue_loan(app, users, testdata, mocker): """Test that an email is sent when an admin performs a loan checkout.""" app.config.update(CELERY_TASK_ALWAYS_EAGER=True) mocker.patch( "invenio_app_ils.records.api.Patron.get_patron", return_value=Patron(users["patron1"].id), ) loan_data = testdata["loans"][-1] loan = Loan.get_record_by_pid(loan_data["pid"]) with app.extensions["mail"].record_messages() as outbox: assert len(outbox) == 0 send_loan_overdue_reminder_mail(loan) assert len(outbox) == 1
def test_search_loans_by_pid(indexed_loans): """Test retrieve loan list given belonging to an item.""" loans = list(LoansSearch.search_loans_by_pid(item_pid='item_pending_1')) assert loans assert len(loans) == 1 loan = Loan.get_record_by_pid(loans[0]['loan_pid']) assert loan.get('item_pid') == 'item_pending_1' loans = list( LoansSearch.search_loans_by_pid( item_pid='item_multiple_pending_on_loan_7', exclude_states=['ITEM_ON_LOAN'], )) assert len(loans) == 2
def test_email_on_loan_checkout(app, users, testdata, loan_params, mocker): """Test that an email is sent when an admin performs a loan checkout.""" app.config.update(CELERY_TASK_ALWAYS_EAGER=True) loan_data = testdata["loans"][1] loan = Loan.get_record_by_pid(loan_data["pid"]) with app.extensions["mail"].record_messages() as outbox: admin = users["admin"] login_user(admin) assert len(outbox) == 0 current_circulation.circulation.trigger( loan, **dict(loan_params, trigger="checkout")) assert len(outbox) == 1
def cancel_expired_loan_requests(): """Cancel loan requests after expiration date has passed.""" SystemAgent = current_app.config["ILS_PATRON_SYSTEM_AGENT_CLASS"] system_agent_id = str(SystemAgent.id) for hit in get_all_expired_loans().scan(): loan = Loan.get_record_by_pid(hit.pid) duration_days = current_app.config[ "ILS_CIRCULATION_LOAN_REQUEST_DURATION_DAYS"] params = deepcopy(loan) params.update( dict( cancel_reason="The loan request has been automatically " "cancelled because {} days have passed.".format(duration_days), transaction_user_pid=system_agent_id, )) current_circulation.circulation.trigger( loan, **dict(params, trigger="cancel")) loan.commit() db.session.commit() current_circulation.loan_indexer().index(loan)
def cancel_active_loans(patron_pid, client, users): """Cancel active loans of a patron.""" user = user_login(client, "admin", users) active_loans = get_active_loans_by_patron_pid(patron_pid).scan() for hit in active_loans: loan = Loan.get_record_by_pid(hit.pid) params = deepcopy(loan) params.update( dict( cancel_reason="Loan cancelled to anonymize user.", transaction_user_pid=str(user.id), )) current_circulation.circulation.trigger( loan, **dict(params, trigger="cancel")) loan.commit() db.session.commit() current_circulation.loan_indexer().index(loan) current_search.flush_and_refresh(index="*")
def test_loan_document_resolver(app, testdata): """Test item resolving from loan.""" loan_pid = testdata["loans"][1]["pid"] loan = Loan.get_record_by_pid(loan_pid) loan = loan.replace_refs() assert loan["document"]["pid"] == loan["document_pid"]
def get(self): """Return the loan for this borrowing request.""" loan_pid = self.record.get("patron_loan", {}).get("pid") if not loan_pid: raise ILLError("There is no patron loan attached to the request.") return Loan.get_record_by_pid(loan_pid)
def test_loan_item_resolver_for_empty_item_pid(app, testdata): """Test item resolving from loan.""" loan_pid = testdata["loans"][0]["pid"] loan = Loan.get_record_by_pid(loan_pid) loan = loan.replace_refs() assert loan["item"] == dict()
def test_search_loans_by_pid(indexed_loans): """Test retrieve loan list belonging to an item.""" loans = list(search_by_pid(item_pid="item_pending_1").scan()) assert len(loans) == 1 loan = Loan.get_record_by_pid(loans[0]["pid"]) assert loan.get("item_pid") == "item_pending_1"
def _set_loan_end_date(loan_pid, new_end_date): """Set loan end date.""" loan = Loan.get_record_by_pid(loan_pid) loan["end_date"] = new_end_date.date().isoformat() loan.commit() db.session.commit()
def test_search_loans_by_pid(indexed_loans): """Test retrieve loan list belonging to an item.""" loans = list(search_by_pid(item_pid="item_pending_1").scan()) assert len(loans) == 1 loan = Loan.get_record_by_pid(loans[0][Loan.pid_field]) assert loan.get("item_pid") == "item_pending_1"