class City(db.Document): city_id = db.IntField() district_id = db.ObjectIdField() state_id = db.ObjectIdField() title = db.DictField() code = db.StringField(max_lenght=255) ward_count = db.IntField(default=0) population_bucket = db.IntField() population = db.IntField() census_code = db.IntField() coordinates = db.PointField() meta = { 'collection': 'cities', 'indexes': [{ 'fields': ['city_id'], 'unique': True, 'name': 'cities_city_id_unique', }, { 'fields': ['state_id'], 'name': 'cities_state_id_index', }, { 'fields': ['district_id'], 'name': 'cities_district_id_index', }, { 'fields': ['title.*'], 'name': 'cities_title_index', }] }
class CivicAgency(db.Document): civic_agency_id = db.IntField() city_id = db.IntField() district_id = db.ObjectIdField() state_id = db.ObjectIdField() title = db.DictField() meta = { 'collection': 'civic_agencies', 'indexes': [{ 'fields': ['civic_agency_id'], 'unique': True, 'name': 'civic_agencies_civic_agency_id_id_unique', }, { 'fields': ['district_id'], 'name': 'civic_agencies_district_id_index', }, { 'fields': ['state_id'], 'name': 'civic_agencies_state_id_index', }, { 'fields': ['city_id'], 'name': 'civic_agencies_city_id_index', }, { 'fields': ['title.*'], 'name': 'civic_agencies_title_index', }] }
class Message(db.Document): from_user = db.ReferenceField(User, db_field="fu", reverse_delete_rule=CASCADE) to_user = db.ReferenceField(User, db_field="tu", default=None, reverse_delete_rule=CASCADE) post = db.StringField(db_field="pt", max_length=1024) live = db.BooleanField(db_field="l", default=None) create_date = db.LongField(db_field="c", default=now()) images = db.ListField(db_field="is", default=None) parent = db.ObjectIdField(db_field="p", default=None) message_type = db.IntField(db_field="mt", default=POST, choices=MESSAGE_TYPE) @property def likes(self): return Message.objects.filter(parent=self.id, message_type=LIKE).order_by("-create_date") @property def comments(self): return Message.objects.filter(parent=self.id, message_type=COMMENT).order_by("create_date") @property def text_linkified(self): return linkify_text(self.post) @property def human_timestamp(self): return ms_stamp_humanize(self.create_date) def post_image_src(self, images_time_stamp, size): if self.images: profile_img = join_path(STATIC_IMAGE_URL, 'posts', "{}.{}.{}.png".format(self.id, images_time_stamp, size)) return profile_img.replace("\\", '/') # mostly for windows because windows uses a black slash to save. meta = { 'indexes': [("from_user", "to_user", "-create_date", "message_type", "parent", "live")] }
class OrderStatus(db.Document): """""" meta = { 'db_alias': 'db_order', 'indexes': ['user_id'], } user_id = db.ObjectIdField(required=True) orders = db.ListField(db.ReferenceField('Order')) items = db.ListField(db.IntField()) total = db.FloatField(default=0) received = db.FloatField(default=0) num_orders = db.IntField(default=0) num_unpaid = db.IntField(default=0) num_waiting = db.IntField(default=0) def clean(self): for field in ('total', 'received', 'num_orders', 'num_unpaid', 'num_waiting'): if getattr(self, field, 0) < 0: setattr(self, field, 0) @classmethod def by_user(cls, user_id): cls.objects(user_id=user_id).update_one(set__user_id=user_id, upsert=True) return cls.objects(user_id=user_id).first()
class ReviewPoint(db.Document): PROS_ID = 1 CONS_ID = 0 content = db.StringField() role = db.BooleanField() parent = db.ObjectIdField()
class BlackListToken(db.Document): """ Document to store blacklisted/invalid auth tokens """ _id = db.ObjectIdField() token = db.StringField() blacklisted_on = db.StringField(default=util.get_current_time()) meta = {'collection': app.config.get('BLACKLISTED_TOKEN_COLLECTION')} def __init__(self, token, *args, **kwargs): super(db.Document, self).__init__(*args, **kwargs) self.token = token self.blacklisted_on = util.get_current_time() def blacklist(self, *args, **kwargs): """ Persist Blacklisted token in the database :return: """ super(BlackListToken, self).save(*args, **kwargs) @staticmethod def check_blacklist(token): """ Check to find out whether a token has already been blacklisted. :param token: Authorization token :return: """ response = BlackListToken.objects(token=token).first() if response: return True return False
class Complaint(db.Document): name = db.StringField(requiered=True) place = db.StringField(requiered=True) location = db.PointField(required=True) complaint_photo = db.StringField() description = db.StringField(required=True) complainer = db.ObjectIdField(requiered=True) cancel = db.BooleanField(default=False) follow = db.ListField(db.ReferenceField(User))
class RedPacketCollectLog(db.Document): STATUS_SUCCESS = 0 STATUS_FAIL = 1 OPTIONS_STATUS = collections.OrderedDict([(STATUS_SUCCESS, '成功'), (STATUS_FAIL, '失败')]) _id = db.ObjectIdField() redpacket_id = db.ObjectIdField() open_id = db.StringField(max_length=64) rp_log_id = db.StringField(max_length=64, default='') status = db.IntField(choices=OPTIONS_STATUS.iteritems()) create_time = db.DateTimeField() meta = { 'db_alias': 'default', 'collection': 'rp_collect_log', 'id_field': '_id', }
class RedPacketLog(db.Document): STATUS_UN = 0 STATUS_DONE = 1 OPTIONS_STATUS = collections.OrderedDict([(STATUS_UN, '未领取'), (STATUS_DONE, '已领取')]) _id = db.ObjectIdField() redpacket_id = db.ObjectIdField() open_id = db.StringField(max_length=64) value = db.IntField() status = db.IntField(choices=OPTIONS_STATUS.iteritems(), default=0) last_modify = db.DateTimeField() meta = { 'db_alias': 'default', 'collection': 'redpacket_log', 'id_field': '_id', }
class Diary(db.Document): user = db.ObjectIdField(User) timestamp = db.DateTimeField(required=True) diary = db.DictField(db.AnythingField(), required=True) def getAll(self): return Diary.query.all() def getAllByUniqueID(self, uniqueID, from_datetime=None, until_datetime=None): query = db.session.query(Diary) query.filter(Diary.user == User().query.filter( User.uniqueID == uniqueID).first().mongo_id) if from_datetime is not None: query.filter(Diary.timestamp >= from_datetime) if until_datetime is not None: query.filter(Diary.timestamp <= until_datetime) return query.all() def getByUniqueIDAndID(self, uniqueID, _id): return Diary.query.filter( Diary.user == User().query.filter( User.uniqueID == uniqueID).first().mongo_id, Diary.mongo_id == _id).first() def addByUniqueID(self, uniqueID, diary): self.user = User().query.filter( User.uniqueID == uniqueID).first().mongo_id self.timestamp = datetime.utcnow() self.diary = diary self.save() return True def updateByUniqueIDAndID(self, uniqueID, _id, diary): Diary.query.filter( Diary.user == User().query.filter( User.uniqueID == uniqueID).first().mongo_id, Diary.mongo_id == _id).set(diary=diary, timestamp=datetime.utcnow()).execute() return True def serialize(self): d = { "id": str(self.mongo_id), "timestamp": self.timestamp.isoformat(), "diary": self.diary } return d
class User(db.Document, ExtUserMixin): OPTIONS_GENDER = collections.OrderedDict([ ('UNKNOWN', '未设置'), ('MAN', '男'), ('WOMAN', '女'), ]) _id = db.ObjectIdField() open_id = db.StringField(max_length=64) union_id = db.StringField(max_length=64) nickname = db.StringField(max_length=64) avatar = db.StringField(max_length=256) gender = db.StringField(max_length=16, choices=OPTIONS_GENDER.iteritems(), default='UNKNOWN') # 性别 province = db.StringField(max_length=64) city = db.StringField(max_length=64) intro = db.StringField() is_active = db.BooleanField() create_time = db.DateTimeField() meta = { 'db_alias': 'default', 'collection': 'user', 'id_field': '_id', } @classmethod def create_user(cls, open_id, union_id): u = cls.objects.filter(open_id=open_id, union_id=union_id).first() if u: return -2 user = cls(open_id=open_id, union_id=union_id, is_active=True, create_time=datetime.datetime.now()) r = cls.objects.insert(user) if r: return r logger.error(msg='insert user err:%s_%s' % (open_id, union_id)) @property def info(self): data = self._data return data @property def capital(self): capital = Capital.objects.filter(open_id=self.open_id).first() return 0 if not capital else capital.value def get_operator(self): return UserOperator(self, self.__class__)
class TransferOrderCode(db.Document): """""" order_id = db.ObjectIdField() code = db.StringField() @classmethod def set_order(cls, order_id): code = random.randint(100000, 999999) cls.objects(order_id=order_id).update_one(set__order_id=order_id, set__code=code, upsert=True)
class AnalysisModel(db.DynamicDocument): question_num = db.IntField(min_value=0, default=-1) exam_id = db.StringField(max_length=32) question_id = db.StringField(max_length=32) score_detail = db.FloatField(default=0, min_value=0) score_key = db.FloatField(default=0, min_value=0) voice_features = db.DictField(default={}) key_hits = db.ListField(db.FloatField(default=0)) detail_hits = db.ListField(db.ListField(db.FloatField(default=0))) user = db.ObjectIdField() date = db.DateTimeField() meta = {'collection': 'analysis'}
class Renant(db.Document): name = db.StringField(required=True) place = db.StringField(required=True) location = db.PointField(required=True) start_time = db.DateTimeField(required=True) end_time = db.DateTimeField(required=True) home_photo = db.StringField() description = db.StringField(min_length=20, required=True) host = db.ObjectIdField(required=True) # link to USER DB cancel = db.BooleanField(default=False) capacity = db.StringField() price = db.StringField() contact = db.StringField() comments = db.ListField(db.ReferenceField(Comment))
class UserOrder(db.Document): PAY_TYPE_WX = 0 PAY_TYPE_REDPACKET = 1 OPTIONS_PAY_TYPE = collections.OrderedDict([ (PAY_TYPE_WX, '微信账户'), (PAY_TYPE_REDPACKET, '红包账户'), ]) PRODUCT_TYPE_WX = 0 PRODUCT_TYPE_REDPACKET = 1 OPTIONS_PRODUCT_TYPE = collections.OrderedDict([ (PRODUCT_TYPE_WX, '微信账户'), (PRODUCT_TYPE_REDPACKET, '红包账户'), ]) STATUS_UNPAY = 0 STATUS_PAID = 1 OPTIONS_STATUS = collections.OrderedDict([ (STATUS_UNPAY, '未支付'), (STATUS_PAID, '已支付'), ]) _id = db.ObjectIdField() open_id = db.StringField(max_length=64) order_no = db.StringField(max_length=64) pay_type = db.IntField(choices=OPTIONS_PAY_TYPE.iteritems(), default=PAY_TYPE_WX) product_type = db.IntField(choices=OPTIONS_PRODUCT_TYPE.iteritems(), default=PRODUCT_TYPE_REDPACKET) product_id = db.StringField(max_length=64) product_value = db.IntField() status = db.IntField(choices=OPTIONS_STATUS.iteritems(), default=STATUS_UNPAY) price_origin = db.IntField() price_pay = db.IntField() product_num = db.IntField() order_msg = db.DictField() create_time = db.DateTimeField() pay_time = db.DateTimeField() meta = { 'db_alias': 'default', 'collection': 'userorder', 'id_field': '_id', }
class Tracker(db.Document): _id = db.ObjectIdField() tracker_name = db.StringField() root_url = db.StringField() search_text = db.StringField() min_price = db.IntField() max_price = db.IntField() notify_email = db.EmailField() notify_every = db.IntField() notify_unit = db.StringField() notify_interval = db.IntField(validation=valid_notify_interval) last_notified_date = db.DateTimeField() def __repr__(self): return '<Tracker {}>'.format(self.tracker_name)
class LogisticLog(db.Document): """""" meta = { 'db_alias': 'db_log', 'allow_inheritance': True, 'indexes': ['logistic_id', 'timestamp'], 'ordering': ['-timestamp'], } log_type = db.StringField() logistic_id = db.ObjectIdField(required=True) timestamp = db.DateTimeField(default=datetime.utcnow) user_id = db.StringField(required=False) info = db.DictField() @classmethod def create(cls, log, data, user_id='system'): return cls(logistic_id=log.id, info=data, user_id=user_id).save()
class Message(db.Document): from_user = db.ReferenceField(User, db_field="from_user", reverse_delete_rule=CASCADE) to_user = db.ReferenceField(User, db_field="to_user", default=None, reverse_delete_rule=CASCADE) text = db.StringField(db_field="text", max_length=1024) live = db.BooleanField(db_field="live", default=None) create_date = db.LongField(db_field="create_date", default=utc_now_ts_ms()) parent = db.ObjectIdField(db_field="parent", default=None) images = db.ListField(db_field="images") message_type = db.IntField(db_field='message_type', default=POST, choices=MESSAGE_TYPE) @property def text_linkified(self): return linkify(self.text) @property def human_timestamp(self): return ms_stamp_humanize(self.create_date) @property def comments(self): return Message.objects.filter( parent=self.id, message_type=COMMENT).order_by('create_date') @property def likes(self): return Message.objects.filter( parent=self.id, message_type=LIKE).order_by('-create_date') def post_imgsrc(self, image_ts, size): return url_for('static', filename=os.path.join( 'images', 'posts', '%s.%s.%s.png' % (self.id, image_ts, size))) meta = { 'indexes': [('from_user', 'to_user', '-create_date', 'parent', 'message_type', 'live')] }
class District(db.Document): district_id = db.IntField() state_id = db.ObjectIdField() title = db.DictField() code = db.StringField(max_lenght=255) meta = { 'collection': 'districts', 'indexes': [{ 'fields': ['district_id'], 'unique': True, 'name': 'districts_district_id_unique', }, { 'fields': ['state_id'], 'name': 'districts_state_id_index', }, { 'fields': ['title.*'], 'name': 'districts_title_index', }] }
class Home(db.Document): name = db.StringField(required=True) place = db.StringField(required=True) location = db.PointField(required=True) start_time = db.DateTimeField(required=True) end_time = db.DateTimeField(required=True) home_photo = db.StringField() description = db.StringField(min_length=20, required=True) host = db.ObjectIdField(required=True) #link to USER DB cancel = db.BooleanField(default=False) occupy = db.BooleanField(default=False) capacity = db.StringField() price = db.StringField() contact = db.StringField() #need one attribute ,"occupier" at specific time attendees = db.ListField(db.ReferenceField(User)) comments = db.ListField(db.ReferenceField(Comment))
class MoneyEntry(db.EmbeddedDocument): class Recurring(IntEnum): SINGLE = 0 EVERY_DAY = 1 EVERY_MONTH = 2 EVERY_YEAR = 3 class Type(IntEnum): INCOME = 0 EXPENSE = 1 class State(IntEnum): PENDING = 0, APPROVED = 1 id = db.ObjectIdField(required=True, default=ObjectId, unique=True, primary_key=True) type = db.IntField(required=True, default=Type.INCOME) description = db.StringField(required=True) value = db.FloatField(required=True, default=1.00) currency = db.StringField(required=True, default=constants.DEFAULT_CURRENCY) category = db.StringField(required=True) date = db.DateTimeField(required=True, default=datetime.now) recurring = db.IntField(default=Recurring.SINGLE) state = db.IntField(required=True, default=State.APPROVED) def clone(self): entry = MoneyEntry() entry.type = self.type entry.description = self.description entry.value = self.value entry.currency = self.currency entry.category = self.category entry.date = self.date entry.recurring = self.recurring entry.state = self.state return entry
class Review(db.Document): title = db.StringField() content = db.StringField() rating = db.DecimalField(min_value=1, max_value=10, precision=1) titleparent = db.ObjectIdField() author = db.ObjectIdField() points = db.ListField(db.ReferenceField(ReviewPoint)) recommended = db.BooleanField() @staticmethod def get_by_id(id): try: return Review.objects.get(id=id) except: return None @staticmethod def get_by_title(title): reviews = Review.objects.filter(titleparent=title.id) return reviews @staticmethod def get_avg_rating(title): reviews = Review.get_by_title(title) avg = 0 review_count = reviews.count() if review_count <= 0: return 0 for review in reviews: avg += review.rating return avg / review_count def get_author(self): try: return User.get_by_id(self.author) except: return None def is_author(self, user): author = self.get_author() return author.id == getattr(user, "id", "") def __query_points(self, point_type): p = [] for point in self.points: if point.role == point_type: p.append(point) return p def pros(self): return self.__query_points(ReviewPoint.PROS_ID) def cons(self): return self.__query_points(ReviewPoint.CONS_ID) def pros_as_string(self): pros = self.pros() pros_string = [] for pro in pros: pros_string.append(pro.content) return pros_string def cons_as_string(self): cons = self.cons() cons_string = [] for con in cons: cons_string.append(con.content) return cons_string def remove_all_points(self): for point in self.points: point.delete self.points = [] def put_pros(self, pros): pros_object = [] for pro in pros: pro_obj = ReviewPoint(content=pro, role=ReviewPoint.PROS_ID, parent=self.id) pro_obj.save() pros_object.append(pro_obj) self.points = pros_object def add_pros(self, pros): for pro in pros: pro_obj = ReviewPoint(content=pro, role=ReviewPoint.PROS_ID, parent=self.id) pro_obj.save() self.points.append(pro_obj) def put_cons(self, cons): cons_object = [] for con in cons: con_obj = ReviewPoint(content=con, role=ReviewPoint.CONS_ID, parent=self.id) con_obj.save() cons_object.append(con_obj) self.points = cons_object def add_cons(self, cons): for con in cons: con_obj = ReviewPoint(content=con, role=ReviewPoint.CONS_ID, parent=self.id) con_obj.save() self.points.append(con_obj)
class RedPacket(db.Document): _id = db.ObjectIdField() open_id = db.StringField(max_length=64) amount = db.IntField() count = db.IntField() left_count = db.IntField() title = db.StringField(max_length=64) level = db.IntField() poster = db.StringField(max_length=256) create_time = db.DateTimeField() expire_time = db.DateTimeField() meta = { 'db_alias': 'default', 'collection': 'redpacket', 'id_field': '_id', } @property def could_collect(self): flag = False if self.left_count and self.expire_time > datetime.datetime.now(): flag = True return flag @classmethod def get_packet(cls, redpacket_id): redpacket_id = str2objectid(redpacket_id) packet = cls.objects.filter( _id=redpacket_id, expire_time__gte=datetime.datetime.now()).first() return packet @classmethod def get_packet_all(cls, redpacket_id): redpacket_id = str2objectid(redpacket_id) packet = cls.objects.filter(_id=redpacket_id).first() if not packet: return return packet @classmethod def has_collect(cls, redpacket_id, open_id=None): redpacket_id = str2objectid(redpacket_id) rpl = RedPacketLog.objects.filter( redpacket_id=redpacket_id, open_id=open_id, status=RedPacketLog.STATUS_DONE).first() if open_id else None has_collect, value = (True, rpl.value) if rpl else (False, 0) return has_collect, value / 100.0 @classmethod def create_redpacket(cls, open_id, amount, number, title, level, posterurl, _id=None): flag, result = redpacketobj.result(amount, number, 1) if not flag: return result now = datetime.datetime.now() if not _id: _id = bson.ObjectId() redpacket = cls(_id=_id, open_id=open_id, amount=amount, count=number, left_count=number, title=title, level=level, create_time=now, expire_time=now + datetime.timedelta(days=7), poster=posterurl) redpacketlog = [] for value in result: redpacketlog.append( RedPacketLog(redpacket_id=_id, value=value, status=0, last_modify=now)) rpl = RedPacketLog.objects.insert(redpacketlog) rp = cls.objects.insert(redpacket) if rpl else None return _id if rp else None @classmethod def collect_redpacket(cls, redpacket_id, open_id): redpacket_id = str2objectid(redpacket_id) rp = cls.objects.filter( _id=redpacket_id, left_count__gte=1).update_one(inc__left_count=-1) if not rp: return False, filters = dict(redpacket_id=redpacket_id, status=RedPacketLog.STATUS_UN, open_id__exists=False) rpl = RedPacketLog.objects.filter(**filters).first() if not rpl: return False, modify = { 'status': RedPacketLog.STATUS_DONE, 'open_id': open_id, 'last_modify': datetime.datetime.now() } result = rpl.modify(query=filters, **modify) if not result: return False, return rpl.value, rpl.pk def collect_report(self, open_id, status, rp_log_id=None): data = dict(redpacket_id=self.pk, status=status, open_id=open_id, create_time=datetime.datetime.now()) if status == RedPacketCollectLog.STATUS_SUCCESS and rp_log_id: data.update({'rp_log_id': str(rp_log_id)}) rpcl = RedPacketCollectLog(**data) elif status == RedPacketCollectLog.STATUS_FAIL: rpcl = RedPacketCollectLog(**data) else: return False RedPacketCollectLog.objects.insert(rpcl) return RedPacketCollectLog.objects.filter(redpacket_id=self.pk, open_id=open_id).count()
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 MasterFile(db.EmbeddedDocument): file_composition = db.ListField(db.ObjectIdField()) file = db.FileField()
class User(db.Document): email = db.StringField(required=True) name = db.StringField() corporate_id = db.ObjectIdField() password = db.StringField()
class Survey(db.Document): user = db.ObjectIdField(User) timestamp = db.DateTimeField(required=True) survey = db.DictField(db.AnythingField(), required=True) tags = db.ListField(db.StringField(), required=True, default=[]) ongoing = db.BoolField(default=True, required=True) def getAll(self, from_datetime=None, until_datetime=None, tags=None, ongoing=None): """ Return all surveys registered. By setting 'from_datetime'm, 'until_datetime', 'tags' or 'ongoing' one could further filter the scope of the query """ # return Survey.query.all() query = db.session.query(Survey) if from_datetime is not None: query.filter(Survey.timestamp >= from_datetime) if until_datetime is not None: query.filter(Survey.timestamp <= until_datetime) if tags is not None: query.filter(Survey.tags.in_(tags)) if ongoing is not None: query.filter(Survey.ongoing == ongoing) return query.all() def getAllByUniqueID(self, uniqueID, from_datetime=None, until_datetime=None, tags=None, ongoing=None): """ Return all surveys registered by a given user. By setting 'from_datetime'm, 'until_datetime', 'tags' or 'ongoing' one could further filter the scope of the query """ # Check if user exists user = User().query.filter(User.uniqueID == uniqueID).first() try: assert not user is None, "User not found" except AssertionError as ax: raise UserNotFound(uniqueID) query = db.session.query(Survey) query.filter(Survey.user == user.mongo_id) if from_datetime is not None: query.filter(Survey.timestamp >= from_datetime) if until_datetime is not None: query.filter(Survey.timestamp <= until_datetime) if tags is not None: query.filter(Survey.tags.in_(tags)) if ongoing is not None: query.filter(Survey.ongoing == ongoing) return query.all() def getByUniqueIDAndID(self, uniqueID, _id): return Survey.query.filter(Survey.user == User().query.filter(User.uniqueID == uniqueID) .first().mongo_id, Survey.mongo_id == _id).first() def getByID(self, survey_id): try: surveys = Survey.query.filter(Survey.mongo_id == survey_id) if surveys.count() == 0: raise SurveyNotFound(survey_id) return surveys.first() except db.BadValueException: raise SurveyNotFound(survey_id) def addByUniqueID(self, uniqueID, survey, tags=[], ongoing=True): self.user = User().query.filter(User.uniqueID == uniqueID).first().mongo_id self.timestamp = datetime.utcnow() self.survey = survey self.tags = tags self.ongoing = ongoing self.save() return True def updateByUniqueIDAndID(self, uniqueID, _id, survey, tags, ongoing): Survey.query.filter(Survey.user == User().query.filter(User.uniqueID == uniqueID).first().mongo_id, Survey.mongo_id == _id).set( survey=survey, tags=tags, ongoing=ongoing, timestamp=datetime.utcnow()).execute() return True def updateByUniqueID(self, _id, survey, tags, ongoing): """ Verify survey exists. Then update its 'survey' content and save it back. """ try: surveys = Survey.query.filter(Survey.mongo_id == _id) if surveys.count() == 0: raise SurveyNotFound(_id) if surveys.count() > 1: raise NonUniqueSurveyIDError(_id) except db.BadValueException as error: raise SurveyNotFound(_id) existing_survey_object = surveys.first() existing_survey_object.survey = survey existing_survey_object.tags = tags existing_survey_object.ongoing = ongoing existing_survey_object.timestamp=datetime.utcnow() existing_survey_object.save() return True def deleteByUniqueID(self, _id): """ Verify survey exists. Then delete it. """ try: surveys = Survey.query.filter(Survey.mongo_id == _id) if surveys.count() == 0: raise SurveyNotFound(_id) if surveys.count() > 1: raise NonUniqueSurveyIDError(_id) except db.BadValueException as error: raise SurveyNotFound(_id) existing_survey_object = surveys.first() existing_survey_object.remove() return True def getCSVReportTagsAndOngoing(self): data = [ob.serializeTagsAndOngoing() for ob in self.getAll()] filename = str(uuid.uuid4()) + '.csv' path = os.path.join(current_app.config['REPORTS_DIR'], filename) csv_file = csv.writer(open(path, mode="w")) csv_file.writerow(['User ID', 'Survey ID', 'timestamp', 'tags', 'ongoing']) for item in data: # the `tags` field can apparently contain arbitrary Unicode data (limited to Latin-1, actually, looking # at the samples collected so far) so we need to escape it to UTF-8 in order to save into a CSV file # According to the Python 2.7 `csv` module docs, "The csv module does not directly support reading # and writing Unicode, but it is 8-bit-clean save for some problems with ASCII NUL characters." # so reading and writing UTF-8 is OK. csv_file.writerow([item['user_id'], item['id'], item['timestamp'], item['tags'].encode('utf-8'), item['ongoing']]) return filename def serialize(self): d = { "id": str(self.mongo_id), "timestamp": self.timestamp.isoformat(), "survey": self.survey, "tags": self.tags, "ongoing": bool(self.ongoing) } return d def serializeTagsAndOngoing(self): d = { "user_id": User().query.filter(User.mongo_id == self.user).first().uniqueID, "id": str(self.mongo_id), "timestamp": self.timestamp.isoformat(), "tags": ', '.join(self.tags), "ongoing": bool(self.ongoing) } return d
class Pomodoro(db.EmbeddedDocument): id = db.ObjectIdField(default=ObjectId, required=True) created_at = db.DateTimeField(default=datetime.datetime.now, required=True) complete = db.BooleanField(default=False, required=True) remaining_length = db.IntField(required=True)
class Discussion(db.Document): title = db.StringField() description = db.StringField() created_at = db.DateTimeField() answers = db.ListField( db.ReferenceField('Discussion', reverse_delete_rule=db.PULL)) parent = db.ObjectIdField() upvotes = db.ListField(db.ReferenceField('Upvote')) author = db.ObjectIdField() is_answer = db.BooleanField() @staticmethod def get_by_id(id): try: return Discussion.objects.get(id=id) except: return None @staticmethod def get_by_title(title): discussions = Discussion.objects.filter(parent=title.id) return discussions def get_author(self): return User.objects.get(id=self.author) def is_author(self, user): author = self.get_author() return author.id == getattr(user, "id", "") def delete_all_answers(self): if not self.is_answer: for answer in self.answers: answer.delete() def delete_all_upvotes(self): for upvote in self.upvotes: upvote.delete() def upvotes_count(self): return Upvote.objects.filter(parent=self.id).count() def upvotes_value(self): return Upvote.objects.filter(parent=self.id).sum("value") def has_upvoted(self, user_id): for upvote in self.upvotes: if upvote.user_id == user_id: if (upvote.value == 1): return True, "upvote", upvote else: return True, "downvote", upvote return False, "", None def manage_upvote(self, user_id, value): has_upvoted, upvote_type, upvote = self.has_upvoted(user_id) if not has_upvoted: upvote = Upvote(user_id=user_id, value=value, parent=self.id) upvote.save() self.upvotes.append(upvote) self.save() return self.upvotes_value() if upvote.value != value: upvote.value = value upvote.save() self.save() else: self.update(pull__upvotes=upvote) upvote.delete() return self.upvotes_value()
class User(db.Document): _id = db.ObjectIdField() username = db.StringField() password = db.StringField() accessString = db.StringField()