def bind_identity(): """绑定实名信息. :request: :class:`.IdentitySchema` :response: :class:`.IdentitySchema` :reqheader Authorization: OAuth 2.0 Bearer Token :status 200: 绑定成功 :status 400: 姓名或身份证号不合法 :status 403: 绑定被拒 """ identity_schema = IdentitySchema(strict=True) result = identity_schema.load(request.get_json(force=True)) if Identity.get(request.oauth.user.id_): abort(403, '该账号已绑定身份信息,无法重复绑定') try: identity = Identity.save(user_id=request.oauth.user.id_, person_name=result.data['person_name'], person_ricn=result.data['person_ricn']) except IdentityBindingError as e: abort(403, unicode(e)) return jsonify(success=True, data=identity_schema.dump(identity).data)
def identity(): form = IdentityForm() if Identity.get(g.user.id_): return jsonify(r=False, error='您已经绑定了身份信息,无需再次绑定') if not form.validate(): return jsonify(r=False, error=u','.join(chain(*form.errors.values()))) try: Identity.save(user_id=g.user.id_, person_name=form.data['person_name'], person_ricn=form.data['person_ricn']) except IdentityBindingError as e: return jsonify(r=False, error=unicode(e)) else: return jsonify(r=True)
def mine(): """用户状况. :reqheader Authorization: OAuth 2.0 Bearer Token :status 200: 返回 :class:`~jupiter.views.api.v1.profile.ProfileSchema` """ profile_schema = ProfileSchema(strict=True) identity = Identity.get(request.oauth.user.id_) yixin_account = YixinAccount.get_by_local(request.oauth.user.id_) zw_account = ZhiwangAccount.get_by_local(request.oauth.user.id_) xm_account = XMAccount.get_by_local(request.oauth.user.id_) coupon_manager = CouponManager(request.oauth.user.id_) sxb_account = None sxb_vendor = Vendor.get_by_name(Provider.sxb) if sxb_vendor: sxb_account = NewAccount.get(sxb_vendor.id_, request.oauth.user.id_) data = { 'user': request.oauth.user, 'has_mobile_phone': bool(request.oauth.user.mobile), 'has_identity': bool(identity), 'has_yixin_account': bool(yixin_account), 'has_zw_account': bool(zw_account), 'has_xm_account': bool(xm_account), 'has_sxb_account': bool(sxb_account), 'coupon_count': len(coupon_manager.available_coupons), 'is_old_user_of_yrd': False, 'masked_person_name': identity.masked_name if identity else '', 'red_packets': g.firewood_flow.balance } return jsonify(success=True, data=profile_schema.dump(data).data)
def register_account(user_id): identity = Identity.get(user_id) local_account = Account.get(user_id) if not local_account.mobile: raise MissingMobilePhoneError if not identity: raise MissingIdentityError vendor = Vendor.get_by_name(Provider.sxb) sxb_account = SxbAccount.get_by_local(vendor.id_, user_id) if sxb_account: return sxb_account try: response = sxb.create_account(user_id=user_id, person_name=identity.person_name, id_card_no=identity.person_ricn, mobile=local_account.mobile) except BusinessError as e: raise MismatchUserError(u'%s,如有问题,请联系客服' % e) else: if not response.is_new: if not current_app.debug: rsyslog.send( u'您的身份信息(%s,%s,%s,%s) 已经被注册过,如有问题,请联系客服' % (user_id, identity.person_ricn, identity.person_name, local_account.mobile), 'sxb_dup_register') return SxbAccount.bind(vendor.id_, user_id, response.user_id)
def main(): user = Account.get_by_alias(EMAIL) if not user: user = register_without_confirm(EMAIL, 'testtest', ACCOUNT_REG_TYPE.EMAIL) bcolors.run(repr(user), key='zhiwang') # 绑定身份证和手机 user.add_alias(MOBILE_PHONE, ACCOUNT_REG_TYPE.MOBILE) identity = Identity.save(user.id_, PERSON_NAME, PERSON_RICN) bcolors.run(repr(identity), key='zhiwang') # 绑定指旺帐号 ZhiwangAccount.bind(user.id_, ZHIWANG_TOKEN) bcolors.run(repr(ZhiwangAccount.get_by_local(user.id_)), key='zhiwang') # 绑定银行卡 bankcards = BankCardManager(user.id_) with patch('core.models.profile.bankcard.DEBUG', True): bankcard = bankcards.create_or_update( mobile_phone=user.mobile, card_number=BANKCARD_NO, bank_id=BANKCARD_BANK, city_id=BANKCARD_DIVISION[:4] + u'00', province_id=BANKCARD_DIVISION[:2] + u'0000', local_bank_name=u'') bcolors.run(repr(bankcard), key='zhiwang') bcolors.run('success: %s' % EMAIL, key='zhiwang')
def register_xm_account(user_id): identity = Identity.get(user_id) local_account = Account.get(user_id) xm_account = XMAccount.get_by_local(user_id) if not local_account.mobile: raise MissingMobilePhoneError if not identity: raise MissingIdentityError if xm_account: return xm_account try: response = xinmi.create_account(user_id=user_id, person_name=identity.person_name, person_ricn=identity.person_ricn, mobile=local_account.mobile) except BusinessError as e: raise MismatchUserError(u'%s,如有问题,请联系客服' % e) else: if not response.is_new: if not current_app.debug: rsyslog.send( u'您的身份信息(%s,%s,%s,%s) 已经被注册过,如有问题,请联系客服' % (user_id, identity.person_ricn, identity.person_name, local_account.mobile), 'xm_dup_register') return XMAccount.bind(user_id, response.user_id)
def register_zhiwang_account(user_id): identity = Identity.get(user_id) local_account = Account.get(user_id) zhiwang_account = ZhiwangAccount.get_by_local(user_id) if not local_account.mobile: raise MissingMobilePhoneError if not identity: raise MissingIdentityError if zhiwang_account: return zhiwang_account try: response = zhiwang.user_create(user_id, identity.person_ricn, identity.person_name, local_account.mobile) except RemoteError as e: raise MismatchUserError(u'绑定账号失败: %s,如有问题,请联系客服' % e.args[1]) else: if not response.is_new: if not current_app.debug: rsyslog.send( u'您的身份信息(%s,%s,%s,%s) 已经被注册过,如有问题,请联系客服' % (user_id, identity.person_ricn, identity.person_name, local_account.mobile), 'zhiwang_dup_register') return ZhiwangAccount.bind(user_id, response.zw_user_code)
def reset_password_identity_verify(): """重置密码(验证身份信息) 要使用本接口, 客户端必须有权以 ``user_info`` 作为 scope. :request: :class:`.IdentityVerifySchema` :response: :class:`.IdentityVoucherSchema` :reqheader X-Client-ID: OAuth 2.0 Client ID :reqheader X-Client-Secret: OAuth 2.0 Client Secret :status 403: 身份验证失败 :status 200: 身份验证成功 """ check_identity_schema = IdentityVerifySchema(strict=True) identity_voucher_schema = IdentityVoucherSchema(strict=True) result = check_identity_schema.load(request.get_json(force=True)) confirmed_code = VerifyVoucher(result.data['uid']) if result.data['confirmed_code'] != confirmed_code.voucher: abort(403, u'未验证手机号,请先验证手机号') identity = Identity.get(result.data['uid']) if not identity: abort(403, u'未绑定身份信息') if identity.person_ricn == result.data['person_ricn']: confirmed_code.voucher = ''.join(random.sample(string.digits, 6)) identity_data = { 'confirmed_code': confirmed_code.voucher, 'uid': identity.id_, 'identity': identity } return jsonify(success=True, data=identity_voucher_schema.dump(identity_data).data) else: abort(403, u'您输入的身份证号与账户不匹配')
def xm_contract(order_id): """新米购买合同. reqheader Authorization: OAuth 2.0 Bearer Token :status 200: 返回 :class:`.XinmiContractSchema` :status 403: 获取合同失败 :status 404: 无相应产品 """ contract_schema = XinmiContractSchema(strict=True) order = obtain_xm_order(order_id) asset = XMAsset.get_by_order_code(order.order_code) if not asset or not g.xm_account: abort(401) identity = Identity.get(asset.user_id) upper_amount = num2chn(asset.create_amount) product = XMFixedDuedayProduct.get(asset.product_id) if not product: abort(404) expect_rate = 100 if product.product_type is XMFixedDuedayProduct.Type.classic: expect_rate = round_half_up( (asset.actual_annual_rate * 90 / 365 + 1) * 100, 4) if not asset: abort(403, u'资产合同正在准备中') contract = render_template('savings/agreement_xinmi.html', asset=asset, identity=identity, expect_rate=expect_rate, product_name=product.name, product_frozen_days=product.frozen_days, upper_amount=upper_amount) data = {'contract': contract} return jsonify(success=True, data=contract_schema.dump(data).data)
def test_create(self): identity = Identity.save(self.user.id_, u'张无忌', u'44011320141005001X') assert has_real_identity(self.user) assert identity and identity.id_ assert identity.id_ == self.user.id_ assert identity.person_name == u'张无忌' assert identity.person_ricn == u'44011320141005001X' assert identity.masked_name == u'**忌'
def subscribe_product(user, product_id, bankcard, buy_amount, coupon=None, pocket_deduction_amount=0): """申购产品""" #: TODO 检查礼券是否可用、返现账户抵扣是否可用、订单是否可建 product = Product.get(product_id) if not product: raise SubscribeProductError(u'申购产品失败: 找不到指定的产品') assert product.ptype == Product.Type.unlimited vendor = Vendor.get_by_name(Provider.sxb) HoarderOrder.check_before_adding(vendor, user.id_, bankcard.id_, product.id_, buy_amount) identity = Identity.get(user.id_) order_code = sxb.gen_order_id() try: response = sxb.order_apply( order_id=order_code, product_id=product.remote_id, buy_amount=buy_amount, discount_fee=pocket_deduction_amount, user_id=user.id_, province=bankcard.province_id, city=bankcard.city_id, person_name=identity.person_name, person_ricn=identity.person_ricn, mobile=bankcard.mobile_phone, bank_code=bankcard.bank.xm_id, redeem_confirm=1, bank_account=bankcard.card_number, account_name=identity.person_name) except BusinessError as e: raise SubscribeProductError(u'申购产品失败: %s' % e) finally: hoarder_order_canceling.produce(order_code, delay=ORDER_TIME_OUT_SECONDS) assert buy_amount == round_half_up(response.buy_amount, 2) # 临时性起息日跳过周六日 effect_day = product.effect_day # effect_day_unit = response.effect_day_unit 临时性只以日为单位计算起息日。 if effect_day > 0: start_date = get_work_day(delta=effect_day) else: start_date = get_next_work_day() effect_date = start_date.strftime('%Y-%m-%d %H:%M:%S') order = HoarderOrder.add( user_id=user.id_, product_id=product.id_, bankcard_id=bankcard.id_, amount=buy_amount, pay_amount=response.buy_amount, expect_interest=response.return_amount, order_code=response.order_id, pay_code=response.pay_code, direction=HoarderOrder.Direction.save, status=HoarderOrder.Status.unpaid, remote_status=response.order_status, start_time=effect_date, due_time=None ) return order
def check_identity(): if ZhiwangAccount.get_by_local(g.user.id_): if not has_real_identity(g.user): # 当用户有指旺账号却没有身份信息时跳转完善信息(基本不可能发生) return redirect(url_for('profile.auth.supply', next=request.path)) else: # 没有指旺账号则跳转注册页 return redirect(url_for('savings.auth.zhiwang', next=request.path)) g.identity = Identity.get(g.user.id_)
def pay_for_order(order): payment_time = datetime.datetime.now().strftime(YXPAY_DATETIME_FORMAT) payment_amount = round_half_up(order.calculate_profit_amount(), 2) identity = Identity.get(order.user_id) notify_url = url_for('savings.hook.yxpay_placebo_notify', _external=True) return yxpay.query.single_pay( YXPAY_ACQ_ID, order.biz_id, YXPAY_PAYMENT_TYPE, YXPAY_BUSINESS_TYPE, YXPAY_ACCOUNT_FLAG, payment_time, order.bankcard.bank.yxpay_id, payment_amount, YXPAY_INDENTITY_TYPE, identity.person_ricn, identity.person_name, order.bankcard.card_number, order.bankcard.province_id, order.bankcard.city_id, YXPAY_PAYMENT_CHANNEL_TYPE, notify_url)
def test_create_failed(self): # TODO IdentityException UnitTest with raises(IdentityValidationError): Identity.save(self.user.id_, u'张无忌' * 10, u'44011320141005001X') with raises(IdentityValidationError): Identity.save(self.user.id_, u'张无忌', u'440113201410050011') Identity.save(self.user.id_, u'张无忌', u'44011320141005001X')
def test_migrate(self, rsyslog): old_user = self.add_account('*****@*****.**', 'foobaz', 'foo') assert not Identity.get(old_user.id_) assert not has_real_identity(self.user) old_profile = OldHoardProfile.add(old_user.id_) old_profile.person_name = u'谢逊' old_profile.person_ricn = u'44011320141005001X' identity = Identity.get(old_user.id_) assert rsyslog.send.called assert identity and identity.id_ == old_user.id_ assert identity.person_name == u'谢逊' assert identity.person_ricn == u'44011320141005001X' # migrated automatically old_profile.person_name = '' old_profile.person_ricn = '' identity = Identity.get(old_user.id_) assert identity and identity.id_ == old_user.id_ assert identity.person_name == u'谢逊' assert identity.person_ricn == u'44011320141005001X'
def initialize_with_user(self, user_id): """Initializes with user and identity. :param user_id: The local account id of user. :raises RealIdentityRequiredError: if the user has not real identity. """ self.user = Account.get(user_id) self.identity = Identity.get(user_id) if not self.user: raise ProgrammingError('user %r not found' % user_id) if not has_real_identity(self.user): raise RealIdentityRequiredError(self.user)
def invite(): code = request.args.get('inviter', None) or request.cookies.get(INVITER_KEY) is_lottery = request.args.get('lottery', False) if not code: return abort(404) # 兼容已分享错误链接 rs = re.search('^(\d+).*', code) if not rs: abort(404) code = rs.group(1) user_id = transform_digit(code) if g.user: if g.user.id_ == str(user_id): if not is_lottery: return redirect(url_for('.mine')) g.firewood_flow = FirewoodWorkflow(g.user.id_) if not g.firewood_flow.account_uid: return redirect( url_for('profile.auth.supply', next=request.path)) user_lottery = UserLottery.get(g.user.id_) return render_template('activity/lottery/index.html', remain_num=user_lottery.remain_num) else: return redirect(url_for('.login')) user = Account.get(user_id) if not user: abort(404) UserLotteryNum.add_by_share(user.id_) @after_this_request def set_cookie(response): response.set_cookie(key=INVITER_KEY, value=str(code), expires=datetime.now() + timedelta(hours=INVITER_KEY_EXPIRE_HOURS)) return response identity = Identity.get(user_id) inviter_name = identity.masked_name if identity else generate_nickname( user.mobile, ACCOUNT_REG_TYPE.MOBILE) return render_template('invite/invite.html', inviter_name=inviter_name)
def test_update(self): assert not Identity.get(self.user.id_) assert not has_real_identity(self.user) Identity.save(self.user.id_, u'张无忌', u'44011320141005001X') Identity.save(self.user.id_, u'谢逊', u'360426199101010071') identity = Identity.get(self.user.id_) assert has_real_identity(self.user) assert identity and identity.id_ assert identity.id_ == self.user.id_ assert identity.person_name == u'谢逊' assert identity.person_ricn == u'360426199101010071' assert identity.masked_name == u'*逊'
def asset_contract(asset_no): asset = XMAsset.get_by_asset_no(asset_no) if not asset or not asset.is_owner(g.user): abort(401) identity = Identity.get(asset.user_id) upper_amount = num2chn(asset.create_amount) product = XMFixedDuedayProduct.get(asset.product_id) if not product: abort(404) expect_rate = 100 if product.product_type is XMFixedDuedayProduct.Type.classic: expect_rate = round_half_up( (asset.annual_rate * product.frozen_days / 365 + 1) * 100, 4) return render_template('savings/agreement_xinmi.html', asset=asset, identity=identity, expect_rate=expect_rate, product_name=product.name, product_frozen_days=product.frozen_days, upper_amount=upper_amount)
def reset_password_sms_verify(): """重置密码(验证短信验证码) 要使用本接口, 客户端必须有权以 ``user_info`` 作为 scope. :request: :class:`.ResetPasswordSmsVerifySchema` :response: :class:`.IdentityVoucherSchema` :reqheader X-Client-ID: OAuth 2.0 Client ID :reqheader X-Client-Secret: OAuth 2.0 Client Secret :status 403: 验证码错误或账号不存在 :status 200: 验证通过 """ reset_password_sms_verify_schema = ResetPasswordSmsVerifySchema( strict=True) identity_voucher_schema = IdentityVoucherSchema(strict=True) result = reset_password_sms_verify_schema.load( request.get_json(force=True)) user = Account.get_by_alias(result.data['mobile_phone']) if not user: abort(403, u'账号不存在') try: v = Verify.validate(user.id_, result.data['sms_code'], VERIFY_CODE_TYPE.FORGOT_PASSWORD_MOBILE) v.delete() identity = Identity.get(user.id_) confirmed_code = VerifyVoucher(user.id_) confirmed_code.voucher = ''.join(random.sample(string.digits, 6)) data = { 'confirmed_code': confirmed_code.voucher, 'uid': user.id_, 'masked_name': identity } return jsonify(success=True, data=identity_voucher_schema.dump(data).data) except VerifyCodeException as e: abort(403, unicode(e))
def award(self): """向手机号对应用户发放礼包""" if self.is_awarded: return # lock it sql = 'select is_awarded from {.table_name} where mobile_phone = %s for update'.format(self) params = (self.mobile_phone,) rs = db.execute(sql, params) if rs and rs[0][0]: db.rollback() # release lock return try: user = Account.get_by_alias(self.mobile_phone) sql = 'update {.table_name} set is_awarded=%s where id=%s'.format(self) params = (True, self.id_) db.execute(sql, params) except: db.rollback() # release lock raise else: db.commit() self.is_awarded = True # distribute package and record package = distribute_welfare_gift( user, self.rank.award, allow_piling_firewood=bool(Identity.get(user.id_))) sql = 'update {.table_name} set awarded_package_id=%s where id=%s'.format(self) params = (package.id_, self.id_) db.execute(sql, params) db.commit() self.clear_cache(self.id_) self.clear_cache_by_mobile_phone(self.mobile_phone)
def identity(sqlstore, redis, user): identity = Identity.get_by_ricn('13112319920611251X') if not identity: identity = Identity.save(user.id_, '李延宗', '13112319920611251X') user.add_alias('13800138001', ACCOUNT_REG_TYPE.MOBILE) return identity
def identity(self): return Identity.get(g.user.id_)
def test_get_nothing(self): assert not Identity.get(self.user.id_)
def subscribe_product(user, product, bankcard, order_amount, pay_amount, due_date=None, coupon=None, pocket_deduction_amount=0): """申购产品""" # 检查礼券是否可用、返现账户抵扣是否可用、订单是否可建 if coupon: coupon.check_before_use(product, order_amount) if pocket_deduction_amount > 0: FirewoodWorkflow(user.id_).check_deduction_enjoyable( product, order_amount, pocket_deduction_amount) XMOrder.check_before_adding(user.id_, bankcard.id_, product.product_id, order_amount) # 获取订单优惠信息并检查合法性 hike_list = collect_profit_hikes(user, coupon, pocket_deduction_amount) rate_bonus = max([h.annual_rate for h in hike_list]) if hike_list else Decimal('0') discount_fee = sum([h.deduction_amount for h in hike_list]) assert rate_bonus < Decimal('5.0') # 新米最高加息限制 assert order_amount - discount_fee == pay_amount # 新米使用加息券需要在赎回确认里加入 redeem_confirm = u'1' if rate_bonus > Decimal('0.0') else None rate_fee = float(order_amount * rate_bonus * product.frozen_days / 100 / 365) order_code = XMOrder.gen_order_code() xm_cancel_order_prepare.produce(order_code, delay=TIME_OUT_SECONDS) identity = Identity.get(user.id_) buy_amount = order_amount try: # 向投米发起申购请求 if DEBUG: # 测试环境要求 购买金额x100后为偶数 => 购买成功,否则失败。 if int(buy_amount) % 2 != 0: buy_amount += round_half_up(0.01, 2) buy_amount = round_half_up(buy_amount, 2) response = xinmi.order_apply(product_id=product.product_id, order_id=order_code, buy_amount=buy_amount, discount_fee=discount_fee, user_id=user.id_, province=bankcard.province_id, city=bankcard.city_id, person_name=identity.person_name, person_ricn=identity.person_ricn, mobile=bankcard.mobile_phone, bank_code=bankcard.bank.xm_id, bank_account=bankcard.card_number, account_name=identity.person_name, redeem_confirm=redeem_confirm) except BusinessError as e: raise SubscribeProductError(u'申购产品失败: %s' % e) assert buy_amount == round_half_up(response.buy_amount, 2) if product.product_type == XMProduct.Type.classic: due_date = get_next_work_day( response.buy_time) + datetime.timedelta(days=product.frozen_days) # 创建订单 order = XMOrder.add(user_id=user.id_, product_id=product.product_id, bankcard_id=bankcard.id_, amount=buy_amount, pay_amount=response['total_amount'], expect_interest=response.return_amount + rate_fee, start_date=get_next_work_day(response.buy_time), due_date=due_date, order_code=order_code, pay_code=response.pay_code) # 创建优惠记录 for hike in hike_list: # FIXME: the operation of hikes should be managed in one session Hike.add(user.id_, order.id_, hike.kind, hike.annual_rate, hike.deduction_amount) # 订单预绑定礼券 if coupon: CouponUsageRecord.add(coupon, user, provider_xinmi, order) # 创建抵扣使用记录 if pocket_deduction_amount > 0: FirewoodBurning.add(user, pocket_deduction_amount, FirewoodBurning.Kind.deduction, provider_xinmi, order.id_) return order
def settings(): mobile = g.user.display_mobile identity = Identity.get(g.user.id_) return render_template('accounts/settings.html', mobile=mobile, identity=identity)
def add_identity(self, user_id, person_name, person_ricn): from core.models.profile.identity import Identity return Identity.save(user_id, person_name, person_ricn)
def test_create_by_old_user(self): Identity.save(self.old_user.id_, u'张无忌', u'44011320141005001X') assert not has_real_identity(self.user)
def test_remove(self): Identity.save(self.user.id_, u'张无忌', u'44011320141005001X') identity = Identity.get(self.user.id_) assert identity.person_name == u'张无忌' Identity.remove(self.user.id_) assert not Identity.get(self.user.id_)
def _identity(self): return Identity.get(self.account_id)