Beispiel #1
0
class Availability(Base):
    """
    Here you can set each availability that any employee has. Each availability is tied to an employee
    and it is also tied to a location. So for example, you could add an availability of employee 3 at location 2,
    from 9:00-5:00 on Tuesday.
    """
    location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    day = db.Column(db.Integer)  # Which day of the week
    start = db.Column(db.Time, nullable=False)  # What time your availability starts
    length = db.Column(db.Integer)  # How many minutes you are available for

    def __init__(self, location_id, user_id, day, hour, minute, length):
        self.location_id = location_id
        self.user_id = user_id
        self.day = day
        self.start = time(hour, minute, 0)
        self.length = length

    @property
    def end(self):
        """
        Returns a new time using the starting time but increasing the minutes by the session length
        """
        hours = self.length // 60
        minutes = self.length % 60
        return time(self.start.hour + hours, self.start.minute + minutes)

    def __repr__(self):
        days = ["", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
        return '(%r) %r-%r' % (days[self.day], self.start.strftime("%H:%M %Z"), self.end.strftime("%H:%M %Z"))
Beispiel #2
0
class Mapping(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    business_id = db.Column(db.Integer, nullable=False)
    location_id = db.Column(db.Integer, nullable=False)
    user_id = db.Column(db.Integer, nullable=False)

    def __init__(self, business_id, location_id, user_id):
        self.business_id = business_id
        self.location_id = location_id
        self.user_id = user_id
Beispiel #3
0
class Location(Base):
    # Needs to list all services offered here

    business_id = db.Column(db.Integer,
                            db.ForeignKey('business.id'),
                            nullable=False)

    # Availabilities that the location has. This is tied to an employee
    availabilities = db.relationship('Availability', backref='location')
    # The opening hours of the location
    hours = db.relationship('Hour', backref='location')

    name = db.Column(db.String(128))

    # Your location information
    country = db.Column(db.String(128))
    province = db.Column(db.String(128))
    city = db.Column(db.String(128))
    address = db.Column(db.String(128))

    timezone = db.Column(db.String(128))
    postalcode = db.Column(db.String(128))

    email = db.Column(db.String(64))
    phone = db.Column(db.String(64))

    def __init__(self, business_id, name="Burnaby", email=None, phone=None):
        self.business_id = business_id
        self.name = name
        self.country = None
        self.province = None
        self.city = None
        self.address = None
        self.timezone = None
        self.postalcode = None

        self.mail = email
        self.phone = phone

    def get_hours_by_day(self, day):
        return [hour for hour in self.hours if hour.day == day]

    def get_user_ids(self):
        return [
            mapping.id for mapping in Mapping.query.filter_by(
                business_id=self.business_id).filter_by(
                    location_id=self.id).all()
        ]

    def get_employee_count(self):
        return len(self.get_user_ids())

    def __repr__(self):
        return '<Location (%r)>' % self.id
Beispiel #4
0
class ContactEmail(Base):
    # Email to be sent on contact page
    sender_email = db.Column(db.String(128), nullable=False)
    content = db.Column(db.String(128), nullable=False)
    sent = db.Column(db.Boolean, nullable=False)

    def __init__(self, sender_email, content):
        self.sender_email = sender_email
        self.content = content
        self.sent = False

    def __repr__(self):
        return '<Message: %r (From: %r [Sent: %r])>' % (
            self.content, self.sender_email, self.sent)
Beispiel #5
0
class VerifyEmail(Base):
    # Email sent to verify accounts
    sender_email = db.Column(db.String(128), nullable=False)
    content = db.Column(db.String(128), nullable=False)
    sent = db.Column(db.Boolean, nullable=False)

    def __init__(self, sender_email, content):
        self.sender_email = sender_email
        self.content = content
        self.sent = False

    def __repr__(self):
        return '<Message: %r (From: %r [Sent: %r])>' % (
            self.content, self.sender_email, self.sent)
Beispiel #6
0
class AnalyticEvent(db.Model):
    __abstract__ = True

    id = db.Column(db.Integer, primary_key=True)
    server_time = db.Column(db.DateTime, default=db.func.current_timestamp())
    user_id = db.Column(db.Integer)
    activity = db.Column(db.String(16))
    validity = db.Column(db.Boolean)

    def __init__(self, user_id=-1, activity="unknown"):
        self.user_id = user_id
        self.activity = activity
        self.validity = self.validate

    @property
    def validate(self):
        raise NotImplementedError
Beispiel #7
0
class TransactionEvent(AnalyticEvent):
    currency = db.Column(db.String(16))
    amount = db.Column(db.Integer)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.currency = "CAD"
        self.amount = 0

    @property
    def validate(self):
        if not isinstance(self.user_id, int):
            return False
        if not isinstance(self.activity, str) and self.activity not in ['purchase', 'refund']:
            return False
        if not isinstance(self.currency, str) and self.currency not in ['CAD']:
            return False
        if not isinstance(self.amount, int):
            return False
        return True
Beispiel #8
0
class AuthenticationEvent(AnalyticEvent):
    session_length = db.Column(db.Integer)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.session_length = 0

    @property
    def validate(self):
        if not isinstance(self.user_id, int):
            return False
        if not isinstance(self.activity, str) or self.activity not in ['login', 'logout']:
            return False
        return True
Beispiel #9
0
class Hour(Base):
    """
    Here you can set the opening hours of any location.
    So you could set location 5 to be open from 9am-3pm on Monday and 1pm-6pm on Friday.
    Each interval of time would be its own object.
    """
    location_id = db.Column(db.Integer, db.ForeignKey('location.id'))

    day = db.Column(db.Integer)  # Which day of the week
    start = db.Column(db.Integer)  # What hour your availability starts
    length = db.Column(db.Integer)  # How many minutes you are available for

    closed = db.Column(db.Boolean)  # If your store is closed that day

    def __init__(self, location_id, day, start_time, length, closed=False):
        self.location_id = location_id
        self.day = day
        self.start = start_time
        self.length = length
        self.closed = closed

    @property
    def end(self):
        return self.start + self.length

    def display(self, day, closed):
        days = [
            "", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
            "Saturday", "Sunday"
        ]
        if not closed:
            return '%r %r:00-%r:00' % (days[day], self.start, self.end)
        else:
            return '%r: Closed' % (days[day])

    def __repr__(self):
        return '%r:00-%r:00' % (self.start, self.end)
Beispiel #10
0
class Service(Base):
    name = db.Column(db.String(128), nullable=False)
    availability = db.Column(db.DateTime)
    cost = db.Column(db.Float(2))
    length = db.Column(db.Integer)
    deposit = db.Column(db.Boolean)  # If a deposit is needed to book this
    location_id = db.Column(db.Integer)  # Which location this is available at
    locations = db.Column(
        db.Boolean
    )  # If this is true, it's available at every location at your business
    appointments = db.relationship('Appointment', backref='service')

    business_id = db.Column(db.Integer,
                            db.ForeignKey('business.id'),
                            nullable=False)

    # Needs to connect to all locations this service is offered at

    def __init__(self, name, business_id, cost, length):
        self.name = name
        self.business_id = business_id
        self.cost = cost
        self.length = length
        self.availability = datetime.now()
        self.deposit = False
        self.location_id = 1
        self.locations = False

    def get_description(self):
        cost = format_as_currency(self.cost)
        return "%{} for %{} minutes - ${}".format(self.name, self.length, cost)

    def __repr__(self):
        cost = format_as_currency(self.cost)
        return '{} for ${} and a length of {} min'.format(
            self.name, cost, self.length)
Beispiel #11
0
class Appointment(Base):
    # The business for which the appointment is for
    business_id = db.Column(db.Integer,
                            db.ForeignKey('business.id'),
                            nullable=False)

    # The client for which the appointment is for
    client_id = db.Column(db.Integer,
                          db.ForeignKey('client.id'),
                          nullable=False)

    # The day and time of the appointment
    date = db.Column(db.DateTime, nullable=False)

    # The length of the appointment in minutes
    service_id = db.Column(db.Integer, db.ForeignKey('service.id'))

    # If the user has paid yet or not
    paid = db.Column(db.Boolean)

    # Name of practitioner, if chosen
    practitioner_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __init__(self,
                 business_id,
                 client_id,
                 service_id,
                 date,
                 practitioner_id=None):
        self.business_id = business_id
        self.client_id = client_id
        self.service_id = service_id
        self.date = date
        self.practitioner_id = practitioner_id
        self.paid = False

    def get_end_time(self):
        return (self.date + timedelta(minutes=self.service.length)).time()

    def __repr__(self):
        return '<Appointment (%r) is on %r/%r/%r at %r:%r>' % (
            self.id, self.date.year, self.date.month, self.date.day,
            self.date.hour, self.date.minute)
Beispiel #12
0
class Client(Base):
    email = db.Column(db.String(128))
    name = db.Column(db.String(128))  # First and Last Name
    phone = db.Column(db.String(128))
    contact_method = db.Column(db.String(128))
    consent_form = db.Column(db.Boolean)  # Unused
    business_id = db.Column(db.Integer,
                            db.ForeignKey('business.id'),
                            nullable=False)

    # List of every appointment
    appointments = db.relationship('Appointment', backref='client')

    def __init__(self, email, business_id, name, phone="No phone number"):
        self.email = email
        self.business_id = business_id
        self.name = name
        self.phone = phone
        self.contact_method = None
        self.consent_form = False

    def __repr__(self):
        return '<Client %r (%r)>' % (self.email, self.id)
Beispiel #13
0
class Business(Base):
    # Name of the business
    name = db.Column(db.String(128), nullable=False)
    # Name of the business
    country = db.Column(db.String(64))
    # Name of the business
    currency = db.Column(db.String(32))
    # Name of the business
    province = db.Column(db.String(64))
    # Name of the business
    city = db.Column(db.String(64))
    # Name of the business
    address = db.Column(db.String(64))
    # Name of the business
    verified = db.Column(db.Boolean)
    # Name of the business
    subscription_days_remaining = db.Column(db.Integer)
    # Referral code
    referral = db.Column(db.String(128), unique=True)
    # List of all admins ids of the business
    owner_ids = db.Column(db.String(128), nullable=False)
    # List of all non-admins ids of the business
    employee_ids = db.Column(db.String(128), nullable=False)
    # List of every appointment
    appointments = db.relationship('Appointment', backref='business')
    # List of every admin/employee user account registered to this business
    users = db.relationship('User', backref='business')
    # List of every service offered by this business
    services = db.relationship('Service', backref='business')
    # List of every client
    clients = db.relationship('Client', backref='business')
    # List of every location
    locations = db.relationship('Location', backref='business')

    def __init__(self, name, country, currency, province, city, address):
        self.name = name
        self.country = country
        self.currency = currency
        self.province = province
        self.city = city
        self.address = address
        self.owner_ids = ""
        self.employee_ids = ""
        self.set_referral_id()
        self.verified = False
        self.subscription_days_remaining = 30
        self._subscription_end_date = None

    def get_subscription_end_date(self):
        if self.subscription_days_remaining == 0:
            return None
        return datetime.now().date() + timedelta(
            days=self.subscription_days_remaining)

    # Custom property setter
    def set_referral_id(self):
        self.referral = random.choice(["A", "B", "C", "D"]) + self.name + str(
            random.randint(1, 1000))
        # I will make this create a unique and random referral string later using a function

    def check_referral(self, referral):
        return True

    def get_client_link(self):
        return request.url_root + "booking/appointment/" + str(self.id)

    def get_employee_link(self):
        return url_for('register_user',
                       business_id=self.id,
                       business_referral=self.referral)

    def get_employees(self):
        # Automatically sorts them so that admins are displayed first
        return [user for user in self.users if user.is_owner
                ] + [user for user in self.users if not user.is_owner]

    def get_clients(self):
        return [
            client for client in self.clients
            if client.email != "*****@*****.**"
        ]

    def get_todays_appointments(self):
        """
        Checks the date of each appointment (ignoring the time) and checks if it's today's date.
        Might bug out if the user is in a different timezone?
        @klondikemarlen please check if this is timezone compatible
        """
        return [
            appointment for appointment in self.appointments
            if appointment.date.date() == datetime.now().date()
        ]

    def get_appointments_by_day(self, year, month, day):
        """
        You can choose a date and it returns all apointments for the business on that date
        This function is really messy
        """
        def correct_size(thing):
            if len(str(thing)) >= 2:
                return str(thing)
            else:
                return "0" + str(thing)

        date_check = correct_size(year) + "-" + correct_size(
            month) + "-" + correct_size(day)
        """
        I think it should probably look like this and be shorter, simpler.
        better_date = datetime.date(year, month, day)
        return [appointment for appointment in self.appointments if appointment.date.date() == better_date.date()]
        """

        return [
            appointment for appointment in self.appointments
            if str(appointment.date.date()) == date_check
        ]

    def __repr__(self):
        return '<Business %r (ID: %r)>' % (self.name, self.id)
Beispiel #14
0
class User(Base):
    # Identification Data: email & password
    name = db.Column(db.String(128), nullable=False)
    email = db.Column(db.String(128), nullable=False, unique=True)
    password_hash = db.Column(db.String(192), nullable=False)
    phone = db.Column(db.Integer)
    # Business associated with the user
    business_id = db.Column(db.Integer,
                            db.ForeignKey('business.id'),
                            nullable=False)
    # Appointments associated with the user
    appointments = db.relationship('Appointment', backref='user')
    # Availabilities that the employee has
    availabilities = db.relationship('Availability', backref='user')
    # Used for login_manager
    is_authenticated = db.Column(
        db.Boolean)  # They have filled in all required fields
    is_active = db.Column(
        db.Boolean)  # Account activated and not currently suspended
    is_anonymous = db.Column(db.Boolean)  # If account is anonymous
    # Permissions
    is_owner = db.Column(
        db.Boolean
    )  # Determines if they are an 'owner' of the business. Grants full permissions
    is_manager = db.Column(
        db.Boolean)  # Determines if they have full control over a location
    # Used for email verification
    is_verified = db.Column(db.Boolean)

    def __init__(self, name, email, password, business_id, is_owner):
        self.name = name
        self.email = email
        self.set_password_hash(password)
        self.phone = 0000000000
        self.business_id = business_id
        self.is_owner = is_owner
        self.is_manager = False
        self.is_authenticated = True
        self.is_active = True
        self.is_anonymous = False
        self.is_verified = False
        self.location_id = 1

    def __repr__(self):
        return '<User %r (%r)>' % (self.email, self.id)

    def get_location_ids(self):
        return [
            mapping.location_id for mapping in Mapping.query.filter_by(
                business_id=self.business_id).filter_by(user_id=self.id).all()
        ]

    # Custom property reminder
    @property
    def password(self):
        raise AttributeError(
            'Password is not a readable attribute. Only password_hash is stored.'
        )

    # Custom property setter
    def set_password_hash(self, password):
        self.password_hash = generate_password_hash(password)

    # Password verifier. Can send in a plain password and it will compare it to the hashed password.
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

    def get_id(self):
        return self.id

    def generate_verification_link(self):
        return str(self.id) + "-" + self.name

    def get_verification_link(self):
        return request.url_root[:-1] + url_for(
            'verification',
            user_id=self.id,
            verification_link=self.generate_verification_link())

    def check_verification_link(self, link):
        if link == request.url_root[:-1] + (str(self.id) + "-" + self.name):
            return True
        return False

    def get_availability_by_day(self, day):
        return [
            availability for availability in self.availabilities
            if availability.day == day
        ]

    @property
    def location(self):
        return Location.query.get(self.location_id)

    def sorted_availabilities(self, day=None):
        """
        Returns availabilities sorted first by day, then by start time. You can pass in one specific day to check.
        """
        if day is not None:
            availabilities = [
                availability for availability in self.availabilities
                if availability.day == day
            ]
        else:
            availabilities = self.availabilities
        return sorted(availabilities, key=lambda x: (x.day, x.start))

    @staticmethod
    def verify_time_value(hour, minute):
        """
        This function lets you pass in hours greater than 23 and minutes 60 or above.
        """
        new_hour = (hour % 24) + (minute // 60)
        new_minute = (minute % 60)
        return new_hour, new_minute

    def working_hours_by_day(self, day):
        """
        This creates a list of all hours that a user is working on any given day.
        Currently this function isnt used anywhere, but it will be used to generate the visuals.
        Feel free to run this function and it'll tell you all hours that the user is busy.
        """
        availabilities = self.sorted_availabilities(day)
        options = []
        if not availabilities:
            return 0
        for availability in availabilities:
            count = 0
            while True:
                new = time(availability.start.hour + count, 0)
                options.append((new.hour, new.__str__()))
                count += 1
                if new >= availability.end:
                    break
        return options

    def available_hours_by_day(self, day, condition):
        """
        This creates a list of hours that a user DOESN'T work in a day.
        That way you can run this function in JSON to have the menus update when you choose a day,
        and let you choose hours that you are available.
        """
        if condition == "close":
            pass
        all_hours = [i for i in range(28)]
        if not self.availabilities:
            # Need to return this first or it will crash when it cant iterate through an empty list
            return [(i, str(i) + ":00") for i in range(23)]
        busy_hours = [i[0] for i in self.working_hours_by_day(day)]
        available_hours = [i for i in all_hours if i not in busy_hours]
        options = []
        for i in available_hours:
            if condition == "open":
                hour, minute = self.verify_time_value(i, 0)
            else:
                hour, minute = self.verify_time_value(i + 1, 0)
            hour = time(hour, minute).hour
            options.append((hour, str(hour) + ":00"))
        return options