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)
Exemplo n.º 2
0
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()
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
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()
Exemplo n.º 7
0
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)
        }
Exemplo n.º 8
0
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()
Exemplo n.º 9
0
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)
Exemplo n.º 10
0
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),
        )
Exemplo n.º 11
0
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
Exemplo n.º 12
0
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()
Exemplo n.º 13
0
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()