コード例 #1
0
 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)
コード例 #2
0
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()
コード例 #3
0
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)
コード例 #4
0
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
コード例 #5
0
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",
    )
コード例 #6
0
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))
コード例 #7
0
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)
コード例 #8
0
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="*")
コード例 #9
0
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",
    )
コード例 #10
0
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