Exemple #1
0
class Serial(db.Model):
    __tablename__ = "serials"
    id = db.Column(db.Integer, primary_key=True)
    number = db.Column(db.Integer)
    timestamp = db.Column(db.DateTime(), index=True, default=datetime.utcnow)
    date = db.Column(db.Date(), default=datetime.utcnow().date)
    name = db.Column(db.String(300), nullable=True)
    n = db.Column(db.Boolean)
    p = db.Column(db.Boolean)
    # stands for proccessed , which be modified after been processed
    pdt = db.Column(db.DateTime())
    # Fix: adding pulled by feature to tickets
    pulledBy = db.Column(db.Integer)
    office_id = db.Column(db.Integer, db.ForeignKey('offices.id'))
    task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))

    def __init__(self, number=100, office_id=1, task_id=1,
    name=None, n=False, p=False, pulledBy=0):
        self.number = number
        self.office_id = office_id
        self.task_id = task_id
        self.name = name
        self.n = n
        # fixing mass use tickets multi operators conflict
        self.p = p
        self.pulledBy = pulledBy

    @property
    def task(self):
        return Task.query.filter_by(id=self.task_id).first()

    @property
    def office(self):
        return Office.query.filter_by(id=self.office_id).first()
Exemple #2
0
class Touch_store(db.Model):
    __tablename__ = 'touchs'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(300))
    message = db.Column(db.Text())
    hsize = db.Column(db.String(100))
    hcolor = db.Column(db.String(100))
    hbg = db.Column(db.String(100))
    tsize = db.Column(db.String(100))
    tcolor = db.Column(db.String(100))
    msize = db.Column(db.String(100))
    mcolor = db.Column(db.String(100))
    mbg = db.Column(db.String(100))
    audio = db.Column(db.String(100))
    hfont = db.Column(db.String(100))
    mfont = db.Column(db.String(100))
    tfont = db.Column(db.String(100))
    mduration = db.Column(db.String(100))
    bgcolor = db.Column(db.String(100))
    p = db.Column(db.Boolean)
    n = db.Column(db.Boolean)
    tmp = db.Column(db.Integer)
    akey = db.Column(db.Integer, db.ForeignKey("media.id",
                                               ondelete='cascade'),
                     nullable=True)
    ikey = db.Column(db.Integer, db.ForeignKey("media.id",
                                               ondelete='cascade'),
                     nullable=True)

    def __init__(self, id=0, title="Please select a task to pull a tick for",
                 hsize="500%", hcolor="rgb(129, 200, 139)",
                 hbg="rgba(0, 0, 0, 0.50)", tsize="400%",
                 mbg="rgba(0, 0, 0, 0.50)", msize="400%",
                 mcolor="rgb(255, 255, 0)", tcolor="btn-danger",
                 message="Ticket has been issued, pleas wait your turn",
                 audio="bell_sound.wav", hfont="El Messiri", mfont="Mada",
                 tfont="Amiri", ikey=1, tmp=2, akey=5,
                 mduration="3000", bgcolor="bg_dark.jpg", p=False, n=True):
        self.id = 0
        self.hfont = hfont
        self.mfont = mfont
        self.tfont = tfont
        self.mduration = mduration
        self.title = title
        self.message = message
        self.hsize = hsize
        self.hcolor = hcolor
        self.hbg = hbg
        self.tsize = tsize
        self.tcolor = tcolor
        self.msize = msize
        self.mcolor = mcolor
        self.mbg = mbg
        self.audio = audio
        self.bgcolor = bgcolor
        self.ikey = ikey
        self.akey = akey
        self.p = p
        self.n = n
        self.tmp = tmp
Exemple #3
0
class Waiting(db.Model):
    __tablename__ = "waitings"
    id = db.Column(db.Integer, primary_key=True)
    number = db.Column(db.Integer)
    name = db.Column(db.String(300), nullable=True)
    n = db.Column(db.Boolean)
    office_id = db.Column(db.Integer, db.ForeignKey('offices.id'))
    task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))

    def __init__(self, number, office_id, task_id, name=None, n=False):
        self.number = number
        self.office_id = office_id
        self.task_id = task_id
        self.name = name
        self.n = n
Exemple #4
0
class User(UserMixin, db.Model, Mixin):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(200), unique=True)
    password_hash = db.Column(db.String(128))
    last_seen = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __init__(self, name, password, role_id):
        self.password = password
        self.name = name
        self.role_id = role_id

    def __str__(self):
        return "<%r>" % self.name

    @property
    def password(self):
        raise AttributeError('password not for reading !!')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    @classmethod
    def has_default_password(cls):
        return cls.query.filter_by(
            id=1).first().verify_password(DEFAULT_PASSWORD)
Exemple #5
0
class Operators(db.Model, Mixin):
    __tablename__ = "operators"
    crap = db.Column(db.Integer, primary_key=True)
    id = db.Column(db.Integer)
    office_id = db.Column(db.Integer, db.ForeignKey('offices.id'))

    def __init__(self, id, office_id):
        self.id = id
        self.office_id = office_id
Exemple #6
0
class Slides(db.Model, Mixin):
    __tablename__ = "slides"
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(300))
    hsize = db.Column(db.String(100))
    hcolor = db.Column(db.String(100))
    hfont = db.Column(db.String(100))
    hbg = db.Column(db.String(100))
    subti = db.Column(db.String(300))
    tsize = db.Column(db.String(100))
    tcolor = db.Column(db.String(100))
    tfont = db.Column(db.String(100))
    tbg = db.Column(db.String(100))
    bname = db.Column(db.String(300))
    ikey = db.Column(db.Integer,
                     db.ForeignKey("media.id", ondelete='cascade'),
                     nullable=True)
Exemple #7
0
class Vid(db.Model, Mixin):
    __tablename__ = "vids"
    id = db.Column(db.Integer, primary_key=True)
    vname = db.Column(db.String(300))
    enable = db.Column(db.Integer)
    ar = db.Column(db.Integer)
    controls = db.Column(db.Integer)
    mute = db.Column(db.Integer)
    vkey = db.Column(db.Integer,
                     db.ForeignKey("media.id", ondelete='cascade'),
                     nullable=True)

    def __init__(self, vname="", enable=0, ar=1, controls=1, mute=2, vkey=6):
        self.vname = vname
        self.enable = enable
        self.ar = ar
        self.controls = controls
        self.mute = mute
        self.vkey = vkey
Exemple #8
0
class AuthTokens(db.Model, Mixin):
    __tablename__ = 'auth_tokens'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))
    description = db.Column(db.String(300), nullable=True)
    token = db.Column(db.String(32), unique=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __init__(self, name, description=None):
        self.name = name
        self.description = description
        self.token = self.get_unique_token()
        # NOTE: defaulting role to Adminstator, most likely in the future
        # we would want this to be customizeable, with varied API permissions.
        self.role_id = USER_ROLE_ADMIN

    @classmethod
    def get_unique_token(cls):
        token = f'{uuid4()}'.replace('-', '')

        while cls.get(token=token):
            token = f'{uuid4()}'.replace('-', '')

        return token
Exemple #9
0
class Display_store(db.Model, Mixin):
    __tablename__ = 'displays'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(300))
    hsize = db.Column(db.String(100))
    hcolor = db.Column(db.String(100))
    h2size = db.Column(db.String(100))
    h2color = db.Column(db.String(100))
    h2font = db.Column(db.String(100))
    hbg = db.Column(db.String(100))
    tsize = db.Column(db.String(100))
    tcolor = db.Column(db.String(100))
    ssize = db.Column(db.String(100))
    scolor = db.Column(db.String(100))
    audio = db.Column(db.String(10))
    hfont = db.Column(db.String(100))
    tfont = db.Column(db.String(100))
    sfont = db.Column(db.String(100))
    mduration = db.Column(db.String(100))
    rrate = db.Column(db.String(100))
    announce = db.Column(db.String(100))
    anr = db.Column(db.Integer)
    anrt = db.Column(db.String(100))
    effect = db.Column(db.String(100))
    repeats = db.Column(db.String(100))
    bgcolor = db.Column(db.String(100))
    tmp = db.Column(db.Integer)
    prefix = db.Column(db.Boolean, default=False)
    always_show_ticket_number = db.Column(db.Boolean, default=False)
    # adding repeat announcement value
    r_announcement = db.Column(db.Boolean)
    akey = db.Column(db.Integer,
                     db.ForeignKey("media.id", ondelete='cascade'),
                     nullable=True)
    ikey = db.Column(db.Integer,
                     db.ForeignKey("media.id", ondelete='cascade'),
                     nullable=True)
    vkey = db.Column(db.Integer,
                     db.ForeignKey("media.id", ondelete='cascade'),
                     nullable=True)

    def __init__(self,
                 id=0,
                 title="FQM Queue Management",
                 hsize="500%",
                 hcolor="rgb(129, 200, 139)",
                 h2size="600%",
                 h2color="rgb(184, 193, 255)",
                 h2font="Mada",
                 hbg="rgba(0, 0, 0, 0.5)",
                 tsize="600%",
                 tcolor="rgb(184, 193, 255)",
                 ssize="500%",
                 scolor="rgb(224, 224, 224)",
                 audio="false",
                 hfont="El Messiri",
                 tfont="Mada",
                 repeats="3",
                 effect="fade",
                 sfont="Amiri",
                 mduration="3000",
                 rrate="2000",
                 announce="en-us",
                 ikey=4,
                 vkey=None,
                 akey=None,
                 anr=2,
                 anrt="each",
                 bgcolor="rgb(0,0,0)",
                 tmp=1):
        self.id = 0
        self.tfont = tfont
        self.hfont = hfont
        self.h2font = h2font
        self.sfont = sfont
        self.mduration = mduration
        self.rrate = rrate
        self.title = title
        self.hsize = hsize
        self.hcolor = hcolor
        self.hsize = hsize
        self.hcolor = hcolor
        self.h2color = h2color
        self.h2size = h2size
        self.hcolor = hcolor
        self.hbg = hbg
        self.tsize = tsize
        self.tcolor = tcolor
        self.ssize = ssize
        self.scolor = scolor
        self.audio = audio
        self.announce = announce
        self.bgcolor = bgcolor
        self.tmp = tmp
        self.anr = anr
        self.anrt = anrt
        self.effect = effect
        self.repeats = repeats
        self.ikey = ikey
        self.vkey = vkey
        self.akey = akey

    @classmethod
    def get(cls):
        return cls.query.first()
Exemple #10
0
class Serial(db.Model, TicketsMixin):
    __tablename__ = "serials"
    id = db.Column(db.Integer, primary_key=True)
    number = db.Column(db.Integer)
    timestamp = db.Column(db.DateTime(), index=True, default=datetime.utcnow)
    date = db.Column(db.Date(), default=datetime.utcnow().date)
    name = db.Column(db.String(300), nullable=True)
    n = db.Column(db.Boolean)
    p = db.Column(db.Boolean)
    # stands for proccessed , which be modified after been processed
    pdt = db.Column(db.DateTime())
    # Fix: adding pulled by feature to tickets
    pulledBy = db.Column(db.Integer)
    on_hold = db.Column(db.Boolean, default=False)
    office_id = db.Column(db.Integer, db.ForeignKey('offices.id'))
    task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))

    def __init__(self,
                 number=100,
                 office_id=1,
                 task_id=1,
                 name=None,
                 n=False,
                 p=False,
                 pulledBy=0):
        self.number = number
        self.office_id = office_id
        self.task_id = task_id
        self.name = name
        self.n = n
        # fixing mass use tickets multi operators conflict
        self.p = p
        self.pulledBy = pulledBy

    @property
    def task(self):
        return Task.query.filter_by(id=self.task_id).first()

    @property
    def office(self):
        return Office.query.filter_by(id=self.office_id).first()

    @property
    def puller_name(self):
        return User.get(self.pulledBy).name

    @classmethod
    def all_office_tickets(cls, office_id):
        ''' get tickets of the common task from other offices.

        Parameters
        ----------
            office_id: int
                id of the office to retreive tickets for.

        Returns
        -------
            Query of office tickets unionned with other offices tickets.
        '''
        strict_pulling = Settings.get().strict_pulling
        office = Office.get(office_id)
        all_tickets = cls.query.filter(cls.office_id == office_id,
                                       cls.number != 100)

        if not strict_pulling:
            for task in office.tasks:
                other_office_tickets = cls.query.filter(
                    and_(cls.task_id == task.id, cls.office_id != office_id))

                if other_office_tickets.count():
                    all_tickets = all_tickets.union(other_office_tickets)

        return all_tickets.filter(Serial.number != 100)\
                          .order_by(Serial.p, Serial.timestamp.desc())

    @classmethod
    def all_task_tickets(cls, office_id, task_id):
        ''' get tickets related to a given task and office.

        Parameters
        ----------
            office_id: int
                id of the office that we're querying from.
            task_id: int
                id of the task we want to retrieve its tickets.

        Returns
        -------
            Query of task tickets filterred based on `strict_pulling`.
        '''
        strict_pulling = Settings.get().strict_pulling
        filter_parameters = {'office_id': office_id, 'task_id': task_id}

        if not strict_pulling:
            filter_parameters.pop('office_id')

        return cls.query.filter_by(**filter_parameters)\
                        .filter(cls.number != 100)\
                        .order_by(cls.p, cls.timestamp.desc())

    @classmethod
    def get_last_pulled_ticket(cls, office_id=None):
        ''' get the last pulled ticket.

        Parameters
        ----------
            office_id: int
                office's id to filter last tickets by.

        Returns
        -------
            Last ticket pulled record.
        '''
        last_ticket = cls.query.filter_by(p=True)\
                               .filter(cls.number != 100)

        if office_id:
            last_ticket = last_ticket.filter_by(office_id=office_id)

        return last_ticket.order_by(cls.pdt.desc())\
                          .first()

    @classmethod
    def get_waiting_list_tickets(cls, office_id=None, limit=9):
        ''' get list of waiting tickets to be processed next.

        Parameters
        ----------
            office_id: int
                office's id to filter tickets by.
            limit: int
                number of ticket to limit the query to.

        Returns
        -------
            List of waiting list tickets.
        '''
        waiting_tickets = cls.query.filter_by(p=False)\
                                   .filter(cls.number != 100)

        if office_id:
            waiting_tickets = waiting_tickets.filter(
                cls.office_id == office_id)

        return waiting_tickets.order_by(cls.pdt.desc())\
                              .limit(limit)\
                              .all()

    def pull(self, office_id):
        ''' Mark a ticket as pulled and do the dues.

        Parameters
        ----------
            office_id: int
                id of the office from which the ticket is pulled.
        '''
        self.p = True
        self.pdt = datetime.utcnow()
        self.pulledBy = getattr(current_user, 'id', None)
        self.office_id = office_id

        db.session.add(self)
        db.session.commit()

    def toggle_on_hold(self):
        ''' Toggle the ticket `on_hold` status. '''
        self.on_hold = not self.on_hold

        db.session.add(self)
        db.session.commit()
Exemple #11
0
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from flask_login import UserMixin, current_user
from sqlalchemy.sql import and_, or_
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from app.middleware import db
from app.constants import USER_ROLES, DEFAULT_PASSWORD

mtasks = db.Table(
    'mtasks',
    db.Column('office_id',
              db.Integer,
              db.ForeignKey('offices.id'),
              primary_key=True),
    db.Column('task_id',
              db.Integer,
              db.ForeignKey('tasks.id'),
              primary_key=True))


class Mixin:
    @classmethod
    def get(cls, id=False):
        if id is False:
            return cls.query.first()

        return cls.query.filter_by(id=id).first()
Exemple #12
0
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from flask_login import UserMixin
from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime
from app.middleware import db

mtasks = db.Table(
    'mtasks',
    db.Column('office_id', db.Integer, db.ForeignKey('offices.id'), primary_key=True),
    db.Column('task_id', db.Integer, db.ForeignKey('tasks.id'), primary_key=True))


class Mixin:
    @classmethod
    def get(cls, id):
        return cls.query.filter_by(id=id).first()

class Office(db.Model, Mixin):
    __tablename__ = "offices"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Integer, unique=True)
    timestamp = db.Column(db.DateTime(), index=True, default=datetime.utcnow)
    prefix = db.Column(db.String(2))
    operators = db.relationship('Operators', backref='operators')
    tasks = db.relationship('Task', secondary=mtasks, lazy='subquery',
                            backref=db.backref('offices', lazy=True))
Exemple #13
0
class Serial(db.Model, TicketsMixin, Mixin):
    __tablename__ = "serials"
    query_class = SerialQuery
    STATUS_WAITING = TICKET_WAITING
    STATUS_PROCESSED = TICKET_PROCESSED
    STATUS_UNATTENDED = TICKET_UNATTENDED

    id = db.Column(db.Integer, primary_key=True)
    number = db.Column(db.Integer)
    timestamp = db.Column(db.DateTime(), index=True, default=datetime.utcnow)
    date = db.Column(db.Date(), default=datetime.utcnow().date)
    name = db.Column(db.String(300), nullable=True)
    n = db.Column(db.Boolean)
    p = db.Column(db.Boolean)
    # stands for proccessed , which be modified after been processed
    pdt = db.Column(db.DateTime())
    # Fix: adding pulled by feature to tickets
    pulledBy = db.Column(db.Integer)
    on_hold = db.Column(db.Boolean, default=False)
    status = db.Column(db.String(10), default=TICKET_PROCESSED)
    office_id = db.Column(db.Integer, db.ForeignKey('offices.id'))
    task_id = db.Column(db.Integer, db.ForeignKey('tasks.id'))

    ORDERS = {
        TICKET_ORDER_NEWEST_PROCESSED: [p, timestamp.desc()],
        TICKET_ORDER_NEWEST: [timestamp.desc()],
        TICKET_ORDER_OLDEST_PROCESSED: [p, timestamp],
        TICKET_ORDER_OLDEST: [timestamp]
    }

    def __init__(self,
                 number=100,
                 office_id=1,
                 task_id=1,
                 name=None,
                 n=False,
                 p=False,
                 pulledBy=0,
                 status=TICKET_WAITING):
        self.number = number
        self.office_id = office_id
        self.task_id = task_id
        self.name = name
        self.n = n
        self.p = p
        self.pulledBy = pulledBy
        self.status = status

    @property
    def task(self):
        return Task.query.filter_by(id=self.task_id).first()

    @property
    def office(self):
        return Office.query.filter_by(id=self.office_id).first()

    @property
    def puller_name(self):
        return User.get(self.pulledBy).name

    @classmethod
    def all_clean(cls):
        return cls.query.filter(cls.number != 100)

    @classmethod
    def all_office_tickets(cls, office_id, desc=True, order=True):
        ''' get tickets of the common task from other offices.

        Parameters
        ----------
            office_id: int
                id of the office to retreive tickets for.
            desc: bool
                if return it in desending oreder, default is True.

        Returns
        -------
            Query of office tickets unionned with other offices tickets.
        '''
        strict_pulling = Settings.get().strict_pulling
        office = Office.get(office_id)
        all_tickets = cls.query.filter(cls.office_id == office_id,
                                       cls.number != 100)

        if not strict_pulling:
            for task in office.tasks:
                other_office_tickets = cls.query.filter(
                    and_(cls.task_id == task.id, cls.office_id != office_id))

                if other_office_tickets.count():
                    all_tickets = all_tickets.union(other_office_tickets)

        all_tickets = all_tickets.filter(Serial.number != 100)

        if order:
            all_tickets = all_tickets.order_by(
                Serial.p,
                Serial.timestamp.desc() if desc else Serial.timestamp)

        return all_tickets

    @classmethod
    def all_task_tickets(cls, office_id, task_id, order=True):
        ''' get tickets related to a given task and office.

        Parameters
        ----------
            office_id: int
                id of the office that we're querying from.
            task_id: int
                id of the task we want to retrieve its tickets.

        Returns
        -------
            Query of task tickets filterred based on `strict_pulling`.
        '''
        strict_pulling = Settings.get().strict_pulling
        filter_parameters = {'office_id': office_id, 'task_id': task_id}

        if not strict_pulling:
            filter_parameters.pop('office_id')

        tickets = cls.query.filter_by(**filter_parameters)\
                           .filter(cls.number != 100)\

        if order:
            return tickets.order_by(cls.p, cls.timestamp.desc())

        return tickets

    @classmethod
    def get_last_pulled_ticket(cls, office_id=None):
        ''' get the last pulled ticket.

        Parameters
        ----------
            office_id: int
                office's id to filter last tickets by.

        Returns
        -------
            Last ticket pulled record.
        '''
        last_ticket = cls.query.filter_by(p=True)\
                               .filter(cls.number != 100)

        if office_id:
            last_ticket = last_ticket.filter_by(office_id=office_id)

        return last_ticket.order_by(cls.pdt.desc())\
                          .first()

    @classmethod
    def get_waiting_list_tickets(cls, office_id=None, limit=9):
        ''' get list of waiting tickets to be processed next.

        Parameters
        ----------
            office_id: int
                office's id to filter tickets by.
            limit: int
                number of ticket to limit the query to.

        Returns
        -------
            List of waiting list tickets.
        '''
        waiting_tickets = cls.query.filter_by(p=False)\
                                   .filter(cls.number != 100)

        if office_id:
            waiting_tickets = waiting_tickets.filter(
                cls.office_id == office_id)

        return waiting_tickets.order_by(cls.pdt.desc())\
                              .limit(limit)\
                              .all()

    @classmethod
    def get_processed_tickets(cls, office_id=None, limit=9, offset=0):
        '''get list of last processed tickets.

        Parameters
        ----------
        office_id : int, optional
            office id to filter tickets for, by default None
        limit : int, optional
            limit the list of ticket to it, by default 9
        '''
        processed_tickets = cls.query.filter(cls.p == True, cls.number != 100)

        if office_id:
            processed_tickets = processed_tickets.filter(
                cls.office_id == office_id)

        return processed_tickets.order_by(cls.pdt.desc())\
                                .limit(limit)\
                                .offset(offset)\
                                .all()

    @classmethod
    def get_next_ticket(cls, task_id=None, office_id=None):
        strict_pulling = Settings.get().strict_pulling
        single_row = Settings.get().single_row
        task = Task.get(0 if single_row else task_id)
        office = Office.get(0 if single_row else office_id)
        global_pull = not bool(task_id and office_id)

        next_tickets = Serial.query.filter(Serial.number != 100,
                                           Serial.p != True,
                                           Serial.on_hold == False)
        next_ticket = None

        if not global_pull:
            next_ticket = next_tickets.filter(Serial.task_id == task.id)

            if strict_pulling:
                next_ticket = next_ticket.filter(Serial.office_id == office.id)

        next_ticket = (next_tickets if global_pull else next_ticket)\
            .order_by(Serial.timestamp)\
            .first()

        if single_row:
            current_ticket = office.tickets\
                                   .order_by(Serial.timestamp.desc())\
                                   .first()
            next_ticket = Serial(
                number=getattr(current_ticket, 'number', 100) + 1,
                office_id=office.id,
                task_id=task.id)

            db.session.add(next_ticket)
            db.session.commit()

        return next_ticket

    @classmethod
    def create_new_ticket(cls, task, office=None, name_or_number=None):
        '''Create a new registered or printed ticket.

        Parameters
        ----------
        task: Task instance
            task to link the ticket to.
        office: Office instance
            office to link the ticket to, default is None.
        name_or_number: str
            ticket's name or number value.

        Returns
        -------
        Serial, exception
            a new ticket printed or registered ticket.
        '''
        from app.printer import assign, printit, printit_ar, print_ticket_cli, print_ticket_cli_ar

        windows = os.name == 'nt'
        touch_screen_stings = Touch_store.get()
        ticket_settings = Printer.get()
        settings = Settings.get()
        printed = not touch_screen_stings.n
        next_number = cls.query.order_by(cls.number.desc()).first().number + 1
        office = office or task.least_tickets_office()
        ticket, exception = None, None

        if printed:
            tickets = Serial.all_office_tickets(office.id, desc=False)
            current_ticket = getattr(tickets.first(), 'number', None)
            common_arguments = (f'{office.prefix}.{next_number}',
                                f'{office.prefix}{office.name}',
                                tickets.count(), task.name,
                                f'{office.prefix}.{current_ticket}')

            try:
                if windows or settings.lp_printing:
                    (print_ticket_cli_ar if ticket_settings.langu == 'ar' else
                     print_ticket_cli)(ticket_settings.name,
                                       *common_arguments,
                                       language=ticket_settings.langu,
                                       windows=windows,
                                       unix=not windows)
                else:
                    printer = assign(ticket_settings.vendor,
                                     ticket_settings.product,
                                     ticket_settings.in_ep,
                                     ticket_settings.out_ep)
                    (printit_ar if ticket_settings.langu == 'ar' else printit)(
                        printer,
                        *common_arguments,
                        lang=ticket_settings.langu,
                        scale=ticket_settings.scale)
            except Exception as e:
                exception = e

        if not exception:
            ticket = Serial(number=next_number,
                            office_id=office.id,
                            task_id=task.id,
                            name=name_or_number,
                            n=not printed)

            db.session.add(ticket)
            db.session.commit()

        return ticket, exception

    def pull(self, office_id=None, puller_id=None):
        ''' Mark a ticket as pulled and do the dues.

        Parameters
        ----------
            office_id: int
                id of the office from which the ticket is pulled.
        '''
        self.p = True
        self.pdt = datetime.utcnow()
        self.pulledBy = puller_id or getattr(current_user, 'id', None)
        self.status = TICKET_PROCESSED

        if office_id:
            self.office_id = office_id

        db.session.add(self)
        db.session.commit()

    def toggle_on_hold(self):
        ''' Toggle the ticket `on_hold` status. '''
        self.on_hold = not self.on_hold

        db.session.add(self)
        db.session.commit()