def new_expiration_date(loan_test_data, date): loan = current_circulation.loan_record_cls.get_record_by_pid( loan_test_data["pid"]) loan.update(end_date=date.isoformat()) loan.commit() db.session.commit() current_circulation.loan_indexer().index(loan)
def create_loan_when_ongoing(ill, legacy_record): """Create a loan for the ongoing borrowing request.""" default_location_pid_value, _ = current_app_ils.get_default_location_pid if ill["status"] != "ON_LOAN": return patron_pid = ill["patron_pid"] item_pid = {"value": ill.pid.pid_value, "type": ill.pid.pid_type} document_pid = ill["document_pid"] loan_dict = dict( patron_pid=str(patron_pid), transaction_location_pid=default_location_pid_value, transaction_user_pid=str(SystemAgent.id), document_pid=document_pid, item_pid=item_pid, state="ITEM_ON_LOAN", start_date=ill["received_date"], # former due date of borrowing request becomes due date of the loan end_date=legacy_record.get("due_date", CDS_ILS_FALLBACK_CREATION_DATE)) validate_loan(loan_dict, item_pid["value"], borrower_id=patron_pid) loan = import_record(loan_dict, rectype="loan", legacy_id="ILL loan", mint_legacy_pid=False) current_circulation.loan_indexer().index(loan) db.session.commit()
def _update_document_pending_request_for_item(item_pid, **kwargs): """Update pending loans on a Document with no Item attached yet. :param item_pid: a dict containing `value` and `type` fields to uniquely identify the item. """ document_pid = get_document_pid_by_item_pid(item_pid) for pending_loan in get_pending_loans_by_doc_pid(document_pid): pending_loan["item_pid"] = item_pid pending_loan.commit() db.session.commit() current_circulation.loan_indexer().index(pending_loan)
def update_dates_loan( record, start_date=None, end_date=None, request_start_date=None, request_expire_date=None, ): """Updates the dates of a loan.""" state = record["state"] is_active_or_completed = ( state in CIRCULATION_STATES_LOAN_ACTIVE or state in CIRCULATION_STATES_LOAN_COMPLETED ) data = copy(record) if is_active_or_completed: today = date.today().strftime("%Y-%m-%d") if request_start_date or request_expire_date: raise IlsException( description="Cannot modify request dates of " "an active or completed loan." ) if start_date: if start_date > today: raise InvalidParameterError( description="Start date cannot be in " "the future for active loans." ) data["start_date"] = start_date if end_date: data["end_date"] = end_date if data["end_date"] < data["start_date"]: raise InvalidParameterError(description="Negative date range.") else: # Pending or cancelled if start_date or end_date: raise IlsException( description="Cannot modify dates of " "a pending or cancelled loan." ) if request_start_date: data["request_start_date"] = request_start_date if request_expire_date: data["request_expire_date"] = request_expire_date if data["request_expire_date"] < data["request_start_date"]: raise InvalidParameterError(description="Negative date range.") record.update(data) record.commit() db.session.commit() current_circulation.loan_indexer().index(record) return record
def clean_loans(user_email, given_date): """Clean loans and doc requests created by given user on given date.""" patron = User.query.filter_by(email=user_email).one() patron_pid = patron.get_id() patron_document_requests = ( current_app_ils.document_request_search_cls().filter( "bool", filter=[ Q("term", patron_pid=patron_pid), Q("term", _created=given_date), ], ).scan()) for hit in patron_document_requests: document_request = ( current_app_ils.document_request_record_cls.get_record_by_pid( hit.pid)) document_request.delete(force=True) db.session.commit() current_app_ils.document_indexer.delete(document_request) patron_loans = (current_circulation.loan_search_cls().filter( "bool", filter=[ Q("term", patron_pid=patron_pid), Q("term", _created=given_date), ], ).scan()) for hit in patron_loans: loan = current_circulation.loan_record_cls.get_record_by_pid(hit.pid) loan.delete(force=True) db.session.commit() current_circulation.loan_indexer().delete(loan) if "item_pid" in loan: item = current_app_ils.item_record_cls.get_record_by_pid( loan["item_pid"]["value"]) loan_index = current_circulation.loan_search_cls.Meta.index wait_es_refresh(loan_index) current_app_ils.item_indexer.index(item) current_search.flush_and_refresh(index="*") click.secho( "Loans and document requests of user with pid '{0}' have been deleted." .format(patron_pid), fg="blue", )
def extend_active_loans_location_closure(location_pid): """Extends all ongoing loans that would end on a closure.""" modified_count = 0 for hit in get_active_loans().scan(): if circulation_item_location_retriever(hit.item_pid) == location_pid: current_end_date = arrow.get(hit.end_date).date() new_end_date = find_next_open_date(location_pid, current_end_date) if new_end_date != current_end_date: # Update loan modified_count += 1 loan = current_circulation.loan_record_cls.get_record_by_pid( hit.pid ) _log("extend_loan_closure_before", loan) loan.update(end_date=new_end_date.isoformat()) loan.commit() current_circulation.loan_indexer().index(loan) _log("extend_loan_closure_after", loan) send_loan_end_date_updated_mail.apply_async((loan,)) db.session.commit() _log("extend_loan_closure_end", dict(modified_count=modified_count))
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 create_loan(user_email, is_past_loan): """Create a loan.""" # hardcode doc/item pids from the demo_data jsons ongoing_loan_item_pid = "vgrh9-jvj8E" past_loan_item_pid = "678e3-an678A" ongoing_loan_doc_pid = "67186-5rs9E" past_loan_doc_pid = "qaywb-gfe4B" active_loan = (get_active_loan_by_item_pid({ "type": "pitmid", "value": ongoing_loan_item_pid }).execute().hits) lt_es7 = ES_VERSION[0] < 7 total = active_loan.total if lt_es7 else active_loan.total.value if total > 0 and not is_past_loan: click.secho( "Item for ongoing loan is already loaned by patron with email {0}." .format(active_loan[0].patron.email), fg="red", ) return patron = User.query.filter_by(email=user_email).one() patron_pid = patron.get_id() loc_pid, _ = current_app_ils.get_default_location_pid delivery = list( current_app.config["ILS_CIRCULATION_DELIVERY_METHODS"].keys())[randint( 0, 1)] loan_dict = { "pid": RecordIdProviderV2.create().pid.pid_value, "patron_pid": "{}".format(patron_pid), "pickup_location_pid": "{}".format(loc_pid), "transaction_location_pid": "{}".format(loc_pid), "transaction_user_pid": "{}".format(patron_pid), "delivery": { "method": delivery }, } if is_past_loan: loan_dict["state"] = "ITEM_RETURNED" loan_dict["document_pid"] = past_loan_doc_pid transaction_date = start_date = arrow.utcnow() - timedelta(days=365) end_date = start_date + timedelta(weeks=4) item_pid = past_loan_item_pid else: loan_dict["state"] = "ITEM_ON_LOAN" loan_dict["document_pid"] = ongoing_loan_doc_pid transaction_date = start_date = arrow.utcnow( ) - (timedelta(weeks=4) - timedelta( days=current_app.config["ILS_CIRCULATION_LOAN_WILL_EXPIRE_DAYS"])) end_date = start_date + timedelta(weeks=4) item_pid = ongoing_loan_item_pid loan_dict["transaction_date"] = transaction_date.isoformat() loan_dict["start_date"] = start_date.date().isoformat() loan_dict["end_date"] = end_date.date().isoformat() loan_dict["extension_count"] = randint(0, 3) loan_dict["item_pid"] = {"type": ITEM_PID_TYPE, "value": item_pid} loan = current_circulation.loan_record_cls.create(loan_dict) minter(CIRCULATION_LOAN_PID_TYPE, "pid", loan) db.session.commit() current_circulation.loan_indexer().index(loan) item = current_app_ils.item_record_cls.get_record_by_pid(item_pid) current_app_ils.item_indexer.index(item) current_search.flush_and_refresh(index="*") doc = current_app_ils.document_record_cls.get_record_by_pid( loan_dict["document_pid"]) click.secho( "Loan with pid '{0}' on document '{1}' was created.".format( loan_dict["pid"], doc["title"]), fg="blue", )
def anonymize_patron_data(patron_pid, force=False): """Anonymize all the data/activity related to the given patron pid.""" if patron_pid is None: raise ValueError("No patron pid was provided.") SystemAgent = current_app.config["ILS_PATRON_SYSTEM_AGENT_CLASS"] if str(patron_pid) == str(SystemAgent.id): raise ValueError("The patron pid cannot be the SystemAgent") try: patron = current_app_ils.patron_cls.get_patron(patron_pid) except PatronNotFoundError: patron = None if not force: raise PatronNotFoundError(patron_pid) n_loans = get_active_loans_by_patron_pid(patron_pid).count() if n_loans > 0: raise AnonymizationActiveLoansError( "Cannot delete user {0}: found {1} active loans.".format( patron_pid, n_loans)) OrderSearch = current_ils_acq.order_search_cls n_orders = ( OrderSearch().get_ongoing_orders_by_patron_pid(patron_pid).count()) if n_orders > 0: raise AnonymizationActiveLoansError( "Cannot delete user {0}: found {1} active orders.".format( patron_pid, n_orders)) # get anonymous patron values cls = current_app.config["ILS_PATRON_ANONYMOUS_CLASS"] anonymous_patron_fields = cls().dumps_loader() patron_loans = get_loans_by_patron_pid(patron_pid).scan() Loan = current_circulation.loan_record_cls indices = 0 for hit in patron_loans: loan = Loan.get_record_by_pid(hit.pid) completed = (current_app.config["CIRCULATION_STATES_LOAN_CANCELLED"] + current_app.config["CIRCULATION_STATES_LOAN_COMPLETED"]) if loan["state"] not in completed: params = deepcopy(loan) params.update( dict( cancel_reason="Loan request cancelled by the system.", transaction_user_pid=str(SystemAgent.id), )) loan = current_circulation.circulation.trigger( loan, **dict(params, trigger="cancel")) loan["patron_pid"] = anonymous_patron_fields["pid"] loan["patron"] = anonymous_patron_fields loan.commit() current_circulation.loan_indexer().index(loan) indices += 1 BorrowingRequestsSearch = current_ils_ill.borrowing_request_search_cls patron_borrowing_requests = ( BorrowingRequestsSearch().search_by_patron_pid(patron_pid).scan()) BorrowingRequest = current_ils_ill.borrowing_request_record_cls indexer = current_ils_ill.borrowing_request_indexer_cls() for hit in patron_borrowing_requests: borrowing_request = BorrowingRequest.get_record_by_pid(hit.pid) borrowing_request["patron"] = anonymous_patron_fields borrowing_request["patron_pid"] = anonymous_patron_fields["pid"] borrowing_request.commit() indexer.index(borrowing_request) indices += 1 DocumentRequestSearch = current_app_ils.document_request_search_cls patron_document_requests = ( DocumentRequestSearch().search_by_patron_pid(patron_pid).scan()) DocumentRequest = current_app_ils.document_request_record_cls for hit in patron_document_requests: document_request = DocumentRequest.get_record_by_pid(hit.pid) if document_request["state"] == "PENDING": document_request["state"] = "DECLINED" document_request["decline_reason"] = "USER_CANCEL" document_request["patron"] = anonymous_patron_fields document_request["patron_pid"] = anonymous_patron_fields["pid"] document_request.commit() current_app_ils.document_request_indexer.index(document_request) indices += 1 patron_acquisitions = OrderSearch().search_by_patron_pid(patron_pid).scan() Order = current_ils_acq.order_record_cls for hit in patron_acquisitions: acquisition = Order.get_record_by_pid(hit.pid) for line in acquisition["order_lines"]: if line["patron_pid"] == patron_pid: line["patron_pid"] = anonymous_patron_fields["pid"] acquisition.commit() current_ils_acq.order_indexer.index(acquisition) indices += 1 # delete rows from db dropped = delete_user_account(patron_pid) # anonymize recipient id in emails emails = anonymize_patron_in_email_logs(patron_pid) db.session.commit() if patron: try: patron_indexer = current_app_ils.patron_indexer patron_indexer.delete(patron) except NotFoundError: pass return dropped, indices, emails