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)