class Api(db.Document): # 字段 api_name = db.StringField() # 服务名称 api_description = db.StringField() # 服务描述 api_id = db.SequenceField() # 服务唯一标示 url = db.URLField() # 自身已经封装成的可以调用的url地址 api_url = db.URLField() # 转接url地址 img_link = db.URLField() json_link = db.URLField() api_crawl_rules_link = db.URLField() # 爬虫规则列表链接 candidate = db.ListField() # api参数列表 main_sec_id = db.IntField() api_network = db.ListField() # 网页可能有效的network请求 api_result_example = db.ListField() form_rules_link = db.URLField() # check click button的json链接 api_request_parameters_candidate = db.ListField() # 调用服务时可以使用的参数 # {"type":"text", # "query_name":"", # "required":false/true, 是否必须 # "level":0/1/2, 0-系统级(__max_page),1-查询级(需要填充到输入框中的),2-返回级(返回参数中的) # "example": # "description" # } def __str__(self): return "service:{} - url:{}".format(self.api_name, self.url)
class ItemSpec(db.Document): """""" meta = { 'db_alias': 'db_inventory', 'indexes': [ 'item_id', 'web_sku', 'sku', 'price', 'original_price', 'availability', 'attributes', 'created_at', 'stock', ], 'ordering': ['price'] } item_id = db.IntField(required=True) sku = db.SequenceField(required=True, unique=True, primary_key=True) web_sku = db.StringField(required=True) images = db.ListField(db.StringField(required=True)) original_price = db.FloatField(required=True, min_value=0) price = db.FloatField(required=True, min_value=0) china_prive = db.FloatField(default=0, min_value=0) availability = db.BooleanField(default=True, required=True) stock = db.IntField(default=-1) # spec.attributes: {color: 'Blue', size: 'M'} attributes = db.DictField() shipping_info = db.DictField() created_at = db.DateTimeField(default=datetime.utcnow, required=True) modified = db.DateTimeField() url = db.StringField() extra = db.DictField(default={}) @property def item(self): return Item.objects(item_id=self.item_id).first() def __unicode__(self): return '{}'.format(self.sku) def update_spec(self, new_spec): for k, v in new_spec.items(): setattr(self, k, v) self.save()
class Diary(db.Document): id = db.SequenceField(primary_key=True) title = db.StringField() username = db.StringField() published_time = db.StringField() # ISO8601 public = db.BooleanField() text = db.StringField() def __str__(self): return self.__repr__() def __repr__(self): return db_object_to_json(self)
class Note(db.Document): meta = {'collection': 'notes'} id = db.SequenceField(primary_key=True) title = db.StringField() content = db.StringField() def create_note(self, title, content): result = {} if title: self.title = title result.update({'title': title}) if content: self.content = content result.update({'content': content}) self.save() result.update({'id': self.id}) return result
class Recipe(db.DynamicDocument): title = db.StringField(max_length=120, required=True) author = db.ReferenceField(User, reverse_delete_rule=CASCADE) # image of the recipe # img = db.FileField(required=True) # description of the recipe desc = db.StringField(max_length=200, required=True) # ingredient ing = db.StringField(max_length=200, required=True) # step?? step = db.StringField(required=True) prl = db.StringField(required=True) rid = db.SequenceField(required=True) region = db.StringField(max_length=40, required=True) ming = db.StringField(max_length=40, required=True) kind = db.StringField(max_length=40, required=True) works = db.ListField(ReferenceField(Dish)) ts = db.DateTimeField(default=datetime.datetime.now) rate = db.DecimalField(default=0.0,precision=1) ppl = db.IntField(default=1) def get_recipe(): return Recipe.objects().first() @staticmethod def generate_fakes(): import json from random import seed, randint import os counts = User.objects.count() path_to_fakes = url_for("static",filename="fakes/recipes/recipes.json") basedir = os.path.abspath(os.path.dirname(__file__)) static_path = basedir+path_to_fakes recipes = json.load(open(static_path)) for recipe in recipes: r = Recipe.from_json(recipe) while 1: try: r.author = User.objects(id=randint(0,counts-1)).first() break except: continue r.save(force_insert=True)
class Card(db.DynamicDocument): card_number = db.StringField(default="", unique=True) # 卡号号码 card_category = db.StringField( # 卡片类别 default="3", choices=(("0", "vip"), ("1", "只测手"), ("2", "只测脚"), ("3", "手脚都测")), ) name = db.StringField(default="") # 姓名 job_number = db.StringField(default="", unique=True) # 工号 department = db.StringField(default="department") # 部门 gender = db.StringField(default="1", choices=(("0", "女"), ("1", "男"))) # 性别 note = db.StringField(default="default") # 其他说明 belong_to_mc = db.StringField(default="all") # 进出标志 name1:1|name2:0|name3 0:可进可出, 1:禁止进入/可出, 2:禁止出去/可进, 3:禁止进出 or all:所有闸机都可进可出 created_time = db.DateTimeField(default=datetime.datetime.utcnow) card_counter = db.SequenceField(collection_name="card_counter", unique=True) # 卡号编号 class_time = db.StringField(default="") # 班别 classes = db.ListField(default=[]) # 多班别 hid_card_number = db.StringField(default="") # HID 号码 def __str__(self): return self.to_json()
class Banner(db.Document): """""" meta = {'db_alias': 'db_content', 'indexes': ['published']} created_at = db.DateTimeField(default=datetime.datetime.utcnow, required=True) banner_type = db.StringField(default='BOARD', choices=['BOARD', 'URL']) target = db.StringField() img = db.StringField() date_from = db.DateTimeField(default=datetime.datetime.today()) date_until = db.DateTimeField(default=datetime.datetime(2029, 12, 30)) published = db.BooleanField(default=True) order = db.SequenceField() def __repr__(self): return '<Banner object: {}>'.format(str(self.id)) @classmethod def get_latest(cls, n=10): now = datetime.datetime.now() docs = cls.objects(date_from__lte=now, date_until__gt=now).order_by( '-order', '-created_at').limit(n) return docs @property def target_obj(self): if self.banner_type == 'BOARD': return Board.objects(id=self.target).first() return self.target def to_json(self): return { 'type': self.banner_type, 'target': self.target, 'img': self.img, 'created_at': format_date(self.created_at) }
class User(db.Document): id = db.SequenceField(primary_key=True) email = db.StringField(required=True,unique=True,index=True) username = db.StringField(max_length=50,required=True,index=True) p_hash = db.StringField(max_length=128,required=True) confirmed = db.BooleanField(default=False) role = db.ReferenceField(Role) last_seen = db.DateTimeField(default=datetime.datetime.now) avatar = db.StringField(default=None) recipe = db.ListField(ReferenceField('Recipe')) dish = db.ListField(ReferenceField('Dish')) def __init__(self,**kwargs): super(User, self).__init__(**kwargs) if self.role is None: if self.email == current_app.config['FY_ADMIN']: self.role = Role.objects(name='Admin').first() else: self.role = Role.objects(default=True).first() if self.avatar is None: self.avatar = "users/"+str(self.id)+".png" @property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.p_hash = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.p_hash, password) # Flask-Login integration def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return str(self.id) def generate_confirmToken(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'],expiration) return s.dumps({'confirm':self.id}) def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except: return False if data.get('confirm') != self.id: return False self.confirmed = True self.save() return True def to_json(self): user = { 'username':self.username, 'last_seen':self.last_seen, 'recipe_created': url_for('api.get_user_recipe', id=self.id, _external=True), 'dish_created': url_for('api.get_user_dish', id=self.id, _external=True), 'num_of_uploads': len(self.recipe) + len(self.dish) } return user @staticmethod def generate_fakes(): import forgery_py import os from random import seed # insert admin admin = User(email=current_app.config['FY_ADMIN'],username='******') admin.password = "******" admin.confirmed = True admin.save() seed() path_to_fakes = url_for("static",filename="fakes/users") basedir = os.path.abspath(os.path.dirname(__file__)) static_path = basedir+path_to_fakes for file in os.listdir(static_path): user = User(email=forgery_py.internet.email_address(), username=forgery_py.internet.user_name(True), confirmed=True, avatar=os.path.join("fakes/users",file)) user.password = forgery_py.lorem_ipsum.word() try: user.save() except: current_app.logger.info("something went wrong...") def is_permitted(self, permission): return self.role is not None and self.role.is_permitted(permission) def is_admin(self): return self.is_permitted(Permission.ADMIN) def ping(self): self.last_seen = datetime.datetime.now self.save()
class Recipe(db.DynamicDocument): title = db.StringField(max_length=120, required=True) author = db.ReferenceField(User, reverse_delete_rule=CASCADE) desc = db.StringField(max_length=500, required=True) ing = db.StringField(max_length=1000, required=True) step = db.StringField(required=True) prl = db.StringField(required=True) rid = db.SequenceField(required=True) region = db.StringField(max_length=40, required=True) ming = db.StringField(max_length=40, required=True) kind = db.StringField(max_length=40, required=True) works = db.ListField(ReferenceField(Dish)) ts = db.DateTimeField(default=datetime.datetime.now) rate = db.DecimalField(default=0.0,precision=1) ppl = db.IntField(default=1) def to_json(self): recipe = { 'url':url_for('api.get_recipe',recipe_id = self.rid, _external=True), 'title':self.title, 'author_id':self.author.id, 'description':self.desc, 'ingredients':self.ing, 'steps':self.step, 'img_url':url_for('static',filename=self.prl,_external =True), 'tags':[self.region,self.ming,self.kind], 'date_created':self.ts, 'rate':str(self.rate), 'people_rated':self.ppl } return recipe @staticmethod def from_json_custom(recipe): title = recipe.get('title') desc = recipe.get('desc') ing = recipe.get('ing') prl = recipe.get('prl') step = recipe.get('step') tags = recipe.get('tags') if tags: region=tags[0] ming = tags[1] kind = tags[2] if title is None or\ desc is None or step is None or\ ing is None or prl is None or\ region is None or ming is None or kind is None: raise ValueError('field missing') recipe = Recipe(title=title,ing=ing,prl=prl,desc=desc,step=step, region=region,ming=ming,kind=kind) return recipe @staticmethod def generate_fakes(): import json from random import seed, randint import os seed() counts = User.objects.count() path_to_fakes = url_for("static",filename="fakes/recipes/recipes.json") basedir = os.path.abspath(os.path.dirname(__file__)) static_path = basedir+path_to_fakes print (static_path) recipes = json.load(open(static_path,encoding='utf-8')).get('recipes') # print (recipes) for recipe in recipes: print (json.dumps(recipe)) r = Recipe.from_json(json.dumps(recipe)) users_count = User.objects.count() offset = randint(0,users_count-1) print (offset) user = User.objects[offset:].first() print (user.id) r.author = user r.save(force_insert=True)
class Item(db.Document): """""" meta = { 'db_alias': 'db_inventory', 'indexes': [ 'item_id', 'url', 'web_id', 'price', 'brand', 'main_category', 'sub_category', 'vendor', 'title', 'num_views', 'attributes', 'created_at' ], 'ordering': ['price'], } item_id = db.SequenceField(required=True, unique=True, primary_key=True) url = db.StringField(required=True) web_id = db.StringField(required=True, unique=True) # price currency = db.StringField(required=True, choices=CURRENCY) original_price = db.FloatField(required=True, min_value=0) price = db.FloatField(required=True, min_value=0) china_price = db.FloatField(default=0, min_value=0) discount = db.IntField() # 折扣 primary_img = db.StringField(required=True) # basic information vendor = db.StringField(required=True) # 供应商 brand = db.StringField(required=True) min_category = db.StringField(required=True) sub_category = db.StringField(required=True) sex_tag = db.StringField(required=True, choices=SEX_TAG) tags = db.ListField(db.StringField()) # description title = db.StringField(required=True) title_en = db.StringField() description = db.StringField(default='') attributes = db.ListField(db.StringField()) information = db.ListField(db.StringField()) size_lookup = db.DictField(default={}) extra = db.DictField(default={}) stock = db.IntField(default=-1) # 库存 # ratings for editors rating = db.FloatField(default=0) num_rates = db.IntField(default=0) # extra num_favors = db.IntField(default=0) num_likes = db.IntField(default=0) num_views = db.IntField(default=0) num_buy = db.IntField(default=0) status = db.StringField(default=ITEM_STATUS.NEW, required=True, choices=ITEM_STATUS) availability = db.BooleanField(default=True, required=True) # time created_at = db.DateTimeField(default=datetime.utcnow, required=True) modified = db.DateTimeField() creator = db.StringField() weight = db.FloatField() time_limited = db.BooleanField(default=False) lookup_table = db.StringField() size_chart = db.ListField(db.StringField()) fields_to_log = { 'url', 'original_price', 'price', 'discount', 'primary_img', 'vendor', 'brand', 'main_category', 'sub_category', 'sex_tag', 'tags', 'availability', } def __unicode__(self): return '{}'.format(self.item_id) def __repr__(self): return '{}'.format(self.item_id) @queryset_manager def available_items(doc_cls, queryset): return queryset.filter(availability=True) @property def specs(self): return ItemSpec.objects(item_id=self.item_id) @property def available_specs(self): return ItemSpec.objects(item_id=self.item_id, availability=True) @property def small_thumbnail(self): return self.primary_img[:23] + 'thumbnails/150x150/' + self.primary_img[ 23:] @property def large_thumbnail(self): return self.primary_img[:23] + 'thumbnails/400x400/' + self.primary_img[ 23:] @classmethod def create(cls, item): meta = item['meta'] specs = item.get('specs', []) i = Item.objects(web_id=meta['web_id']) if i: item['meta']['status'] = ITEM_STATUS.MOD return cls.modify(item) Category.get_category_or_create(meta['main_category'], 1) Category.get_category_or_create(meta['sub_category'], 2) Brand.get_brand_or_create(meta['brand']) Vendor.get_or_create(meta['vendor']) for tag in meta['tags']: Tag.get_tag_or_create(tag) Statistics.create(meta['main_category'], meta['sub_category'], meta['brand'], meta['tags'], meta['sex_tag']) item = Item(**meta).save() item_id = item.item_id old_specs = ItemSpec.objects(item_id=item_id) for spec in old_specs: spec.delete() for spec in specs: spec['item_id'] = item_id ItemSpec(**spec).save() PriceHistory.upsert_price_history(item_id, meta['price']) return item_id @classmethod def modify(cls, new_item, current_price=None): try: old_item = Item.objects.get(web_id=new_item['meta']['web_id']) except DoesNotExist: current_app.logger.warning( 'crawler send item not exist in db: {}'.format(new_item)) return # old item is an mongoengine object # new item is a dictionary cls.update_item(old_item, new_item) old_item.save() if current_price: PriceHistory.upsert_price_history(old_item.item_id, current_price) return old_item.item_id @classmethod def update_item(cls, old_item, new_item): meta = new_item['meta'] # if category, brand and tags does not exist then create Category.get_category_or_create(meta['main_category'], 1) Category.get_category_or_create(meta['sub_category'], 2) Brand.get_brand_or_create(meta['brand']) Vendor.get_or_create(meta['vendor']) Statistics.create(meta['min_category'], meta['sub_category'], meta['brand'], meta['tags'], meta['sex_tag']) for k, v in meta.items(): setattr(old_item, k, v) old_item.save() @classmethod def delete_item(cls, web_id): try: item = cls.objects.get(web_id=web_id) item.status = 'DEL' item.availability = False item.save() return item.item_id except DoesNotExist: pass def to_simple_json(self): return dict( id=str(self.item_id), title=self.title, price=getattr(self, 'price_details', lambda: '')(), primary_image=self.primary_img, status=self.status, ) def price_details(self): return dict( price=self.price, original_price=self.original_price, discount=ceil( ((self.original_price - self.price) / self.original_price) * 100), )
class Order(db.Document): """""" meta = { 'db_alias': 'db_order', 'ordering': ['-created_at'], 'indexes': [ 'customer_id', 'status', 'address', 'amount', 'final', 'order_type', 'is_paid', 'is_payment_abnormal', 'refund_entries' ], } created_at = db.DateTimeField(default=datetime.datetime.utcnow, required=True) order_type = db.StringField(choices=ORDER_TYPE, default=ORDER_TYPE.COMMODITY) # one day expired_in = db.IntField(default=1440) # in minutes payment_expired_in = db.IntField(default=1440) short_id = db.SequenceField(required=True, unique=True) is_vip = db.BooleanField(default=False) status = db.StringField(max_length=256, required=True, choices=ORDER_STATUS, default=ORDER_STATUS.PAYMENT_PENDING) status_modified = db.DateTimeField() source = db.StringField(choices=ORDER_SOURCES) is_rewards_given = db.BooleanField(default=False) # order detail amount_usd = db.FloatField(default=0) amount = db.FloatField(default=0) discount = db.ListField(db.DictField()) # 优惠卷兑换码 coupon_codes = db.ListField(db.StringField()) coin = db.IntField() lucky_money = db.IntField() cash = db.IntField() final = db.FloatField(required=True) # 库存 logistic_provider = db.StringField() # 预估退税 estimated_tax = db.FloatField(default=0) real_tax = db.FloatField(default=-1) paid_tax = db.FloatField(default=-1) # for internal usage # 汇率 forex = db.FloatField() real_shipping = db.FloatField() cn_shipping = db.FloatField(default=0) address = db.ReferenceField('Address') customer_id = db.ObjectIdField(required=True) is_new_customer = db.BooleanField(default=False) entries = db.ListField( db.ReferenceField('OrderEntry', reverse_delete_rule=mongoengine.PULL)) extra = db.StringField() logistics = db.ListField(db.ReferenceField('Logistic')) # 库存 closed_logistics = db.ListField(db.ReferenceField('Logistic')) is_paid = db.BooleanField(default=False) # 是否支付 is_payment_abnormal = db.BooleanField(default=False) # 是否支付异常 paid_date = db.DateTimeField() # 支付时间 pay_tax_deadline = db.DateTimeField() # 支付税截至时间 refund_entries = db.ListField( db.ReferenceField('OrderEntry', reverse_delete_rule=mongoengine.PULL)) refund_amount = db.FloatField(default=0) is_test = db.BooleanField(default=False) fields_to_log = { 'status', 'amount', 'coin', 'final', 'estimated_tax', 'real_tax', 'paid_tax', 'real_shipping', 'is_paid', } # 处理中的状态 PROCESSING_STATUS = [ORDER_STATUS.PAYMENT_RECEIVED, ORDER_STATUS.SHIPPING] # 异常状态 ABNORMAL_STATUS = [ ORDER_STATUS.CANCELLED, ORDER_STATUS.ABNORMAL, ORDER_STATUS.ORDER_DELETE, ORDER_STATUS.EXPIRED, ORDER_STATUS.REFUNDED ] def __unicode__(self): return '%s' % self.sid def __str__(self): return '{}'.format(self.id) @classmethod def get_order_or_404(cls, order_id, check_user=True): try: order = cls.objects(id=order_id).first_or_404() except mongoengine.ValidationError: try: short_id = int(order_id) except (ValueError, TypeError): abort(404) order = cls.objects(short_id=short_id).first_or_404() if check_user and str(order.customer_id) != str(current_user.id): abort(404) return order @queryset_manager def commodities(doc_cls, queryset): return queryset.filter(order_type=ORDER_TYPE.COMMODITY, status__nin=doc_cls.ABNORMAL_STATUS) @queryset_manager def transfer(doc_cls, queryset): return queryset.filter(order_type=ORDER_TYPE.TRANSFER, status__nin=doc_cls.ABNORMAL_STATUS) @queryset_manager def processing(doc_cls, queryset): return queryset.filter(status__in=doc_cls.PROCESSING_STATUS) @queryset_manager def payment_pending(doc_cls, queryset): return queryset.filter(status=ORDER_STATUS.PAYMENT_PENDING) @queryset_manager def abnormal(doc_cls, queryset): return queryset.filter( Q(status__in=doc_cls.ABNORMAL_STATUS) | Q(refund_entries__0__exists=True) & Q(status__in=doc_cls.PROCESSING_STATUS + [ORDER_STATUS.RECEIVED])) @queryset_manager def received(doc_cls, queryset): return queryset.filter(status=ORDER_STATUS.RECEIVED) @queryset_manager def is_processing(self): return self.status in self.PROCESSING_STATUS @queryset_manager def is_payment_pending(self): return self.status == ORDER_STATUS.PAYMENT_PENDING @queryset_manager def is_abnormal(self): if self.status in self.ABNORMAL_STATUS: return True if self.status in self.PROCESSING_STATUS or self.status == ORDER_STATUS.RECEIVED: return len(self.refund_entries) > 0 return False def has_refund_entries(self): if self.status in (self.PROCESSING_STATUS + [ORDER_STATUS.RECEIVED, ORDER_STATUS.REFUNDED]): return len(self.refund_entries) > 0 return False @property def tax(self): if self.real_tax == -1: return self.estimated_tax else: return self.real_tax @property def shipping(self): return self.cn_shipping @property def estimated_weight(self): return sum( float(entry.item_snapshot.weight) * entry.quantity for entry in self.entries) @property def pay_tax_remain_days(self): if self.pay_tax_deadline: time_remain = self.pay_tax_deadline.date() - datetime.date.today() if time_remain.days > 0: return time_remain.days @property def latest_logistic(self): attr = LogisticDetail.attr_by_log_status.get(self.status) if not attr: return None return max(self.logistics, key=lambda l: getattr(l.detail, attr)) @classmethod def create_transfer(cls, customer_id, entries, logistic_provider, coupon_codes, coin=0, cash=0, address=None, **kwargs): order = cls(customer_id=customer_id, entries=entries, logistic_provider=logistic_provider, coupon_codes=coupon_codes, coin=coin, cash=cash, **kwargs) if not order.forex: order.forex = ForexRate.get() order.update_amount() order.reload() if address: order.set_address(address) order_created.send('system', order=order) return order @classmethod def create_from_skus(cls, customer_id, skus, logistic_provider, coupon_codes, coin=0, cash=0, address=None, **kwargs): entries = [] for s in skus: availability = check_availability_and_update_stock( s['item_id'], s['sku'], s['quantity']) if not availability: return s spec = ItemSpec.objects(sku=s['sku']).first() item = Item.objects(item_id=['item_id']).first() entry = OrderEntry(spec=spec, item=item, quantity=s['quantity']).save() entries.append(entry) order = cls(customer_id=customer_id, entries=entries, logistic_provider=logistic_provider, coupon_codes=coupon_codes, coin=coin, cash=cash, **kwargs) if not order.forex: order.forex = ForexRate.get() order.update_amount() order.reload() # 简介 for e in order.entries: e.create_snapshot() if address: order.set_address(address) order_created.send('system', order=order) return order @classmethod def create(cls, customer_id, entries, logistic_provider, coupon_codes, coin=0, cash=0, address=None, **kwargs): order_entries = [] for entry in entries: availability = check_availability_and_update_stock( entry.item_snapshot.item_id, entry.item_spec_snapshot.sku, entry.quantity) if not availability: return entry if isinstance(entry, (CartEntry, OrderEntry)): e = deepcopy(entry) e.__class__ = OrderEntry e.id = None order_entries.append(e.save()) order = cls(customer_id=customer_id, entries=order_entries, logistic_provider=logistic_provider, coupon_codes=coupon_codes, coin=coin, cash=cash, **kwargs) if not order.forex: order.forex = ForexRate.get() order.update_amount() order.reload() for e in order.entries: e.create_snapshot() if address: order.set_address(address) order_created.send('system', order=order) return order @property def item_changed(self): res = False for e in self.entries: res = res and e.item_changed if res: return res return res def __get__(self, *args, **kwargs): order = super(Order, self).__get__(*args, **kwargs) if (not order.is_paid) and order.item_changed: order.update_entry() return order def update_entry(self): if self.is_paid: return map(lambda e: e.update_snapshot(), self.entries) self.update_amount() def set_address(self, addr): if not isinstance(addr, Address): addr = Address.objects(id=addr).first() if not addr: return False addr_snapshot = deepcopy(addr) addr_snapshot.id = None addr_snapshot.order_id = self.id addr_snapshot.save() if self.address: self.address.delete(w=1) self.address = addr_snapshot self.save() return True @property def customer(self): return User.objects(id=self.customer_id).first() def create_payment(self, ptype, trader): ptype = ptype.upper() self.update_entry() self.reload() if self.order_type != ORDER_TYPE.TRANSFER: is_available = self.check_entries_avaliable() if not is_available or self.status in [ 'CANCELLED', 'ABNORMAL', 'ORDER_DELETED', 'EXPIRED' ]: return None new_payment = Payment(order=self, ptype=ptype, trader=trader).save() return new_payment def get_payment(self, ptype): ptype = ptype.upper() payments = Payment.objects(order=self, ptype=ptype).order_by('-created_at') paid_payments = payments.filter(status=PAYMENT_STATUS.PAID) if paid_payments: return paid_payments.first() else: return payments.first() @property def goods_payment(self): return self.get_payment(PAYMENT_TYPE.WITHOUT_TAX) @property def tax_payment(self): return self.get_payment(PAYMENT_TYPE.WITH_TAX) @property def refunds(self): return Refund.objects(order=self) def check_entries_avaliable(self): availability = all( map(lambda e: e.is_available or e.item_spec_snapshot.stock != -1, self.entries)) if not availability: self.status = ORDER_STATUS.EXPIRED self.save() return availability def set_paid(self): if self.is_paid: return self.is_new_customer = not bool( Order.objects(custom_id=self.customer_id, is_paid=True)) self.is_paid = True self.status = ORDER_STATUS.PAYMENT_RECEIVED self.paid_date = datetime.datetime.utcnow() self.save() payment_received(self) def update_payment(self, paid_type, paid_amount, trader): if paid_type == PAYMENT_TYPE.WITHOUT_TAX and not self.is_paid and self.status in [ ORDER_STATUS.PAYMENT_PENDING, ORDER_STATUS.W ]: if paid_amount == self.final and trader == PAYMENT_TRADERS.PAYPAL: self.set_paid() elif paid_amount == float('%.2f' % (self.final * self.forex) ) and trader == PAYMENT_TRADERS.WEIXIN: self.set_paid() else: current_app.logger.error( 'error at updating payment. trader: {}; ptype: {}; amount: {} order id: {}' .format(trader, paid_type, paid_amount, self.id)) self.is_payment_abnormal = True else: current_app.logger.error( 'error at updating payment. trader: {}; ptype: {}; amount: {}; order id: {}' .format(trader, paid_type, paid_amount, self.id)) self.is_payment_abnormal = True self.save() @property def coin_trades(self): return Trade.objects(reason_id=str(self.id)) def update_logistic_status(self): if self.logistics: log_status = map(lambda m: m.detail.status, self.logistics) new_status = min(log_status, key=lambda l: LOG_STATUS.index(1)) self._change_status(new_status) def _change_status(self, new_status): if self.status == new_status: return self.status = new_status self.status_modified = datetime.datetime.utcnow() self.save() if new_status in LOG_STATUS: notification_order(self, new_status) order_logistic_status_changed.send('Order.Logistic.Status.Changed', order=self, new_status=new_status) else: order_status_changed.send('order_status_changed', order=self, new_status=new_status) def delete_order(self): for l in self.logistics: l.delete(w=1) for entry in self.entries: entry.delete(w=1) if self.goods_payment: self.goods_payment.delete(w=1) self.delete(w=1) def cancel_order(self, reason, status=None): """ :param reason: :param status: :return: """ for l in self.logistics: l.close(reason) self.extra = reason self.save() if not status: status = ORDER_STATUS.ABNORMAL self._change_status(status) for entry in self.entries: try: if entry.spec.stock != -1: entry.spec.update(inc__stock=entry.quantity, set__availability=True) entry.item.update(set__availability=True, set__status='MOD') except AttributeError: pass def update_amount(self): for e in self.entries: e.update_amount() cal_order_price_and_apply(self) self.estimated_tax = cal_order_tax(self) self.save() @property def sid(self): return self.short_id def to_json(self, include_logistic=False, replace_entries_to_refunded=False): if not self.is_paid: self.update_amount() self.reload() entries_json = [] if replace_entries_to_refunded and self.has_refund_entries(): for e in self.refund_entries: entries_json.append(e.to_json()) else: for e in self.entries: entries_json.append(e.to_json()) refund_entries_json = [] for e in self.refund_entries: refund_entries_json.append(e.to_json()) result = dict( id=str(self.id), short_id=str(self.sid), status=self.status, customer_id=str(self.customer_id), amount=self.amount, cn_shipping=self.cn_shipping, coin=self.coin, lucky_money=self.lucky_money, discount=self.discount, final=self.final, estimated_tax=self.estimated_tax, payment_status='PAID' if self.is_paid else 'UNPAID', payment_ref_number=[ p.ref_number for p in Payment.objects(order=self) ], created_at=format_date(self.created_at), entries=entries_json, refund_entries=refund_entries_json, refund_amount=self.refund_amount, real_tax=self.real_tax, ) if self.address: result.update({'address': self.address.to_json()}) if include_logistic: result.update(logistics=[l.to_json() for l in self.logistics]) return result def to_grouped_json(self): """ :return: """ res = dict( estimated_weight=self.estimated_weight, amount=self.amount, cn_shipping=self.cn_shipping, coin=self.coin, lucky_money=self.lucky_money, discount=self.discount, final=self.final, extimated_tax=self.extimated_tax, ) res['sid'] = self.id res['status'] = self.status if self.address: res.update(dict(address=self.address.to_json())) return res
class User(db.Document): id = db.SequenceField(primary_key=True) email = db.StringField(required=True,unique=True,index=True) username = db.StringField(max_length=50,required=True,index=True) p_hash = db.StringField(max_length=128,required=True) confirmed = db.BooleanField(default=False) role = db.ReferenceField(Role) last_seen = db.DateTimeField(default=datetime.datetime.now) avatar = db.StringField(default=None) recipe = db.ListField(ReferenceField('Recipe')) dish = db.ListField(ReferenceField('Dish')) following = db.ListField(ReferenceField('User'),reverse_delete_rule=CASCADE) def __init__(self,**kwargs): super(User, self).__init__(**kwargs) if self.role is None: if self.email == current_app.config['FY_ADMIN']: self.role = Role.objects(name='Admin').first() else: self.role = Role.objects(default=True).first() if self.avatar is None: self.avatar = str(self.id)+".png" @property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.p_hash = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.p_hash, password) # Flask-Login integration def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return str(self.id) def generate_confirmToken(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'],expiration) return s.dumps({'confirm':self.id}) def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except: return False if data.get('confirm') != self.id: return False self.confirmed = True self.save() return True def follow(self, user): if not self.is_following(user): self.following.append(user) self.save() def unfollow(self, user): uid = User.objects(id=user.id).first() for i in range(len(self.following)): if self.following[i].id== uid: del following[i] self.save() @staticmethod def generate_fakes(): import forgery_py import os from random import seed import logging seed() path_to_fakes = url_for("static",filename="fakes/users") basedir = os.path.abspath(os.path.dirname(__file__)) print (basedir) static_path = basedir+path_to_fakes print (static_path) for file in os.listdir(static_path): user = User(email=forgery_py.internet.email_address(), username=forgery_py.internet.user_name(True), confirmed=True, avatar=os.path.join("fakes\\users",file)) user.password = forgery_py.lorem_ipsum.word() try: user.save() except: current_app.logger.info("something went wrong...") def is_permitted(self, permission): return self.role is not None and self.role.is_permitted(permission) def is_admin(self): return self.is_permitted(Permission.ADMIN) def ping(self): self.last_seen = datetime.datetime.now self.save()
class User(db.Document): id = db.SequenceField(primary_key=True) email = db.StringField(required=True, unique=True, index=True) username = db.StringField(max_length=50, required=True, index=True) p_hash = db.StringField(max_length=128, required=True) confirmed = db.BooleanField(default=False) role = db.ReferenceField(Role) last_seen = db.DateTimeField(default=datetime.datetime.now) def __init__(self, **kwargs): super(User, self).__init__(**kwargs) if self.role is None: if self.email == current_app.config['FY_ADMIN']: self.role = Role.objects(name='Admin').first() else: self.role = Role.objects(default=True).first() @property def password(self): raise AttributeError('password is not a readable attribute') @password.setter def password(self, password): self.p_hash = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.p_hash, password) # Flask-Login integration def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return str(self.id) def generate_confirmToken(self, expiration=3600): s = Serializer(current_app.config['SECRET_KEY'], expiration) return s.dumps({'confirm': self.id}) def confirm(self, token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except: return False if data.get('confirm') != self.id: return False self.confirmed = True # db.session.add(self) self.save() return True def is_permitted(self, permission): return self.role is not None and self.role.is_permitted(permission) def is_admin(self): return self.is_permitted(Permission.ADMIN) def ping(self): self.last_seen = datetime.datetime.now self.save()