class Location(db.Model): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80)) lat = db.Column(db.Float()) lng = db.Column(db.Float()) # for faster calculation of Distance Difference Index('dist', func.ll_to_earth(lat, lng), postgresql_using='gist') def __init__(self, name, lat, lng): self.name = name self.lat = lat self.lng = lng
class FiatCurrency(AutoIncrementBase): country = db.Column(db.String(60), nullable=False) # 国家名称 country_code = db.Column(db.String(20), nullable=False) # 国家编码 currency = db.Column(db.String(60), nullable=False) # 货币名称 currency_code = db.Column(db.String(20), nullable=False) # 货币编码 usd_rate = db.Column(db.Numeric(24, 8), nullable=False) # 美元汇率 sequence = db.Column(db.SmallInteger, nullable=False) # 排序 __table_args__ = (db.UniqueConstraint('country_code', 'currency_code'), ) @staticmethod def initialize(): fiat_currency_list = (('中华人民共和国', 'CN', 'CNY', '人民币元'), ('中国香港', 'HK', 'HKD', '港元'), ('中国台湾', 'TW', 'TWD', '台湾元'), ('英国', 'GB', 'GBP', '英镑'), ('美国', 'US', 'USD', '美元'), ('法国', 'FR', 'EUR', '欧元'), ('德国', 'DE', 'EUR', '欧元'), ('日本', 'JP', 'JPY', '日元'), ('阿拉伯联合酋长国', 'AE', 'AED', '阿联酋 迪拉姆'), ('泰国', 'TH', 'THB', '泰铢'), ('俄罗斯', 'RU', 'RUB', '俄罗斯卢布'), ('加拿大', 'CA', 'CAD', '加拿大元'), ('韩国', 'KR', 'KRW', '韩元'), ('马来西亚', 'MY', 'MYR', '马来西亚林吉特'), ('新加坡', 'SG', 'SGD', '新加坡元')) for fiat_currency in fiat_currency_list: currency = FiatCurrency.query.filter_by( country_code=fiat_currency[1], currency_code=fiat_currency[2]).first() if currency is None: currency = FiatCurrency(country=fiat_currency[0], country_code=fiat_currency[1], currency=fiat_currency[3], currency_code=fiat_currency[2], usd_rate=0, sequence=0) db.session.add(currency) db.session.commit()
class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key = True) email = db.Column(db.String(64), unique = True) password = db.Column(db.String(255)) active = db.Column(db.Boolean()) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return unicode(self.id) def __repr__(self): return '<User %r>' % (self.name)
class AdminUserBase(UuidBase): __abstract__ = True ROOT_ID = '00000000-0000-0000-0000-000000000000' uid = db.Column(db.String(32), unique=True, nullable=False) password = db.Column(db.String(256), nullable=False) role = db.Column(db.SmallInteger, nullable=False) # 1 超级管理员 2 系统管理员 4 代理 locked = db.Column(db.SmallInteger, default=0, nullable=False) # 0 未锁定 1 锁定 token = db.Column(db.String(256)) permission = db.Column(db.Text) # 权限 def set_password(self, password): self.password = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.password, password) def generate_auth_token(self, expiration=365 * 24 * 60 * 60): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) self.token = s.dumps({'id': self.id}) @classmethod def verify_auth_token(cls, token): if not token: return None s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except SignatureExpired: return None # valid token, but expired except BadSignature: return None # invalid token user = cls.query.get(data['id']) if user and not user.locked and user.token == token: return user return None
class UserModel(db.Model, UserMixin): __tablename__ = 'user_model' id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(100), nullable=False, unique=True) password = db.Column(db.String(255), nullable=False, server_default='') forename = db.Column(db.String(100), nullable=False, server_default='') surname = db.Column(db.String(100), nullable=False, server_default='') # roles = db.relationship('Role', secondary='user_roles') def set_password(self, password): self.password = generate_password_hash(password, method='sha256') def check_password(self, password): return check_password_hash(self.password, password) def save_to_db(self): db.session.add(self) db.session.commit() def __repr__(self): return '<User %r>' % self.username
class User(UuidBaseModel): mobile = db.Column(db.String(16), unique=True) # 用户手机号 token = db.Column(db.String(256)) # 访问令牌 password = db.Column(db.String(256), nullable=False) # 密码 def generate_auth_token(self, expiration=31 * 24 * 60 * 60, parameter=None): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) data = {'id': self.id} if parameter: data = dict(data.items() + parameter.items()) self.token = s.dumps(data) def set_password(self, password): self.password = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.password, password) @classmethod def verify_auth_token(cls, token): # if not token: # return None if not token: abort(401, code=1001, message={'token': 'token does not exist'}) s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except SignatureExpired: return None, None # valid token, but expired except BadSignature: return None, None # invalid token user = cls.query.get(data['id']) if user and user.token == token: return user, data return None, None
class User(UserMixin, db.Model, TimestampMixin): id = db.Column(db.Integer, primary_key=True, nullable=False) email = db.Column(db.String(200), unique=True, nullable=False, index=True) password = db.Column(db.String(200), nullable=False) status = db.Column(ChoiceType(UserStatus, impl=db.Integer()), default=UserStatus.ACTIVE) def encode_password(self): self.password = generate_password_hash(self.password) def check_password(self, password): return check_password_hash(self.password, password) def is_active(self): return self.status == UserStatus.ACTIVE def leave(self): self.status = UserStatus.INACTIVE def is_exists(self): temp = User.query.filter(User.email == self.email).one_or_none() if temp: return True else: return False def is_liked(self, post_id): if Likes.query.filter(Likes.post_id == post_id, Likes.user_id == self.id).one_or_none(): return True return False def __repr__(self): return "<User email: %s, password: %s, created_at: %s, updated_at: %s>" \ % (self.email, self.password, self.created_at, self.updated_at)
class User(db.Model, CRUD): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(250), nullable=False, unique=True) password = db.Column(db.String(250), nullable=False) firstname = db.Column(db.String(250)) lastname = db.Column(db.String(250)) role = db.Column(db.String(250), db.ForeignKey('role.name')) active = db.Column(db.Integer, nullable=False) create = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), nullable=False) def is_active(self): return True def get_id(self): return self.email def is_authenticated(self): return self.authenticated def is_anonymous(self): return def __init__(self, email, password, firstname, lastname, role, active): self.email = email self.password = password self.firstname = firstname self.lastname = lastname self.role = role self.active = active def __repr__(self): return '<User %s>' % self.email
class CryptoCurrency(AutoIncrementBase): currency_code = db.Column(db.String(20), nullable=False) # 货币编码 erc20_token = db.Column(db.SmallInteger, nullable=False) # 代币: 0 不是 1 是 usd_price = db.Column(db.Numeric(24, 8), nullable=False) # 美元价格 sequence = db.Column(db.SmallInteger, nullable=False) # 排序 init_block_number = db.Column(db.Integer, default=0, nullable=False) # 初始索引块数 indexed_block_number = db.Column(db.Integer, default=0, nullable=False) # 已索引块数 start_price = db.Column(db.Numeric(24, 8), nullable=False) # 0 点时价格 用于计算涨幅 percent_change_1h = db.Column(db.Numeric(24, 8), default=0, nullable=False) percent_change_24h = db.Column(db.Numeric(24, 8), default=0, nullable=False) percent_change_7d = db.Column(db.Numeric(24, 8), default=0, nullable=False) __table_args__ = (db.UniqueConstraint('currency_code', 'erc20_token'), ) @property def percent_change(self): if self.start_price: return (self.usd_price - self.start_price) / self.start_price * 100 else: return 0 @staticmethod def initialize(): crypto_currency_list = [ 'BTC', 'USDT', 'ETH', 'LTC', 'EOS', 'ETC', 'DASH', 'BSV', 'XRP', 'DOGE' ] for crypto_currency in crypto_currency_list: currency = CryptoCurrency.query.filter_by( currency_code=crypto_currency, erc20_token=0).first() if currency is None: currency = CryptoCurrency(currency_code=crypto_currency, erc20_token=0, usd_price=0, start_price=0, sequence=0) db.session.add(currency) db.session.commit()
class AdminUser(AdminUserBase): parent_id = db.Column(db.String(36), db.ForeignKey('admin_user.id')) # relationship parent = db.relationship('AdminUser', foreign_keys=[parent_id], remote_side="AdminUser.id") @staticmethod def initialize(): root_admin = AdminUser.query.get(AdminUserBase.ROOT_ID) if root_admin is None: root_admin = AdminUser(id=AdminUserBase.ROOT_ID, uid='admin', role=1) root_admin.set_password('888888') root_admin.generate_auth_token() db.session.add(root_admin) db.session.commit()
class SmsPinCode(PinCodeBase): id = db.Column(db.String(11), primary_key=True)
class MyUser(db.Model): __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(16)) password = db.Column(db.String(32))
class Language(Base): __tablename__ = "language" Lang = db.Column(db.String(10), primary_key=True, unique=True) Iso6391Name = db.Column(db.String(20))
class TypeModel(db.Model): __tablename__ = 'types' id = db.Column(db.Integer, primary_key=True, nullable=False) name = db.Column(db.String(255), nullable=False)
class User(db.Model): id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(64), unique=True, index=True) email = db.Column(db.String(120), unique=True, index=True) password_hash = db.Column(db.String(128), nullable=False) email_confirmed = db.Column(db.Boolean, default=False)
class Role(db.Model, RoleMixin): id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(80), unique=True) description = db.Column(db.String(255))
class Setting(db.Model): name = db.Column(db.String(50), primary_key=True) value = db.Column(db.Text, nullable=False) title = db.Column(db.Text, nullable=False) description = db.Column(db.Text, nullable=False) GENERAL_OPTION = { 'evaluation_reward_amount': 200, 'lebo_price': '0.2', 'lebo_change_price_cnt': 2500, 'lebo_price_step': '0.001', 'recommend_reward_amount': [200, 150, 100, 50, 30, 25, 20, 15, 10, 5], 'transaction_allow_amount': 3000, 'sell_amount': 300, 'sell_people': 300, 'buy_people': 300, 'buy_count': 3, 'sell_count': 3, 'order_fee_rate': '0.0', 'contact_us': '1234567890', 'buy_sell_free_amount': 100, 'buy_sell_rate': '0.03', 'transaction_free_generation': 3, 'transaction_free_amount': 5, 'transaction_time_begin': ['09:00', '14:00'], 'transaction_time_end': ['12:00', '18:00'], 'exchange_amount_min': 300, 'exchange_amount_max': 5000, 'community_node_cnt': [314, 400, 600], 'community_total_balance': [100000, 200000, 300000], 'community_transaction_day_cnt': 10, 'community_sponsor_cnt': [10, 20, 30], 'community_line_cnt': [2, 3, 4], 'community_line_people_cnt': 100, 'qr_host': 'http://qr.99lebo.com', 'community_dividend_rate': '0.01', 'community_transaction_fee_rate': '0.05', 'community_free_amount': 5, 'community_free_generation': 10, 'order_status_change_time': 2, 'match_order_cnt': 0, 'dollar2rmb': '7.0' } GENERAL_OPTION_DESCRIPTION = { 'evaluation_reward_amount': u'测评奖励(美元)', 'lebo_price': u'乐宝初始价格(美元)', 'lebo_change_price_cnt': u'乐宝价格变化的交易笔数(笔)', 'lebo_price_step': u'乐宝价格变化步进(美元)', 'recommend_reward_amount': u'每代推荐人获得奖励(个)', 'transaction_allow_amount': u'达到该个数允许交易(个)', 'sell_amount': u'一次的卖单数量(个)', 'sell_people': u'一天可挂卖单人数(人)', 'buy_people': u'一天可挂买单人数(人)', 'buy_count': u'一人一天最多的买入单数(单)', 'sell_count': u'一人一天最多的卖出单数(单)', 'order_fee_rate': u'订单手续费率', 'contact_us': u'联系我们', 'buy_sell_free_amount': u'买卖各一单时释放个数', 'buy_sell_rate': u'买卖各一单时的手续费率', 'transaction_free_generation': u'交易加速释放代数', 'transaction_free_amount': u'交易加速释放数量', 'transaction_time_begin': u'交易开始时间', 'transaction_time_end': u'交易结束时间', 'exchange_amount_min': u'兑换的最小数量', 'exchange_amount_max': u'兑换的最大数量', 'community_node_cnt': u'社区节点阶段对应数量', 'community_total_balance': u'社区节点阶段对应总资产', 'community_transaction_day_cnt': u'社区节点连续交易天数', 'community_sponsor_cnt': u'社区节点阶段对应所需直推用户数', 'community_line_cnt': u'社区节点阶段对应所需线数', 'community_line_people_cnt': u'社区节点线对应用户数', 'qr_host': u'推荐注册地址', 'community_dividend_rate': u'社区节点分红比率', 'community_transaction_fee_rate': u'社区节点转账手续费', 'community_free_amount': u'社区节点交易加速释放个数', 'community_free_generation': u'社区节点交易加速释放代数', 'order_status_change_time': u'订单状态变化时间(h)', 'match_order_cnt': u'订单匹配数量', 'dollar2rmb': u'美元兑人民币汇率' } DEFAULT_OPTIONS = (('general_option', json.dumps(GENERAL_OPTION), u'常规选项', json.dumps(GENERAL_OPTION_DESCRIPTION)), ) @staticmethod def update_default_options(): for name, value, title, description in Setting.DEFAULT_OPTIONS: setting = Setting.query.get(name) if setting: setting.title = title setting.description = description runtime_json = json.loads(setting.value) default_json = json.loads(value) for k, v in default_json.items(): if k not in runtime_json: runtime_json[k] = v setting.value = json.dumps(runtime_json) else: setting = Setting(name=name, value=value, title=title, description=description) db.session.add(setting) db.session.commit() @staticmethod def get_json(name): return json.loads(Setting.query.get(name).value)
class News(AutoIncrementBase): title = db.Column(db.String(128), nullable=False) # 新闻名称 details = db.Column(db.Text, nullable=False) # 新闻内容
class EmailPinCode(PinCodeBase): id = db.Column(db.String(60), primary_key=True)
class User(UserBase): VIRTUAL_ID = '00000000-0000-0000-0000-000000000000' name = db.Column(db.String(64)) # 姓名 avatar = db.Column(db.String(512)) # 头像 URL order_mobile = db.Column(db.String(16)) nickname = db.Column(db.String(64)) # 昵称 gender = db.Column(db.SmallInteger, default=0) # 性别: 0 未填 1 男 2 女 sponsor_id = db.Column(db.String(36), db.ForeignKey('user.id')) # 推荐人 active = db.Column(db.SmallInteger, default=0) # 是否激活: 0 未激活 1 激活 left_id = db.Column(db.Integer, default=0) # 用于推荐网络图子节点的查询 right_id = db.Column(db.Integer, default=0) wechat = db.Column(db.String(64)) # 微信 state = db.Column(db.Integer, default=0) # 资料和测评状态,参见 g_user_state_type allow_transaction = db.Column(db.Integer, default=0) # 允许交易 0 不允许 1 允许 transaction_level = db.Column( db.Integer, default=0) # 交易级别 参见 g_user_transaction_level buy_order_cnt = db.Column(db.Integer, default=0) # 买进的单数 continuous_buy_cnt = db.Column(db.Integer, default=0) # 持续购买天数 today_have_transaction = db.Column(db.SmallInteger, default=0) # 今天是否拥有一次买卖交易 0 没有 1 有 team_qualified_cnt = db.Column(db.Integer, default=0) # 团队合格用户人数 is_community_node = db.Column(db.SmallInteger, default=0) # 是否为社区节点 0 不是 1 是 # relationship sponsor = db.relationship('User', foreign_keys=[sponsor_id], remote_side="User.id") assets = db.relationship('Assets', uselist=False) def is_virtual(self): return self.id == User.VIRTUAL_ID def is_active(self): return self.active == 1 def activate(self): from app.model.schedule_task import RegisterScheduleTask self.active = 1 task = RegisterScheduleTask(user_id=self.id) db.session.add(task) from app.model.assets import Assets assets = Assets(user_id=self.id) db.session.add(assets) db.session.flush() # 保证顺序 def update_state(self, state): from app.model.schedule_task import RecommendScheduleTask rows_changed = User.query.filter(User.id == self.id, User.state != state).update( dict(state=state)) if rows_changed: if state == g_user_state_type.EVALUATION: task = RecommendScheduleTask.query.filter( RecommendScheduleTask.user_id == self.id).first() if task is None: task = RecommendScheduleTask(user_id=self.id) db.session.add(task) db.session.flush() # 保证顺序 def update_left_right_id(self): if self.left_id or self.right_id: return False parent = User.query.get(self.sponsor_id) new_user_left = parent.right_id User.query.filter(User.left_id > new_user_left).update( dict(left_id=User.left_id + 2)) User.query.filter(User.right_id >= new_user_left).update( dict(right_id=User.right_id + 2)) self.left_id = new_user_left self.right_id = new_user_left + 1 db.session.flush() return True def update_team_qualified_cnt(self): sponsor = self.sponsor # 自己也算 User.query.filter(User.id == self.id).update( dict(team_qualified_cnt=User.team_qualified_cnt + 1)) while sponsor: User.query.filter(User.id == sponsor.id).update( dict(team_qualified_cnt=User.team_qualified_cnt + 1)) sponsor = sponsor.sponsor def update_recommend_reward(self): option = Setting.get_json('general_option') recommend_reward_amount = [ decimal.Decimal(x) for x in option['recommend_reward_amount'] ] evaluation_reward_amount = decimal.Decimal( option['evaluation_reward_amount']) # 先赠送本用户 usd_price = Currency.get_price() if usd_price == 0: abort(400, code=1002, message={'usd_price': 'usd_price is invaild'}) # amount = evaluation_reward_amount / usd_price amount = 1000 assets = Assets.get_assets(self.id) details = {'message': u'完成评测奖励'} assets.update_total_balance(amount, g_assets_record_type.EVALUATION, details) # 再赠送每一代推荐 layer = 0 layer_max = len(recommend_reward_amount) sponsor = self.sponsor while sponsor and layer < layer_max: details = { 'message': '被推荐人:{}, 第几代:{}'.format(self.uid, layer + 1) } if sponsor.state == g_user_state_type.EVALUATION: assets = Assets.get_assets(sponsor.id) assets.update_total_balance(recommend_reward_amount[layer], g_assets_record_type.SPONSOR, details) layer += 1 sponsor = sponsor.sponsor def update_transaction_free(self): option = Setting.get_json('general_option') transaction_free_generation = option['transaction_free_generation'] transaction_free_amount = option['transaction_free_amount'] community_free_generation = option['community_free_generation'] community_free_amount = option['community_free_amount'] # 加速释放每一代 layer = 0 sponsor = self.sponsor while sponsor and layer < community_free_generation: if sponsor.is_community_node == 0 and layer < transaction_free_generation: amount = transaction_free_amount elif sponsor.is_community_node == 1: amount = community_free_amount else: amount = 0 if amount != 0: details = { 'message': '交易加速释放,交易完成者:{}, 第几代:{}'.format(self.uid, layer + 1) } assets = Assets.get_assets(sponsor.id) # amount = min(assets.total_balance, amount) if assets.update_total_balance( -amount, g_assets_record_type.ACCELERATE_FREE, details): assets.update_transaction_balance( amount, g_assets_record_type.ACCELERATE_FREE, details) layer += 1 sponsor = sponsor.sponsor # def update_buy_order_cnt(self, delta_amount): # rows_changed = User.query.filter( # User.id == self.id, # User.buy_order_cnt >= -delta_amount).update( # dict(buy_order_cnt=User.buy_order_cnt + delta_amount)) # if rows_changed == 1: # return True # return False @staticmethod def update_continuous_buy_cnt(): rows_changed = User.query.filter( User.today_have_transaction == 1).update( dict(continuous_buy_cnt=User.continuous_buy_cnt + 1)) if rows_changed: User.query.filter(User.today_have_transaction == 0).update( dict(continuous_buy_cnt=0)) User.query.update(dict(today_have_transaction=0)) return True return False def update_today_have_transaction(self): rows_changed = User.query.filter(User.id == self.id).update( dict(today_have_transaction=1)) if rows_changed: return True return False @property def cal_team_count(self): count = db.session.query(db.func.count(User.id)).filter( User.left_id > self.left_id, User.locked != 2, User.right_id < self.right_id).first()[0] if count is None: count = 0 return count def update_is_community_node(self): rows_changed = User.query.filter(User.id == self.id).update( dict(is_community_node=1)) if rows_changed: return True return False @property def node_profit(self): amount = db.session.query(db.func.sum( AssetsBalanceRecord.delta_amount)).filter( AssetsBalanceRecord.user_id == self.id, AssetsBalanceRecord.record_type == g_assets_record_type.DIVIDEND).first()[0] return amount if amount else 0 @staticmethod def initialize(): virtual_user = User.query.get(User.VIRTUAL_ID) if virtual_user is None: # 生成虚拟用户 virtual_user = User( id=User.VIRTUAL_ID, mobile='13288888888', left_id=1, right_id=2, active=1, transaction_level=g_user_transaction_level.ULTIMATE) virtual_user.set_password('8RBcdxlofE8F') virtual_user.set_security_password('8RBcdxlofE8F') virtual_user.uid = 'root' db.session.add(virtual_user) db.session.flush() virtual_user.activate() virtual_user.update_state(g_user_state_type.COMPLETED_DATA) db.session.commit()
class UserModel(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True, nullable=False) username = db.Column(db.String(255), nullable=False) password = db.Column(db.String(255), nullable=False)
class Article(db.Model): __tablename__ = "articles" id = db.Column(db.Integer(), primary_key=1) title = db.Column(db.String(255), unique=1) cover = db.Column(db.String(255)) digest = db.Column(db.String(255)) content = db.Column(db.Text()) read_num = db.Column(db.Integer()) post_date = db.Column(db.Date()) account_id = db.Column(db.Integer(), db.ForeignKey("accounts.id")) def __init__(self, title="", cover="", digest="", content="", read_num=0, post_date="", account=None): self.title = title self.cover = cover self.digest = digest self.content = content self.account = account self.read_num = read_num self.post_date = post_date def __repr__(self): return self.title def to_json(self): article = dict() article["id"] = self.id article["title"] = self.title article["cover"] = self.cover article["digest"] = self.digest article["content"] = self.content article["account"] = self.account article["read_num"] = self.read_num article["post_date"] = self.post_date return article
class Order(AutoIncrementBase): match_order_id = db.Column(db.Integer, db.ForeignKey('match_order.id'), nullable=True) # 匹配订单 user_id = db.Column(db.String(36), db.ForeignKey('user.id'), nullable=False) # 用户 side = db.Column(db.SmallInteger, nullable=False) # 单类型 参见 g_order_side number = db.Column(db.String(16), nullable=False) amount = db.Column(db.Numeric(24, 8), nullable=False) # 数量 status = db.Column(db.SmallInteger, default=g_order_status.PENDING, nullable=False) # 订单状态参见 g_order_status priority = db.Column(db.SmallInteger, default=0) # 订单优先级 数值越大优先级越高 user = db.relationship(User, foreign_keys=[user_id]) match_order = db.relationship(MatchOrder, foreign_keys=[match_order_id]) __table_args__ = (db.UniqueConstraint('side', 'number'),) @staticmethod def confirm_order(match_order): rows_changed = Order.query.filter_by( user_id=match_order.sell_user_id, side=g_order_side.SELL, number=match_order.sell_number, status=g_order_status.PAID).update(dict(status=g_order_status.CONFIRMED)) if not rows_changed: return False, dict(code=1001, message={'order_number': 'order does not exist'}) rows_changed = Order.query.filter_by( user_id=match_order.buy_user_id, side=g_order_side.BUY, number=match_order.buy_number, status=g_order_status.PAID).update(dict(status=g_order_status.CONFIRMED)) if not rows_changed: return False, dict(code=1001, message={'order_number': 'order does not exist'}) confirm_order = ConfirmOrder(sell_user_id=match_order.sell_user_id, buy_user_id=match_order.buy_user_id, amount=match_order.sell_order.amount) return True, confirm_order @staticmethod def generate_order_process(): option = Setting.get_json('general_option') sell_people = option['sell_people'] buy_people = option['buy_people'] sell_count = option['sell_count'] buy_count = option['buy_count'] str_time = datetime.datetime.now().strftime('%Y-%m-%d') order_list = SellOrder.query.filter(SellOrder.status == g_sell_order_status.UNPROCESSED).all() buy_list = BuyOrder.query.filter(BuyOrder.status == g_buy_order_status.UNPROCESSED).all() order_list.extend(buy_list) order_list = sorted(order_list, key=lambda e: e.created_at) for item in order_list: logging.info('Order side:{}, id:{}'.format(item.side, item.id)) if item.side == g_order_side.SELL: if item.user.transaction_level != g_user_transaction_level.ULTIMATE: order = Order.query.filter(Order.user_id == item.user_id, Order.side == g_order_side.BUY, Order.status == g_order_status.CONFIRMED).first() if not order: # 提示语"该用户从未购买过" error_details = dict(code=1001, message={'user': '******'}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue order_people = db.session.query(Order.user_id).filter( Order.created_at >= str_time, Order.side == g_order_side.SELL, Order.status != g_order_status.CANCELLED).count() order_people = order_people if order_people else 0 if order_people >= sell_people: # 提示语"当日入场单量已满" error_details = dict(code=1003, message={'count': 'count >= {}'.format(sell_people)}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue count = db.session.query(db.func.count(SellOrder.id)).filter( db.func.date_format(SellOrder.created_at, '%Y-%m-%d') == str_time, SellOrder.user_id == item.user_id, SellOrder.status == g_sell_order_status.PROCESSED).first()[0] count = count if count else 0 if count >= sell_count: # 提示语"今天卖出的单数已满" error_details = dict(code=1006, message={'user': '******'.format(sell_count)}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue detail = {'message': '挂单冻结'} assets = Assets.get_assets(item.user_id) if not assets.update_community_balance(-item.amount, g_assets_record_type.SELL, detail): # 提示语"余额不足" if assets.community_today_balance > 0: error_details = dict(code=1007, message={ 'order': 'please tomorrow to sell, today buy balance:{}'.format( assets.community_today_balance)}) else: error_details = dict(code=1008, message={'balance': 'current balance < {}'.format(item.amount)}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue item.status = g_sell_order_status.PROCESSED else: order_people = db.session.query(Order.user_id).filter( Order.created_at >= str_time, Order.side == g_order_side.BUY, Order.status != g_order_status.CANCELLED).count() order_people = order_people if order_people else 0 if order_people >= buy_people: # 提示语"当日入场单量已满" error_details = dict(code=1003, message={'count': 'count >= {}'.format(buy_people)}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue # 用于计算今天买入的单数 count = db.session.query(db.func.count(BuyOrder.id)).filter( db.func.date_format(BuyOrder.created_at, '%Y-%m-%d') == str_time, BuyOrder.user_id == item.user_id, BuyOrder.status == g_buy_order_status.PROCESSED).first()[0] count = count if count else 0 if count >= buy_count: # 提示语"今天买入的单数已满" error_details = dict(code=1006, message={'user': '******'.format(buy_count)}) item.details = json.dumps(error_details) item.status = g_sell_order_status.FAILED db.session.commit() continue item.status = g_buy_order_status.PROCESSED order = Order(created_at=item.created_at, user_id=item.user_id, side=item.side, amount=item.amount, number=item.number) db.session.add(order) db.session.commit() @staticmethod def match_order_process(): option = Setting.get_json('general_option') # match_order_cnt = option['match_order_cnt'] dollar2rmb = decimal.Decimal(option['dollar2rmb']) task = MatchOrderTask.query.filter(MatchOrderTask.status == g_match_order_task_status.UNPROCESSED).first() if task is None: return change = MatchOrderTask.query.filter(MatchOrderTask.status == g_match_order_task_status.UNPROCESSED).update( dict(status=g_match_order_task_status.PROCESSED)) if not change: return sell_list = Order.query.filter( Order.side == g_order_side.SELL, Order.status == g_order_status.PENDING) sell_list = sell_list.order_by(Order.priority.desc(), Order.created_at.asc()) i = 0 for item in sell_list: if i >= task.order_cnt: break buy_order = Order.query.filter( Order.side == g_order_side.BUY, Order.user_id != item.user_id, Order.status == g_order_status.PENDING).order_by(Order.priority.desc(), Order.created_at.asc()).first() if buy_order is None: continue change = Order.query.filter(Order.id == item.id, Order.status == g_order_status.PENDING).update( dict(status=g_order_status.MATCH)) if not change: continue change = Order.query.filter(Order.id == buy_order.id, Order.status == g_order_status.PENDING).update( dict(status=g_order_status.MATCH)) if not change: item.status = g_order_status.PENDING db.session.commit() continue usd_price = CryptoCurrency.query.filter(CryptoCurrency.currency_code == 'USDT').first().usd_price dollar = Currency.get_price() * item.amount usdt = dollar / usd_price order = MatchOrder(sell_user_id=item.user_id, buy_user_id=buy_order.user_id, sell_order_id=item.id, buy_order_id=buy_order.id, sell_number=item.number, buy_number=buy_order.number, payment_amount=dollar * dollar2rmb, payment_amount_usdt=usdt, current_price=Currency.get_price()) db.session.add(order) db.session.flush() item.match_order_id = order.id buy_order.match_order_id = order.id db.session.commit() try: if order.buy_user.order_mobile: clnt = YunpianClient('fcf725316cbb8ff1438c90ff76c6cebe') param = {YC.MOBILE: '+' + order.buy_user.order_mobile.replace(' ', ''), YC.TEXT: "【乐宝】您的订单{}已匹配成功,请尽快安排处理。".format('')} clnt.sms().single_send(param) except: pass i += 1 db.session.commit() @staticmethod def confirm_order_process(): order_list = ConfirmOrder.query.filter(ConfirmOrder.status == g_confirm_order_status.UNPROCESSED).all() for order in order_list: change = ConfirmOrder.query.filter( ConfirmOrder.id == order.id, ConfirmOrder.status == g_confirm_order_status.UNPROCESSED).update( dict(status=g_confirm_order_status.PROCESSED)) if not change: continue detail = {'message': '挂单交易'} assets = Assets.get_assets(order.buy_user_id) assets.update_community_today_balance(order.amount, g_assets_record_type.BUY, detail) # 用于计算一个买卖周期 order.buy_user.buy_order_cnt += 1 if order.sell_user.buy_order_cnt > 0: order.sell_user.buy_order_cnt -= 1 option = Setting.get_json('general_option') buy_sell_free_amount = option['buy_sell_free_amount'] buy_sell_rate = decimal.Decimal(option['buy_sell_rate']) fee = order.amount * buy_sell_rate amount = buy_sell_free_amount - fee detail = { 'message': '成功买卖各一单,释放数量:{}, 单数量:{}, 扣除手续费:{}'.format( buy_sell_free_amount, order.amount, fee) } assets = Assets.get_assets(order.sell_user_id) if assets.update_total_balance(-buy_sell_free_amount, g_assets_record_type.BUY_SELL_FREE, detail): assets.update_transaction_balance(amount, g_assets_record_type.BUY_SELL_FREE, detail) sell_user = order.sell_user sell_user.update_today_have_transaction() sell_user.update_transaction_free() currency = Currency.get_currency() currency.update_transaction_cnt() db.session.commit() @staticmethod def check_order_process(): option = Setting.get_json('general_option') change_time = int(option['order_status_change_time']) # 接单后不打款 q = db.session.query(Order).filter(Order.id == MatchOrder.sell_order_id, MatchOrder.created_at < datetime.datetime.now() - datetime.timedelta(hours=change_time), Order.status == g_order_status.MATCH).all() for order in q: match_order = order.match_order if match_order is None: continue rows_changed = Order.query.filter( Order.side == g_order_side.SELL, Order.number == match_order.sell_number, Order.status == g_order_status.MATCH).update(dict(status=g_order_status.CANCELLED)) if not rows_changed: continue detail = {'message': "超时不打款,卖单号:{},买单号:{},买方手机:{}".format(match_order.sell_number, match_order.buy_number, match_order.buy_user.mobile)} rows_changed = Order.query.filter( Order.side == g_order_side.BUY, Order.number == match_order.buy_number, Order.status == g_order_status.MATCH).update(dict(status=g_order_status.CANCELLED)) if rows_changed: assets = Assets.get_assets(order.user_id) assets.update_community_balance(order.amount, g_assets_record_type.SELL, detail) else: order.status = g_order_status.MATCH db.session.commit()
class Assets(UuidBase): user_id = db.Column(db.String(36), db.ForeignKey('user.id'), nullable=False) total_balance = db.Column(db.Numeric(24, 8), default=0, nullable=False) # 总资产钱包 冻结 community_balance = db.Column(db.Numeric(24, 8), default=0, nullable=False) # 社区钱包 用于交易 community_today_balance = db.Column(db.Numeric(24, 8), default=0, nullable=False) # 社区钱包 今日买入的冻结值 用于交易 transaction_balance = db.Column(db.Numeric(24, 8), default=0, nullable=False) # 交易钱包 用于冻结释放 grand_total_balance = db.Column(db.Numeric(24, 8), default=0, nullable=False) # 累计总资产钱包 # relationship user = db.relationship('User', foreign_keys=[user_id]) @staticmethod def get_assets(user_id): return Assets.query.filter_by(user_id=user_id).first() def update_grand_total_balance(self, delta_amount): delta_amount = decimal.Decimal(delta_amount) if delta_amount > 0: Assets.query.filter( Assets.id == self.id, Assets.grand_total_balance >= -delta_amount).update( dict(grand_total_balance=Assets.grand_total_balance + delta_amount)) return True return False def update_total_balance(self, delta_amount, record_type, details): delta_amount = decimal.Decimal(delta_amount) rows_changed = Assets.query.filter( Assets.id == self.id, Assets.total_balance >= -delta_amount).update( dict(total_balance=Assets.total_balance + delta_amount)) if rows_changed == 1: option = Setting.get_json('general_option') transaction_allow_amount = option['transaction_allow_amount'] if self.total_balance >= transaction_allow_amount: self.user.allow_transaction = 1 self.update_grand_total_balance(delta_amount) record = AssetsBalanceRecord(user_id=self.user_id, current_amount=self.total_balance, delta_amount=delta_amount, assets_type=g_assets_type.TOTAL, record_type=record_type, details=json.dumps(details)) db.session.add(record) db.session.flush() return True return False def update_community_balance(self, delta_amount, record_type, details): delta_amount = decimal.Decimal(delta_amount) rows_changed = Assets.query.filter( Assets.id == self.id, Assets.community_balance >= -delta_amount).update( dict(community_balance=Assets.community_balance + delta_amount)) if rows_changed == 1: record = AssetsBalanceRecord(user_id=self.user_id, current_amount=self.community_balance + self.community_today_balance, delta_amount=delta_amount, assets_type=g_assets_type.COMMUNITY, record_type=record_type, details=json.dumps(details)) db.session.add(record) db.session.flush() return True return False def update_community_today_balance(self, delta_amount, record_type, details): delta_amount = decimal.Decimal(delta_amount) rows_changed = Assets.query.filter( Assets.id == self.id, Assets.community_today_balance >= -delta_amount).update( dict(community_today_balance=Assets.community_today_balance + delta_amount)) if rows_changed == 1: record = AssetsBalanceRecord(user_id=self.user_id, current_amount=self.community_today_balance + self.community_balance, delta_amount=delta_amount, assets_type=g_assets_type.COMMUNITY, record_type=record_type, details=json.dumps(details)) db.session.add(record) db.session.flush() return True return False def update_transaction_balance(self, delta_amount, record_type, details): delta_amount = decimal.Decimal(delta_amount) rows_changed = Assets.query.filter( Assets.id == self.id, Assets.transaction_balance >= -delta_amount).update( dict(transaction_balance=Assets.transaction_balance + delta_amount)) if rows_changed == 1: record = AssetsBalanceRecord(user_id=self.user_id, current_amount=self.transaction_balance, delta_amount=delta_amount, assets_type=g_assets_type.TRANSACTION, record_type=record_type, details=json.dumps(details)) db.session.add(record) db.session.flush() return True return False @property def community_frozen_balance(self): from app.model.order import g_order_side from app.model.order import Order, g_order_status amount = db.session.query(db.func.sum(Order.amount)).filter( Order.user_id == self.user_id, Order.side == g_order_side.SELL, Order.status.op('&')(g_order_status.CONFIRMED | g_order_status.CANCELLED) == 0).first()[0] return amount if amount else 0
class UserBase(UuidBase): __abstract__ = True uid = db.Column(db.String(32), unique=True) # 用户ID country_code = db.Column(db.String(16)) # 国际电话区号 mobile = db.Column(db.String(16), unique=True) # 手机号 login_email = db.Column(db.String(100), unique=True) # 登录邮箱 password = db.Column(db.String(256), nullable=False) # 密码 security_password = db.Column(db.String(256)) # 安全密码 token = db.Column(db.String(256)) # 访问令牌 source = db.Column(db.String(64), default='') # 来源 locked = db.Column(db.SmallInteger, default=0) # 是否锁定: 0 未锁定 1 锁定 2 已经删除用户 @property def has_security_password(self): return 1 if self.security_password else 0 def set_uid(self): if self.uid: return try_times = 5 code = ''.join( random.sample( 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM', 3)) while try_times: try_times -= 1 code += str(random.randint(100000, 999999)) if not User.query.filter(User.uid == code).first(): self.uid = code return True try_times = 5 while try_times: try_times -= 1 code += str(random.randint(10000000, 99999999)) if not User.query.filter(User.uid == code).first(): self.uid = code return True abort(400, code=1011, message={'uid': 'uid already exists'}) def set_password(self, password): self.password = generate_password_hash(password) def verify_password(self, password): return check_password_hash(self.password, password) def set_security_password(self, password): self.security_password = generate_password_hash(password) def verify_security_password(self, password): if self.security_password is None: return False return check_password_hash(self.security_password, password) def generate_random_password(self): self.set_password(str(random.randint(100000, 999999))) def generate_auth_token(self, expiration=5 * 24 * 60 * 60): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) self.token = s.dumps({'id': self.id}) def bind_id(self, unique_id, pin_code, country_code): # 带有 @ 用 login_email # 首位字符为数字用 mobile if '@' in unique_id: if self.login_email: abort(400, code=1011, message={'login_email': 'login_email already exists'}) EmailPinCode.flask_check(unique_id, pin_code) self.login_email = unique_id elif len(unique_id) and unique_id[0].isdigit(): if self.mobile: abort(400, code=1011, message={'mobile': 'mobile already exists'}) SmsPinCode.flask_check(unique_id, pin_code) self.mobile = unique_id self.country_code = country_code def rebind_id(self, unique_id, pin_code, new_unique_id, new_pin_code, country_code): # 带有 @ 用 login_email # 首位字符为数字用 mobile if '@' in unique_id: if self.login_email != unique_id: abort(400, code=1002, message={'unique_id': 'login_email does not match'}) EmailPinCode.flask_check(unique_id, pin_code) EmailPinCode.flask_check(new_unique_id, new_pin_code) self.login_email = new_unique_id elif len(unique_id) and unique_id[0].isdigit(): if self.mobile != unique_id: abort(400, code=1002, message={'unique_id': 'mobile does not match'}) SmsPinCode.flask_check(unique_id, pin_code) SmsPinCode.flask_check(new_unique_id, new_pin_code) self.mobile = new_unique_id self.country_code = country_code @classmethod def verify_auth_token(cls, token): if not token: return None s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except SignatureExpired: return None # valid token, but expired except BadSignature: return None # invalid token user = cls.query.get(data['id']) if user and not user.locked and user.token == token: return user return None @classmethod def get_user(cls, unique_id): # 带有 @ 用 login_email # 首位字符为数字用 mobile # 其它用 uid if '@' in unique_id: user = cls.query.filter_by(login_email=unique_id).first() elif len(unique_id) and unique_id[0].isdigit(): user = cls.query.filter_by(mobile=unique_id).first() else: user = cls.query.filter_by(uid=unique_id).first() return user @classmethod def reset_password(cls, unique_id, pin_code, password): # 带有 @ 用 login_email # 首位字符为数字用 mobile user = None if '@' in unique_id: EmailPinCode.flask_check(unique_id, pin_code) user = cls.query.filter_by(login_email=unique_id).first() elif len(unique_id) and unique_id[0].isdigit(): SmsPinCode.flask_check(unique_id, pin_code) user = cls.query.filter_by(mobile=unique_id).first() if user: user.set_password(password) user.generate_auth_token() return user @classmethod def reset_security_password(cls, unique_id, pin_code, password): # 带有 @ 用 login_email # 首位字符为数字用 mobile user = None if '@' in unique_id: EmailPinCode.flask_check(unique_id, pin_code) user = cls.query.filter_by(login_email=unique_id).first() elif len(unique_id) and unique_id[0].isdigit(): SmsPinCode.flask_check(unique_id, pin_code) user = cls.query.filter_by(mobile=unique_id).first() if user: user.set_security_password(password) return user
class CaptchaPinCode(PinCodeBase): id = db.Column(db.String(36), primary_key=True)