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 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&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 verify_credential(token): """ 使用basic auth进行JWT token鉴权 加了装饰器 @auth.login_required 的view都需要先进这个函数进行token鉴权 :param token: :return: """ # 初始化g对象的error属性 g.error = None rst = UserLoginToken.verify_token(token) if isinstance(rst, (APIException, )): # token 验证失败 g.error = rst return False # 账户被封处理 merchant = MerchantEnum(rst['merchant']) user = User.query_user(merchant=merchant, uid=rst['uid']) if not user: # 用户不存在 g.error = AccountNotExistError() return False if not user.is_active: g.error = DisableUserError() return False g.user = user return True
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 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 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="参数规则:?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 post(self): """ 通道管理: 获取通道配置信息 :return: """ form, error = ChannelConfigQueryForm().request_validate() if error: return error.as_response() pay_type = form.pay_type.data config_channels_dict = ChannelListHelper.get_config_channels( pay_type, ret_dict=True) if pay_type == PayTypeEnum.DEPOSIT: configs = [ c for c in ChannelConfigEnum if c.value not in config_channels_dict and c.conf['payment_type'] ] else: configs = [ c for c in ChannelConfigEnum if c.value not in config_channels_dict and not c.conf['payment_type'] ] channel_config_list = [ dict( channel_id=i.value, channel_desc=i.desc, id=i.conf["id"], provider=i.conf["provider"], name=i.conf["name"], payment_type=i.conf["payment_type"].desc if i.conf['payment_type'] else '', payment_method=i.conf["payment_method"].desc if i.conf['payment_method'] else '', ) for i in configs ] data = dict( channel_config=channel_config_list, payment_fee_type=PaymentFeeTypeEnum.get_desc_value_pairs(), settlement_type=SettleTypeEnum.get_name_value_pairs(), channel_state=ChannelStateEnum.get_desc_value_pairs(), banks=PaymentBankEnum.get_desc_value_pairs(), # banks=[item.value for item in PaymentBankEnum], interfaces=InterfaceTypeEnum.get_name_value_pairs(), payment_method=PayMethodEnum.get_desc_value_pairs(), merchant_name=MerchantEnum.get_name_value_pairs(), payment_types=PaymentTypeEnum.get_desc_name_pairs(), ) return ChannelConfigResult(bs_data=data).as_response()
def post(self): """ 获取创建商户所需的配置信息 :return: """ result = dict( merchant_names=MerchantEnum.get_name_type_pairs(), payment_methods=PayMethodEnum.get_desc_value_pairs(), withdraw_type=DeliverTypeEnum.get_desc_value_pairs(), channels_withdraw=ChannelConfigEnum.get_withdraw_desc_name_pairs(), channels_deposit=ChannelConfigEnum.get_deposit_desc_name_pairs(), ) return MerchantConfigResult(bs_data=result).as_response()
def post(self): """ 商户基本信息 :return: """ user = g.user info = MerchantInfo.query_merchant(MerchantEnum(user.mid)) if not info: return MerchantInfoNoExistError().as_response() merchant_info = dict(account=user.account, balance_total=info.balance_total, available_balance=info.balance_available, incoming_balance=info.balance_income, frozen_balance=info.balance_frozen) return MerchantBaseInfoResponse(bs_data=merchant_info).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 merchant(self) -> MerchantEnum: return MerchantEnum(self._merchant)
), 'deposit_info': fields.List(fields.Nested(DepositTypeList)), 'withdraw_info': fields.Nested(WithdrawType) }) ##################################################### # 商户余额编辑 ##################################################### MerchantBalanceEdit = api.model( 'MerchantBalanceEdit', { 'name': fields.String( required=True, description='商户名称', example=MerchantEnum.description(), ), 'adjustment_type': fields.String( required=True, description='调整类型', example=ManualAdjustmentType.description(), ), 'amount': fields.String( required=True, description='调整金额(浮点数转为字符串)', example="500.34", ), 'reason': fields.String(required=True, description='原因说明', example="原因说明.....")
def test_merchant_fee_config_model(self): # 添加测试 count = 0 latest_count = 0 for merchant in MerchantEnum: for payment_way in PayTypeEnum: if payment_way == PayTypeEnum.DEPOSIT: for payment_method in PayMethodEnum: for fee_type in PaymentFeeTypeEnum: params = [ dict( merchant=merchant, payment_way=payment_way, payment_method=payment_method, fee_type=fee_type, value=Decimal("1.22"), ), ] self.add_one_config(merchant, params) count += 1 latest_count += 1 else: for fee_type in PaymentFeeTypeEnum: params = [ dict( merchant=merchant, payment_way=payment_way, fee_type=fee_type, value=Decimal("3.22"), ), ] self.add_one_config(merchant, params) count += 1 latest_count += 1 all_configs = MerchantFeeConfig.query_all() add_num = len(list(all_configs)) self.assertEqual(count, add_num) latest_configs = MerchantFeeConfig.filter_latest_items(all_configs) x_latest_count = len(list(latest_configs)) self.assertEqual(len(MerchantEnum.get_names()), x_latest_count) # 修改测试 count = 0 for merchant in MerchantEnum: for payment_way in PayTypeEnum: if payment_way == PayTypeEnum.DEPOSIT: for payment_method in PayMethodEnum: for fee_type in PaymentFeeTypeEnum: params = [ dict( merchant=merchant, payment_way=payment_way, payment_method=payment_method, fee_type=fee_type, value=Decimal("1.33"), ), ] self.add_one_config(merchant, params) count += 1 else: for fee_type in PaymentFeeTypeEnum: params = [ dict( merchant=merchant, payment_way=payment_way, fee_type=fee_type, value=Decimal("2.33"), ), ] self.add_one_config(merchant, params) count += 1 add_num += count # 更新不会增加条目 all_configs = MerchantFeeConfig.query_all() num = len(list(all_configs)) self.assertEqual(add_num, num) latest_configs = MerchantFeeConfig.filter_latest_items(all_configs) x_latest_count = len(list(latest_configs)) self.assertEqual(len(MerchantEnum.get_names()), x_latest_count) # 批量修改测试 count = 0 valid_count = 0 for merchant in MerchantEnum: params = [] for payment_way in PayTypeEnum: if payment_way == PayTypeEnum.DEPOSIT: for payment_method in PayMethodEnum: params.append(dict( merchant=merchant, payment_way=payment_way, payment_method=payment_method, fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, value=Decimal("1.22"), )) count += 1 else: params.append(dict( merchant=merchant, payment_way=payment_way, fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, value=Decimal("3.22"), )) count += 1 valid_count += len(params) self.add_one_config(merchant, params) add_num += count all_configs = MerchantFeeConfig.query_all() num = len(list(all_configs)) self.assertEqual(add_num, num) latest_configs = MerchantFeeConfig.filter_latest_items(all_configs) x_latest_count = len(list(latest_configs)) self.assertEqual(valid_count, x_latest_count) MerchantFeeConfig.delete_all() num = len(list(MerchantFeeConfig.query_all())) self.assertEqual(0, num)
def merchants(self): if not self._merchants: return [] _values = StringParser(',', int).split(self._merchants) return [MerchantEnum(v) for v in _values]
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 post(self): """ 商户提现订单查询 :return: """ form, error = WithdrawOrderSelectForm().request_validate() if error: return error.as_response() user = g.user try: order_list_query = OrderWithdraw.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)) except MultiMonthQueryException as e: return MultiMonthQueryError().as_response() kwargs = {} tx_id = form.order_id.data if tx_id: if OrderUtils.is_sys_tx_id(tx_id): kwargs["sys_tx_id"] = tx_id else: kwargs["mch_tx_id"] = tx_id if form.state.data != "0": kwargs["_state"] = form.state.data.value query = order_list_query.filter_by(**kwargs) pagination = query.paginate(form.page_index.data, form.page_size.data, False) entries = pagination.items total = pagination.total bank_lst = list(set([o.bank_id for o in entries])) kwargs = {} if tx_id and entries: kwargs['id'] = entries[0].order_id bank_items = dict() if not MerchantEnum(user.mid).is_api_merchant: bank_items = { bank.id: bank for bank in BankCard.query.filter(BankCard.id.in_( bank_lst)).all() } order_items = { item.id: item for item in OrderDetailWithdraw.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all() } items = [] for order in entries: if not MerchantEnum(user.mid).is_api_merchant: bank = bank_items.get(order.bank_id, {}) else: bank = order.get_bank_card() detail = order_items.get(order.order_id, {}) if not bank or not detail: continue items.append( dict(mch_tx_id=order.mch_tx_id, sys_tx_id=order.sys_tx_id, amount=detail.amount, fee=detail.fee, account_name=bank.account_name, bank_name=bank.bank_name, branch="{}{}{}".format(bank.province, bank.city, bank.branch), card_no=bank.card_no, create_time=order.str_create_time, done_time=order.update_time, state=order.state.desc, deliver=order.deliver.desc)) items = sorted(items, key=lambda item: item['create_time']) return MerchantWithdrawOrderResult( bs_data=dict(entries=items, total=total)).as_response()
"fee_type": fields.Nested(DescValuePair), "limit_per_min": fields.String(required=True, description='单笔交易下限'), "limit_per_max": fields.String(required=True, description='单笔交易上限'), "limit_day_max": fields.String(required=True, description='日交易限额'), "settlement_type": fields.Nested(NameValuePair), "trade_start_time": fields.String(required=True, description='交易开始时间'), "trade_end_time": fields.String(required=True, description='交易结束时间'), "main_time": fields.Nested(maintain_datetime), "state": fields.Nested(DescValuePair, description="可操作类型列表"), "reason": fields.String(required=True, description='不可用原因'), "priority": fields.String(required=True, description='优先级'), "merchants": fields.List( fields.String, required=True, description='适用的商户列表', example=MerchantEnum.get_names(), ), }) ChannelList = api.model('ChannelList', { 'counts': fields.String( required=True, description='渠道总个数', example="10" ), 'channels': fields.List(fields.Nested(ChannelItem)), }) class ChannelListResult(ResponseSuccess): data_model = ChannelList
def post(self): """ 商户充值订单查询数据导出 :return: """ form, error = DepositOrderSelectForm().request_validate() if error: return error.as_response() user = g.user try: order_list_query = OrderDeposit.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)) except MultiMonthQueryException as e: return MultiMonthQueryError().as_response() kwargs = {} if form.order_id.data: kwargs["sys_tx_id"] = form.order_id.data if form.state.data != "0": kwargs["_state"] = form.state.data.value entries = order_list_query.filter_by(**kwargs).all() items = [] channel_lst = list(set([o.channel_id for o in entries])) channel_items = { Channel.id: Channel for Channel in ChannelConfig.query.filter( ChannelConfig.id.in_(channel_lst)).all() } kwargs = {} if form.order_id.data and entries: kwargs['id'] = entries[0].order_id order_items = { item.id: item for item in OrderDetailDeposit.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all() } for order in entries: item_channel = channel_items.get(order.channel_id, {}) detail = order_items.get(order.order_id, {}) if not item_channel or not detail: continue items.append( dict(mch_tx_id=order.mch_tx_id, sys_tx_id=order.sys_tx_id, payment_type=item_channel.channel_enum. conf['payment_type'].desc, amount=detail.amount, tx_amount=detail.tx_amount, fee=detail.fee, create_time=order.str_create_time, done_time=order.update_time, state=order.state.desc, deliver=order.deliver.desc)) items = sorted(items, key=lambda item: item['create_time']) if items: data = list() for item in items: data.append({ "商户订单号": item['mch_tx_id'], "支付方式": item['payment_type'], "发起金额": str(item['amount']), "实际支付金额": str(item['tx_amount']), "手续费": str(item['fee']), "创建时间": item['create_time'], "完成时间": item['done_time'], "订单状态": item['state'], "通知状态": item['deliver'] }) filename = 'epay_deposit_record_%s.csv' % ( DateTimeKit.datetime_to_str( DateTimeKit.get_cur_datetime(), DateTimeFormatEnum.TIGHT_DAY_FORMAT)) return CsvKit.send_csv(data, filename=filename, fields=data[0].keys())
def post(self): """ 商户提现订单查询 :return: """ form, error = WithdrawOrderSelectForm().request_validate() if error: return error.as_response() user = g.user try: order_list_query = OrderWithdraw.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)) except MultiMonthQueryException as e: return MultiMonthQueryError().as_response() kwargs = {} if form.order_id.data: kwargs["mch_tx_id"] = form.order_id.data if form.state.data != "0": kwargs["_state"] = form.state.data.value entries = order_list_query.filter_by(**kwargs).all() bank_lst = list(set([o.bank_id for o in entries])) kwargs = {} if form.order_id.data and entries: kwargs['id'] = entries[0].order_id if not MerchantEnum(user.mid).is_api_merchant: bank_items = { bank.id: bank for bank in BankCard.query.filter(BankCard.id.in_( bank_lst)).all() } order_items = { item.id: item for item in OrderDetailWithdraw.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all() } items = [] for order in entries: if not MerchantEnum(user.mid).is_api_merchant: bank = bank_items.get(order.bank_id, {}) else: bank = order.get_bank_card() detail = order_items.get(order.order_id, {}) if not bank or not detail: continue items.append( dict(mch_tx_id=order.mch_tx_id, sys_tx_id=order.sys_tx_id, amount=detail.amount, fee=detail.fee, account_name=bank.account_name, bank_name=bank.bank_name, branch="{}{}{}".format(bank.province, bank.city, bank.branch), card_no=bank.card_no, create_time=order.str_create_time, done_time=order.update_time, state=order.state.desc, deliver=order.deliver.desc)) items = sorted(items, key=lambda item: item['create_time']) if items: data = list() for item in items: data.append({ "商户订单号": item['mch_tx_id'], "提现金额": str(item['amount']), "手续费": str(item['fee']), "开户名": item['account_name'], "开户银行": item['bank_name'], "开户地址": item['branch'], "银行卡号": item['card_no'], "创建时间": item['create_time'], "完成时间": item['done_time'], "订单状态": item['state'], "通知状态": item['deliver'] }) filename = 'epay_withdraw_record_%s.csv' % ( DateTimeKit.datetime_to_str( DateTimeKit.get_cur_datetime(), DateTimeFormatEnum.TIGHT_DAY_FORMAT)) return CsvKit.send_csv(data, filename=filename, fields=data[0].keys())
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 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 post(self): """ 商户充值订单查询 :return: """ form, error = DepositOrderSelectForm().request_validate() if error: return error.as_response() user = g.user try: order_list_query = OrderDeposit.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)) except MultiMonthQueryException as e: return MultiMonthQueryError().as_response() kwargs = {} tx_id = form.order_id.data if tx_id: if OrderUtils.is_sys_tx_id(tx_id): kwargs["sys_tx_id"] = tx_id else: kwargs["mch_tx_id"] = tx_id if form.state.data != "0": kwargs["_state"] = form.state.data.value query = order_list_query.filter_by(**kwargs) pagination = query.paginate(form.page_index.data, form.page_size.data, False) entries = pagination.items total = pagination.total items = [] channel_lst = list(set([o.channel_id for o in entries])) channel_items = { Channel.id: Channel for Channel in ChannelConfig.query.filter( ChannelConfig.id.in_(channel_lst)).all() } kwargs = {} if tx_id and entries: kwargs['id'] = entries[0].order_id order_items = { item.id: item for item in OrderDetailDeposit.query_by_create_time( begin_time=form.start_datetime.data, end_time=form.end_datetime.data, merchant=MerchantEnum(user.mid)).filter_by(**kwargs).all() } for order in entries: item_channel = channel_items.get(order.channel_id, {}) detail = order_items.get(order.order_id, {}) if not item_channel or not detail: continue items.append( dict(mch_tx_id=order.mch_tx_id, sys_tx_id=order.sys_tx_id, payment_type=item_channel.channel_enum. conf['payment_type'].desc, amount=detail.amount, tx_amount=detail.tx_amount, fee=detail.fee, create_time=order.str_create_time, done_time=order.update_time, state=order.state.desc, deliver=order.deliver.desc)) items = sorted(items, key=lambda item: item['create_time']) return MerchantDepositOrderResult( bs_data=dict(entries=items, total=total)).as_response()
from app.enums.balance import ManualAdjustmentType from app.enums.trade import PaymentFeeTypeEnum, PayMethodEnum, OrderSourceEnum, OrderStateEnum, DeliverTypeEnum, \ DeliverStateEnum, PaymentBankEnum, PayTypeEnum from app.extensions.ext_api import api_backoffice as api from app.libs.error_code import ResponseSuccess from config import MerchantEnum ################################################### # withdraw list ################################################### NameTypePair = api.model( "NameTypePair", { "name": fields.String( description=MerchantEnum.description(), example=MerchantEnum.QF2.name, ), "type": fields.String( description=MerchantTypeEnum.description(), example=MerchantTypeEnum.NORMAL.value, ) }) DescValuePair = api.model( "DescValuePair", { "desc": fields.String( description="支付方式描述", example=PayMethodEnum.WEIXIN_H5.desc,
def validate_account(self, value): try: self.account.data = MerchantEnum.from_name(value.data) except Exception as e: raise StopValidation("无效的商户名称")
def validate_merchant_id(self, value): try: self.merchant_id.data = MerchantEnum(int(value.data)) except Exception as e: raise StopValidation("无效的 merchant_id")
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()