Esempio n. 1
0
class ConfigModel(BasicConfigModel):
    class Meta:
        tab_pages = [u'後台設定', u'Manifest 相關設定']

    name = Fields.StringProperty(verbose_name=u'識別名稱')
    style = Fields.StringProperty(default='material',
                                  verbose_name=u'後台樣式',
                                  choices=('default', 'material'))

    start_url = Fields.StringProperty(verbose_name=u'manifest start_url',
                                      default='/admin#/admin/welcome',
                                      tab_page=1)
    display = Fields.StringProperty(verbose_name=u'manifest display',
                                    default='fullscreen',
                                    tab_page=1)
    background_color = Fields.StringProperty(
        verbose_name=u'manifest background_color',
        default='#1C5D87',
        tab_page=1)
    theme_color = Fields.StringProperty(verbose_name=u'manifest theme_color',
                                        default='#1C5D87',
                                        tab_page=1)
    icon_128 = Fields.ImageProperty(verbose_name=u'manifest icon_128',
                                    default='',
                                    tab_page=1)
    icon_256 = Fields.ImageProperty(verbose_name=u'manifest icon_256',
                                    default='',
                                    tab_page=1)
class PageTrackerModel(BasicModel):
    name = Fields.StringProperty(verbose_name=u'識別名稱')
    title = Fields.StringProperty(verbose_name=u'標題')
    content = Fields.RichTextProperty(verbose_name=u'內容')
    image = Fields.ImageProperty(verbose_name=u'圖片')
    is_enable = Fields.BooleanProperty(verbose_name=u'顯示於前台', default=True)

    @classmethod
    def all_enable(cls, category=None, *args, **kwargs):
        return cls.query(cls.is_enable==True).order(-cls.sort)

    @classmethod
    def insert(cls, name, title, content=u'', is_enable=True, image=u''):
        item = cls.get_by_name(name)
        if item is not None:
            return
        if content == u'':
            content = title
        item = cls()
        item.name = name
        item.title = title
        item.content = content
        item.is_enable = is_enable
        item.image = image
        item.put()
        return item
class StockKeepingUnitModel(BasicModel):
    class Meta:
        label_name = {
            'is_enable': u'啟用',
            'title': u'完整規格名稱',
            'sku_full_name': u'sku 完整編號'
        }

    name = Fields.StringProperty(verbose_name=u'識別名稱')
    product_no = Fields.StringProperty(verbose_name=u'產品編號')
    sku_no = Fields.StringProperty(verbose_name=u'sku 編號')
    spec_full_name = Fields.StringProperty(verbose_name=u'完整規格名稱')
    image = Fields.ImageProperty(verbose_name=u'圖片')
    use_price = Fields.BooleanProperty(verbose_name=u'使用獨立銷售價格', default=False)
    price = Fields.FloatProperty(verbose_name=u'獨立銷售價格', default=-1)
    use_cost = Fields.BooleanProperty(verbose_name=u'使用成本', default=False)
    cost = Fields.FloatProperty(verbose_name=u'成本', default=0.0)
    quantity = Fields.IntegerProperty(verbose_name=u'現存數量', default=0)
    estimate = Fields.IntegerProperty(verbose_name=u'預估數量', default=0)
    in_order_quantity = Fields.IntegerProperty(verbose_name=u'在訂單中的數量',
                                               default=0)
    pre_order_quantity = Fields.IntegerProperty(verbose_name=u'在預購中的數量',
                                                default=0)
    low_stock_quantity = Fields.IntegerProperty(verbose_name=u'庫存警戒線',
                                                default=-1)
    last_in_quantity = Fields.IntegerProperty(verbose_name=u'最後入庫數量',
                                              default=0)
    last_in_datetime = Fields.DateTimeProperty(verbose_name=u'最後入庫時間',
                                               auto_now_add=True)
    last_out_quantity = Fields.IntegerProperty(verbose_name=u'最後出庫數量',
                                               default=0)
    last_out_datetime = Fields.DateTimeProperty(verbose_name=u'最後入庫時間',
                                                auto_now_add=True)

    is_enable = Fields.BooleanProperty(verbose_name=u'顯示於前台', default=True)
    can_be_purchased = Fields.BooleanProperty(verbose_name=u'可購買',
                                              default=True)

    use_automatic_increment = Fields.BooleanProperty(verbose_name=u'自動增量',
                                                     default=False)
    automatic_increment_quantity = Fields.IntegerProperty(
        verbose_name=u'增量的數量', default=0)
    product = Fields.SearchingHelperProperty(verbose_name=u'所屬產品',
                                             target='product_object',
                                             target_field_name='title')
    product_object = Fields.KeyProperty(verbose_name=u'所屬產品',
                                        kind=ProductModel)
    spec_name_1 = Fields.HiddenProperty(verbose_name=u'規格名稱 1')
    spec_name_2 = Fields.HiddenProperty(verbose_name=u'規格名稱 2')
    spec_name_3 = Fields.HiddenProperty(verbose_name=u'規格名稱 3')
    spec_name_4 = Fields.HiddenProperty(verbose_name=u'規格名稱 4')
    spec_name_5 = Fields.HiddenProperty(verbose_name=u'規格名稱 5')
    spec_value_1 = Fields.HiddenProperty(verbose_name=u'規格值 1')
    spec_value_2 = Fields.HiddenProperty(verbose_name=u'規格值 2')
    spec_value_3 = Fields.HiddenProperty(verbose_name=u'規格值 3')
    spec_value_4 = Fields.HiddenProperty(verbose_name=u'規格值 4')
    spec_value_5 = Fields.HiddenProperty(verbose_name=u'規格值 5')

    @property
    def sku_full_name(self):
        product_no = u''
        if self.product_no is not u'' and self.product_no is not None:
            product_no = '%s' % self.product_no
        sku_post_name = u''
        if self.name is not u'' and self.name is not None:
            sku_post_name = self.name
        if self.sku_no is not u'' and self.sku_no is not None:
            sku_post_name = self.sku_no
        if product_no is not u'' and sku_post_name is not u'':
            return '%s-%s' % (product_no, sku_post_name)
        return '%s%s' % (product_no, sku_post_name)

    def before_put(self):
        super(StockKeepingUnitModel, self).before_put()
        product_no = u''
        cat = self.product_object
        if cat is not None:
            try:
                cat = cat.get()
                product_no = cat.product_no
            except:
                pass
        spec_list = (u'%s' % self.spec_full_name).split(u',')
        i = 0
        setattr(self, 'product_no', product_no)
        for index in range(0, len(spec_list)):
            spec = spec_list[index].split(u':')
            setattr(self, 'spec_name_%s' % (index + 1), spec[0])
            setattr(self, 'spec_value_%s' % (index + 1), spec[1])

    @property
    def title(self):
        return self.spec_full_name

    @property
    def quantity_percent(self):
        quantity = self.quantity if self.quantity is not None else 0
        last_in_quantity = self.last_in_quantity if self.last_in_quantity is not None else 0
        if last_in_quantity == 0:
            return 0
        if last_in_quantity < self.low_stock_quantity:
            last_in_quantity = self.low_stock_quantity
        return int((float(quantity) / float(last_in_quantity)) * 10000) / 100.0

    @property
    def is_low_stock_level(self):
        quantity = self.quantity if self.quantity is not None else 0
        low_stock_quantity = self.low_stock_quantity if self.low_stock_quantity is not None else -1
        return quantity <= low_stock_quantity

    @classmethod
    def all_enable(cls, product=None, *args, **kwargs):
        cat = None
        if product:
            cat = ProductModel.get_by_name(product)
        if cat is None:
            return cls.query(cls.is_enable == True).order(-cls.sort)
        else:
            return cls.query(cls.product_object == cat.key,
                             cls.is_enable == True).order(-cls.sort)

    @classmethod
    def find_by_product(cls, product):
        return cls.query(cls.product_object == product.key).order(
            cls.spec_full_name)

    def change_estimate_quantity(self, sub_quantity=0, add_quantity=0):
        self.estimate = self.estimate - abs(sub_quantity) + abs(add_quantity)
        if self.estimate < 0:
            self.estimate = 0

    def change_pre_order_quantity(self, sub_quantity=0, add_quantity=0):
        self.pre_order_quantity = self.pre_order_quantity - abs(
            sub_quantity) + abs(add_quantity)
        if self.pre_order_quantity < 0:
            self.pre_order_quantity = 0

    def change_in_order_quantity(self, sub_quantity=0, add_quantity=0):
        self.in_order_quantity = self.in_order_quantity - abs(
            sub_quantity) + abs(add_quantity)
        if self.in_order_quantity < 0:
            self.in_order_quantity = 0

    @property
    def quantity_can_be_used(self):
        n = self.quantity - self.in_order_quantity - self.estimate
        if n < 0:
            return 0
        return n
class UserContactDataModel(BasicModel):
    user = Fields.ApplicationUserProperty(verbose_name=u'使用者', is_lock=True)
    user_name_proxy = Fields.StringProperty(verbose_name=u'使用者名稱')
    user_email_proxy = Fields.StringProperty(verbose_name=u'E-Mail')
    user_avatar_proxy = Fields.ImageProperty(verbose_name=u'頭像')
    telephone = Fields.StringProperty(verbose_name=u'電話', default=u'')
    mobile = Fields.StringProperty(verbose_name=u'手機', default=u'')
    sex = Fields.StringProperty(verbose_name=u'性別', default=u'保密')
    address_country = Fields.StringProperty(verbose_name=u'國家', default=u'')
    address_city = Fields.StringProperty(verbose_name=u'縣市', default=u'')
    address_district = Fields.StringProperty(verbose_name=u'鄉鎮', default=u'')
    address_detail = Fields.StringProperty(verbose_name=u'地址', default=u'')
    address_zip = Fields.StringProperty(verbose_name=u'郵遞區號', default=u'')

    birthday_year = Fields.IntegerProperty(verbose_name=u'出生年', default=0)
    birthday_month = Fields.IntegerProperty(verbose_name=u'出生月', default=0)
    birthday_day = Fields.IntegerProperty(verbose_name=u'出生日', default=0)
    referrals = Fields.StringProperty(verbose_name=u'推薦人', default=u'')
    is_referrals_change = Fields.BooleanProperty(verbose_name=u'推薦人已修改', default=False)

    mobile_verification_code = Fields.HiddenProperty(verbose_name=u'手機驗証碼', default=u'')
    is_mobile_verified = Fields.BooleanProperty(verbose_name=u'手機是否已驗証', default=False)
    need_verification_mobile = Fields.HiddenProperty(verbose_name=u'需驗証的手機', default=u'')
    last_verified_mobile = Fields.HiddenProperty(verbose_name=u'最後驗証成功的手機', default=u'')

    email_verification_code = Fields.HiddenProperty(verbose_name=u'信箱驗証碼', default=u'')
    is_email_verified_proxy = Fields.BooleanProperty(verbose_name=u'信箱是否已驗証', default=False)
    need_verification_email = Fields.HiddenProperty(verbose_name=u'需驗証的信箱', default=u'')
    last_verified_email = Fields.HiddenProperty(verbose_name=u'最後驗証成功的信箱', default=u'')

    address_verification_code = Fields.HiddenProperty(verbose_name=u'地址驗証碼', default=u'')
    is_address_verified = Fields.BooleanProperty(verbose_name=u'地址是否已驗証', default=False)

    @classmethod
    def get_or_create(cls, user):
        r = cls.query(cls.user==user.key).get()
        if r is None:
            r = cls(user=user.key)
            r.user_name_proxy = user.name
            r.user_email_proxy = user.email
            r.user_avatar_proxy = user.avatar
            r.is_email_verified_proxy = user.is_email_verified
            r.put()
        r._user = user
        r.password = r._user.password
        r.old_password = r._user.password
        return r

    @property
    def user_instance(self):
        if not hasattr(self, '_user'):
            self._user = self.user.get()
        return self._user

    def update_user(self, user=None):
        if user is None:
            user = self.user_instance
        if user is None:
            return

        if hasattr(self, 'old_password') and self.old_password != self.password:
            user.password = self.password
            user.bycrypt_password()
            self.password = user.password
            self.old_password = user.password
        try:
            user.name = self.user_name_proxy
            user.email = self.user_email_proxy
            user.avatar = self.user_avatar_proxy
            user.is_email_verified = self.is_email_verified_proxy
        except:
            pass
        user.put()

    @property
    def user_name(self):
        if self.user_instance:
            return self.user_instance.name
        return u'該帳號已被刪除'

    @user_name.setter
    def user_name(self, value):
        self.user_name_proxy = value

    @property
    def email(self):
        if self.user_instance:
            return self.user_instance.email
        return u''

    @email.setter
    def email(self, value):
        self.user_email_proxy = value

    @property
    def avatar(self):
        if self.user_instance:
            return self.user_instance.avatar
        return u''

    @avatar.setter
    def avatar(self, value):
        self.user_avatar_proxy = value

    @property
    def is_email_verified(self):
        if self.user_instance:
            return self.user_instance.is_email_verified
        return False

    @is_email_verified.setter
    def is_email_verified(self, value):
        self.is_email_verified_proxy = value

    @classmethod
    def after_get(cls, key, item):
        if item.user_instance:
            item.user_name_proxy = item.user_instance.name
            item.user_email_proxy = item.user_instance.email
            item.user_avatar_proxy = item.user_instance.avatar
            item.is_email_verified_proxy = item.user_instance.is_email_verified
        else:
            item.user_name_proxy = u'該帳號已被刪除'

    def gen_email_verification_code(self, email):
        import random, string
        r = ''.join(random.choice(string.lowercase) for i in range(25))
        self.need_verification_email = email
        self.email_verification_code = u'%s-%s-%s-%s' % (r[0:4], r[5:9], r[10:14], r[15:19])

    def gen_mobile_verification_code(self, mobile):
        import random
        self.need_verification_mobile = mobile
        self.mobile_verification_code = u'%s' % (random.randint(100000, 999999))

    def verify_email(self, code):
        if self.email_verification_code == code:
            self.last_verified_email = self.need_verification_email
            self.is_email_verified_proxy = True
            self.user_email_proxy = self.last_verified_email
            self.user_instance.email = self.last_verified_email
            self.user_instance.is_email_verified = True
            self.user_instance.put()
            self.email_verification_code = ''
            self.put()
            return True
        return False

    def verify_mobile(self, code):
        if self.mobile_verification_code == code:
            self.last_verified_mobile = self.need_verification_mobile
            self.is_mobile_verified = True
            self.mobile_verification_code = ''
            self.put()
            return True
        return False

    @property
    def birthday(self):
        return '%d-%02d-%02d' % (self.birthday_year, self.birthday_month, self.birthday_day)
class ApplicationUserModel(UserModel):
    name = Fields.StringProperty(required=True, verbose_name=u'名稱')
    account = Fields.StringProperty(required=True, verbose_name=u'帳號')
    password = Fields.StringProperty(required=True, verbose_name=u'密碼')
    email = Fields.StringProperty(verbose_name=u'E-Mail', default=u'')
    is_email_verified = Fields.BooleanProperty(verbose_name=u'信箱是否已驗証', default=False)
    avatar = Fields.ImageProperty(verbose_name=u'頭像')
    is_enable = Fields.BooleanProperty(verbose_name=u'啟用', default=True)
    rest_password_token = Fields.StringProperty(verbose_name=u'重設密碼令牌', default=u'')
    need_check_old_password = Fields.BooleanProperty(verbose_name=u'可設定新密碼', default=True)
    role = Fields.HiddenProperty(verbose_name=u'角色', default=u'user')
    provider = Fields.HiddenProperty(verbose_name=u'provider', default=u'website')
    federated_id = Fields.HiddenProperty(verbose_name=u'federated id', default=u'')

    @property
    def title(self):
        return self.account

    @classmethod
    def get_user(cls, account, password, is_enable=True):
        a = cls.query(
            cls.account == account,
            cls.is_enable == is_enable).get()
        if a is None:
            return None
        if bcrypt.hashpw(password, a.password) != a.password:
            return None
        return a

    @classmethod
    def get_user_by_account(cls, account, check_is_enable=False):
        if check_is_enable:
            return cls.query(cls.account == account, cls.is_enable==True).get()
        return cls.query(cls.account == account).get()

    @classmethod
    def get_user_by_email(cls, email, check_is_enable=False):
        if check_is_enable:
            return cls.query(cls.email == email, cls.is_enable==True).get()
        return cls.query(cls.email == email).get()

    @classmethod
    def get_user_by_rest_password_token(cls, token, check_is_enable=True):
        if check_is_enable:
            return cls.query(cls.rest_password_token == token, cls.is_enable==True).get()
        return cls.query(cls.rest_password_token == token).get()

    @classmethod
    def get_user_by_email_and_password(cls, email, password, check_is_enable=True):
        a = cls.get_user_by_email(email, check_is_enable)
        if a is None:
            return None
        if bcrypt.hashpw(password, a.password) != a.password:
            return None
        return a

    def check_password(self, check):
        if bcrypt.hashpw(check, self.password) != self.password:
            return False
        return True

    @classmethod
    def create_account(cls, name, account, password, avatar=None, email=None):
        n = cls()
        n.name = name
        n.account = account
        n.password = bcrypt.hashpw(password, bcrypt.gensalt())
        n.avatar = avatar
        if email:
            n.email = email
        n.put()
        return n

    @classmethod
    def create_account_by_email(cls, email, password, role=None, avatar=None, account=None, user_name=None):
        if account is None:
            account = str(email).split('@')[0]
        if role is None:
            role = RoleModel.find_lowest_level()
        if user_name is None:
            user_name = account
        user = cls.create_account(user_name, account, password, '/plugins/backend_ui_material/static/images/users/avatar-001.jpg', email)
        from ..models.user_role_model import UserRoleModel
        UserRoleModel.set_role(user, role)
        return user

    @classmethod
    def get_list(cls):
        return cls.query(cls.account != 'super_user').order(cls.account, -cls.sort, -cls._key)

    def bycrypt_password_with_old_password(self):
        if self.old_password != self.new_password:
            self.password = u'' + bcrypt.hashpw(u'' + self.new_password, bcrypt.gensalt())
            self.put()

    def bycrypt_password(self):
        self.password = u'' + bcrypt.hashpw(u'' + self.password, bcrypt.gensalt())
        self.put()

    def before_put(self):
        n = []
        try:
            for r in self.roles:
                n.append(r.role_name)
            self.role = ','.join(n)
        except (BadValueError, AttributeError):
            self.role = ''

    @property
    def roles(self):
        if not hasattr(self, '_roles'):
            from user_role_model import UserRoleModel
            self._roles = UserRoleModel.get_user_roles(self).fetch()
        return self._roles

    @property
    def role_list(self):
        roles = []
        for r in self.roles:
            roles.append(r.role.get().name)
        return roles

    def get_role_level(self, highest=True):
        if not hasattr(self, '_level'):
            level = 0
            for r in self.roles:
                r_level = r.role.get().level
                if r_level > level:
                    level = r_level
            setattr(self, '_level', level)
        else:
            level = getattr(self, '_level')
        return level

    def has_role(self, role):
        from user_role_model import UserRoleModel
        return UserRoleModel.has_role(self, role)

    def set_role(self, role):
        from user_role_model import UserRoleModel
        return UserRoleModel.set_role(self, role)

    def remove_role(self, role):
        from user_role_model import UserRoleModel
        return UserRoleModel.remove_role(self, role)

    def check_and_get_role(self, role):
        from user_role_model import UserRoleModel
        role = UserRoleModel.get_role(role)
        if len(self.roles) > 0:
            for item in self.roles:
                if item.key == role.key:
                    return role
            return None
        else:
            if UserRoleModel.has_role(self, role):
                return role
            return None

    def has_permission(self, action_full_name, strict=False):
        if len(self.roles) == 0:
            return False
        not_in_count = 0
        if not hasattr(self, '_roles_object'):
            self._roles_object = []
            for item in self.roles:
                r = item.role.get()
                if r:
                    self._roles_object.append(r)
        for item in self._roles_object:
            if action_full_name not in item.prohibited_actions:
                not_in_count += 1
                if strict is False:
                    break
        if strict:
            return (not_in_count > 0) and (len(self.roles) == not_in_count)
        return not_in_count > 0

    def gen_password_token(self):
        from argeweb.core.random_util import gen_random_code
        self.rest_password_token = gen_random_code()

    @classmethod
    def after_delete(cls, key):
        from user_role_model import UserRoleModel
        from google.appengine.ext import ndb
        keys = []
        for i in UserRoleModel.query(UserRoleModel.user == key).fetch():
            keys.append(i.key)
        ndb.delete_multi(keys)

    @classmethod
    def all_count(cls, *args, **kwargs):
        """ 回傳目前的總使用者人數
        :return: 人數
        """
        return cls.query().count(keys_only=True)

    @classmethod
    def all_count_with_date(cls, date=None, *args, **kwargs):
        """ 回傳特定日期加入的使用者人數
        :return: 人數
        """
        from datetime import timedelta
        if date is None:
            from datetime import datetime
            date = datetime.today()
        date_start = date + timedelta(days=-1)
        date_end = date + timedelta(days=+1)
        return cls.query(cls.created > date_start, cls.created < date_end).count(keys_only=True)