コード例 #1
0
class EwayTransaction(DB.Model):
    """Model for representing an eWay Transaction."""
    __tablename__ = 'eway_transaction'
    object_id = DB.Column(DB.Integer, primary_key=True)

    # This holds the order_id
    access_code = DB.Column(DB.Unicode(200), nullable=False)
    charged = DB.Column(DB.Integer(), nullable=False)

    completed = DB.Column(DB.DateTime(), nullable=True)
    result_code = DB.Column(DB.Unicode(2), nullable=True)
    # This holds the PASREF field for realex
    eway_id = DB.Column(DB.String(50), nullable=True)
    refunded = DB.Column(DB.Integer(), nullable=False, default=0)

    def __init__(self, access_code, charged):
        self.access_code = access_code
        self.charged = charged

    @property
    def status(self):
        """Get a better representation of the status of this transaction.

        The eWay API returns statuses as 2 digit codes; this function provides
        a mapping from these codes to a boolean success value and associated
        explanation.

        Returns:
            (bool, str) pair of success value and explanation
        """
        try:
            return REALEX_RESULT_CODES[self.result_code[0]]
        except KeyError as err:
            return (False, 'Unknown response: {0}'.format(err.args[0]))

    @property
    def success(self):
        """Get whether the transaction was completed successfully."""
        success = self.status[0]
        if success is None:
            return 'Uncompleted'
        elif success:
            return 'Successful'
        else:
            return 'Unsuccessful'
コード例 #2
0
class PayPalTransaction(transaction.Transaction):
    """Model for representing a paypal transaction."""
    __tablename__ = 'paypal_transaction'
    __mapper_args__ = {'polymorphic_identity': 'PayPal'}
    object_id = DB.Column(DB.Integer, primary_key=True)

    object_id = DB.Column(DB.Integer(),
                          DB.ForeignKey('transaction.object_id'),
                          primary_key=True)

    # This holds the order_id
    access_code = DB.Column(DB.Unicode(200), nullable=True)
    charged = DB.Column(DB.Integer(), nullable=False, default=0)

    completed = DB.Column(DB.DateTime(), nullable=True)
    result_code = DB.Column(DB.Unicode(2), nullable=True)
    # This holds the PASREF field for realex
    paypal_id = DB.Column(DB.String(50), nullable=True)
    refunded = DB.Column(DB.Integer(), nullable=False, default=0)

    order_id = DB.Column(DB.Integer(), nullable=True)

    # eway_transaction_id = DB.Column(
    #     DB.Integer(),
    #     DB.ForeignKey('eway_transaction.object_id'),
    #     nullable=True
    # )
    # eway_transaction = DB.relationship(
    #     'EwayTransaction',
    #     backref=DB.backref(
    #         'transactions',
    #         lazy='dynamic'
    #     )
    # )

    def __init__(self, user, eway_trans=None):
        super(PayPalTransaction, self).__init__(user, 'PayPal')

        # if eway_transaction is not None:
        #     self.eway_transaction = eway_trans

    def __repr__(self):
        return '<PayPalTransaction({0}): {1} item(s)>'.format(
            self.object_id, self.items.count())
コード例 #3
0
ファイル: user.py プロジェクト: gwynethbradbury/oussshop
class User(DB.Model):
    """Model for users."""
    __tablename__ = 'user'

    object_id = DB.Column(DB.Integer, primary_key=True)

    # Class level properties for Flask-Login
    #
    # Sessions don't expire, and no users are anonymous, so these can be hard
    # coded
    is_authenticated = True
    is_anonymous = False

    email = DB.Column(DB.Unicode(120), unique=True, nullable=False)
    new_email = DB.Column(DB.Unicode(120), unique=True, nullable=True)
    password_hash = DB.Column(DB.BINARY(60), nullable=False)
    forenames = DB.Column(DB.Unicode(120), nullable=False)
    surname = DB.Column(DB.Unicode(120), nullable=False)
    full_name = DB.column_property(forenames + ' ' + surname)
    phone = DB.Column(DB.Unicode(20), nullable=False)
    phone_verification_code = DB.Column(DB.Unicode(6), nullable=True)
    phone_verified = DB.Column(DB.Boolean, nullable=False, default=False)
    prepaid_classes = DB.Column(DB.Integer, nullable=False, default=0)
    secret_key = DB.Column(DB.Unicode(64), nullable=True)
    secret_key_expiry = DB.Column(DB.DateTime(), nullable=True)
    verified = DB.Column(DB.Boolean, default=False, nullable=False)
    deleted = DB.Column(DB.Boolean, default=False, nullable=False)
    note = DB.Column(DB.UnicodeText, nullable=True)
    role = DB.Column(DB.Enum('User', 'Admin'), nullable=False)

    college_id = DB.Column(DB.Integer,
                           DB.ForeignKey('college.object_id'),
                           nullable=False)
    college = DB.relationship('College',
                              backref=DB.backref('users', lazy='dynamic'))

    affiliation_id = DB.Column(DB.Integer,
                               DB.ForeignKey('affiliation.object_id'),
                               nullable=False)
    affiliation = DB.relationship('Affiliation',
                                  backref=DB.backref('users', lazy='dynamic'))

    # battels_id = DB.Column(
    #     DB.Integer,
    #     DB.ForeignKey('battels.object_id'),
    #     nullable=True
    # )
    # battels = DB.relationship(
    #     'Battels',
    #     backref=DB.backref(
    #         'user',
    #         uselist=False
    #     )
    # )

    affiliation_verified = DB.Column(DB.Boolean, default=False, nullable=True)

    photo_id = DB.Column(DB.Integer,
                         DB.ForeignKey('photo.object_id'),
                         nullable=True)
    photo = DB.relationship('Photo', backref=DB.backref('user', uselist=False))

    def has_membership(self):
        if membership.Membership.query.filter_by(
                owner_id=self.object_id).count() > 0:
            return True
        return False

    def memberships(self):
        if self.has_membership():
            return membership.Membership.query.filter_by(
                owner_id=self.object_id).all()
        return None

    def has_unpaid_memberships(self):
        if membership.Membership.query.filter_by(owner_id=self.object_id,
                                                 paid=0).count() > 0:
            return True
        return False

    def has_paid_memberships(self):
        if membership.Membership.query.filter_by(owner_id=self.object_id,
                                                 paid=1).count() > 0:
            return True
        return False

    def can_claim_membership(self):
        return False

#todo: check logic
# def has_collected_memberships(self):
#     return False
# def has_uncollected_memberships(self):
#     return False

    def has_held_membership(self):
        # if membership.Membership.query.filter_by(holder_id=self.object_id):
        #     return True
        return False

    def can_update_details(self):
        return APP.config['ENABLE_CHANGING_DETAILS']

    def __init__(self, email, password, forenames, surname, phone, college,
                 affiliation, photo):
        self.email = email
        self.forenames = forenames
        self.surname = surname
        self.phone = phone
        self.college = college
        self.affiliation = affiliation
        self.photo = photo

        self.set_password(password)

        self.secret_key = util.generate_key(64)
        self.verified = False
        self.deleted = False
        self.role = 'User'
        if affiliation.name == 'None':
            self.affiliation_verified = True
        else:
            self.affiliation_verified = False
            #todo add logic for checking if they are on the member list

        # self.battels = battels.Battels.query.filter(
        #     battels.Battels.email == email
        # ).first()

    def __repr__(self):
        return '<User {0}: {1} {2}>'.format(self.object_id, self.forenames,
                                            self.surname)

    def can_pay_by_battels(self):
        return False

    @property
    def group_purchase_requests(self):
        """Get this user's group purchase requests.

        Not just a database backref so that old requests can hang around when
        the user leaves a group.
        """
        if self.purchase_group:
            for request in self.purchase_group.requests:
                if request.requester == self:
                    yield request

    def group_purchase_requested(self, membership_type_slug):
        return 0

    @property
    def total_group_purchase_requested(self):
        return 0

    @property
    def total_group_purchase_value(self):
        return 0

    def check_password(self, candidate):
        """Check if a password matches the hash stored for the user.

        Runs the bcrypt.Bcrypt checking routine to validate the password.

        Args:
            candidate: (str) the candidate password

        Returns:
            (bool) whether the candidate password matches the stored hash
        """
        return BCRYPT.check_password_hash(self.password_hash, candidate)
        # return check_password_hash(self.password_hash, candidate)

    def set_password(self, password):
        """Set the password for the user.

        Hashes the password using bcrypt and stores the resulting hash.

        Args:
            password: (str) new password for the user.
        """
        self.password_hash = BCRYPT.generate_password_hash(password)
        # self.password_hash = generate_password_hash(password)

    def promote(self):
        """Make the user an admin."""
        self.role = 'Admin'

    def demote(self):
        """Make the user an ordinary user (no admin privileges)"""
        self.role = 'User'

    @property
    def is_admin(self):
        """Check if the user is an admin, or is currently being impersonated.

        For future-proofing purposes, the role of the impersonating user is also
        checked.
        """
        return self.role == 'Admin' or (
            'actor_id' in flask.session
            and User.get_by_id(flask.session['actor_id']).role == 'Admin')

    @property
    def is_waiting(self):
        """Is the user on the waiting list?"""
        return self.waiting.count() > 0

    @property
    def memberships(self):
        """Get the active memberships owned by the user."""
        return self.memberships.filter(membership.Membership.cancelled == False  # pylint: disable=singleton-comparison
                                       )

    @property
    def active_membership_count(self):
        """How many active memberships does the user own?"""
        return self.active_memberships.count()

    @property
    def waiting_for(self):
        return 0

    @property
    def is_verified(self):
        """Has the user's email address been verified?"""
        return self.verified

    @property
    def is_deleted(self):
        """Has the user been deleted?

        In order to maintain referential integrity, when a user is deleted we
        scrub their personal details, but maintain the user object referenced by
        log entries, memberships, transactions etc.
        """
        return self.deleted

    @property
    def is_active(self):
        """Is the user active?

        This method is specifically for the use of the Flask-Login extension,
        and refers to whether the user can log in.
        """
        return self.is_verified and not self.is_deleted

    def get_id(self):
        """What is this user's ID?

        This method is specifically for the use of the Flask-Login extension,
        and is a defined class method which returns a unique identifier for the
        user, in this case their database ID.
        """
        return unicode(self.object_id)

    @staticmethod
    def get_by_email(email):
        """Get a user object by the user's email address."""
        user = User.query.filter(User.email == email).first()

        if not user:
            return None

        return user

    def add_manual_battels(self):
        """Manually add a battels account for the user

        If we don't have a battels account automatically matched to the user,
        the admin can manually create one for them.
        """
        self.battels = battels.Battels.query.filter(
            battels.Battels.email == self.email).first()

        if not self.battels:
            self.battels = battels.Battels(None, self.email, None,
                                           self.surname, self.forenames, True)
            DB.session.add(self.battels)

        DB.session.commit()

    @staticmethod
    def write_csv_header(csv_writer):
        """Write the header of a CSV export file."""
        csv_writer.writerow([
            'User ID',
            'Email',
            'Forenames',
            'Surname',
            'Phone Number',
            'Notes',
            'Role',
            'College',
            'Affiliation',
            'Battels ID',
        ])

    def write_csv_row(self, csv_writer):
        """Write this object as a row in a CSV export file."""
        csv_writer.writerow([
            self.object_id,
            self.email,
            self.forenames,
            self.surname,
            self.phone,
            self.note,
            self.role,
            self.college.name,
            self.affiliation.name,
            self.battels.battels_id if self.battels is not None else 'N/A',
        ])
コード例 #4
0
class Transaction(DB.Model):
    """Model for representing a monetary exchange transaction."""
    __tablename__ = 'transaction'
    object_id = DB.Column(DB.Integer, primary_key=True)

    payment_method = DB.Column(DB.Enum('Battels', 'Card', 'PayPal', 'Free',
                                       'Dummy'),
                               nullable=False)

    paid = DB.Column(DB.Boolean, default=False, nullable=False)
    created = DB.Column(DB.DateTime(), nullable=False)

    user_id = DB.Column(DB.Integer,
                        DB.ForeignKey('user.object_id'),
                        nullable=False)
    user = DB.relationship('User',
                           backref=DB.backref('transactions', lazy='dynamic'))

    __mapper_args__ = {'polymorphic_on': payment_method}

    def __init__(self, user, payment_method):
        self.user = user
        self.payment_method = payment_method

        self.created = datetime.datetime.utcnow()

    def __repr__(self):
        return '<Transaction {0}: {1} item(s)>'.format(self.object_id,
                                                       self.items.count())

    @property
    def value(self):
        """Get the total value of the transaction."""
        if self.items.count() >= APP.config['GROUP_SIZE']:
            if self.items.count() >= APP.config['GROUP_SIZE2']:
                return sum(1600 for item in
                           self.items)  #APP.config['GROUP_TICKET_PRICE_p']
            else:
                return sum(1800 for item in
                           self.items)  #APP.config['GROUP_TICKET_PRICE_p']
        return sum(item.value for item in self.items)

    @property
    def value_pounds(self):
        """Get the total value of the transaction."""
        value_str = "{0:03d}".format(self.value)

        return value_str[:-2] + '.' + value_str[-2:]

    def value_pounds_surcharge(self, surcharge=0):
        """Get the total value of the transaction."""
        value_str = "{0:03d}".format(self.value + surcharge)

        return value_str[:-2] + '.' + value_str[-2:]

    @property
    def tickets(self):
        """Get the tickets paid for in this transaction.

        Returns a list of Ticket objects.
        """
        return list(item.ticket for item in self.items
                    if item.item_type == 'Ticket')

    @property
    def postage(self):
        """Get the postage paid for in this transaction.

        Returns a single Postage object, or None.
        """
        try:
            return list(item.postage for item in self.items
                        if item.item_type == 'Postage')[0]
        except IndexError:
            return None

    @property
    def admin_fee(self):
        """Get the admin_fee paid for in this transaction.

        Returns a single AdminFee object, or None.
        """
        try:
            return list(item.admin_fee for item in self.items
                        if item.item_type == 'AdminFee')[0]
        except IndexError:
            return None

    def mark_as_paid(self):
        """Mark the transaction as paid for.

        Marks all tickets in the transaction as paid for.
        """
        self.paid = True

        for ticket in self.tickets:
            ticket.mark_as_paid()

        postage = self.postage
        if postage:
            postage.paid = True

        admin_fee = self.admin_fee
        if admin_fee:
            admin_fee.mark_as_paid()
コード例 #5
0
class Membership(DB.Model):
    """Model for membership."""
    __tablename__ = 'membership'
    object_id = DB.Column(DB.Integer, primary_key=True)

    membership_type = DB.Column(DB.Unicode(50), nullable=False)
    owner_id = DB.Column(DB.Integer,
                         DB.ForeignKey('user.object_id'),
                         nullable=False)
    owner = DB.relationship('User',
                            backref=DB.backref(
                                'memberships',
                                lazy='dynamic',
                                order_by=b'Membership.cancelled'),
                            foreign_keys=[owner_id])

    paid = DB.Column(DB.Boolean(), default=False, nullable=False)
    cancelled = DB.Column(DB.Boolean(), default=False, nullable=False)
    price_ = DB.Column(DB.Integer(), nullable=False)
    note = DB.Column(DB.UnicodeText(), nullable=True)
    expires = DB.Column(DB.DateTime(), nullable=True)
    barcode = DB.Column(DB.Unicode(20), unique=True, nullable=True)

    def __init__(self, owner, membership_type, price):
        self.owner = owner
        self.membership_type = membership_type
        self.price = price

        y = datetime.datetime.utcnow().year
        m = datetime.datetime.utcnow().month
        if m >= 10:
            y = y + 1

        self.expires = datetime.datetime(y, 10,
                                         1)  #(datetime.datetime.utcnow()) +
        #APP.config['MEMBERSHIP_EXPIRY_TIME'])

    def generate_barcode(self):
        # generate barcode
        key = util.generate_key(20).decode('utf-8')
        self.barcode = key

    def generate_qrcode(self):
        # generate QR
        qrcode_img = pyqrcode.create(
            '{0}admin/membership/validate-ticket/{1}/{2}'.format(
                APP.config['EISITIRIO_URL'], self.object_id, self.barcode))
        buffer = io.BytesIO()
        qrcode_img.png(buffer, scale=20)

        f = open(
            '/Users/Gwyneth/Documents/repositories/oussshop/flaskshop/tmp.png',
            'wb')
        f.write(buffer)
        f.close()
        return buffer.getvalue()

    def __repr__(self):
        return '<Membership {0} owned by {1} ({2})>'.format(
            self.object_id, self.owner.full_name, self.owner.object_id)

    def can_be_cancelled(self):
        return False

    def can_be_resold(self):
        return False

    def can_be_claimed(self):
        return False

    def can_be_reclaimed(self):
        return False

    def has_holder(self):
        return False

    def can_be_paid_for(self):
        if self.paid == 0:
            return True
        return False

    def can_be_collected(self):
        return False

    def is_assigned(self):
        return True

    @property
    def price_pounds(self):
        """Get the price of this membership as a string of pounds and pence."""
        price = '{0:03d}'.format(self.price)
        return price[:-2] + '.' + price[-2:]

    @property
    def transaction(self):
        """Get the transaction this membership was paid for in."""
        for transaction_item in self.transaction_items:
            if transaction_item.transaction.paid:
                return transaction_item.transaction

        return None

    @property
    def payment_method(self):
        """Get the payment method for this membership."""
        transaction = self.transaction

        if transaction:
            return transaction.payment_method
        else:
            return 'Unknown Payment Method'

    @property
    def price(self):
        """Get the price of the membership."""
        return self.price_

    @property
    def status(self):
        """Get the status of this membership."""
        if not self.paid:
            return 'Awaiting payment. Expires {0}.'.format(
                self.expires.strftime('%H:%M %d/%m/%Y'))
        elif APP.config['REQUIRE_USER_PHOTO']:
            if not self.holder.photo.verified:
                return 'Awaiting verification of holder photo.'
        else:
            return 'Valid membership'

    @price.setter
    def price(self, value):
        """Set the price of the membership."""
        self.price_ = max(value, 0)

        if self.price_ == 0:
            self.mark_as_paid()

    @hybrid.hybrid_property
    def collected(self):
        """Has this membership been assigned a barcode."""
        return self.barcode != None  # pylint: disable=singleton-comparison

    def mark_as_paid(self):
        """Mark the membership as paid, and clear any expiry."""
        self.paid = True
        self.expires = None

    def add_note(self, note):
        """Add a note to the membership."""
        if not note.endswith('\n'):
            note = note + '\n'

        if self.note is None:
            self.note = note
        else:
            self.note = self.note + note

    @staticmethod
    def count():
        """How many memberships have been sold."""
        # TODO
        return Membership.query.filter(Membership.paid == True).count()  # pylint: disable=singleton-comparison

    @staticmethod
    def write_csv_header(csv_writer):
        """Write the header of a CSV export file."""
        csv_writer.writerow([
            'Membership ID',
            'Membership Type',
            'Paid',
            'Cancelled',
            'Price (Pounds)',
            'Notes',
            'Expires',
            'Barcode',
            'Owner\' User ID',
            'Owner\'s Name',
        ])

    def write_csv_row(self, csv_writer):
        """Write this object as a row in a CSV export file."""
        csv_writer.writerow([
            self.object_id,
            self.membership_type,
            'Yes' if self.paid else 'No',
            'Yes' if self.cancelled else 'No',
            self.price_pounds,
            self.note,
            self.expires.strftime('%Y-%m-%d %H:%M:%S')
            if self.expires is not None else 'N/A',
            self.barcode if self.barcode is not None else 'N/A',
            self.owner_id,
            self.owner.full_name.encode('utf-8'),
        ])