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 _validate_bucket_size(self):
        """Validate bucket size parameter."""
        size_param = request.args.get("size", self.default_bucket_size)
        try:
            value = int(size_param)
        except ValueError:
            msg = "Parameter `size` is not a number: {}".format(size_param)
            raise InvalidParameterError(description=msg)

        if value > self.max_result_window:
            msg = "Parameter `size` should be lower than {}".format(
                self.max_result_window)
            raise InvalidParameterError(description=msg)
        return value
 def validate_date(param, date):
     """Validate a date."""
     try:
         return datetime.strptime(date, "%Y-%m-%d")
     except ValueError:
         msg = "Parameter '{}' is invalid: {}".format(param, date)
         raise InvalidParameterError(description=msg)
    def _validate_start_date_range(self):
        """Validate start date range parameters."""
        def validate_date(param, date):
            """Validate a date."""
            try:
                return datetime.strptime(date, "%Y-%m-%d")
            except ValueError:
                msg = "Parameter '{}' is invalid: {}".format(param, date)
                raise InvalidParameterError(description=msg)

        from_date = request.args.get("from_date", None)
        from_date_obj = None
        to_date = request.args.get("to_date", None)
        to_date_obj = None

        if from_date:
            from_date_obj = validate_date("from_date", from_date)
        if to_date:
            to_date_obj = validate_date("to_date", to_date)

        if from_date_obj and to_date_obj and to_date_obj < from_date_obj:
            msg = "Parameter 'to_date' cannot be before 'from_date'."
            raise InvalidParameterError(description=msg)

        return from_date, to_date