def validate_name(self, value): try: self.name.data = MerchantEnum.from_name(value.data) except Exception: raise StopValidation("无效的商户名称") if not MerchantInfo.query_merchant(self.name.data): raise StopValidation("未创建的商户")
def validate_merchant_name(self, value): try: if value.data: self.merchant_name.data = MerchantEnum.from_name(value.data) else: self.merchant_name.data = None except Exception as e: raise StopValidation("无效的商户名称")
def get(self): """ 商户配置查询 :return: """ if not request.args: return ResponseSuccess(message="参数规则:?merchant=test").as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() merchant_info = MerchantInfo.query_merchant(merchant) if not merchant_info: return ResponseSuccess(message="未创建商户").as_response() bs_data = dict( balance=dict( balance_total=str(merchant_info.balance_total), balance_available=str(merchant_info.balance_available), balance_income=str(merchant_info.balance_income), balance_frozen=str(merchant_info.balance_frozen), ), merchant=merchant.name, domains=MerchantDomainConfig.get_domains(merchant), # db=DBEnum(merchant.name).get_db_name(), ) deposit_fees = MerchantFeeConfig.query_active_configs( query_fields=dict( merchant=merchant, payment_way=PayTypeEnum.DEPOSIT, )) deposit_fees = MerchantFeeConfig.filter_latest_items(deposit_fees) if not deposit_fees: return MerchantConfigDepositError(bs_data=bs_data).as_response() bs_data['deposit_fees'] = [x.short_description for x in deposit_fees] withdraw_fees = MerchantFeeConfig.query_latest_one(query_fields=dict( merchant=merchant, payment_way=PayTypeEnum.WITHDRAW, )) if not withdraw_fees: return MerchantConfigWithdrawError(bs_data=bs_data).as_response() bs_data['withdraw_fees'] = withdraw_fees.short_description channels = ChannelListHelper.get_available_channels( merchant, PayTypeEnum.DEPOSIT) bs_data['deposit_channels'] = [x.short_description for x in channels] channels = ChannelListHelper.get_available_channels( merchant, PayTypeEnum.WITHDRAW) bs_data['withdraw_channels'] = [x.short_description for x in channels] return ResponseSuccess(bs_data=bs_data).as_response()
def get(self): """ 查询可用的通道 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?merchant=test&interface=&amount=&uid=" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess( message="请输入正确的 merchant,有效的 merchant 包括:%s" % MerchantEnum.get_names()).as_response() try: interface = request.args.get('interface') if interface: interface = InterfaceTypeEnum.from_name(interface) except: return ResponseSuccess( message="请输入正确的 interface,有效的 interface 包括:%s" % InterfaceTypeEnum.get_names()).as_response() try: amount = request.args.get('amount') or 0 if amount: amount = Decimal(amount) except: return ResponseSuccess(message="请输入正确的 amount") try: uid = request.args.get('uid') if uid: uid = int(uid) except: return ResponseSuccess(message="请输入正确的 uid") routers = ChannelListHelper.get_channel_payment_type_router( interface=interface, amount=amount, merchant=merchant, uid=uid, ) channels = ChannelListHelper.get_available_channels( merchant, PayTypeEnum.DEPOSIT) payment_type_list = ChannelListHelper.choice_one_channel_for_payment_type( channels, routers, merchant, amount) for item in payment_type_list: item['limit_min'] = str(item['limit_min']) item['limit_max'] = str(item['limit_max']) return ResponseSuccess(bs_data=payment_type_list).as_response()
def validate_merchants(self, value): try: if value.data: self.merchants.data = [ MerchantEnum.from_name(x) for x in value.data ] else: self.merchants.data = [] except Exception as e: raise StopValidation("无效的 merchants 参数")
def get(self): """ 给用户绑定信息 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?merchant=test&account=861891111&flag=VIP" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: account = request.args['account'] account = '+' + account.strip('+').strip() if not PhoneNumberParser.is_valid_number(account): raise except: return ResponseSuccess( message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999" ).as_response() try: flag = AccountFlagEnum.from_name(request.args['flag']) except: return ResponseSuccess( message="标签错误,有效的标签包括: %s" % AccountFlagEnum.get_name_list()).as_response() user = User.query_user(merchant, account=account) if not user: return ResponseSuccess(message="手机号码未注册").as_response() User.update_user_flag(merchant, flag, account=account) user = User.query_user(merchant, account=account) bs_data = dict( account=account, uid=user.uid, flag=user.flag.desc, is_auth=user.is_official_auth, cache_flag=UserFlagCache(user.uid).get_flag().name, ) return ResponseSuccess(bs_data=bs_data).as_response()
def get(self): """ 给用户绑定信息 :return: """ if not request.args: return ResponseSuccess( message= "参数规则:?merchant=test&account=861891111&perm=DEPOSIT|BINDCARD" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: account = request.args['account'] account = '+' + account.strip('+').strip() if not PhoneNumberParser.is_valid_number(account): raise except: return ResponseSuccess( message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999" ).as_response() try: perms = request.args['perm'].split('|') perms = [UserPermissionEnum.from_name(perm) for perm in perms] except: return ResponseSuccess( message="标签权限,有效的权限包括: %s" % UserPermissionEnum.get_name_list()).as_response() user = User.query_user(merchant, account=account) if not user: return ResponseSuccess(message="手机号码未注册").as_response() User.update_user_permission(merchant, perms, account=account) user = User.query_user(merchant, account=account) bs_data = dict( account=account, uid=user.uid, perms=user.permission_names, ) return ResponseSuccess(bs_data=bs_data).as_response()
def get(self): """ 检查热表数据 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?merchant=test&date=20190901").as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: date = request.args.get('date') if date: date = DateTimeKit.str_to_datetime( date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True) else: date = DateTimeKit.get_cur_date() except: return ResponseSuccess( message="请输入有效的查询日期,格式为:20190901").as_response() kwargs = dict( date=date, merchant=merchant, only_hot=request.args.get('only_hot'), only_cold=request.args.get('only_cold'), ) rst = dict( OrderDeposit=OrderDeposit.query_by_date(date, **kwargs).count(), OrderWithdraw=OrderWithdraw.query_by_date(date, **kwargs).count(), OrderDetailDeposit=OrderDetailDeposit.query_by_date( date, **kwargs).count(), OrderDetailWithdraw=OrderDetailWithdraw.query_by_date( date, **kwargs).count(), ) kwargs['merchant'] = merchant.name kwargs['date'] = DateTimeKit.datetime_to_str(date) rst['kwargs'] = kwargs return ResponseSuccess(bs_data=rst).as_response()
def get(self): """ 查询用户余额 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?account=8613812349999&merchant=test" ).as_response() try: account = request.args.get('account') if account: account = '+' + account.strip('+').strip() if not PhoneNumberParser.is_valid_number(account): raise else: raise except: return ResponseSuccess( message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() user = User.query_user(merchant, account=account) if not user: return ResponseSuccess(message="手机号码未注册, account: %s" % account).as_response() user_balance = UserBalance.query_balance(user.uid, merchant).first() return ResponseSuccess(bs_data=dict( account=account, uid=user.uid, balance=str(user_balance.real_balance), )).as_response()
def get(self): """ 联通性测试 :return: """ from scripts.admin_user import init_merchant_user if not request.args: return ResponseSuccess(message="参数规则:?merchant=TEST").as_response() try: account = request.args['merchant'] except: return ResponseSuccess(message="请输入商户分配的账号名称").as_response() try: merchant = MerchantEnum.from_name(account) except: return ResponseSuccess(message="请输入有效的商户名称").as_response() account, password = init_merchant_user(merchant.value, merchant.name, None) return ResponseSuccess( bs_data=dict(account=account, password=password)).as_response()
def validate_merchant_name(self, value): try: self.merchant_name.data = MerchantEnum.from_name(value.data) except Exception as e: raise StopValidation("无效的 merchant_name")
def get_merchant(cls): """ 获取商户名称 :return: """ return MerchantEnum.from_name(cls.get_bind_name())
def validate_merchant(self, value): try: self.merchant.data = MerchantEnum.from_name(value.data.upper()) except Exception as e: raise StopValidation("无效的商户名称")
def get(self): """ 查询用户余额变更流水 :return: """ if not request.args: return ResponseSuccess( message= "参数规则:?merchant=test&account=8618912341234&date=20190901&export=1" ).as_response() try: account = request.args.get('account') if account: account = '+' + account.strip('+').strip() if not PhoneNumberParser.is_valid_number(account): raise except: return ResponseSuccess( message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: date = request.args.get('date') if date: date = DateTimeKit.str_to_datetime( date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True) else: date = DateTimeKit.get_cur_date() except: return ResponseSuccess( message="请输入有效的查询日期,格式为:20190901").as_response() rst = dict( data=list(), sum_value=0, ) events = UserBalanceEvent.query_by_date(date, merchant=merchant, date=date) if account: user = User.query_user(merchant, account=account) if not user: return ResponseSuccess(message="用户不存在,请检查参数。商户:%s,手机号码:%s" % (merchant.name, account)) user_balance = UserBalance.query_balance(user.uid, merchant).first() rst.update(user=dict( account=user.account, uid=user.uid, user_balance=str(user_balance.real_balance), )) events = events.filter_by(uid=user.uid) rst['sql'] = str(events) for event in events: rst['sum_value'] += event.value_real rst['data'].append( dict( create_time=event.create_time, uid=event.uid, ref_id=event.ref_id, order_type=event.order_type.desc, source=event.source.desc, bl_type=event.bl_type.desc, value=str(event.value_real), ad_type=event.ad_type.desc, tx_id=event.tx_id, # 大整数,转为字符串 comment=event.comment, extra=event.raw_extra, )) rst['data'] = sorted(rst['data'], key=lambda x: x['create_time'], reverse=True) for x in rst['data']: x['create_time'] = DateTimeKit.datetime_to_str(x['create_time']) if rst['data'] and request.args.get('export'): filename = 'user_balance_events_%s.csv' % DateTimeKit.datetime_to_str( date, DateTimeFormatEnum.TIGHT_DAY_FORMAT) return CsvKit.send_csv(rst['data'], filename=filename, fields=rst['data'][0].keys()) rst['sum_value'] = str(rst['sum_value']) return ResponseSuccess(bs_data=rst).as_response()
def get(self): """ 查询商户余额变更流水 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?merchant=test&date=20190901&export=1" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) merchant_info = MerchantInfo.query_merchant(merchant) if not merchant_info: raise except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: date = request.args.get('date') if date: date = DateTimeKit.str_to_datetime( date, DateTimeFormatEnum.TIGHT_DAY_FORMAT, to_date=True) else: date = DateTimeKit.get_cur_date() except: return ResponseSuccess( message="请输入有效的查询日期,格式为:20190901").as_response() balance = dict( balance_total=str(merchant_info.balance_total), balance_available=str(merchant_info.balance_available), balance_income=str(merchant_info.balance_income), balance_frozen=str(merchant_info.balance_frozen), ) events = MerchantBalanceEvent.query_by_date(date, merchant=merchant, date=date) rst = dict( data=list(), sum_value=0, balance=balance, ) rst['sql'] = str(events) for event in events: rst['sum_value'] += event.value_real rst['data'].append( dict( create_time=event.create_time, ref_id=event.ref_id, order_type=event.order_type.desc, source=event.source.desc, bl_type=event.bl_type.desc, value=str(event.value_real), ad_type=event.ad_type.desc, tx_id=event.tx_id, comment=event.comment, )) rst['data'] = sorted(rst['data'], key=lambda x: x['create_time'], reverse=True) for x in rst['data']: x['create_time'] = DateTimeKit.datetime_to_str(x['create_time']) if rst['data'] and request.args.get('export'): filename = 'merchant_balance_events_%s.csv' % DateTimeKit.datetime_to_str( date, DateTimeFormatEnum.TIGHT_DAY_FORMAT) return CsvKit.send_csv(rst['data'], filename=filename, fields=rst['data'][0].keys()) rst['sum_value'] = str(rst['sum_value']) return ResponseSuccess(bs_data=rst).as_response()
def __test_api_withdraw(self): """ 后台准备数据: 充值通道数据 代付通道数据 商户费率配置数据 钱包端: 1. 创建充值订单 2. 充值 3. 用户设置支付密码 4. 用户绑定银行卡 5. 获取充值配置信息(用户余额,充值最低最高限制) 发起提现请求: :return: """ merchant = MerchantEnum.from_name("TEST") info = dict(merchant=merchant, account="+8618988888888", auth_code="8888", password="******", trade_pwd="b943a52cc24dcdd12bf2ba3afda92351", ac_type=AccountTypeEnum.MOBILE) user = User.register_account(info['merchant'], info['account'], info['ac_type'], info['password']) self.path = '/auth/account/login' login_data = dict(number=info['account'], password=info['password']) response = self.do_request(login_data) self.assertEqual(ResponseSuccessLogin.code, response.status_code) self.assertEqual(ResponseSuccessLogin.error_code, response.json['error_code']) self.token = response.json['data']['token'] self.path = "/withdraw/banks/list" # 1. 向数据库添加代付通道信息 withdraw_item = dict(fee="2.5", fee_type=PaymentFeeTypeEnum(1), limit_per_min="200", limit_per_max="5000", limit_day_max="50000", trade_begin_hour="00", trade_begin_minute="00", trade_end_hour="23", trade_end_minute="59", maintain_begin=DateTimeKit.str_to_datetime( "2019-09-27 00:00:00", DateTimeFormatEnum.SECONDS_FORMAT), maintain_end=DateTimeKit.str_to_datetime( "2019-10-20 23:59:00", DateTimeFormatEnum.SECONDS_FORMAT), state=ChannelStateEnum(10), banks=[ PaymentBankEnum(1), PaymentBankEnum(2), PaymentBankEnum(4), PaymentBankEnum(3), PaymentBankEnum(15) ]) ProxyChannelConfig.update_channel(ChannelConfigEnum.CHANNEL_1001, **withdraw_item) # 2. 向数据库插入 商户费率配置信息 # 充值费率设置 merchant_fee_dict = [] merchant_fee_dict.append( dict( merchant=MerchantEnum.from_name('TEST'), payment_way=PayTypeEnum.DEPOSIT, value="3.5", fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, payment_method=PayMethodEnum.ZHIFUBAO_SAOMA, )) # 提现费率 merchant_fee_dict.append( dict( merchant=MerchantEnum.from_name('TEST'), payment_way=PayTypeEnum.WITHDRAW, value="3.5", fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, )) rst, error = MerchantFeeConfig.update_fee_config( merchant, merchant_fee_dict) self.assertEqual(True, rst) # 3. 给用户和商户充值 uid = user.uid ref_id = hashlib.md5('lakjdflasjfadl;kfja'.encode('utf8')).hexdigest() data = dict( uid=uid, merchant=merchant, ref_id=ref_id, source=OrderSourceEnum.TESTING, order_type=PayTypeEnum.DEPOSIT, bl_type=BalanceTypeEnum.AVAILABLE, ad_type=BalanceAdjustTypeEnum.PLUS, tx_id=OrderUtils.gen_normal_tx_id(uid), value=Decimal("10000.00"), comment="xxx", ) rst, msg = UserBalanceEvent.update_user_balance(**data) self.assertEqual(0, rst) balance = UserBalance.query_balance(data['uid'], data['merchant']).first() # 添加商户余额 data = dict( merchant=MerchantEnum.TEST, source=OrderSourceEnum.TESTING, order_type=PayTypeEnum.DEPOSIT, bl_type=BalanceTypeEnum.AVAILABLE, ad_type=BalanceAdjustTypeEnum.PLUS, tx_id=OrderUtils.gen_normal_tx_id(100), value=Decimal("10000.00"), comment=msg, ) ref_id = hashlib.md5( RandomString.gen_random_str( length=128).encode('utf8')).hexdigest() data['ref_id'] = ref_id event_check = dict(total=1) event_check.update(data) rst, msg = MerchantBalanceEvent.update_balance(**data) self.assertEqual(0, rst) # 设置支付密码 flag = User.set_payment_password(merchant, uid=uid, trade_pwd=info["trade_pwd"]) self.assertEqual(True, flag) # 绑定银行卡 bank_info = { "payment_password": info['trade_pwd'], "bank_name": "中国工商银行", "bank_code": "ICBC", "card_no": "6212260405014627955", "account_name": "张三", "branch": "广东东莞东莞市长安镇支行", "province": "广东省", "city": "东莞市" } flag = BankCard.add_bank_card(merchant, uid=uid, bank_name=bank_info['bank_name'], bank_code=bank_info['bank_code'], card_no=bank_info['card_no'], account_name=bank_info['account_name'], branch=bank_info['branch'], province=bank_info['province'], city=bank_info['city']) self.assertEqual(bank_info['card_no'], flag.card_no) self.path = "/withdraw/limit/config/get" response = self.do_request() self.assertEqual(ResponseBankWithdraw.code, response.status_code) self.assertEqual(ResponseBankWithdraw.error_code, response.json['error_code']) self.assertEqual("10000", response.json['data']['balance']) self.assertEqual("200", response.json['data']['limit_min']) self.assertEqual("5000", response.json['data']['limit_max']) self.path = "/withdraw/order/create" create_data = dict(amount=1000.001, user_bank=1, trade_password=info['trade_pwd']) # 测试小于 最低限额 create_data['amount'] = 100 response = self.do_request(json_data=create_data) self.assertEqual(WithdrawOrderAmountInvalidError.code, response.status_code) self.assertEqual(WithdrawOrderAmountInvalidError.error_code, response.json['error_code']) create_data['amount'] = 6000 response = self.do_request(json_data=create_data) self.assertEqual(WithdrawOrderAmountInvalidError.code, response.status_code) self.assertEqual(WithdrawOrderAmountInvalidError.error_code, response.json['error_code']) create_data['amount'] = str(500.56) create_data['user_bank'] = 100 response = self.do_request(json_data=create_data) self.assertEqual(WithdrawBankNoExistError.code, response.status_code) self.assertEqual(WithdrawBankNoExistError.error_code, response.json['error_code'], response.json['message']) use_balance = UserBalance.query_balance(user.uid, merchant).first() ori_merchant = MerchantInfo.query_merchant(merchant) balance = ori_merchant.bl_ava - BalanceKit.round_4down_5up( Decimal(create_data['amount'])) * 100 - BalanceKit.round_4down_5up( Decimal(create_data['amount']) * Decimal(3.5)) merchant_balance = BalanceKit.round_4down_5up( balance / Decimal(100)) * 100 u_balance = BalanceKit.round_4down_5up( Decimal(use_balance.balance) / Decimal(100) - Decimal(create_data['amount'])) * Decimal(100) create_data['user_bank'] = 1 response = self.do_request(json_data=create_data) self.assertEqual(ResponseSuccess.code, response.status_code) self.assertEqual(ResponseSuccess.error_code, response.json['error_code']) cur_balance = UserBalance.query_balance(user.uid, merchant).first() cur_merchant = MerchantInfo.query_merchant(merchant) self.assertEqual(int(merchant_balance), int(cur_merchant.bl_ava)) self.assertEqual(int(u_balance), int(cur_balance.balance))
def validate_account(self, value): try: self.account.data = MerchantEnum.from_name(value.data) except Exception as e: raise StopValidation("无效的商户名称")
def get(self): """ 给用户绑定信息 :return: """ if not request.args: return ResponseSuccess( message="参数规则:?merchant=test&account=861891111&name=大王&unbind=" ).as_response() try: merchant = MerchantEnum.from_name(request.args['merchant']) except: return ResponseSuccess(message="请输入正确的商户名称,有效的商户名称包括:%s" % MerchantEnum.get_names()).as_response() try: account = request.args['account'] account = '+' + account.strip('+').strip() if not PhoneNumberParser.is_valid_number(account): raise except: return ResponseSuccess( message="请输入正确的用户手机号码,必须有完整区号,不填+号,如:8613812349999" ).as_response() try: name = request.args['name'] except: return ResponseSuccess(message="绑定名称必填").as_response() user = User.query_user(merchant, account=account) if not user: return ResponseSuccess(message="手机号码未注册").as_response() bind_info = UserBindInfo.query_bind_by_uid(user.uid) if request.args.get('unbind'): if not bind_info: return ResponseSuccess(message="未绑定任何别名,无需解绑").as_response() if UserBindInfo.unbind_account(user.uid): return ResponseSuccess(message="解绑成功").as_response() else: return ResponseSuccess(message="解绑失败").as_response() else: if not bind_info: if UserBindInfo.bind_account(user.uid, merchant, account=user.account, name=name): msg = "绑定成功" else: msg = "绑定失败" return ResponseSuccess(message=msg).as_response() else: msg = "无需重复绑定,已经绑定名称:%s" % bind_info.name bind_info = UserBindInfo.query_bind_by_uid(user.uid) bs_data = dict( name=bind_info.name, account=bind_info.account, uid=user.uid, ) return ResponseSuccess(bs_data=bs_data, message=msg).as_response()