class UserShopPointProductModel(BasicModel): name = Fields.StringProperty(verbose_name=u'識別名稱') title = Fields.StringProperty(verbose_name=u'標題', default=u'50點') price = Fields.FloatProperty(verbose_name=u'價格', default=50.0) point = Fields.FloatProperty(verbose_name=u'獲得點數', default=50.0) is_enable = Fields.BooleanProperty(verbose_name=u'啟用', default=True) remark = Fields.TextProperty(verbose_name=u'說明', default=u'')
class ConfigModel(BasicConfigModel): class Meta: tab_pages = [u'購物時折抵', u'購物時獲得', u'點數購買'] title = Fields.HiddenProperty(verbose_name=u'設定名稱', default=u'購物金設定') max_use_point_for_order = Fields.RangeProperty( verbose_name=u'每筆訂單可折抵最大購物金', unit='%', default=5, step=0.1, multiple=True) discount_ratio = Fields.RangeProperty(verbose_name=u'貨幣折換比率', unit='%', default=100, step=0.1) is_must_use = Fields.BooleanProperty(verbose_name=u'強制使用', default=False) min_amount = Fields.FloatProperty(verbose_name=u'金額閥值', default=0.0) available_point = Fields.RangeProperty(verbose_name=u'每訂單可獲得的購物金', tab_page=1, unit='%', default=0.5, step=0.1) can_buy = Fields.BooleanProperty(verbose_name=u'是否可以直接購買點數', default=False, tab_page=2) give_time = Fields.StringProperty(verbose_name=u'發放時間', default=u'after_order_checkout', choices=[ 'after_order_checkout', 'after_order_close', ], choices_text={ 'after_order_checkout': u'訂單建立後', 'after_order_close': u'訂單完成後', })
class UserShopPointHistoryModel(BasicModel): name = Fields.StringProperty(verbose_name=u'識別名稱') shop_point_target = Fields.KeyProperty(verbose_name=u'所屬單位', kind=UserShopPointModel) order_no = Fields.StringProperty(verbose_name=u'訂單編號', default=u'') order_amount = Fields.StringProperty(verbose_name=u'訂單金額', default=u'') decrease_point = Fields.FloatProperty(verbose_name=u'點數减少', default=0) increase_point = Fields.FloatProperty(verbose_name=u'點數增加', default=0) point = Fields.FloatProperty(verbose_name=u'剩餘點數', default=0) remark = Fields.TextProperty(verbose_name=u'說明', default=u'') @classmethod def all_enable(cls, target=None, *args, **kwargs): if target: return cls.query( cls.shop_point_target == target.key).order(-cls.sort) return cls.query().order(-cls.sort)
class CurrencyModel(BasicModel): name = Fields.StringProperty(verbose_name=u'識別名稱') title = Fields.StringProperty(verbose_name=u'幣值名稱') short_name = Fields.StringProperty(verbose_name=u'簡短的名稱', default=u'') unit_name = Fields.StringProperty(verbose_name=u'單位名稱', default=u'元') exchange_rate = Fields.FloatProperty(verbose_name=u'匯率', default=1.0) is_enable = Fields.BooleanProperty(verbose_name=u'顯示於前台', default=True) is_main = Fields.BooleanProperty(verbose_name=u'是否為基準貨幣', default=False) @classmethod def all_enable(cls, category=None, *args, **kwargs): return cls.query(cls.is_enable == True).order(-cls.sort) @classmethod def get_or_create_main_currency(cls): main = cls.get_by_name('main') if main is None: main = cls() main.name = 'main' main.is_main = True main.title = '基準貨幣' main.short_name = u'Main' main.unit_name = u'元' main.is_enable = False main.exchange_rate = 1 main.put() return main @classmethod def get_current_or_main_currency(cls, currency_name): current_currency = cls.get_by_name(currency_name) if current_currency is None: current_currency = CurrencyModel.get_or_create_main_currency() return current_currency @classmethod def get_current_or_main_currency_with_controller(cls, controller): use_currency_name = '' if 'use_currency' in controller.session: use_currency_name = controller.session['use_currency'] if use_currency_name is '': use_currency_name = 'main' return cls.get_current_or_main_currency(use_currency_name) def calc(self, target, places=2): return exchange(self.exchange_rate, target, places)
class LineBotModel(BasicModel): title = Fields.TextProperty(verbose_name=u'檢查的字串', default=u'') py_code = Fields.TextProperty(verbose_name=u'PyCode', default=u'') source_type = Fields.StringProperty(verbose_name=u'要處理的訊息來源', default=u'user', choices=( u'user', u'group', u'room', u'input', u'all', )) message_type = Fields.StringProperty(verbose_name=u'要處理的訊息類型', default=u'text', choices=( u'text', u'image', u'video', u'audio', u'location', u'sticker', u'follow', u'unfollow', u'join', u'leave', u'postback', )) return_message_type = Fields.StringProperty(verbose_name=u'回傳的訊息類型', default=u'TextSendMessage', choices=( u'TextSendMessage', u'ImageSendMessage', u'TemplateSendMessage', )) weights = Fields.FloatProperty(verbose_name=u'權重', default=0.0) @classmethod def get_or_create_by_name(cls, name): item = cls.get_by_name(name) if item is None: import time item = cls() item.name = name item.weights = time.time() 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 ShoppingCartItemModel(BasicModel): cart = Fields.KeyProperty(verbose_name=u'購物車', kind=ShoppingCartModel) spec = Fields.KeyProperty(verbose_name=u'產品規格', kind=ProductSpecificationModel) user = Fields.ApplicationUserProperty(verbose_name=u'使用者') product_object = Fields.KeyProperty(verbose_name=u'所屬產品', kind=ProductModel) title = Fields.StringProperty(verbose_name=u'產品名稱', default=u'') product_name = Fields.StringProperty(verbose_name=u'產品名稱(系統)', default=u'') product_no = Fields.StringProperty(verbose_name=u'產品型號', default=u'') product_image = Fields.StringProperty(verbose_name=u'產品圖片', default=u'') price = Fields.FloatProperty(verbose_name=u'銷售價格', default=-1) cost = Fields.FloatProperty(verbose_name=u'成本', default=0.0) spec_full_name = Fields.StringProperty(verbose_name=u'完整規格名稱', default=u'') # 庫存相關 try: from plugins.product_stock.models.stock_keeping_unit_model import StockKeepingUnitModel except ImportError: class StockKeepingUnitModel(BasicModel): pass sku = Fields.KeyProperty(verbose_name=u'最小庫存單位', kind=StockKeepingUnitModel) sku_full_name = Fields.StringProperty(verbose_name=u'產品最小庫存名稱') expired_time = Fields.FloatProperty(verbose_name=u'庫存回收時間') quantity = Fields.IntegerProperty(verbose_name=u'數量', default=0) quantity_has_count = Fields.IntegerProperty(verbose_name=u'已計入庫存的數量', default=0) can_add_to_order = Fields.BooleanProperty(verbose_name=u'加至訂單中', default=False) try: from plugins.supplier.models.supplier_model import SupplierModel except ImportError: class SupplierModel(BasicModel): pass supplier = Fields.CategoryProperty(kind=SupplierModel, verbose_name=u'供應商') # 0=訂購(無庫存), 1=現貨, 2預購 order_type = Fields.StringProperty(verbose_name=u'訂購方式') order_type_value = Fields.IntegerProperty(verbose_name=u'訂購方式(值)') size_1 = Fields.FloatProperty(verbose_name=u'長度(公分)', default=10.0) size_2 = Fields.FloatProperty(verbose_name=u'寬度(公分)', default=10.0) size_3 = Fields.FloatProperty(verbose_name=u'高度(公分)', default=10.0) weight = Fields.FloatProperty(verbose_name=u'重量(公斤)', default=10.0) @classmethod def get_or_create(cls, cart, user, product, spec, order_type=0): try: user_key = user.key except AttributeError: user_key = user item = cls.query(cls.cart == cart.key, cls.user == user_key, cls.product_object == product.key, cls.spec == spec.key, cls.order_type_value == order_type).get() need_put = False if item is None: item = cls() item.cart = cart.key item.user = user_key item.product_object = product.key item.spec = spec.key item.order_type_value = order_type item.order_type = [u'訂購', u'現貨', u'預購'][order_type] item.spec_full_name = spec.full_name item.product_name = product.name item.product_image = product.image need_put = True if order_type == 0: item.can_add_to_order = True for field_name in [ 'title', 'product_no', 'price', 'cost', 'size_1', 'size_2', 'size_3', 'weight' ]: if getattr(item, field_name) != getattr(product, field_name): setattr(item, field_name, getattr(product, field_name)) need_put = True if need_put: item.put() return item @classmethod def get(cls, user, sku, order_type_value=0): return cls.query(cls.sku == sku.key, cls.user == user.key, cls.order_type_value == order_type_value).get() @classmethod def get_or_create_with_spec(cls, user, spec, quantity=0, order_type_value=0): product = spec.product_object.get() item = cls.query(cls.sku == spec.key, cls.user == user.key, cls.order_type_value == order_type_value).get() if item is None: item = cls() item.spec = spec.key item.user = user.key item.order_type_value = order_type_value item.product_object = product.key try: item.supplier = product.supplier.get().key except: pass if order_type_value == 0: item.order_type = u'訂購' else: item.order_type = u'預購' item._spec = spec item._product = product item.title = product.title item.product_no = product.product_no item.product_image = product.image item.spec_full_name = spec.spec_full_name item.change_quantity(quantity) item.put() return item @classmethod def all_with_user(cls, user): key = None if user is not None: key = user.key return cls.query(cls.user == key).order(-cls.sort) @classmethod def before_delete(cls, key): item = key.get() if item.order_type_value == 0: if item.quantity > 0: try: sku = item.sku_instance sku.change_estimate_quantity(item.quantity_has_count) sku.put() except: pass def volumetric_weight(self, divisor=6000.0): n = self.size_1 * self.size_2 * self.size_3 / float(divisor) return n @property def spec_instance(self): if not hasattr(self, '_spec'): self._spec = self.spec.get() return self._spec @property def sku_instance(self): if not hasattr(self, '_sku'): self._sku = self.sku.get() return self._sku @property def product_instance(self): if not hasattr(self, '_product'): self._product = self.spec_instance.product_object.get() return self._product def change_quantity(self, quantity): spec = self.spec_instance product = self.product_instance if self.order_type_value == 0: config = ConfigModel.get_config() if config.stock_recover: self.expired_time = time() + config.stock_recover_time else: self.expired_time = time() + 525600 can_use_quantity = spec.quantity_can_be_used + int( self.quantity_has_count) old_quantity_has_count = self.quantity_has_count if can_use_quantity >= quantity and product.can_order: self.can_add_to_order = True self.quantity = quantity self.quantity_has_count = quantity else: self.can_add_to_order = False self.quantity = 0 self.quantity_has_count = 0 spec.change_estimate_quantity(sub_quantity=old_quantity_has_count, add_quantity=self.quantity) spec.put() else: if product.can_pre_order: self.can_add_to_order = True self.quantity = quantity else: self.can_add_to_order = False self.quantity = 0 spec.change_pre_order_quantity(sub_quantity=int( self.quantity_has_count), add_quantity=self.quantity) spec.put() def quantity_can_be_order(self, user=None, sku=None): if sku is None: sku = self.sku.get() if self.order_type_value > 0: return 999 if user and self.quantity is not None: c = sku.quantity_can_be_used + self.quantity if c > 0: return c return sku.quantity_can_be_used
class UserShopPointModel(BasicModel): class Meta: label_name = { 'modified': u'最後變動時間', } name = Fields.StringProperty(verbose_name=u'識別名稱') user = Fields.ApplicationUserProperty(verbose_name=u'使用者') user_name_proxy = Fields.StringProperty(verbose_name=u'使用者名稱') user_email_proxy = Fields.StringProperty(verbose_name=u'E-Mail') point = Fields.FloatProperty(verbose_name=u'現餘點數', default=0.0) used_point = Fields.FloatProperty(verbose_name=u'已使用點數', default=0.0) @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 = user r.user_name_proxy = r._user.name r.user_email_proxy = r._user.email r.put() r.user_name_proxy = user.name r.user_email_proxy = user.email return r @classmethod def after_get(cls, key, item): super(UserShopPointModel, cls).after_get(key, item) item._user = item.user.get() if item._user: item.user_name_proxy = item._user.name item.user_email_proxy = item._user.email else: item.user_name_proxy = u'該帳號已被刪除' def increase_point(self, point, remark=u'', order_no=u'', order_amount=None): from user_shop_point_history_model import UserShopPointHistoryModel point = int(point) history = UserShopPointHistoryModel() history.shop_point_target = self.key history.remark = remark history.increase_point = point history.order_no = order_no if order_amount is not None: history.order_amount = str(order_amount) if self.point is None: self.point = 0.0 history.point = self.point + point history.put() self.point += point def decrease_point(self, point, remark, order_no=u'', order_amount=None): from user_shop_point_history_model import UserShopPointHistoryModel point = point history = UserShopPointHistoryModel() history.shop_point_target = self.key history.remark = remark history.decrease_point = point history.order_no = order_no if order_amount is not None: history.order_amount = str(order_amount) if self.point is None: self.point = 0.0 history.point = self.point - point history.put() self.point -= point self.used_point += point def get_max_usable_point(self, total): from ..models.config_model import ConfigModel config = ConfigModel.get_config() if total > config.min_amount: n = total * (config.max_use_point_for_order / 100.0) * (config.discount_ratio / 100.0) // 1.0 if n > self.point: return self.point return n else: return 0.0
class ShoppingCartModel(BasicModel): title = Fields.StringProperty(verbose_name=u'購物車名稱', default=u'預設') user = Fields.ApplicationUserProperty(verbose_name=u'使用者') total_size = Fields.FloatProperty(verbose_name=u'尺寸合計', default=0.0) total_volume = Fields.FloatProperty(verbose_name=u'體積合計', default=0.0) total_price = Fields.FloatProperty(verbose_name=u'金額合計', default=0.0) total_weight = Fields.FloatProperty(verbose_name=u'重量總重', default=0.0) total_volumetric_weight = Fields.FloatProperty(verbose_name=u'材積總重', default=0.0) cost_for_items = Fields.FloatProperty(verbose_name=u'成本(項目)', default=0.0, tab_page=4) freight = Fields.FloatProperty(verbose_name=u'運費', default=0.0) freight_type = Fields.KeyProperty(verbose_name=u'運送方式', kind=FreightTypeModel) try: from plugins.supplier.models.supplier_model import SupplierModel except ImportError: class SupplierModel(BasicModel): pass supplier = Fields.CategoryProperty(verbose_name=u'供應商', kind=SupplierModel) @classmethod def get_or_create(cls, user, supplier=None, supplier_key=None): if supplier is not None and supplier_key is None: supplier_key = supplier.key cart = cls.query(cls.user == user.key, cls.supplier == supplier_key).get() if cart is None: cart = cls() cart.user = user.key if supplier_key: cart.supplier = supplier_key cart.put() return cart def get_shopping_cart_item(self, product, spec, item_order_type): from shopping_cart_item_model import ShoppingCartItemModel return ShoppingCartItemModel.get_or_create(self, self.user, product, spec, item_order_type) @property def items(self): from shopping_cart_item_model import ShoppingCartItemModel return ShoppingCartItemModel.query( ShoppingCartItemModel.cart == self.key).fetch() def clean(self): if len(self.items) == 0: self.key.delete() def calc_size_weight_price_and_put(self, items=None): if items is None: items = self.items total_volume = 0.0 total_size = 0.0 total_price = 0.0 total_weight = 0.0 total_volumetric_weight = 0.0 total_cost_for_items = 0.0 for cart_item in items: total_size += cart_item.quantity * ( cart_item.size_1 + cart_item.size_2 + cart_item.size_3) total_volume += cart_item.quantity * cart_item.size_1 * cart_item.size_2 * cart_item.size_3 total_price += cart_item.quantity * cart_item.price total_weight += cart_item.quantity * cart_item.weight total_volumetric_weight += cart_item.quantity * cart_item.volumetric_weight( ) total_cost_for_items += cart_item.quantity * cart_item.cost self.total_volume = total_volume self.total_size = total_size self.total_price = total_price self.total_weight = total_weight self.total_volumetric_weight = total_volumetric_weight self.cost_for_items = total_cost_for_items self.put()