Ejemplo n.º 1
0
class Book(Document):
    """
    Book document type.
    These could be checked out for 2 weeks, if they are bestsellers.
    Otherwise, students check out these for 3 weeks, and faculty members check out these for 4 weeks.
    """

    __tablename__ = 'books'

    id = db.Column(db.Integer, db.ForeignKey('documents.id'), primary_key=True)
    """ Integer primary foreign key to documents. """

    edition = db.Column(db.Integer)
    """ Book edition. """

    publishment_year = db.Column(db.Integer)
    """ Publishment year. """

    bestseller = db.Column(db.Boolean, default=False)
    """ Whether this book is a bestseller. """

    publisher = db.Column(db.String(80))
    """ Relation with publisher. """

    reference = db.Column(db.Boolean, default=False)
    """ Whether this book is a reference book"""

    __mapper_args__ = {'polymorphic_identity': 'book'}
Ejemplo n.º 2
0
class QueuedRequest(db.Model):
    __tablename__ = 'queued_requests'

    patron = db.relationship('Patron', back_populates='queued_requests')
    patron_id = db.Column(db.ForeignKey('users.id'), primary_key=True)

    document = db.relationship('Document', back_populates='queued_requests')
    document_id = db.Column(db.ForeignKey('documents.id'), index=True)

    created_at = db.Column(db.DateTime, default=text('NOW()'))
    resolved_at = db.Column(db.DateTime, default=None, nullable=True)

    priority = association_proxy('patron', 'queuing_priority')

    notified = db.Column(db.Boolean, nullable=False, default=False)

    def resolve(self):
        self.resolved_at = datetime.datetime.now()
Ejemplo n.º 3
0
class AVMaterial(Document):
    """
    AVMaterial document type.
    These could be checked out for 2 weeks by anyone.
    """

    __tablename__ = 'av_materials'

    id = db.Column(db.Integer, db.ForeignKey('documents.id'), primary_key=True)
    """ Primary foreign key to documents. """

    __mapper_args__ = {
        'polymorphic_identity': 'av_material'
    }
Ejemplo n.º 4
0
class JournalArticle(Document):
    """
    Journal article type of document.
    These could be checked out for two weeks by anyone.
    """

    __tablename__ = 'journal_articles'

    id = db.Column(db.Integer, db.ForeignKey('documents.id'), primary_key=True)
    """ Integer primary key. """

    issue_editor = db.Column(db.String(80))
    """ Editor of the issue. """

    issue_publication_date = db.Column(db.Date)
    """ Publication date of the issue. """

    journal = db.Column(db.String(80))
    """ Journal. """

    __mapper_args__ = {'polymorphic_identity': 'journal_article'}
Ejemplo n.º 5
0
class DocumentCopy(db.Model):
    """
    Copy of a document.
    References a specific document and document type by foreign key.
    """

    __tablename__ = 'document_copies'

    id = db.Column(db.Integer, primary_key=True)
    """ Integer primary key. """

    document_id = db.Column(db.Integer, db.ForeignKey('documents.id'))
    """ Foreign key to documents. """

    document = db.relationship('Document', back_populates='copies')
    """ Associated document. """

    location = db.Column(db.String(200))
    """ Location of the copy in the physical library. """

    loan = db.relationship('Loan',
                           back_populates='document_copy',
                           uselist=False)
    """ Relation to current loan. May be None when document is available. """
Ejemplo n.º 6
0
class Loan(db.Model):
    """
    Model for one loan of a specific document by a specific user.
    Internal model, gets squashed in the api.
    """
    class Status(enum.Enum):
        """
        Loan status.
        Each loan can be:

         * `requested` - which means that it has been requested by a patron.

         * `approved` - which means that a librarian has approved the request, and the document is now in patron's possession

         * `returned` - which means that the patron has supposedly brought the document into the library, and it is now waiting for approval from a librarian
        """
        approved = 1
        requested = 2
        returned = 3

    __tablename__ = 'loans'

    id = db.Column(db.Integer, primary_key=True)
    """ Integer primary key. """

    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    """ Foreign key to user. """

    user = db.relationship('User')
    """ Borrowing user id. """

    document_copy_id = db.Column(db.Integer,
                                 db.ForeignKey('document_copies.id'))
    """ Foreign key to document_copy. """

    document_copy = db.relationship('DocumentCopy', back_populates='loan')
    """ Loaned document_copy. """

    due_date = db.Column(db.Date)
    """ Date when the document_copy must be returned. """

    renewed = db.Column(db.Boolean, default=False)
    """ Whether this loan was renewed. """

    status = db.Column(db.Enum(Status), default=Status.requested)
    """ Current loan status. """

    document = association_proxy('document_copy', 'document')

    def get_overdue_fine(self):
        """
        Get total overdue fine for this loan.
        Returns 0 if it is not overdue.

        :return: the overdue fine, in rubles.
        """
        days = (datetime.date.today() - self.due_date).days
        return max(
            0,
            min(days * app.config.get('OVERDUE_FINE_PER_DAY', 100),
                self.document.price))

    @staticmethod
    def overdue_loan_query():
        """
        Get the query for overdue loans.

        :return: query for overdue loans.
        """

        return Loan.query.filter(Loan.status == Loan.Status.approved,
                                 Loan.due_date < datetime.date.today())

    @staticmethod
    def get_overdue_loans():
        """
        Get overdue loans.

        :return: list.
        """

        return Loan.overdue_loan_query().all()

    @staticmethod
    def get_overdue_loan_count():
        """
        Get the amount of overdue loans.

        :return: amount.
        """

        return Loan.overdue_loan_query().count()

    @staticmethod
    def requested_loan_query():
        """
        Get the query for requested loans.

        :return: query for requested loans.
        """

        return Loan.query.filter(Loan.status == Loan.Status.requested)

    @staticmethod
    def get_requested_loans():
        """
        Get requested loans.

        :return: list.
        """

        return Loan.requested_loan_query().all()

    @staticmethod
    def get_requested_loan_count():
        """
        Get the amount of requested loans.

        :return: amount.
        """

        return Loan.requested_loan_query().count()

    @staticmethod
    def returned_loan_query():
        """
        Get the query for returned loans.

        :return: query for returned loans.
        """

        return Loan.query.filter(Loan.status == Loan.Status.returned)

    @staticmethod
    def get_returned_loans():
        """
        Get returned loans.

        :return: list.
        """

        return Loan.returned_loan_query().all()

    @staticmethod
    def get_returned_loan_count():
        """
        Get the amount of returned loans.

        :return: amount.
        """

        return Loan.returned_loan_query().count()

    def overdue(self):
        """
        Check whether this loan is overdue.

        :return: whether this loan is overdue.
        """

        return datetime.date.today() >= self.due_date

    def overdue_days(self):
        """
        Gives number of overdued days of loan.

        Overdued or overdue? English is my second language.
        But Leonid Lyigin says that my eNgLiSh is finish <3

        :return: number of days
        """

        if self.overdue():
            delta = datetime.date.today() - self.due_date
            return ((delta.total_seconds() / 60) / 60) / 24

    def renew_document(self):
        """

        Allows user to renew his period of book checkout for one more period,
        without overduing the renewable document by old date

        :return: new date, when book will become overdued
        """

        if self.document.outstanding:
            raise ValueError

        if self.can_be_renewed():
            self.renewed = True
            delta = self.user.get_checkout_period_for(self.document)
            self.due_date = datetime.date.today() + delta
            return self.due_date
        else:
            raise ValueError

    def can_be_renewed(self):
        """
        Flag for renew_document function.
        Gives information is renew option is it available to renew loan or not.

        :return: whether the loan can be renewed.
        """

        from hexagonal.model.visiting_professor_patron import VisitingProfessorPatron

        if self.due_date > datetime.date.today():
            if isinstance(self.user,
                          VisitingProfessorPatron) or not self.renewed:
                return True
        return False