예제 #1
0
class UserBankDelete(Resource):
    method_decorators = admin_decorators

    @ns.expect(UserBankInfo)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        用户银行信息编辑
        """
        form, error = UserBankDeleteForm().request_validate()
        if error:
            return error.as_response()

        print(form.card_id, "****************", form.card_id.data)
        card_id = form.card_id.data

        # 判断该用户银行卡 信息是否存在
        card_entry = BankCard.query.filter_by(
            **dict(id=card_id, valid=1)).first()
        if not card_entry:
            return AdjustUserBalanceError(message="card_id 不存在").as_response()

        BankCard.delete_bankcard_by_card_id(card_id=card_id)

        return ResponseSuccess().as_response()
예제 #2
0
class OrderStateNotifyResource(Resource):
    method_decorators = merchant_decorators

    @ns.expect(OrderStateNotifyDoc)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        给商户发通知
        :return:
        """
        form, error = OrderStateNotifyFrom().request_validate()
        if error:
            return error.as_response()

        order_id = str(form.order_id.data)
        if form.type.data == PayTypeEnum.WITHDRAW:
            order = WithdrawTransactionCtl.get_order(order_id)
            rst = WithdrawTransactionCtl.do_notify(order=order,
                                                   op_account=g.user.account,
                                                   comment="商户后台手动通知")
        elif form.type.data == PayTypeEnum.DEPOSIT:
            order = DepositTransactionCtl.get_order(order_id)
            rst = DepositTransactionCtl.do_notify(
                order=order,
                op_account=g.user.account,
                comment="商户后台手动通知",
            )

        return ResponseSuccess(message=rst['msg'])
예제 #3
0
class OrderManuallyDone(Resource):
    method_decorators = admin_decorators

    @ns.expect(OrderIdCommentDoc)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        人工完成充值订单
        :return:
        """
        form, error = OrderIdCommentForm().request_validate()
        if error:
            return error.as_response()

        order_id = form.order_id.data
        g_order_id = GlobalOrderId.query_global_id(order_id)

        order = OrderDeposit.query_by_order_id(merchant=g_order_id.merchant,
                                               order_id=order_id)

        if DepositTransactionCtl.success_order_process(
                order,
                order.amount,
                comment=form.comment.data,
                op_account=g.user.account):
            return ResponseSuccess(message="处理成功")
        else:
            return ResponseSuccess(message="处理失败")
예제 #4
0
class WithdrawPersonDone(Resource):
    method_decorators = admin_decorators

    @ns.expect(WithDrawPersonExecuteDoneParams)
    @ns.marshal_with(ResponseSuccess.gen_doc(api), as_list=True)
    def post(self):
        """
        运营确定出款成功
        :return:
        """
        form, error = WithDrawPersonExecutedDoneForm().request_validate()
        if error:
            return error.as_response()

        fee = form.fee.data if form.fee.data else "0"
        comment = form.comment.data

        rsp = WithdrawTransactionCtl.manually_withdraw_success(
            admin_user=g.user,
            merchant=form.merchant.data,
            order_id=form.order_id.data,
            channel_cost=fee,
            comment=comment,
        )

        return rsp.as_response()
예제 #5
0
class ResetPassword(Resource):
    method_decorators = admin_decorators

    # 请求数据格式
    @ns.expect(AdminResetPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        修改登录密码
        :return:
        """
        # 格式验证
        form, error = ResetWordForm().request_validate()
        if error:
            return error.as_response()

        # 获取用户ID
        uid = g.user.uid

        if not AdminUser.verify_password(uid=uid, password=form.ori_password.data):
            return PasswordError().as_response()

        if AdminUser.verify_password(uid=uid, password=form.new_password.data):
            return RePasswordError().as_response()

        flag = AdminUser.reset_password(
            uid=uid,
            login_pwd=form.new_password.data
        )
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #6
0
class ForgetPasswordVerifyAuth(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 请求数据格式
    @ns.expect(MobileAuthCode)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --验证验证码
        :return:
        """
        # 用户手机号格式验证
        form, error = AuthCodeTrueForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        return ResponseSuccess().as_response()
예제 #7
0
class AuthUsername(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    @ns.expect(MobileNumber)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
            检查手机号是否已经注册
        """
        form, error = MobileRegisterCheckForm().request_validate()
        if error:
            return error.as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        return ResponseSuccess().as_response()
예제 #8
0
class SMSCodeAuthentication(Resource):

    method_decorators = [limiter.limit("1/second"), ]

    # 期待客户端请求的数据模型,使用expect来装饰
    @ns.expect(MobileAuthCode)
    # 给客户端返回的的响应数据模型,使用marshal_with来装饰
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        验证短信动态验证码
        """
        # 验证表单手机号及验证码格式验证
        form, error = AuthCodeForm.request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(form.auth_code.data):
            return AuthCodeError().as_response()

        return ResponseSuccess().as_response()
예제 #9
0
class PaymentPasswordForgetSet(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(SetForgetPaymentPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记支付密码,重置支付密码
        """
        """
        检查验证码
        判断是否存在支付密码
        设置新的支付密码
        """

        form, error = SetForgetPaymentPasswordForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        # 判断是否存在支付密码
        user = User.query_user(form.merchant.data, uid)

        if not user.trade_pwd:
            return PaymentPwdNotExistError().as_response()

        # 设置新的支付密码
        flag = User.set_payment_password(
            form.merchant.data,
            uid=uid,
            trade_pwd=form.new_payment_password.data)

        # 设置失败的情况
        if not flag:
            return NoSourceError().as_response()

        try:
            # 清理掉支付密码输入错误的次数记录
            cache = UserPaymentPasswordLimitCache(uid=uid)

            # 密码设置成功 删除密码输入错误记录
            cache.delete_cache()
        except:
            pass

        return ResponseSuccess().as_response()
예제 #10
0
class PaymentPasswordCheck(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(PaymentPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        校验支付密码
        """
        """
        判断是否设置了支付密码
        校验支付密码
        """

        form, error = SetPaymentPassword().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        # 判断是否存在支付密码
        user = User.query_user(form.merchant.data, uid)

        if not user.trade_pwd:
            return PaymentPwdNotExistError().as_response()

        cache = UserPaymentPasswordLimitCache(uid=uid)
        # 获取支付密码输入错误次数是否达到上限
        if cache.is_limited():
            return PaymentPasswordLimitedError().as_response()

        flag = User.verify_payment_password(
            form.merchant.data, uid=uid, password=form.payment_password.data)

        # 交易密码校验失败
        if not flag:
            cache.incr_times()
            times = cache.get_left_times()
            # 获取支付密码输入错误次数是否达到上限(多判断一次 防止出现剩余0次的情况)
            if cache.is_limited():
                return PaymentPasswordLimitedError().as_response()
            return PaymentPasswordError(message=PaymentPasswordError.message.
                                        format(times)).as_response()

        # 密码校验成功 删除密码输入错误记录
        cache.delete_cache()

        return ResponseSuccess().as_response()
예제 #11
0
class BankCardDelete(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(BankCardDeleteParams)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        删除用户银行卡
        """
        """
        校验老的支付密码
        删除银行卡
        """

        form, error = DeleteBankCardForm().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        # 获取支付密码输入错误次数是否达到上限
        if UserPaymentPasswordLimitCache(uid=uid).is_limited():
            return PaymentPasswordLimitedError().as_response()

        # 校验支付密码
        flag = User.verify_payment_password(
            form.merchant.data, uid=uid, password=form.payment_password.data)

        # 交易密码校验失败
        if not flag:
            UserPaymentPasswordLimitCache(uid=uid).incr_times()
            return PaymentPasswordError().as_response()

        # 密码校验成功 删除密码输入错误记录
        UserPaymentPasswordLimitCache(uid=uid).delete_cache()

        # 查询银行卡信息
        bank_card = BankCard.query_bankcard_by_id(form.bank_card_id.data)
        if bank_card is None:
            return BankCardNotExistError().as_response()

        if uid != bank_card.uid:
            return BankCardNotMeError().as_response()

        BankCard.delete_bankcard_by_card_no(form.merchant.data,
                                            card_no=bank_card.card_no)

        return ResponseSuccess().as_response()
예제 #12
0
class ClientLogout(Resource):
    method_decorators = merchant_decorators

    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        商户后台 登出
        :return:
        """
        # current_app.logger.debug('logout, path: %s, uid: %s', request.path, g.user.uid)

        # 记录登录状态
        MerchantLoginToken.remove_token(g.user.mid)

        return ResponseSuccess().as_response()
예제 #13
0
class UserRegisterAccount(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(PassWordAuthCode)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        手机号码注册
        :return:
        """
        # 验证 手机号 验证码  密码格式
        form, error = PasswordForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.DEPOSIT,
        )):
            return MerchantConfigDepositError().as_response()

        if not MerchantFeeConfig.query_latest_one(query_fields=dict(
                merchant=form.merchant.data,
                payment_way=PayTypeEnum.WITHDRAW,
        )):
            return MerchantConfigWithdrawError().as_response()

        User.register_account(
            merchant=form.merchant.data,
            account=form.number.data,
            ac_type=AccountTypeEnum.MOBILE,
            login_pwd=form.password.data,
        )

        return ResponseSuccess().as_response()
예제 #14
0
class ResetPasswordVerify(Resource):
    method_decorators = cashier_decorators

    # 请求数据格式
    @ns.expect(ResetPasswordVerify)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        修改密码  验证原始密码是否正确
        :return:
        """

        # 用户手机号格式验证
        form, error = ResetWordVerify().request_validate()
        if error:
            return error.as_response()

        # 获取用户信息
        user = g.user

        # 判断当前用户状态是否为 INACTIVE 如果是则返回错误信息
        if not user.is_active:
            return DisableUserError().as_response()

        # 验证原始密码是否正确
        if not User.verify_password(merchant=form.merchant.data,
                                    uid=user.uid,
                                    password=form.ori_password.data):
            # 密码输入错误 则将密码输入错误次数 + 1 返回密码有误 信息
            UserPasswordLimitCache(user.account).incr_times()

            # 判断用户当天密码错误次数是否达到上限 如果达到上限 更改账户状态 返回错误
            if UserPasswordLimitCache(user.account).is_limited():
                User.update_user_state(user.merchant,
                                       account=user.account,
                                       state=AccountStateEnum.INACTIVE)
                return OriPasswordError().as_response()

            return PasswordError().as_response()

        # 如果密码输入次数未达上限 且密码验证成功则删除缓存数据
        UserPasswordLimitCache(user.account).delete_cache()

        return ResponseSuccess().as_response()
예제 #15
0
class WithdrawOrderCreate(Resource):
    method_decorators = cashier_decorators

    # 相应数据格式 前端传入用户 提现金额,用户所选的银行卡 标示号, 支付密码
    @ns.expect(WithdrawRequestDoc)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        提现接口: 检查支付密码是否正确,如果密码正确则创建用户提现订单
        """
        form, error = CreateWithdrawOrderForm().request_validate()
        if error:
            return error.as_response()

        uid = g.user.uid
        merchant = g.user.merchant

        if not g.user.has_permission(UserPermissionEnum.WITHDRAW):
            return UserPermissionDeniedError().as_response()

        amount = BalanceKit.round_4down_5up(Decimal(form.amount.data))
        user_bank_id = form.user_bank.data
        client_ip = form.client_ip.data
        trade_password = form.trade_password.data

        # 判断 支付密码是否正确
        if not User.verify_payment_password(
                merchant=merchant, uid=uid, password=trade_password):
            cache = UserPaymentPasswordLimitCache(uid=uid)
            cache.incr_times()
            times = cache.get_left_times()
            return PaymentPasswordError(message=PaymentPasswordError.message.
                                        format(times)).as_response()

        order, error = WithdrawTransactionCtl.order_create(
            user=g.user,
            amount=amount,
            client_ip=client_ip,
            user_bank_id=user_bank_id,
        )
        if error:
            return error.as_response()

        return ResponseSuccess().as_response()
예제 #16
0
class ForgetPasswordGetAuth(Resource):
    method_decorators = [
        limiter.limit("1/10"),
    ]

    # 请求数据格式
    @ns.expect(MobileNumber)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --验证手机号,获取验证码
        :return:
        """
        # 用户手机号格式验证
        form, error = MobileRegisterTrueCheckForm().request_validate()
        if error:
            return error.as_response()

        # 首先获取当日是否已发送过验证码
        if AuthCodeLimiter(form.number.data).is_limited():
            return AuthCodeTimesLimitError().as_response()

        # 生成验证码
        code = AuthCodeGenerator(form.number.data).generate_code()

        current_app.logger.info('code generated success, code: %s', code)
        # print('code: %s' % code)

        # 将验证码以短信方式发送到用户手机
        try:
            if not current_app.config['DEBUG']:
                from app.services.celery.sms import async_send_auth_code
                async_send_auth_code.delay(phone=form.number.data, code=code)
        except:
            current_app.config['SENTRY_DSN'] and current_app.logger.fatal(
                traceback.format_exc())

        # 验证码发送成功后,发送次数+1
        AuthCodeLimiter(form.number.data).incr_times()

        return ResponseSuccess().as_response()
예제 #17
0
class WithdrawLaunch(Resource):
    method_decorators = admin_decorators

    @ns.expect(WithDrawChannelAllowed)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        运营发起确认对订单的提现,向第三方发起提现请求
        :return:
        """
        form, error = WithdrawOrderPerformForm().request_validate()
        if error:
            return error.as_response()

        merchant = form.merchant.data
        order_id = form.order_id.data
        channel_id = form.channel_id.data
        rst = WithdrawTransactionCtl.order_deal(g.user.account, order_id,
                                                merchant, channel_id)
        return rst.as_response()
예제 #18
0
class AllowedOrderResource(Resource):
    method_decorators = admin_decorators

    @ns.expect(AllowedOrder)
    @ns.marshal_with(ResponseSuccess.gen_doc(api), as_list=True)
    def post(self):
        """
        提现订单: 运营人员认领订单
        :return:
        """
        form, error = WithDrawOrderAllowedForm().request_validate()
        if error:
            return error.as_response()

        order_id = form.order_id.data
        merchant = form.merchant_name.data

        rst = WithdrawTransactionCtl.order_alloc(g.user.account, order_id,
                                                 merchant)
        return rst.as_response()
예제 #19
0
class PaymentPasswordSet(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(PaymentPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        设置支付密码
        """
        """
        判断密码是否是6位纯数字
        判断密码是否是连续的
        判断是否存在支付密码
        写入支付密码到数据库
        """

        form, error = SetPaymentPassword().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        # 判断是否存在支付密码
        user = User.query_user(form.merchant.data, uid)

        if user.trade_pwd:
            return PaymentPwdNotExistError().as_response()

        # 设置支付密码
        flag = User.set_payment_password(form.merchant.data,
                                         uid=uid,
                                         trade_pwd=form.payment_password.data)

        # 设置失败的情况
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #20
0
class WithdrawRefuseReimburse(Resource):
    method_decorators = admin_decorators

    @ns.expect(WithDrawPersonExecuteParams)
    @ns.marshal_with(ResponseSuccess.gen_doc(api), as_list=True)
    def post(self):
        """
        拒绝提现 或 提现失败
        :return:
        """
        form, error = WithDrawBankForm().request_validate()
        if error:
            return error.as_response()

        rsp = WithdrawTransactionCtl.manually_withdraw_failed(
            admin_user=g.user,
            merchant=form.merchant.data,
            order_id=form.order_id.data,
        )

        return rsp.as_response()
예제 #21
0
class ClientRegister(Resource):
    method_decorators = [
        check_ip_in_white_list(MERCHANT_ADMIN_IP_LIST),
        limiter.limit("1/second")
    ]

    @ns.expect(MerchantRegister)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        商户后台 注册
        """
        form, error = MerchantLoginForm().request_validate()
        if error:
            return error.as_response()

        merchant_enum = form.account.data
        user = MerchantUser.register_account(mid=merchant_enum.value,
                                             account=merchant_enum.name,
                                             password=form.password.data)
        if user:
            return ResponseSuccess().as_response()
예제 #22
0
class GatewayDemoNotify(Resource):

    @ns.expect(DocOrderNotify)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        发货通知,由商户实现
        :return:
        """
        if not EnvironEnum.is_local_evn(current_app.config['FLASK_ENV']):
            # 无论如何都记录一条log
            current_app.logger.info('path: %s, ip: %s, args: %s, data: %s',
                                     url_for("gateway_demo_notify"), IpKit.get_remote_ip(), request.args,
                                     request.json)

        form, error = DepositNotifyForm.request_validate()
        if error:
            return error.as_response()

        checker = GatewayFormChecker(form.merchant_id.data)

        # 1. IP白名单校验
        if not checker.verify_ip(form.client_ip.data):
            current_app.logger.error('msg: %s, ip: %s, white ips: %s', GatewayIPError.message, IpKit.get_remote_ip(),
                                     checker.get_white_ips())
            return GatewayIPError().as_response()

        # 2. 签名校验
        sign_fields = form.get_sign_fields()
        if not checker.verify_sign(form.sign.data, sign_fields):
            current_app.logger.error('msg: %s, sign: %s, fields: %s, sign_str: %s',
                                     GatewaySignError.message, form.sign.data, sign_fields,
                                     checker.get_sign_str(sign_fields))
            return GatewaySignError().as_response()

        # 商户自己的业务逻辑处理
        current_app.logger.info('notify success: %s', form.json_data)

        return ResponseSuccess().as_response()
예제 #23
0
class SMSCodeGenerator(Resource):
    # 验证码的发送要限速
    method_decorators = [limiter.limit("1/10")]

    # 期待客户端请求的数据模型,使用expect来装饰
    @ns.expect(MobileNumber)
    # 给客户端返回的的响应数据模型,使用marshal_with来装饰
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        获取短信动态验证码
        """
        # 用户手机号格式验证
        form, error = MobileRegisterCheckForm().request_validate()
        if error:
            return error.as_response()

        # 首先获取当日是否已发送过验证码
        if AuthCodeLimiter(form.number.data).is_limited():
            return AuthCodeTimesLimitError().as_response()

        # 生成验证码
        code = AuthCodeGenerator(form.number.data).generate_code()

        # current_app.logger.info('code generated success, code: %s', code)

        # 将验证码以短信方式发送到用户手机
        try:
            if not current_app.config['DEBUG'] or current_app.config['TESTING']:
                from app.services.celery.sms import async_send_auth_code
                async_send_auth_code.delay(phone=form.number.data, code=code)
        except:
            current_app.config['SENTRY_DSN'] and current_app.logger.fatal(traceback.format_exc())

        # 验证码发送成功后,发送次数+1
        AuthCodeLimiter(form.number.data).incr_times()

        return ResponseSuccess().as_response()
예제 #24
0
class ForgetPasswordReset(Resource):
    method_decorators = [
        limiter.limit("1/second"),
    ]

    # 请求数据格式
    @ns.expect(PassWordAuthCode)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        忘记密码 --设置新密码
        :return:
        """
        # 用户手机号格式验证
        form, error = PasswordTrueForm().request_validate()
        if error:
            return error.as_response()

        # 判断验证码是否过期
        if AuthCodeGenerator(form.number.data).is_expired(form.auth_code.data):
            return AuthCodeExpiredError().as_response()

        # 判断验证码是否正确
        if not AuthCodeGenerator(form.number.data).verify_code(
                form.auth_code.data):
            return AuthCodeError().as_response()

        User.reset_password(form.merchant.data,
                            account=form.number.data,
                            login_pwd=form.password.data)

        UserPasswordLimitCache(form.number.data).delete_cache()
        User.update_user_state(merchant=form.merchant.data,
                               account=form.number.data,
                               state=AccountStateEnum.ACTIVE)

        return ResponseSuccess().as_response()
예제 #25
0
class ResetPassword(Resource):
    method_decorators = cashier_decorators

    # 请求数据格式
    @ns.expect(ResetPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        修改密码
        :return:
        """

        # 用户手机号格式验证
        form, error = ResetWordForm().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        if not User.verify_password(merchant=form.merchant.data,
                                    uid=uid,
                                    password=form.ori_password.data):
            return PasswordError().as_response()

        if User.verify_password(merchant=form.merchant.data,
                                uid=uid,
                                password=form.new_password.data):
            return RePasswordError().as_response()

        flag = User.reset_password(form.merchant.data,
                                   uid=uid,
                                   login_pwd=form.new_password.data)
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #26
0
class PaymentPasswordReset(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(ResetPaymentPassword)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        修改支付密码
        """
        """
        判断两次的密码是否相同
        判断是否存在支付密码
        校验老的支付密码
        设置新的支付密码
        """

        form, error = ResetPaymentPasswordForm().request_validate()
        if error:
            return error.as_response()

        # 判断两次的密码是否相同
        if form.ori_payment_password.data == form.new_payment_password.data:
            return PaymentPwdResetSameError().as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        # 判断是否存在支付密码
        user = User.query_user(form.merchant.data, uid)

        if not user.trade_pwd:
            return PaymentPwdNotExistError().as_response()

        cache = UserPaymentPasswordLimitCache(uid=uid)

        # 获取支付密码输入错误次数是否达到上限
        if cache.is_limited():
            return PaymentPasswordLimitedError().as_response()

        # 校验支付密码
        flag = User.verify_payment_password(
            form.merchant.data,
            uid=uid,
            password=form.ori_payment_password.data)

        # 交易密码校验失败
        if not flag:
            cache.incr_times()
            times = cache.get_left_times()
            return PaymentPasswordError(message=PaymentPasswordError.message.
                                        format(times)).as_response()

        # 密码校验成功 删除密码输入错误记录
        cache.delete_cache()

        # 设置新的支付密码
        flag = User.set_payment_password(
            form.merchant.data,
            uid=uid,
            trade_pwd=form.new_payment_password.data)

        # 设置失败的情况
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #27
0
class BankCardAdd(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(BankCardParams)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        给用户添加银行卡
        """
        """
        判断是否达到了8张银行卡的限制
        读取用户之前的银行卡信息
        如果存在需要判断开户人跟之前的一致
        判断卡号是否已经存在了
        写入数据库
        """

        form, error = CreateBankCardForm().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid
        merchant = g.user.merchant

        if not g.user.has_permission(UserPermissionEnum.BINDCARD):
            return UserPermissionDeniedError().as_response()

        # 获取支付密码输入错误次数是否达到上限
        if UserPaymentPasswordLimitCache(uid=uid).is_limited():
            return PaymentPasswordLimitedError().as_response()

        # 校验支付密码
        flag = User.verify_payment_password(
            form.merchant.data, uid=uid, password=form.payment_password.data)

        # 交易密码校验失败
        if not flag:
            UserPaymentPasswordLimitCache(uid=uid).incr_times()
            return PaymentPasswordError().as_response()

        # 密码校验成功 删除密码输入错误记录
        UserPaymentPasswordLimitCache(uid=uid).delete_cache()

        # 判断是否达到了8张银行卡的限制
        bank_card_list = BankCard.query_bankcards_by_uid(merchant, uid)
        bank_card_num = len(bank_card_list)
        if bank_card_num > USER_BANK_CARD_NUM_LIMIT:
            return BankCardNumLimitedError().as_response()

        account_name = form.account_name.data
        # 如果存在需要判断开户人跟之前的一致
        if bank_card_num > 0:
            account_name = bank_card_list[0]['account_name']

        if account_name != form.account_name.data:
            return BankCardAccountNameError().as_response()

        # 判断卡号是否已经存在了
        bank_card_info = BankCard.query_bankcard_by_card_no(
            merchant, form.card_no.data)
        if bank_card_info is not None:
            return BankCardExistError().as_response()

        # 写入数据库
        flag = BankCard.add_bank_card(
            merchant,
            uid=uid,
            bank_name=form.bank_name.data,
            bank_code=form.bank_code.data,
            card_no=form.card_no.data,
            account_name=form.account_name.data,
            branch=form.branch.data,
            province=form.province.data,
            city=form.city.data,
        )

        # 设置失败的情况
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #28
0
class CreateDepositOrder(Resource):
    method_decorators = admin_decorators

    # 期望的参数
    @ns.expect(CreateDepositOrderParams)
    @ns.marshal_with(ResponseSuccess.gen_doc(api), as_list=True)
    def post(self):
        """
        手动补单
        :return:
        """
        form, error = CreateDepositOrderForm().request_validate()
        if error:
            return error.as_response()
        '''
        根据商户查询用户是否存在
        构造数据
        创建充值订单
        更改订单状态为完成
        '''
        # 根据商户查询用户是否存在
        user = User.query_user(form.merchant.data, uid=form.uid.data)
        if not user:
            return AccountNotExistError().as_response()

        # 构造数据
        client_ip = form.client_ip.data
        channel_enum = form.channel_id.data
        payment_type = form.payment_type.data
        amount = Decimal(form.amount.data)

        # 判断当前传入的支付类型是否该渠道支持
        if payment_type != channel_enum.conf['payment_type']:
            return InvalidDepositPaymentTypeError()

        merchant = form.merchant.data

        # 找出最新版本的商户费率配置
        channel_config = ChannelConfig.query_latest_one(query_fields=dict(
            channel_enum=channel_enum))
        if not channel_config:
            return InvalidDepositChannelError().as_response()

        if not channel_config.is_channel_valid(merchant.is_test):
            return ChannelNoValidityPeriodError().as_response()

        if ChannelListHelper.is_amount_out_of_range(
                amount=amount,
                merchant=merchant,
                payment_way=PayTypeEnum.DEPOSIT,
                client_ip=client_ip):
            return DepositOrderAmountInvalidError().as_response()

        # limit_min, limit_max = ChannelLimitCacheCtl(
        #     PayTypeEnum.DEPOSIT).get_channel_limit()
        # try:
        #     if limit_min > amount or limit_max < amount:
        #         return DepositOrderAmountInvalidError().as_response()
        # except Exception as e:
        #     return MustRequestDepositLimitError().as_response()

        # 找出最新版本的商户费率配置
        merchant_fee = MerchantFeeConfig.query_latest_one(
            query_fields=dict(merchant=merchant,
                              payment_way=PayTypeEnum.DEPOSIT,
                              payment_method=channel_enum.conf.payment_method))

        if not merchant_fee:
            return MerchantConfigDepositError().as_response()

        try:
            with db.auto_commit():
                # 创建待支付订单
                order, _ = OrderCreateCtl.create_order_event(
                    uid=user.uid,
                    merchant=merchant,
                    amount=amount,
                    channel_id=channel_config.channel_id,
                    mch_fee_id=merchant_fee.config_id,
                    order_type=PayTypeEnum.DEPOSIT,
                    source=OrderSourceEnum.MANUALLY,
                    in_type=InterfaceTypeEnum.CASHIER_H5,
                    ip=client_ip,
                    pay_method=channel_enum.conf.payment_method,
                    op_account=g.user.account,  # 后台管理员账号,后台人工修改数据时必填
                    comment=form.remark.data,  # 管理后台修改备注,后台人工修改数据时必填
                    mch_tx_id=form.mch_tx_id.data,
                    commit=False,
                )
                if not order:
                    raise Exception('order create failed')

                # 支付成功
                if not DepositTransactionCtl.success_order_process(
                        order=order,
                        tx_amount=amount,
                        channel_tx_id=form.mch_tx_id.data,
                        comment="手动补单订单",
                        commit=False,
                ):
                    raise Exception('order process failed')
        except Exception as e:
            if str(e).find("Duplicate entry") >= 0:
                return PreOrderCreateError(message="商户订单号重复: {}".format(
                    form.mch_tx_id.data)).as_response()
            return PreOrderCreateError(message=str(e)).as_response()

        return ResponseSuccess().as_response()
예제 #29
0
class Transfer(Resource):
    method_decorators = cashier_decorators

    # 期待客户端请求数据模型, 用response 来装饰
    @ns.expect(TransferParam)
    # 相应数据格式
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        转账
        判断接受转账的用户是否存在
        判断是否存在支付密码
        校验老的支付密码
        判断余额是否足够
        执行转账操作
        """

        form, error = TransferForm().request_validate()
        if error:
            return error.as_response()

        # 从全局变量中取出用户ID,参考:verify_credential
        uid = g.user.uid

        if not g.user.has_permission(UserPermissionEnum.TRANSFER):
            return UserPermissionDeniedError().as_response()

        # 判断接受转账的用户是否存在
        bind_user = UserBindInfo.query_bind(form.merchant.data,
                                            form.number.data)
        if not bind_user:
            # 未绑定账号,验证手机号码是否正确
            account = form.join_phone_number()
            if not account:
                return AccountNotExistError(message="您输入的账号不存在").as_response()
            form.number.data = account
        else:
            # 使用绑定的手机号码
            form.number.data = bind_user.account

        user_info = User.query_user(form.merchant.data,
                                    account=form.number.data)
        if not user_info:
            return AccountNotExistError(message="账号(%s)不存在" %
                                        form.number.data).as_response()

        no_transfer_limit = UserBindInfo.query_bind_by_uid(user_info.uid)
        if not no_transfer_limit and form.amount.data > TRANSFER_AMOUNT_LIMIT:
            # 非绑定用户转账限额检查
            return UserPermissionDeniedError(
                message="单次转账额度不能超过%s" % TRANSFER_AMOUNT_LIMIT).as_response()

        # 判断是否是给自己转账
        if uid == user_info.uid:
            return TransferToMeError().as_response()

        # 判断是否存在支付密码
        user = User.query_user(form.merchant.data, uid)

        if not user.trade_pwd:
            return PaymentPwdNotExistError().as_response()

        cache = UserPaymentPasswordLimitCache(uid=uid)

        # 获取支付密码输入错误次数是否达到上限
        if cache.is_limited():
            return PaymentPasswordLimitedError().as_response()

        # 校验支付密码
        flag = User.verify_payment_password(
            form.merchant.data, uid=uid, password=form.payment_password.data)

        # 交易密码校验失败
        if not flag:
            cache.incr_times()
            times = cache.get_left_times()
            return PaymentPasswordError(message=PaymentPasswordError.message.
                                        format(times)).as_response()

        # 密码校验成功 删除密码输入错误记录
        cache.delete_cache()

        # 判断余额是否足够
        balance = UserBalance.query_balance(uid=uid,
                                            merchant=g.user.merchant).first()
        if BalanceKit.divide_unit(balance.balance) < form.amount.data:
            return AccountBalanceInsufficientError().as_response()

        # 执行转账动作
        flag, msg = UserBalanceEvent.transfer(from_user=g.user,
                                              to_user=user_info,
                                              merchant=form.merchant.data,
                                              amount=form.amount.data,
                                              comment=form.comment.data)

        # 设置失败的情况
        if not flag:
            return NoSourceError().as_response()

        return ResponseSuccess().as_response()
예제 #30
0
class UserBalanceEdit(Resource):
    method_decorators = admin_decorators

    @ns.expect(UserBalanceEditApi)
    @ns.marshal_with(ResponseSuccess.gen_doc(api))
    def post(self):
        """
        用户余额调整
        :return:
        """

        form, error = UserBalanceEditForm.request_validate()
        if error:
            return error.as_response()

        uid = form.uid.data
        # 判断该用户id是否存在
        user = User.query.filter_by(**dict(id=uid)).first()
        if not user:
            return AdjustUserBalanceError(message="系统找不到该用户").as_response()

        ad_type = BalanceAdjustTypeEnum.PLUS

        # 当调整状态为 减少时 需要判断 当前用户余额和商户余额值
        amount = BalanceKit.round_4down_5up(Decimal(form.amount.data))
        if form.adjust_type.data == BalanceAdjustTypeEnum.MINUS:
            ad_type = BalanceAdjustTypeEnum.MINUS
            # 获取用户余额 并判断
            user_balance_info = UserBalance.query.filter(
                UserBalance.id == uid).first()
            if not user_balance_info:
                return UserBalanceNoFoundError().as_response()

            user_balance = user_balance_info.real_balance
            if Decimal(user_balance) - amount < 0:
                print("用户没有足够的金额", user_balance, amount)
                return AdjustUserBalanceError(
                    message="用户没有足够的金额").as_response()

            # 获取商户余额 并判断
            merchant_balance_info = MerchantInfo.query.filter_by(**dict(
                _merchant=user_balance_info.merchant.value)).first()
            if not merchant_balance_info:
                return AdjustUserBalanceError(message="该商户信息不存在").as_response()

            bl_ava = merchant_balance_info.balance_available
            if Decimal(bl_ava) - amount < 0:
                print("商户没有足够的余额", bl_ava, amount)
                return AdjustUserBalanceError(
                    message="商户没有足够的余额").as_response()

        # 调整用户及商户余额
        flag, error = AdjustTransactionCtl.adjust_create(
            user=user,
            source=OrderSourceEnum.MANUALLY,
            amount=amount,
            order_type=PayTypeEnum.MANUALLY,
            bl_type=BalanceTypeEnum.AVAILABLE,
            ad_type=ad_type,
            comment=form.comment.data)

        if not flag:
            return AdjustUserBalanceError(message="余额调整失败").as_response()

        return ResponseSuccess().as_response()