Пример #1
0
class RoleInvite(SoftDeletionModel):
    __tablename__ = 'role_invites'
    __table_args__ = (UniqueConstraint('email',
                                       'role_id',
                                       'event_id',
                                       name='email_role_event_uc'), )

    id = db.Column(db.Integer, primary_key=True)

    email = db.Column(db.String, nullable=False)
    role_name = db.Column(db.String, nullable=False)

    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', back_populates='role_invites')

    role_id = db.Column(db.Integer,
                        db.ForeignKey('roles.id', ondelete='CASCADE'))
    role = db.relationship("Role")

    hash = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    status = db.Column(db.String, default="pending")

    def __init__(
        self,
        email=None,
        role_name=None,
        event_id=None,
        role_id=None,
        created_at=None,
        status="pending",
        hash=None,
        deleted_at=None,
    ):
        self.email = email
        self.role_name = role_name
        self.event_id = event_id
        self.role_id = role_id
        self.created_at = created_at
        self.status = status
        self.hash = generate_hash()
        self.deleted_at = deleted_at

    def has_expired(self):
        # Check if invitation link has expired (it expires after 24 hours)
        return datetime.now(pytz.utc) > self.created_at + timedelta(hours=24)

    def __repr__(self):
        return '<RoleInvite %r:%r:%r>' % (
            self.email,
            self.event_id,
            self.role_id,
        )

    def __str__(self):
        return self.__repr__()
Пример #2
0
class UserTokenBlackListTime(db.Model):
    """user token blacklist time model class"""
    __tablename__ = 'user_token_blacklist_time'
    __table_args__ = (db.UniqueConstraint('user_id', name='user_blacklist_time_uc'),)

    id = db.Column(db.Integer, primary_key=True)
    created_at = db.Column(db.DateTime(timezone=True), default=sql_func.now(), nullable=False)
    blacklisted_at = db.Column(db.DateTime(timezone=True), default=sql_func.now(), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    user = db.relationship("User", backref="token_blacklist_times", foreign_keys=[user_id])

    def __init__(self, user_id=None, created_at=None, blacklisted_at=None):
        self.user_id = user_id
        self.created_at = created_at
        self.blacklisted_at = blacklisted_at

    def __str__(self):
        return '<TokenBlackListTime User %s blacklisted at %s>' % (self.user, self.blacklisted_at)
Пример #3
0
class UserTokenBlackListTime(db.Model):
    """user token blacklist time model class"""

    __tablename__ = 'user_token_blacklist_time'
    __table_args__ = (db.UniqueConstraint('user_id', name='user_blacklist_time_uc'),)

    id: int = db.Column(db.Integer, primary_key=True)
    created_at: datetime = db.Column(
        db.DateTime(timezone=True), default=sql_func.now(), nullable=False
    )
    blacklisted_at: datetime = db.Column(
        db.DateTime(timezone=True), default=sql_func.now(), nullable=False
    )
    user_id: int = db.Column(
        db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False
    )
    user = db.relationship(
        "User", backref="token_blacklist_times", foreign_keys=[user_id]
    )
Пример #4
0
class VideoRecording(db.Model):
    "Video Recording"

    __tablename__ = 'video_recordings'
    id = db.Column(db.Integer, primary_key=True)
    bbb_record_id = db.Column(db.String, nullable=True)
    participants = db.Column(db.Integer, nullable=False)
    url = db.Column(db.String, nullable=False)
    start_time = db.Column(db.DateTime(timezone=False), nullable=False)
    end_time = db.Column(db.DateTime(timezone=False), nullable=False)

    video_stream_id = db.Column(db.Integer,
                                db.ForeignKey('video_streams.id',
                                              ondelete='CASCADE'),
                                nullable=False)
    video_stream = db.relationship('VideoStream', backref='video_recordings')

    def __repr__(self):
        return f'<VideoRecording {self.video_stream.name!r} {self.url!r}>'
Пример #5
0
class Group(SoftDeletionModel):
    __tablename__ = 'groups'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'),
                        nullable=False)
    social_links = db.Column(db.JSON)
    logo_url = db.Column(db.String)
    banner_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    is_promoted = db.Column(db.Boolean, default=False, nullable=False)
    about = db.Column(db.Text)
    created_at: datetime = db.Column(db.DateTime(timezone=True),
                                     default=datetime.utcnow)
    modified_at: datetime = db.Column(db.DateTime(timezone=True),
                                      default=datetime.utcnow,
                                      onupdate=datetime.utcnow)

    @aggregated('followers',
                db.Column(db.Integer,
                          default=0,
                          server_default='0',
                          nullable=False))
    def follower_count(self):
        return func.count('1')

    user = db.relationship('User', backref='groups')
    roles = db.relationship("UsersGroupsRoles", backref="group")

    @property
    def follower(self):
        if not current_user:
            return None
        return UserFollowGroup.query.filter_by(user=current_user,
                                               group=self).first()

    @property
    def view_page_link(self):
        frontend_url = get_settings()['frontend_url']
        return f"{frontend_url}/g/{self.id}"
Пример #6
0
class Disease(db.Model):
    __tablename__ = 'diseases'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255))
    link = db.Column(db.String(255))
    added = db.Column(db.DateTime())

    def __repr__(self):
        return "<Disease(name='{}', link='{}', added={})>".format(
            self.name, self.link, self.added)
Пример #7
0
class Mail(db.Model):
    __tablename__ = 'mails'
    id = db.Column(db.Integer, primary_key=True)
    recipient = db.Column(db.String)
    time = db.Column(db.DateTime(timezone=True), default=func.now())
    action = db.Column(db.String)
    subject = db.Column(db.String)
    message = db.Column(db.String)

    def __repr__(self):
        return '<Mail %r to %r>' % (self.id, self.recipient)
Пример #8
0
class EventOrgaModel(SoftDeletionModel):
    """Event Orga object table"""

    __tablename__ = 'events_orga'

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String, nullable=False)
    starts_at = db.Column(db.DateTime(timezone=True), default=func.now())
    payment_currency = db.Column(db.String, nullable=False)

    def __repr__(self):
        return '<EventOrgaModel %r>' % self.name
Пример #9
0
class Usuario(db.Model, UserMixin):
    __tablename__ = 'usuarios'
    sequencial = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), unique=True, nullable=False)
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255), nullable=False)
    last_login = db.Column(db.DateTime())
    last_logout = db.Column(db.DateTime())
    papel_id = db.Column(db.Integer,
                         db.ForeignKey('papeis.sequencial'),
                         nullable=False)
    papel = db.relationship('Papel', backref="usuario", lazy=True)

    @property
    def is_authenticated(self):
        return True

    @property
    def is_active(self):
        return True

    @property
    def is_anonymous(self):
        return False

    def get_id(self):
        return str(self.sequencial)

    def get(self):
        return self

    def __init__(self):
        # Usuario()
        username = self.username
        email = self.email
        password = self.password
        # self.active = active

    def __repr__(self):
        return self.username
Пример #10
0
class AccessCode(SoftDeletionModel):
    __tablename__ = "access_codes"

    id: int = db.Column(db.Integer, primary_key=True)
    code: str = db.Column(db.String)
    access_url: str = db.Column(db.String)
    is_active: bool = db.Column(db.Boolean)
    tickets_number: int = db.Column(
        db.Integer)  # For event level access this holds the max. uses
    min_quantity: int = db.Column(db.Integer)
    max_quantity: int = db.Column(
        db.Integer
    )  # For event level access this holds the months for which it is valid
    valid_from: datetime = db.Column(db.DateTime(timezone=True), nullable=True)
    valid_till: datetime = db.Column(db.DateTime(timezone=True), nullable=True)
    ticket_id: int = db.Column(db.Integer,
                               db.ForeignKey('tickets.id', ondelete='CASCADE'))
    event_id: int = db.Column(db.Integer,
                              db.ForeignKey('events.id', ondelete='CASCADE'))
    created_at: datetime = db.Column(db.DateTime(timezone=True),
                                     default=func.now())
    marketer_id: int = db.Column(db.Integer,
                                 db.ForeignKey('users.id', ondelete='CASCADE'))

    marketer = db.relationship('User', backref='access_codes_')
    ticket = db.relationship('Ticket',
                             backref='access_code',
                             foreign_keys=[ticket_id])
    event = db.relationship('Event',
                            backref='access_codes',
                            foreign_keys=[event_id])

    @staticmethod
    def get_service_name():
        return 'access_code'

    @property
    def valid_expire_time(self):
        return self.valid_till or self.event.ends_at
Пример #11
0
class Task(Base):

    __tablename__ = 'task'

    id = db.Column(db.Integer(), primary_key=True)
    project_id = db.Column(db.Integer())
    project_name = db.Column(db.String(200))
    project_task_id = db.Column(db.Integer())
    project_task_name = db.Column(db.String(200))
    user_id = db.Column(db.Integer())
    date = db.Column(db.Date())
    updated = db.Column(db.DateTime(timezone=True))
    hour = db.Column(db.Float(scale=12, precision=2))
    minute = db.Column(db.Float(scale=6, precision=0))
    timesheet_id = db.Column(db.Integer())
    cost_center_id = db.Column(db.Integer())
    decimal_hours = hour + minute / 60.00

    @staticmethod
    def get_my_tasks(user_email):
        query = '''SELECT DISTINCT
                      t.id,
                      t.project_id,
                      p.name AS project_name,
                      t.project_task_id,
                      pt.name AS project_task_name,
                      t.user_id,
                      t.date,
                      t.updated,
                      t.hour,
                      t.minute,
                      t.timesheet_id,
                      t.cost_center_id
                    FROM task t
                    INNER JOIN project_task pt ON t.project_task_id = pt.id
                    INNER JOIN project p ON pt.project_id = p.id
                    LEFT JOIN user u ON t.user_id = u.id
                    WHERE
                    u.email = :email OR
                    p.id IN (SELECT DISTINCT p2.id FROM project p2
                         LEFT JOIN project_task pt2 ON pt2.project_id = p2.id
                         LEFT JOIN project_task_assign pta ON pta.project_task_id = pt2.id
                         LEFT JOIN booking b ON b.project_id = p2.id
                         LEFT JOIN user u ON (p2.user_id = u.id OR pta.user_id = u.id OR b.user_id = u.id)
                         WHERE u.email = :email AND p2.active="1");'''
        return Task.query.from_statement(
            text(query)).params(email=user_email).all()

    def __repr__(self):
        return '<Task %r>' % self.id
Пример #12
0
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    fullname = db.Column(db.String(255))
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role',
                            secondary=roles_users,
                            lazy='dynamic',
                            backref=db.backref('users', lazy='dynamic'))

    def has_role(self, role_name):
        return self.roles.filter_by(name=role_name).first()
Пример #13
0
class RoleInvite(db.Model):
    __tablename__ = 'role_invites'
    __table_args__ = (UniqueConstraint(
        'email',
        'role_id',
        'event_id',
        name='email_role_event_uc',
    ), )

    id = db.Column(db.Integer, primary_key=True)

    email = db.Column(db.String, nullable=False)
    role_name = db.Column(db.String, nullable=False)

    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', back_populates='role_invites')

    role_id = db.Column(db.Integer,
                        db.ForeignKey('roles.id', ondelete='CASCADE'))
    role = db.relationship("Role")

    hash = db.Column(db.String, default=generate_hash)
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    status = db.Column(db.String, default="pending")

    def has_expired(self):
        # Check if invitation link has expired (it expires after 24 hours)
        return datetime.now(pytz.utc) > self.created_at + timedelta(hours=24)

    def send_invite(self):
        """
        Send mail to invitee
        """
        user = User.query.filter_by(email=self.email).first()
        event = Event.query.filter_by(id=self.event_id).first()
        frontend_url = get_settings()['frontend_url']
        link = f"{frontend_url}/role-invites?token={self.hash}"
        if not has_access('is_coorganizer', event_id=event.id):
            raise ForbiddenError({'source': ''},
                                 "Co-Organizer Access Required")

        send_email_role_invite(self.email, self.role_name, event.name, link)
        if user:
            notify_event_role_invitation(self, user, current_user)

    def __repr__(self):
        return '<RoleInvite {!r}:{!r}:{!r}>'.format(self.email, self.event_id,
                                                    self.role_id)
Пример #14
0
class User(BaseMixin, UserMixin, db.Model):
    name = db.Column(db.String(255), unique=True)
    email = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role',
                            secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

    def __repr__(self):
        return "<User({id:d}|{name:s}|{email:s})".format(
            id=self.id,
            name=self.name,
            email=self.email,
        )
Пример #15
0
class ExportJob(db.Model):
    """Export Jobs model class"""

    __tablename__ = 'export_jobs'
    id = db.Column(db.Integer, primary_key=True)
    task = db.Column(db.String, nullable=False)
    starts_at = db.Column(db.DateTime(timezone=True), default=func.now())

    user_email = db.Column(db.String)
    # not linking to User because when user is deleted, this will be lost

    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref=backref('export_jobs'))

    def __repr__(self):
        return '<ExportJob %d for event %d>' % (self.id, self.event.id)
Пример #16
0
class Process(db.Model):
    """Request model class"""

    __tablename__ = 'processes'

    id = db.Column(db.Integer, primary_key=True)
    time = db.Column(db.DateTime(timezone=True),
                     default=datetime.now(pytz.utc))
    method = db.Column(db.String)
    path = db.Column(db.String)
    query = db.Column(db.String)
    body = db.Column(db.String)
    headers = db.relationship('Header',
                              secondary=process_headers,
                              backref=db.backref('processes', lazy='dynamic'))
    duration = db.Column(db.String)

    def __init__(self,
                 time=None,
                 method=None,
                 path=None,
                 query=None,
                 body=None,
                 headers=None):
        self.time = time
        self.method = method
        self.path = path
        self.query = query
        self.body = body
        if headers is None:
            self.headers = []
        else:
            self.headers = headers
        self.duration = self.time_duration()

    def time_duration(self):
        then = time.time()
        time.sleep(random.randint(15, 30))
        now = time.time()
        return now - then

    def __repr__(self):
        return '<Request %r>' % self.id

    def __str__(self):
        return self.__repr__()
class Notification(SoftDeletionModel):
    """
        Model for storing user notifications.
    """

    __tablename__ = 'notifications'

    id = db.Column(db.Integer, primary_key=True)

    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'))
    user = db.relationship('User', backref='notifications', foreign_keys=[user_id])

    title = db.Column(db.String)
    message = db.Column(db.Text)
    received_at = db.Column(db.DateTime(timezone=True))
    is_read = db.Column(db.Boolean)

    def __repr__(self):
        return f'<Notif {self.user}:{self.title}>'
class Activity(db.Model):
    __tablename__ = 'activities'
    id = db.Column(db.Integer, primary_key=True)
    actor = db.Column(db.String)  # user email + id
    time = db.Column(db.DateTime(timezone=True))
    action = db.Column(db.String)

    def __init__(self, actor=None, time=None, action=None):
        self.actor = actor
        self.time = time
        if self.time is None:
            self.time = datetime.now(pytz.utc)
        self.action = action

    def __repr__(self):
        return '<Activity by %s>' % self.actor

    def __str__(self):
        return self.__repr__()
class RoleInvite(db.Model):
    __tablename__ = 'role_invites'

    id = db.Column(db.Integer, primary_key=True)

    email = db.Column(db.String, nullable=False)
    role_name = db.Column(db.String, nullable=False)

    event_id = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', back_populates='role_invites')

    role_id = db.Column(db.Integer, db.ForeignKey('roles.id', ondelete='CASCADE'))
    role = db.relationship("Role")

    hash = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True))
    status = db.Column(db.String, default="pending")

    def __init__(self, email=None, role_name=None, event_id=None, role_id=None, created_at=None, status="pending", hash=None):
        self.email = email
        self.role_name = role_name
        self.event_id = event_id
        self.role_id = role_id
        self.created_at = created_at
        self.status = status
        self.hash = generate_hash()

    def has_expired(self):
        # Check if invitation link has expired (it expires after 24 hours)
        return datetime.now(pytz.utc) > self.created_at + timedelta(hours=24)

    def __repr__(self):
        return '<RoleInvite %r:%r:%r>' % (self.email,
                                          self.event_id,
                                          self.role_id,)

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return 'Invite for %r:%r:%r' % (self.email,
                                        self.event_id,
                                        self.role_id)
Пример #20
0
class Notification(db.Model):
    """
    Model for storing user notifications.
    """
    __tablename__ = 'notifications'

    id = db.Column(db.Integer, primary_key=True)

    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='CASCADE'))
    user = db.relationship('User',
                           backref='notifications',
                           foreign_keys=[user_id])

    title = db.Column(db.String)
    message = db.Column(db.Text)
    action = db.Column(db.String)
    received_at = db.Column(db.DateTime(timezone=True))
    is_read = db.Column(db.Boolean)

    def __init__(self,
                 user_id=None,
                 title=None,
                 message=None,
                 action=None,
                 is_read=False):
        self.user_id = user_id
        self.title = title
        self.message = message
        self.action = action
        self.received_at = datetime.now(pytz.utc)
        self.is_read = is_read

    def __repr__(self):
        return '<Notif %s:%s>' % (self.user, self.title)

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return '%r: %r' % (self.user, self.title)
Пример #21
0
class ImportJob(db.Model):
    """Import Jobs model class"""
    __tablename__ = 'import_jobs'
    id = db.Column(db.Integer, primary_key=True)
    task = db.Column(db.String, nullable=False)
    starts_at = db.Column(db.DateTime(timezone=True))

    user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'))
    user = db.relationship('User', backref='import_jobs')
    result = db.Column(db.String)
    result_status = db.Column(db.String)

    def __init__(self, task=None, user=None, result=None, result_status=None):
        self.task = task
        self.user = user
        self.result = result
        self.result_status = result_status
        self.starts_at = datetime.now(pytz.utc)

    def __repr__(self):
        return '<ImportJob %d by user %s>' % (self.id, str(self.user))

    def __str__(self):
        return self.__repr__()
Пример #22
0
class TicketHolder(SoftDeletionModel):
    __tablename__ = "ticket_holders"

    id: int = db.Column(db.Integer, primary_key=True)
    firstname: str = db.Column(db.String, nullable=False)
    lastname: str = db.Column(db.String, nullable=False)
    email: str = db.Column(CIText)
    address: str = db.Column(db.String)
    city: str = db.Column(db.String)
    state: str = db.Column(db.String)
    country: str = db.Column(db.String)
    job_title: str = db.Column(db.String)
    phone: str = db.Column(db.String)
    tax_business_info: str = db.Column(db.String)
    billing_address: str = db.Column(db.String)
    home_address: str = db.Column(db.String)
    shipping_address: str = db.Column(db.String)
    company: str = db.Column(db.String)
    work_address: str = db.Column(db.String)
    work_phone: str = db.Column(db.String)
    website: str = db.Column(db.String)
    blog: str = db.Column(db.String)
    twitter: str = db.Column(db.String)
    facebook: str = db.Column(db.String)
    instagram: str = db.Column(db.String)
    linkedin: str = db.Column(db.String)
    github: str = db.Column(db.String)
    gender: str = db.Column(db.String)
    accept_video_recording: bool = db.Column(db.Boolean)
    accept_share_details: bool = db.Column(db.Boolean)
    accept_receive_emails: bool = db.Column(db.Boolean)
    age_group: str = db.Column(db.String)
    birth_date: datetime = db.Column(db.DateTime(timezone=True))
    pdf_url: str = db.Column(db.String)
    ticket_id: int = db.Column(
        db.Integer, db.ForeignKey('tickets.id', ondelete='CASCADE'), nullable=False
    )
    order_id: int = db.Column(db.Integer, db.ForeignKey('orders.id', ondelete='CASCADE'))
    is_checked_in: bool = db.Column(db.Boolean, default=False)
    is_checked_out: bool = db.Column(db.Boolean, default=False)
    device_name_checkin: str = db.Column(db.String)
    checkin_times: str = db.Column(db.String)
    checkout_times: str = db.Column(db.String)
    attendee_notes: str = db.Column(db.String)
    event_id: int = db.Column(
        db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'), nullable=False
    )
    created_at: datetime = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
    modified_at: datetime = db.Column(
        db.DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow
    )
    complex_field_values: str = db.Column(db.JSON)
    user = db.relationship(
        'User',
        foreign_keys=[email],
        primaryjoin='User.email == TicketHolder.email',
        viewonly=True,
        backref='attendees',
        sync_backref=False,
    )
    order = db.relationship('Order', backref='ticket_holders')
    ticket = db.relationship('Ticket', backref='ticket_holders')

    @property
    def name(self):
        firstname = self.firstname if self.firstname else ''
        lastname = self.lastname if self.lastname else ''
        if firstname and lastname:
            return f'{firstname} {lastname}'
        else:
            return ''

    @property
    def qr_code(self):
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=0,
        )
        qr.add_data(self.order.identifier + "-" + str(self.id))
        qr.make(fit=True)
        img = qr.make_image()

        buffer = BytesIO()
        img.save(buffer, format="JPEG")
        img_str = str(base64.b64encode(buffer.getvalue()), 'utf-8')
        return img_str

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        return {
            'id': self.id,
            'firstname': self.firstname,
            'lastname': self.lastname,
            'email': self.email,
            'city': self.city,
            'address': self.address,
            'state': self.state,
            'country': self.country,
            'company': self.company,
            'taxBusinessInfo': self.tax_business_info,
        }

    @property
    def pdf_url_path(self) -> str:
        key = UPLOAD_PATHS['pdf']['tickets_all'].format(
            identifier=self.order.identifier, extra_identifier=self.id
        )
        return (
            'generated/tickets/{}/{}/'.format(key, generate_hash(key))
            + self.order.identifier
            + '.pdf'
        )
Пример #23
0
class Order(SoftDeletionModel):
    __tablename__ = "orders"

    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, unique=True, default=get_new_id)
    amount = db.Column(db.Float, nullable=False, default=0)
    address = db.Column(db.String)
    city = db.Column(db.String)
    state = db.Column(db.String)
    country = db.Column(db.String)
    zipcode = db.Column(db.String)
    company = db.Column(db.String)
    tax_business_info = db.Column(db.String)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='SET NULL'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='SET NULL'))
    marketer_id = db.Column(db.Integer,
                            db.ForeignKey('users.id', ondelete='SET NULL'))
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    completed_at = db.Column(db.DateTime(timezone=True),
                             nullable=True,
                             default=None)
    trashed_at = db.Column(db.DateTime(timezone=True),
                           nullable=True,
                           default=None)
    transaction_id = db.Column(db.String)
    paid_via = db.Column(db.String)
    payment_mode = db.Column(db.String)
    is_billing_enabled = db.Column(db.Boolean, nullable=False, default=False)
    brand = db.Column(db.String)
    exp_month = db.Column(db.Integer)
    exp_year = db.Column(db.Integer)
    last4 = db.Column(db.String)
    stripe_token = db.Column(db.String)
    paypal_token = db.Column(db.String)
    status = db.Column(db.String, default='initializing')
    cancel_note = db.Column(db.String, nullable=True)
    order_notes = db.Column(db.String)
    tickets_pdf_url = db.Column(db.String)

    discount_code_id = db.Column(
        db.Integer,
        db.ForeignKey('discount_codes.id', ondelete='SET NULL'),
        nullable=True,
        default=None,
    )
    discount_code = db.relationship('DiscountCode', backref='orders')

    event = db.relationship('Event', backref='orders')
    user = db.relationship('User', backref='orders', foreign_keys=[user_id])
    invoices = db.relationship("EventInvoice", backref='invoice_order')
    marketer = db.relationship('User',
                               backref='marketed_orders',
                               foreign_keys=[marketer_id])
    tickets = db.relationship("Ticket",
                              secondary='orders_tickets',
                              backref='order')
    order_tickets = db.relationship("OrderTicket", backref='order')

    def __repr__(self):
        return '<Order %r>' % self.id

    def get_invoice_number(self):
        return ('O' + str(int(time.mktime(self.created_at.timetuple()))) +
                '-' + str(self.id))

    @property
    def invoice_number(self):
        return self.get_invoice_number()

    @property
    def tickets_count(self):
        return sum(t.quantity for t in self.order_tickets)

    @property
    def is_free(self):
        return self.payment_mode == 'free'

    def get_revenue(self):
        if self.amount:
            return self.amount - min(self.amount * (self.event.fee / 100.0),
                                     self.event.maximum_fee)
        else:
            return 0.0

    # Saves the order and generates and sends appropriate
    # documents and notifications
    def populate_and_save(self):
        from app.api.orders import save_order

        save_order(self)
Пример #24
0
class Event(SoftDeletionModel):
    """Event object table"""
    __tablename__ = 'events'
    __versioned__ = {'exclude': ['schedule_published_on', 'created_at']}
    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String)
    name = db.Column(db.String, nullable=False)
    external_event_url = db.Column(db.String)
    logo_url = db.Column(db.String)
    starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    timezone = db.Column(db.String, nullable=False, default="UTC")
    is_event_online = db.Column(db.Boolean, default=False)
    latitude = db.Column(db.Float)
    longitude = db.Column(db.Float)
    location_name = db.Column(db.String)
    searchable_location_name = db.Column(db.String)
    is_featured = db.Column(db.Boolean, default=False, nullable=False)
    description = db.Column(db.Text)
    original_image_url = db.Column(db.String)
    thumbnail_image_url = db.Column(db.String)
    large_image_url = db.Column(db.String)
    show_remaining_tickets = db.Column(db.Boolean,
                                       default=False,
                                       nullable=False)
    icon_image_url = db.Column(db.String)
    owner_name = db.Column(db.String)
    is_map_shown = db.Column(db.Boolean)
    has_owner_info = db.Column(db.Boolean)
    owner_description = db.Column(db.String)
    is_sessions_speakers_enabled = db.Column(db.Boolean, default=False)
    track = db.relationship('Track', backref="event")
    microlocation = db.relationship('Microlocation', backref="event")
    session = db.relationship('Session', backref="event")
    speaker = db.relationship('Speaker', backref="event")
    sponsor = db.relationship('Sponsor', backref="event")
    tickets = db.relationship('Ticket', backref="event_")
    tags = db.relationship('TicketTag', backref='events')
    roles = db.relationship("UsersEventsRoles", backref="event")
    role_invites = db.relationship('RoleInvite', back_populates='event')
    custom_form = db.relationship('CustomForms', backref="event")
    faqs = db.relationship('Faq', backref="event")
    feedbacks = db.relationship('Feedback', backref="event")
    attendees = db.relationship('TicketHolder', backref="event")
    privacy = db.Column(db.String, default="public")
    state = db.Column(db.String, default="Draft")
    event_type_id = db.Column(
        db.Integer, db.ForeignKey('event_types.id', ondelete='CASCADE'))
    event_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_topics.id', ondelete='CASCADE'))
    event_sub_topic_id = db.Column(
        db.Integer, db.ForeignKey('event_sub_topics.id', ondelete='CASCADE'))
    events_orga_id = db.Column(
        db.Integer, db.ForeignKey('events_orga.id', ondelete='CASCADE'))
    ticket_url = db.Column(db.String)
    db.UniqueConstraint('track.name')
    code_of_conduct = db.Column(db.String)
    schedule_published_on = db.Column(db.DateTime(timezone=True))
    is_ticketing_enabled = db.Column(db.Boolean, default=False)
    is_donation_enabled = db.Column(db.Boolean, default=False)
    is_ticket_form_enabled = db.Column(db.Boolean,
                                       default=True,
                                       nullable=False)
    payment_country = db.Column(db.String)
    payment_currency = db.Column(db.String)
    paypal_email = db.Column(db.String)
    is_tax_enabled = db.Column(db.Boolean, default=False)
    is_billing_info_mandatory = db.Column(db.Boolean, default=False)
    can_pay_by_paypal = db.Column(db.Boolean, default=False)
    can_pay_by_stripe = db.Column(db.Boolean, default=False)
    can_pay_by_cheque = db.Column(db.Boolean, default=False)
    can_pay_by_bank = db.Column(db.Boolean, default=False)
    can_pay_onsite = db.Column(db.Boolean, default=False)
    can_pay_by_omise = db.Column(db.Boolean, default=False)
    can_pay_by_alipay = db.Column(db.Boolean, default=False)
    cheque_details = db.Column(db.String)
    bank_details = db.Column(db.String)
    onsite_details = db.Column(db.String)
    created_at = db.Column(db.DateTime(timezone=True))
    pentabarf_url = db.Column(db.String)
    ical_url = db.Column(db.String)
    xcal_url = db.Column(db.String)
    is_sponsors_enabled = db.Column(db.Boolean, default=False)
    refund_policy = db.Column(
        db.String,
        default='All sales are final. No refunds shall be issued in any case.')
    is_stripe_linked = db.Column(db.Boolean, default=False)
    discount_code_id = db.Column(
        db.Integer, db.ForeignKey('discount_codes.id', ondelete='CASCADE'))
    discount_code = db.relationship('DiscountCode',
                                    backref='events',
                                    foreign_keys=[discount_code_id])
    event_type = db.relationship('EventType',
                                 backref='event',
                                 foreign_keys=[event_type_id])
    event_topic = db.relationship('EventTopic',
                                  backref='event',
                                  foreign_keys=[event_topic_id])
    event_sub_topic = db.relationship('EventSubTopic',
                                      backref='event',
                                      foreign_keys=[event_sub_topic_id])
    events_orga = db.relationship('EventOrgaModel',
                                  backref='event',
                                  foreign_keys=[events_orga_id])
    owner = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "owner"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='owner_events',
        uselist=False)
    organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='organizer_events')
    coorganizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "coorganizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='coorganizer_events')
    track_organizers = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id,'
        ' Role.name == "track_organizer"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='track_organizer_events')
    registrars = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "registrar"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='registrar_events')
    moderators = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name == "moderator"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='moderator_events')
    # staff
    users = db.relationship(
        'User',
        viewonly=True,
        secondary='join(UsersEventsRoles, Role,'
        ' and_(Role.id == UsersEventsRoles.role_id, Role.name != "attendee"))',
        primaryjoin='UsersEventsRoles.event_id == Event.id',
        secondaryjoin='User.id == UsersEventsRoles.user_id',
        backref='events')

    def __init__(
            self,
            name=None,
            logo_url=None,
            starts_at=None,
            ends_at=None,
            timezone='UTC',
            is_event_online=False,
            latitude=None,
            longitude=None,
            location_name=None,
            description=None,
            external_event_url=None,
            original_image_url=None,
            thumbnail_image_url=None,
            large_image_url=None,
            icon_image_url=None,
            owner_name=None,
            owner_description=None,
            state=None,
            event_type_id=None,
            privacy=None,
            event_topic_id=None,
            event_sub_topic_id=None,
            events_orga_id=None,
            ticket_url=None,
            copyright=None,
            code_of_conduct=None,
            schedule_published_on=None,
            is_sessions_speakers_enabled=False,
            show_remaining_tickets=False,
            is_ticket_form_enabled=True,
            is_donation_enabled=False,
            is_map_shown=False,
            has_owner_info=False,
            searchable_location_name=None,
            is_ticketing_enabled=None,
            deleted_at=None,
            payment_country=None,
            payment_currency=None,
            paypal_email=None,
            speakers_call=None,
            can_pay_by_paypal=None,
            can_pay_by_stripe=None,
            can_pay_by_cheque=None,
            can_pay_by_omise=None,
            can_pay_by_alipay=None,
            identifier=None,
            can_pay_by_bank=None,
            is_featured=False,
            can_pay_onsite=None,
            cheque_details=None,
            bank_details=None,
            pentabarf_url=None,
            ical_url=None,
            xcal_url=None,
            discount_code_id=None,
            onsite_details=None,
            is_tax_enabled=None,
            is_billing_info_mandatory=False,
            is_sponsors_enabled=None,
            stripe_authorization=None,
            tax=None,
            refund_policy='All sales are final. No refunds shall be issued in any case.',
            is_stripe_linked=False):

        self.name = name
        self.logo_url = logo_url
        self.starts_at = starts_at
        self.ends_at = ends_at
        self.timezone = timezone
        self.is_event_online = is_event_online
        self.latitude = latitude
        self.longitude = longitude
        self.location_name = location_name
        self.description = clean_up_string(description)
        self.external_event_url = external_event_url
        self.original_image_url = original_image_url
        self.original_image_url = self.set_default_event_image(event_topic_id) if original_image_url is None \
            else original_image_url
        self.thumbnail_image_url = thumbnail_image_url
        self.large_image_url = large_image_url
        self.icon_image_url = icon_image_url
        self.owner_name = owner_name
        self.owner_description = clean_up_string(owner_description)
        self.state = state
        self.is_map_shown = is_map_shown
        self.has_owner_info = has_owner_info
        self.privacy = privacy
        self.event_type_id = event_type_id
        self.event_topic_id = event_topic_id
        self.show_remaining_tickets = show_remaining_tickets
        self.copyright = copyright
        self.event_sub_topic_id = event_sub_topic_id
        self.events_orga_id = events_orga_id
        self.ticket_url = ticket_url
        self.code_of_conduct = code_of_conduct
        self.schedule_published_on = schedule_published_on
        self.is_sessions_speakers_enabled = is_sessions_speakers_enabled
        self.searchable_location_name = searchable_location_name
        self.is_ticketing_enabled = is_ticketing_enabled
        self.deleted_at = deleted_at
        self.payment_country = payment_country
        self.payment_currency = payment_currency
        self.paypal_email = paypal_email
        self.speakers_call = speakers_call
        self.can_pay_by_paypal = can_pay_by_paypal
        self.can_pay_by_stripe = can_pay_by_stripe
        self.can_pay_by_cheque = can_pay_by_cheque
        self.can_pay_by_bank = can_pay_by_bank
        self.can_pay_onsite = can_pay_onsite
        self.can_pay_by_omise = can_pay_by_omise
        self.can_pay_by_alipay = can_pay_by_alipay
        self.is_donation_enabled = is_donation_enabled
        self.is_featured = is_featured
        self.is_ticket_form_enabled = is_ticket_form_enabled
        self.identifier = get_new_event_identifier()
        self.cheque_details = cheque_details
        self.bank_details = bank_details
        self.pentabarf_url = pentabarf_url
        self.ical_url = ical_url
        self.xcal_url = xcal_url
        self.onsite_details = onsite_details
        self.discount_code_id = discount_code_id
        self.created_at = datetime.now(pytz.utc)
        self.is_tax_enabled = is_tax_enabled
        self.is_billing_info_mandatory = is_billing_info_mandatory
        self.is_sponsors_enabled = is_sponsors_enabled
        self.stripe_authorization = stripe_authorization
        self.tax = tax
        self.refund_policy = refund_policy
        self.is_stripe_linked = is_stripe_linked

    def __repr__(self):
        return '<Event %r>' % self.name

    def __str__(self):
        return self.__repr__()

    def __setattr__(self, name, value):
        if name == 'owner_description' or name == 'description' or name == 'code_of_conduct':
            super(Event, self).__setattr__(name,
                                           clean_html(clean_up_string(value)))
        else:
            super(Event, self).__setattr__(name, value)

    @classmethod
    def set_default_event_image(self, event_topic_id):
        if event_topic_id is None:
            return None
        else:
            event_topic = EventTopic.query.filter_by(id=event_topic_id).first()
            return event_topic.system_image_url

    @property
    def fee(self):
        """
        Returns the fee as a percentage from 0 to 100 for this event
        """
        return get_fee(self.payment_country, self.payment_currency)

    @property
    def maximum_fee(self):
        """
        Returns the maximum fee for this event
        """
        return get_maximum_fee(self.payment_country, self.payment_currency)

    def notification_settings(self, user_id):
        try:
            return EmailNotification.query.filter_by(
                user_id=(login.current_user.id if not user_id else int(user_id))). \
                filter_by(event_id=self.id).first()
        except:
            return None

    def get_average_rating(self):
        avg = db.session.query(func.avg(
            Feedback.rating)).filter_by(event_id=self.id).scalar()
        if avg is not None:
            avg = round(avg, 2)
        return avg

    def is_payment_enabled(self):
        return self.can_pay_by_paypal or self.can_pay_by_stripe or self.can_pay_by_omise or self.can_pay_by_alipay \
            or self.can_pay_by_cheque or self.can_pay_by_bank or self.can_pay_onsite

    @property
    def average_rating(self):
        return self.get_average_rating()

    def get_organizer(self):
        """returns organizer of an event"""
        for role in self.roles:
            if role.role.name == ORGANIZER:
                return role.user
        return None

    def get_owner(self):
        """returns owner of an event"""
        for role in self.roles:
            if role.role.name == OWNER:
                return role.user
        return None

    def has_staff_access(self, user_id):
        """does user have role other than attendee"""
        for _ in self.roles:
            if _.user_id == (login.current_user.id
                             if not user_id else int(user_id)):
                if _.role.name != ATTENDEE:
                    return True
        return False

    def get_staff_roles(self):
        """returns only roles which are staff i.e. not attendee"""
        return [role for role in self.roles if role.role.name != ATTENDEE]

    def as_dict(self):
        return {c.name: getattr(self, c.name) for c in self.__table__.columns}

    def calc_tickets_sold_count(self):
        """Calculate total number of tickets sold for the event"""
        return db.session.query(Order.event_id).filter_by(event_id=self.id, status='completed').join(TicketHolder)\
            .count()

    def calc_total_tickets_count(self):
        """Calculate total available tickets for all types of tickets"""
        total_available = db.session.query(func.sum(
            Ticket.quantity)).filter_by(event_id=self.id).scalar()
        if total_available is None:
            total_available = 0
        return total_available

    def calc_revenue(self):
        """Returns total revenues of all completed orders for the given event"""
        revenue = db.session.query(func.sum(Order.amount)).filter_by(
            event_id=self.id, status='completed').scalar()
        if revenue is None:
            revenue = 0
        return revenue

    def calc_monthly_revenue(self):
        """Returns revenue of current month. Invoice sent every 1st of the month for the previous month"""
        previous_month = datetime.datetime.now().month - 1
        monthly_revenue = db.session.query(func.sum(Order.amount)).filter(
            Order.event_id == self.id,
            Order.completed_at.month == previous_month,
            Order.status == 'completed').scalar()
        if monthly_revenue is None:
            monthly_revenue = 0
        return monthly_revenue

    @property
    def tickets_available(self):
        return self.calc_total_tickets_count()

    @property
    def tickets_sold(self):
        return self.calc_tickets_sold_count()

    @property
    def revenue(self):
        return self.calc_revenue()

    @property
    def has_sessions(self):
        return Session.query.filter_by(event_id=self.id).count() > 0

    @property
    def has_speakers(self):
        return Speaker.query.filter_by(event_id=self.id).count() > 0
Пример #25
0
class Ticket(SoftDeletionModel):
    __tablename__ = 'tickets'
    __table_args__ = (db.UniqueConstraint('name',
                                          'event_id',
                                          'deleted_at',
                                          name='name_event_deleted_at_uc'), )

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    description = db.Column(db.String)
    is_description_visible = db.Column(db.Boolean)
    type = db.Column(db.String, nullable=False)
    quantity = db.Column(db.Integer, default=100)
    position = db.Column(db.Integer, default=1)
    price = db.Column(db.Float, default=0)
    min_price = db.Column(db.Float, default=0, nullable=False)
    max_price = db.Column(db.Float, default=0)
    is_fee_absorbed = db.Column(db.Boolean, default=False)
    sales_starts_at = db.Column(db.DateTime(timezone=True), nullable=False)
    sales_ends_at = db.Column(db.DateTime(timezone=True), nullable=False)
    is_hidden = db.Column(db.Boolean, default=False)

    min_order = db.Column(db.Integer, default=1)
    max_order = db.Column(db.Integer, default=10)
    is_checkin_restricted = db.Column(db.Boolean)
    auto_checkin_enabled = db.Column(db.Boolean, default=False)
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='CASCADE'))
    event = db.relationship('Event', backref='tickets_')

    tags = db.relationship('TicketTag',
                           secondary=ticket_tags_table,
                           backref='tickets')
    order_ticket = db.relationship('OrderTicket',
                                   backref="ticket",
                                   passive_deletes=True)

    access_codes = db.relationship('AccessCode',
                                   secondary=access_codes_tickets,
                                   backref='tickets')

    discount_codes = db.relationship('DiscountCode',
                                     secondary=discount_codes_tickets,
                                     backref="tickets")

    def has_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        from app.api.helpers.db import get_count

        orders = Order.id.in_(
            OrderTicket.query.with_entities(
                OrderTicket.order_id).filter_by(ticket_id=self.id).all())
        count = get_count(
            Order.query.filter(orders).filter(Order.status != 'deleted'))
        # Count is zero if no completed orders are present
        return bool(count > 0)

    def has_completed_order_tickets(self):
        """Returns True if ticket has already placed orders.
        Else False.
        """
        order_tickets = OrderTicket.query.filter_by(ticket_id=self.id)

        count = 0
        for order_ticket in order_tickets:
            order = Order.query.filter_by(id=order_ticket.order_id).first()
            if order.status == "completed" or order.status == "placed":
                count += 1

        return bool(count > 0)

    def tags_csv(self):
        """Return list of Tags in CSV."""
        tag_names = [tag.name for tag in self.tags]
        return ','.join(tag_names)

    @property
    def has_current_orders(self):
        return db.session.query(
            Order.query.join(TicketHolder).filter(
                TicketHolder.ticket_id == self.id,
                or_(Order.status == 'completed', Order.status == 'placed',
                    Order.status == 'pending',
                    Order.status == 'initializing')).exists()).scalar()

    @property
    def reserved_count(self):
        from app.api.attendees import get_sold_and_reserved_tickets_count

        return get_sold_and_reserved_tickets_count(self.id)

    @property
    def is_available(self):
        return self.reserved_count < self.quantity

    def raise_if_unavailable(self):
        if not self.is_available:
            raise ConflictError({'id': self.id},
                                f"Ticket {self.id} already sold out")

    def __repr__(self):
        return '<Ticket %r>' % self.name
Пример #26
0
class Order(db.Model):
    __tablename__ = "orders"

    class Status:
        INITIALIZING = 'initializing'
        PENDING = 'pending'
        COMPLETED = 'completed'
        CANCELLED = 'cancelled'
        EXPIRED = 'expired'

    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, unique=True, default=get_new_id)
    amount = db.Column(db.Float, nullable=False, default=0)
    address = db.Column(db.String)
    city = db.Column(db.String)
    state = db.Column(db.String)
    country = db.Column(db.String)
    zipcode = db.Column(db.String)
    company = db.Column(db.String)
    tax_business_info = db.Column(db.String)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='SET NULL'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='SET NULL'))
    marketer_id = db.Column(db.Integer,
                            db.ForeignKey('users.id', ondelete='SET NULL'))
    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    completed_at = db.Column(db.DateTime(timezone=True),
                             nullable=True,
                             default=None)
    trashed_at = db.Column(db.DateTime(timezone=True),
                           nullable=True,
                           default=None)
    transaction_id = db.Column(db.String)
    paid_via = db.Column(db.String)
    payment_mode = db.Column(db.String)
    is_billing_enabled = db.Column(db.Boolean, nullable=False, default=False)
    brand = db.Column(db.String)
    exp_month = db.Column(db.Integer)
    exp_year = db.Column(db.Integer)
    last4 = db.Column(db.String)
    stripe_token = db.Column(db.String)
    stripe_payment_intent_id = db.Column(db.String)
    paypal_token = db.Column(db.String)
    status = db.Column(db.String, default='initializing')
    cancel_note = db.Column(db.String, nullable=True)
    order_notes = db.Column(db.String)
    tickets_pdf_url = db.Column(db.String)

    discount_code_id = db.Column(
        db.Integer,
        db.ForeignKey('discount_codes.id', ondelete='SET NULL'),
        nullable=True,
        default=None,
    )
    discount_code = db.relationship('DiscountCode', backref='orders')

    event = db.relationship('Event', backref='orders')
    user = db.relationship('User', backref='orders', foreign_keys=[user_id])
    marketer = db.relationship('User',
                               backref='marketed_orders',
                               foreign_keys=[marketer_id])
    tickets = db.relationship("Ticket",
                              secondary='orders_tickets',
                              backref='order')
    order_tickets = db.relationship("OrderTicket", backref='order')

    def __repr__(self):
        return '<Order %r>' % self.id

    def get_invoice_number(self):
        return ('O' + str(int(time.mktime(self.created_at.timetuple()))) +
                '-' + str(self.id))

    @property
    def invoice_number(self):
        return self.get_invoice_number()

    @property
    def tickets_count(self):
        return sum(t.quantity for t in self.order_tickets)

    @property
    def is_free(self):
        return self.payment_mode == 'free'

    def get_revenue(self):
        if self.amount:
            return self.amount - min(self.amount * (self.event.fee / 100.0),
                                     self.event.maximum_fee)
        return 0.0

    # Saves the order and generates and sends appropriate
    # documents and notifications
    def populate_and_save(self) -> None:
        from app.api.orders import save_order

        save_order(self)

    def is_attendee(self, user) -> bool:
        return db.session.query(
            TicketHolder.query.filter_by(order_id=self.id,
                                         user=user).exists()).scalar()

    @property
    def ticket_pdf_path(self) -> str:
        key = UPLOAD_PATHS['pdf']['tickets_all'].format(
            identifier=self.identifier, extra_identifier=self.identifier)
        return ('generated/tickets/{}/{}/'.format(key, generate_hash(key)) +
                self.identifier + '.pdf')

    @property
    def invoice_pdf_path(self) -> str:
        key = UPLOAD_PATHS['pdf']['order'].format(identifier=self.identifier)
        return ('generated/invoices/{}/{}/'.format(key, generate_hash(key)) +
                self.identifier + '.pdf')

    @property
    def filtered_ticket_holders(self):
        from app.api.helpers.permission_manager import has_access

        query_ = TicketHolder.query.filter_by(order_id=self.id,
                                              deleted_at=None)
        if (not has_access(
                'is_coorganizer',
                event_id=self.event_id,
        ) and current_user.id != self.user_id):
            query_ = query_.filter(TicketHolder.user == current_user)
        return query_.all()

    @property
    def safe_user(self):
        from app.api.helpers.permission_manager import has_access

        if (not has_access(
                'is_coorganizer',
                event_id=self.event_id,
        ) and current_user.id != self.user_id):
            return None
        return self.user

    @property
    def site_view_link(self) -> str:
        frontend_url = get_settings()['frontend_url']
        return frontend_url + '/orders/' + self.identifier + '/view'
class Order(db.Model):
    __tablename__ = "orders"

    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, unique=True)
    amount = db.Column(db.Float)
    address = db.Column(db.String)
    city = db.Column(db.String)
    state = db.Column(db.String)
    country = db.Column(db.String)
    zipcode = db.Column(db.String)
    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='SET NULL'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='SET NULL'))
    marketer_id = db.Column(db.Integer,
                            db.ForeignKey('users.id', ondelete='SET NULL'))
    created_at = db.Column(db.DateTime(timezone=True))
    completed_at = db.Column(db.DateTime(timezone=True),
                             nullable=True,
                             default=None)
    trashed_at = db.Column(db.DateTime(timezone=True),
                           nullable=True,
                           default=None)
    transaction_id = db.Column(db.String)
    paid_via = db.Column(db.String)
    payment_mode = db.Column(db.String)
    brand = db.Column(db.String)
    exp_month = db.Column(db.Integer)
    exp_year = db.Column(db.Integer)
    last4 = db.Column(db.String)
    stripe_token = db.Column(db.String)
    paypal_token = db.Column(db.String)
    status = db.Column(db.String)
    cancel_note = db.Column(db.String, nullable=True)

    discount_code_id = db.Column(db.Integer,
                                 db.ForeignKey('discount_codes.id',
                                               ondelete='SET NULL'),
                                 nullable=True,
                                 default=None)
    discount_code = db.relationship('DiscountCode', backref='orders')

    event = db.relationship('Event', backref='orders')
    user = db.relationship('User', backref='orders', foreign_keys=[user_id])
    marketer = db.relationship('User',
                               backref='marketed_orders',
                               foreign_keys=[marketer_id])
    tickets = db.relationship("Ticket",
                              secondary='orders_tickets',
                              backref='order')
    order_tickets = db.relationship("OrderTicket", backref='order')

    def __init__(self,
                 quantity=None,
                 amount=None,
                 address=None,
                 city=None,
                 state=None,
                 country=None,
                 zipcode=None,
                 transaction_id=None,
                 paid_via=None,
                 user_id=None,
                 discount_code_id=None,
                 event_id=None,
                 status='pending',
                 payment_mode=None):
        self.identifier = get_new_order_identifier()
        self.quantity = quantity
        self.amount = amount
        self.city = city
        self.address = address
        self.state = state
        self.country = country
        self.zipcode = zipcode
        self.user_id = user_id
        self.event_id = event_id
        self.transaction_id = transaction_id
        self.paid_via = paid_via
        self.created_at = datetime.datetime.utcnow()
        self.discount_code_id = discount_code_id
        self.status = status
        self.payment_mode = payment_mode

    def __repr__(self):
        return '<Order %r>' % self.id

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return self.identifier

    def get_invoice_number(self):
        return 'O' + str(int(time.mktime(
            self.created_at.timetuple()))) + '-' + str(self.id)

    @property
    def invoice_number(self):
        return self.get_invoice_number()

    def get_tickets_count(self):
        count = 0
        for order_ticket in self.order_tickets:
            count += order_ticket.quantity
        return count

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        return {
            'id': self.id,
            'identifier': self.identifier,
            'quantity': self.quantity,
            'amount': self.amount,
            'address': self.address,
            'state': self.state,
            'zipcode': self.zipcode,
            'country': self.country,
            'transaction_id': self.transaction_id,
            'paid_via': self.paid_via,
            'payment_mode': self.payment_mode,
            'brand': self.brand,
            'exp_month': self.exp_month,
            'exp_year': self.exp_year,
            'last4': self.last4,
        }
Пример #28
0
class TicketHolder(SoftDeletionModel):
    __tablename__ = "ticket_holders"

    id: int = db.Column(db.Integer, primary_key=True)
    firstname: str = db.Column(db.String, nullable=False)
    lastname: str = db.Column(db.String, nullable=False)
    email: str = db.Column(db.String)
    address: str = db.Column(db.String)
    city: str = db.Column(db.String)
    state: str = db.Column(db.String)
    country: str = db.Column(db.String)
    job_title: str = db.Column(db.String)
    phone: str = db.Column(db.String)
    tax_business_info: str = db.Column(db.String)
    billing_address: str = db.Column(db.String)
    home_address: str = db.Column(db.String)
    shipping_address: str = db.Column(db.String)
    company: str = db.Column(db.String)
    work_address: str = db.Column(db.String)
    work_phone: str = db.Column(db.String)
    website: str = db.Column(db.String)
    blog: str = db.Column(db.String)
    twitter: str = db.Column(db.String)
    facebook: str = db.Column(db.String)
    github: str = db.Column(db.String)
    gender: str = db.Column(db.String)
    birth_date: datetime = db.Column(db.DateTime(timezone=True))
    pdf_url: str = db.Column(db.String)
    ticket_id: int = db.Column(db.Integer, db.ForeignKey('tickets.id', ondelete='CASCADE'))
    order_id: int = db.Column(db.Integer, db.ForeignKey('orders.id', ondelete='CASCADE'))
    is_checked_in: bool = db.Column(db.Boolean, default=False)
    is_checked_out: bool = db.Column(db.Boolean, default=False)
    device_name_checkin: str = db.Column(db.String)
    checkin_times: str = db.Column(db.String)
    checkout_times: str = db.Column(db.String)
    attendee_notes: str = db.Column(db.String)
    event_id: int = db.Column(db.Integer, db.ForeignKey('events.id', ondelete='CASCADE'))
    complex_field_values: str = db.Column(db.JSON)
    user = db.relationship('User', foreign_keys=[email], primaryjoin='User.email == TicketHolder.email', viewonly=True,
                           backref='attendees')
    order = db.relationship('Order', backref='ticket_holders')
    ticket = db.relationship('Ticket', backref='ticket_holders')

    @property
    def name(self):
        firstname = self.firstname if self.firstname else ''
        lastname = self.lastname if self.lastname else ''
        if firstname and lastname:
            return u'{} {}'.format(firstname, lastname)
        else:
            return ''

    @property
    def qr_code(self):
        qr = qrcode.QRCode(
            version=1,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=10,
            border=0,
        )
        qr.add_data(self.order.identifier + "-" + str(self.id))
        qr.make(fit=True)
        img = qr.make_image()

        buffer = BytesIO()
        img.save(buffer, format="JPEG")
        img_str = str(base64.b64encode(buffer.getvalue()), 'utf-8')
        return img_str

    @property
    def serialize(self):
        """Return object data in easily serializable format"""
        return {'id': self.id,
                'firstname': self.firstname,
                'lastname': self.lastname,
                'email': self.email,
                'city': self.city,
                'address': self.address,
                'state': self.state,
                'country': self.country,
                'company': self.company,
                'taxBusinessInfo': self.tax_business_info}
Пример #29
0
class EventInvoice(SoftDeletionModel):
    DUE_DATE_DAYS = 30
    MIN_AMOUNT = 2  # Minimum amount for which the invoice will be generated

    __tablename__ = 'event_invoices'

    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, unique=True, nullable=False)
    amount = db.Column(db.Float)

    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='SET NULL'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='SET NULL'))

    created_at = db.Column(db.DateTime(timezone=True), default=func.now())
    issued_at = db.Column(db.DateTime(timezone=True), nullable=False)

    # Payment Fields
    completed_at = db.Column(db.DateTime(timezone=True),
                             nullable=True,
                             default=None)
    transaction_id = db.Column(db.String)
    paid_via = db.Column(db.String)
    payment_mode = db.Column(db.String)
    brand = db.Column(db.String)
    exp_month = db.Column(db.Integer)
    exp_year = db.Column(db.Integer)
    last4 = db.Column(db.String)
    stripe_token = db.Column(db.String)
    paypal_token = db.Column(db.String)
    status = db.Column(db.String, default='due')

    invoice_pdf_url = db.Column(db.String)

    event = db.relationship('Event', backref='invoices')
    user = db.relationship('User', backref='event_invoices')

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        if not self.issued_at:
            self.issued_at = datetime.now()

        if not self.identifier:
            self.identifier = self.get_new_id()

    def __repr__(self):
        return '<EventInvoice {!r} {!r} {!r}>'.format(
            self.id,
            self.identifier,
            self.invoice_pdf_url,
        )

    def get_new_id(self) -> str:
        with db.session.no_autoflush:
            identifier = self.issued_at.strftime(
                '%Y%mU-') + '%06d' % (EventInvoice.query.count() + 1)
            count = EventInvoice.query.filter_by(identifier=identifier).count()
            if count == 0:
                return identifier
            return self.get_new_id()

    @property
    def previous_month_date(self):
        return monthdelta(self.issued_at, -1)

    @property
    def due_at(self):
        return self.issued_at + timedelta(days=EventInvoice.DUE_DATE_DAYS)

    def populate(self):
        assert self.event is not None

        with db.session.no_autoflush:
            self.user = self.event.owner
            return self.generate_pdf()

    def generate_pdf(self, force=False):
        with db.session.no_autoflush:
            latest_invoice_date = (EventInvoice.query.filter_by(
                event=self.event).filter(
                    EventInvoice.issued_at < self.issued_at).with_entities(
                        func.max(EventInvoice.issued_at)).scalar())

            admin_info = Setting.query.first()
            currency = self.event.payment_currency
            ticket_fee_object = (
                TicketFees.query.filter_by(
                    country=self.event.payment_country).first()
                or TicketFees.query.filter_by(country='global').first())
            if not ticket_fee_object:
                logger.error('Ticket Fee not found for event %s', self.event)
                return

            ticket_fee_percentage = ticket_fee_object.service_fee
            ticket_fee_maximum = ticket_fee_object.maximum_fee
            gross_revenue = self.event.calc_revenue(start=latest_invoice_date,
                                                    end=self.issued_at)
            invoice_amount = gross_revenue * (ticket_fee_percentage / 100)
            if invoice_amount > ticket_fee_maximum:
                invoice_amount = ticket_fee_maximum
            self.amount = round_money(invoice_amount)
            if not force and self.amount == 0:
                logger.warning(
                    'Invoice amount of Event %s is 0, hence skipping generation',
                    self.event,
                )
                return
            if not force and self.amount < EventInvoice.MIN_AMOUNT:
                logger.warning(
                    'Invoice amount of Event %s is %f which is less than %f, hence skipping generation',
                    self.event,
                    self.amount,
                    EventInvoice.MIN_AMOUNT,
                )
                return
            net_revenue = round_money(gross_revenue - invoice_amount)
            orders_query = self.event.get_orders_query(
                start=latest_invoice_date, end=self.issued_at)
            first_order_date = orders_query.with_entities(
                func.min(Order.completed_at)).scalar()
            last_order_date = orders_query.with_entities(
                func.max(Order.completed_at)).scalar()
            payment_details = {
                'tickets_sold': self.event.tickets_sold,
                'gross_revenue': round_money(gross_revenue),
                'net_revenue': round_money(net_revenue),
                'first_date': first_order_date or self.previous_month_date,
                'last_date': last_order_date or self.issued_at,
            }
            self.invoice_pdf_url = create_save_pdf(
                render_template(
                    'pdf/event_invoice.html',
                    user=self.user,
                    admin_info=admin_info,
                    currency=currency,
                    event=self.event,
                    ticket_fee=ticket_fee_object,
                    payment_details=payment_details,
                    net_revenue=net_revenue,
                    invoice=self,
                ),
                UPLOAD_PATHS['pdf']['event_invoice'],
                dir_path='/static/uploads/pdf/event_invoices/',
                identifier=self.identifier,
                extra_identifiers={'event_identifier': self.event.identifier},
                new_renderer=True,
            )

        return self.invoice_pdf_url

    def send_notification(self, follow_up=False):
        prev_month = self.previous_month_date.astimezone(
            pytz.timezone(self.event.timezone)).strftime(
                "%b %Y")  # Displayed as Aug 2016
        app_name = get_settings()['app_name']
        frontend_url = get_settings()['frontend_url']
        link = f'{frontend_url}/event-invoice/{self.identifier}/review'
        currency = self.event.payment_currency
        amount = f"{currency} {self.amount}"
        send_email_for_monthly_fee_payment(
            self.user,
            self.event.name,
            prev_month,
            amount,
            app_name,
            link,
            follow_up=follow_up,
        )
        if isinstance(follow_up, bool):
            send_notif_monthly_fee_payment(
                self.user,
                self.event.name,
                prev_month,
                amount,
                app_name,
                link,
                self.event_id,
                follow_up=follow_up,
            )
Пример #30
0
class EventInvoice(SoftDeletionModel):
    """
    Stripe authorization information for an event.
    """
    __tablename__ = 'event_invoices'

    id = db.Column(db.Integer, primary_key=True)
    identifier = db.Column(db.String, unique=True)
    amount = db.Column(db.Float)
    address = db.Column(db.String)
    city = db.Column(db.String)
    state = db.Column(db.String)
    country = db.Column(db.String)
    zipcode = db.Column(db.String)

    user_id = db.Column(db.Integer,
                        db.ForeignKey('users.id', ondelete='SET NULL'))
    event_id = db.Column(db.Integer,
                         db.ForeignKey('events.id', ondelete='SET NULL'))

    created_at = db.Column(db.DateTime(timezone=True))
    completed_at = db.Column(db.DateTime(timezone=True),
                             nullable=True,
                             default=None)
    transaction_id = db.Column(db.String)
    paid_via = db.Column(db.String)
    payment_mode = db.Column(db.String)
    brand = db.Column(db.String)
    exp_month = db.Column(db.Integer)
    exp_year = db.Column(db.Integer)
    last4 = db.Column(db.String)
    stripe_token = db.Column(db.String)
    paypal_token = db.Column(db.String)
    status = db.Column(db.String)
    invoice_pdf_url = db.Column(db.String)

    event = db.relationship('Event', backref='invoices')
    user = db.relationship('User', backref='invoices')

    discount_code_id = db.Column(db.Integer,
                                 db.ForeignKey('discount_codes.id',
                                               ondelete='SET NULL'),
                                 nullable=True,
                                 default=None)
    discount_code = db.relationship('DiscountCode', backref='event_invoices')

    def __init__(self,
                 amount=None,
                 address=None,
                 city=None,
                 state=None,
                 country=None,
                 zipcode=None,
                 transaction_id=None,
                 paid_via=None,
                 user_id=None,
                 discount_code_id=None,
                 event_id=None,
                 invoice_pdf_url=None,
                 payment_mode=None,
                 brand=None,
                 exp_month=None,
                 exp_year=None,
                 last4=None,
                 stripe_token=None,
                 paypal_token=None,
                 deleted_at=None):
        self.identifier = get_new_identifier()
        self.amount = amount
        self.address = address
        self.state = state
        self.country = country
        self.zipcode = zipcode
        self.city = city
        self.user_id = user_id
        self.event_id = event_id
        self.transaction_id = transaction_id
        self.paid_via = paid_via
        self.created_at = datetime.utcnow()
        self.discount_code_id = discount_code_id
        self.status = 'pending'
        self.invoice_pdf_url = invoice_pdf_url
        self.payment_mode = payment_mode
        self.brand = brand
        self.exp_month = exp_month
        self.exp_year = exp_year
        self.last4 = last4
        self.stripe_token = stripe_token
        self.paypal_token = paypal_token
        self.deleted_at = deleted_at

    def get_invoice_number(self):
        return 'I' + str(int(time.mktime(
            self.created_at.timetuple()))) + '-' + str(self.id)

    def __repr__(self):
        return '<EventInvoice %r>' % self.invoice_pdf_url

    def __str__(self):
        return self.__repr__()