def loans(): """Load test data fixture.""" record_uuid = uuid.uuid4() new_loan = {} pid = loan_pid_minter(record_uuid, data=new_loan) Loan.create(data=new_loan, id_=record_uuid) db.session.commit() click.secho("Loan #{} created.".format(pid.pid_value), fg="green")
def test_get_loans(indexed_loans): """Test retrive loan list given belonging to an item.""" loans = list(Loan.get_loans(item_pid='item_pending_1')) assert loans assert len(loans) == 1 assert loans[0].get('item_pid') == 'item_pending_1' loans = list( Loan.get_loans( item_pid='item_multiple_pending_on_loan_7', exclude_states=['ITEM_ON_LOAN'], )) assert len(loans) == 2
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 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 request_loan(document_pid, patron_pid, transaction_location_pid, transaction_user_pid, **kwargs): """Create a new loan and trigger the first transition to PENDING.""" if patron_has_request_on_document(patron_pid=patron_pid, document_pid=document_pid): raise PatronHasRequestOnDocumentError(patron_pid, document_pid) _validate_delivery(kwargs.get("delivery")) # create a new loan record_uuid = uuid.uuid4() new_loan = dict( patron_pid=patron_pid, transaction_location_pid=transaction_location_pid, transaction_user_pid=transaction_user_pid, ) pid = loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) params = deepcopy(loan) params.update(document_pid=document_pid, **kwargs) # trigger the transition to request loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="request")) return pid, loan
def request_loan(params): """Create a loan and trigger the first transition to create a request.""" if "patron_pid" not in params: raise MissingRequiredParameterError( description="'patron_pid' is required on loan request") if "document_pid" not in params: raise MissingRequiredParameterError( description="'document_pid' is required on loan request") if patron_has_active_loan_on_item(patron_pid=params["patron_pid"], document_pid=params["document_pid"]): raise PatronHasLoanOnDocumentError(params["patron_pid"], params["document_pid"]) # create a new loan record_uuid = uuid.uuid4() new_loan = { "document_pid": params["document_pid"], "patron_pid": params["patron_pid"], } pid = loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) # trigger the first transition loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="request")) return pid, loan
def create_loan(params): """Create a loan for behalf of a user.""" if "patron_pid" not in params or "item_pid" not in params: raise CirculationException( "Patron or item not defined on loan request.") if patron_has_active_loan_on_item(patron_pid=params["patron_pid"], item_pid=params["item_pid"]): raise CirculationException( "Patron has already a request or active loan on this item.") if "document_pid" not in params: document_pid = circulation_document_retriever(params["item_pid"]) if document_pid: params["document_pid"] = document_pid # create a new loan record_uuid = uuid.uuid4() new_loan = {} pid = loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) # trigger the first transition loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="checkout")) return pid, loan
def create_loan(params, should_force_checkout): """Create a loan on behalf of a user.""" if "patron_pid" not in params: raise MissingRequiredParameterError( description="'patron_pid' is required when creating a loan") if "item_pid" not in params: raise MissingRequiredParameterError( description="'item_pid' is required when creating a loan") if patron_has_active_loan_on_item(patron_pid=params["patron_pid"], item_pid=params["item_pid"]): raise PatronHasLoanOnItemError(params["patron_pid"], params["item_pid"]) if "document_pid" not in params: document_pid = Item.get_document_pid(params["item_pid"]) if document_pid: params["document_pid"] = document_pid if should_force_checkout: _ensure_item_can_circulate(params['item_pid']) # create a new loan record_uuid = uuid.uuid4() new_loan = {"item_pid": params["item_pid"]} pid = loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) # trigger the first transition loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="checkout")) return pid, loan
def test_api_automatic_loan_valid_action(app, db, json_headers, params): """Test API valid action on loan.""" loan = Loan.create({}) minted_loan = loan_pid_minter(loan.id, loan) loan = current_circulation.circulation.trigger( loan, **dict(params, trigger='request', pickup_location_pid='pickup_location_pid')) db.session.commit() assert loan['state'] == 'PENDING' app.config[ 'CIRCULATION_ITEM_LOCATION_RETRIEVER'] = lambda x: 'pickup_location_pid' loan_pid = loan_pid_fetcher(loan.id, loan) assert minted_loan.pid_value == loan_pid.pid_value with app.test_client() as client: url = url_for('invenio_circulation.loan_pid_actions', pid_value=loan_pid.pid_value, action='next') res = client.post(url, headers=json_headers, data=json.dumps(params)) assert res.status_code == HTTP_CODES['accepted'] loan_dict = json.loads(res.data.decode('utf-8')) assert loan_dict['metadata']['state'] == 'ITEM_AT_DESK'
def checkout_loan(item_pid, patron_pid, transaction_location_pid, transaction_user_pid, force=False, **kwargs): """Create a new loan and trigger the first transition to ITEM_ON_LOAN.""" if patron_has_active_loan_on_item(patron_pid=patron_pid, item_pid=item_pid): raise PatronHasLoanOnItemError(patron_pid, item_pid) optional_delivery = kwargs.get("delivery") if optional_delivery: _validate_delivery(optional_delivery) if force: _set_item_to_can_circulate(item_pid) # create a new loan record_uuid = uuid.uuid4() new_loan = dict( patron_pid=patron_pid, transaction_location_pid=transaction_location_pid, transaction_user_pid=transaction_user_pid, ) pid = loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) params = deepcopy(loan) params.update(item_pid=item_pid, **kwargs) # trigger the transition to request loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="checkout")) return pid, loan
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_api_loan_invalid_action(app, db, json_headers, params, mock_is_item_available): """Test API invalid action on loan.""" loan = Loan.create({}) minted_loan = loan_pid_minter(loan.id, loan) loan = current_circulation.circulation.trigger( loan, **dict(params, trigger='request', pickup_location_pid='pickup_location_pid')) db.session.commit() assert loan['state'] == 'PENDING' loan_pid = loan_pid_fetcher(loan.id, loan) assert minted_loan.pid_value == loan_pid.pid_value with app.test_client() as client: url = url_for('invenio_circulation.loan_pid_actions', pid_value=loan_pid.pid_value, action='checkout') res = client.post(url, headers=json_headers, data=json.dumps(params)) assert res.status_code == HTTP_CODES['method_not_allowed'] error_dict = json.loads(res.data.decode('utf-8')) assert 'message' in error_dict
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 create_loan(data): """Create a test record.""" with db.session.begin_nested(): data = copy.deepcopy(data) rec_uuid = uuid.uuid4() pid = current_pidstore.minters['loanid'](rec_uuid, data) record = Loan.create(data, id_=rec_uuid) return pid, record
def create_loan(data): """Create a test record.""" with db.session.begin_nested(): data = copy.deepcopy(data) rec_uuid = uuid.uuid4() pid = current_pidstore.minters[CIRCULATION_LOAN_MINTER](rec_uuid, data) record = Loan.create(data, id_=rec_uuid) return pid, record
def loan_created(app): """Minimal Loan object.""" record_uuid = uuid.uuid4() new_loan = {} loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) db.session.commit() yield loan
def testdata(app, db, es_clear): """Create, index and return test data.""" indexer = RecordIndexer() locations = load_json_from_datadir("locations.json") for location in locations: record = Location.create(location) mint_record_pid(LOCATION_PID_TYPE, Location.pid_field, record) record.commit() db.session.commit() indexer.index(record) internal_locations = load_json_from_datadir("internal_locations.json") iloc_records = [] for internal_location in internal_locations: record = InternalLocation.create(internal_location) mint_record_pid(INTERNAL_LOCATION_PID_TYPE, InternalLocation.pid_field, record) record.commit() iloc_records.append(record) db.session.commit() indexer.index(record) documents = load_json_from_datadir("documents.json") for doc in documents: record = Document.create(doc) mint_record_pid(DOCUMENT_PID_TYPE, Document.pid_field, record) record.commit() db.session.commit() indexer.index(record) items = load_json_from_datadir("items.json") for item in items: record = Item.create(item) mint_record_pid(ITEM_PID_TYPE, Item.pid_field, record) record.commit() db.session.commit() indexer.index(record) loans = load_json_from_datadir("loans.json") for loan in loans: record = Loan.create(loan) mint_record_pid(CIRCULATION_LOAN_PID_TYPE, Loan.pid_field, record) record.commit() db.session.commit() indexer.index(record) # re-index item attached to the loan index_record_after_loan_change(app, record) # flush all indices after indexing, otherwise ES won't be ready for tests current_search.flush_and_refresh(index=None) return { "locations": locations, "documents": documents, "items": items, "loans": loans, }
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 persist(self): """Persist.""" recs = [] for obj in self.holder.loans["objs"]: rec = self._persist(CIRCULATION_LOAN_PID_TYPE, "pid", Loan.create(obj)) recs.append(rec) db.session.commit() return recs
def test_document_requests_on_item_returned(mock_available_item, mock_pending_loans_for_document, mock_is_item_available, loan_created, db, params): """Test loan request action.""" # return item is not available mock_available_item.return_value = False with SwappedConfig('CIRCULATION_DOCUMENT_RETRIEVER_FROM_ITEM', lambda x: 'document_pid'): same_location = params['transaction_location_pid'] with SwappedConfig('CIRCULATION_ITEM_LOCATION_RETRIEVER', lambda x: same_location): # start a loan on item with pid 'item_pid' new_loan = current_circulation.circulation.trigger( loan_created, **dict(params, trigger='checkout', item_pid='item_pid', pickup_location_pid='pickup_location_pid') ) db.session.commit() assert new_loan['state'] == 'ITEM_ON_LOAN' # create a new loan request on document_pid without items available new_loan_created = Loan.create({}) # remove item_pid params.pop('item_pid') pending_loan = current_circulation.circulation.trigger( new_loan_created, **dict(params, trigger='request', document_pid='document_pid', pickup_location_pid='pickup_location_pid') ) db.session.commit() assert pending_loan['state'] == 'PENDING' # no item available found. Request is created with no item attached assert 'item_pid' not in pending_loan assert pending_loan['document_pid'] == 'document_pid' # resolve pending document requests to `document_pid` mock_pending_loans_for_document.return_value = [pending_loan] returned_loan = current_circulation.circulation.trigger( new_loan, **dict(params, item_pid='item_pid', pickup_location_pid='pickup_location_pid') ) db.session.commit() assert returned_loan['state'] == 'ITEM_RETURNED' # item `item_pid` has been attached to pending loan request on # `document_pid` automatically assert pending_loan['state'] == 'PENDING' assert pending_loan['item_pid'] == 'item_pid' assert pending_loan['document_pid'] == 'document_pid'
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_state_checkout_with_loan_pid(db, params, loan_schema): """.""" data = {} data.update({'loan_pid': 'loan_pid'}) data.update(loan_schema) loan_created = Loan.create(data) new_params = deepcopy(params) new_params['trigger'] = 'checkout' loan = current_circulation.circulation.trigger(loan_created, **new_params) loan.validate()
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_loan_request(db, params): """Test loan request action.""" loan = Loan.create({}) assert loan['state'] == 'CREATED' loan = current_circulation.circulation.trigger( loan, **dict(params, trigger='request', pickup_location_pid='pickup_location_pid')) db.session.commit() assert loan['state'] == 'PENDING'
def checkout_loan( item_pid, patron_pid, transaction_location_pid, transaction_user_pid=None, force=False, **kwargs ): """Create a new loan and trigger the first transition to ITEM_ON_LOAN. :param item_pid: a dict containing `value` and `type` fields to uniquely identify the item. :param patron_pid: the PID value of the patron :param transaction_location_pid: the PID value of the location where the checkout is performed :param transaction_user_pid: the PID value of the user that performed the checkout :param force: if True, ignore the current status of the item and do perform the checkout. If False, the checkout will fail when the item cannot circulate. """ if patron_has_active_loan_on_item( patron_pid=patron_pid, item_pid=item_pid ): raise PatronHasLoanOnItemError(patron_pid, item_pid) optional_delivery = kwargs.get("delivery") if optional_delivery: _validate_delivery(optional_delivery) if force: _set_item_to_can_circulate(item_pid) transaction_user_pid = transaction_user_pid or str(current_user.id) # create a new loan record_uuid = uuid.uuid4() new_loan = dict( patron_pid=patron_pid, transaction_location_pid=transaction_location_pid, transaction_user_pid=transaction_user_pid, ) pid = ils_circulation_loan_pid_minter(record_uuid, data=new_loan) loan = Loan.create(data=new_loan, id_=record_uuid) params = deepcopy(loan) params.update(item_pid=item_pid, **kwargs) # trigger the transition to request loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="checkout") ) return pid, loan
def testdata(app, db, es_clear, system_user): """Create, index and return test data.""" indexer = RecordIndexer() locations = load_json_from_datadir("locations.json") for location in locations: record = Location.create(location) mint_record_pid(LOCATION_PID_TYPE, "pid", record) record.commit() db.session.commit() indexer.index(record) internal_locations = load_json_from_datadir("internal_locations.json") for internal_location in internal_locations: record = InternalLocation.create(internal_location) mint_record_pid(INTERNAL_LOCATION_PID_TYPE, "pid", record) record.commit() db.session.commit() indexer.index(record) documents = load_json_from_datadir("documents.json") for doc in documents: record = Document.create(doc) mint_record_pid(DOCUMENT_PID_TYPE, "pid", record) record.commit() db.session.commit() indexer.index(record) items = load_json_from_datadir("items.json") for item in items: record = Item.create(item) mint_record_pid(ITEM_PID_TYPE, "pid", record) record.commit() db.session.commit() indexer.index(record) loans = load_json_from_datadir("loans.json") for loan in loans: record = Loan.create(loan) mint_record_pid(CIRCULATION_LOAN_PID_TYPE, "pid", record) record.commit() db.session.commit() indexer.index(record) # flush all indices after indexing, otherwise ES won't be ready for tests current_search.flush_and_refresh(index='*') return { "locations": locations, "documents": documents, "items": items, "loans": loans, }
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_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 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_document_requests_on_item_returned( mock_available_item, mock_pending_loans_for_document, mock_is_item_available_for_checkout, loan_created, db, params ): """Test loan request action.""" # return item is not available mock_available_item.return_value = False with SwappedConfig( "CIRCULATION_DOCUMENT_RETRIEVER_FROM_ITEM", lambda x: "document_pid" ): same_location = params["transaction_location_pid"] with SwappedConfig( "CIRCULATION_ITEM_LOCATION_RETRIEVER", lambda x: same_location ): # start a loan on item with pid 'item_pid' new_loan = current_circulation.circulation.trigger( loan_created, **dict( params, trigger="checkout", item_pid="item_pid", pickup_location_pid="pickup_location_pid", ) ) db.session.commit() assert new_loan["state"] == "ITEM_ON_LOAN" # create a new loan request on document_pid without items available new_loan_created = Loan.create({ Loan.pid_field: "2" }) # remove item_pid params.pop("item_pid") pending_loan = current_circulation.circulation.trigger( new_loan_created, **dict( params, trigger="request", document_pid="document_pid", pickup_location_pid="pickup_location_pid", ) ) db.session.commit() assert pending_loan["state"] == "PENDING" # no item available found. Request is created with no item attached assert "item_pid" not in pending_loan assert pending_loan["document_pid"] == "document_pid" # resolve pending document requests to `document_pid` mock_pending_loans_for_document.return_value = [pending_loan] returned_loan = current_circulation.circulation.trigger( new_loan, **dict( params, item_pid="item_pid", pickup_location_pid="pickup_location_pid", ) ) db.session.commit() assert returned_loan["state"] == "ITEM_RETURNED" # item `item_pid` has been attached to pending loan request on # `document_pid` automatically assert pending_loan["state"] == "PENDING" assert pending_loan["item_pid"] == "item_pid" assert pending_loan["document_pid"] == "document_pid"
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"