def post(self): """ 获取当前可用的充值方式 """ form, error = AmountInputForm().request_validate() if error: return error.as_response() routers = ChannelListHelper.get_channel_payment_type_router( interface=InterfaceTypeEnum.CASHIER_H5, amount=form.amount.data, merchant=form.merchant.data, uid=g.user.uid, ) channels = ChannelListHelper.get_available_channels( form.merchant.data, PayTypeEnum.DEPOSIT, client_ip=form.client_ip.data, ) payment_type_list = ChannelListHelper.choice_one_channel_for_payment_type( channels, routers, form.merchant.data, form.amount.data, ) return ResponsePaymentType(bs_data=dict( payment_type_list=payment_type_list)).as_response()
def post(self): """ 充值请求 """ 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_config_get"), IpKit.get_remote_ip(), request.args, request.json) form, error = DepositConfigForm.request_validate() if error: return error.as_response() merchant = form.merchant_id.data checker = GatewayFormChecker(merchant) # 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() # 3. 返回可用的支付方式以及限额 # 充值每种支付类型的限额 payment_types = ChannelListHelper.get_channels_for_gateway( merchant, PayTypeEnum.DEPOSIT, client_ip=form.user_ip.data, ) # 提现限额 # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit() limit_min, limit_max = ChannelListHelper.get_channel_limit_range( merchant=merchant, payment_way=PayTypeEnum.WITHDRAW, client_ip=form.user_ip.data, ) withdraw_config = dict( limit_min=limit_min, # 最小限额列表的最小值 limit_max=limit_max, # 最大限额列表的最大值 ) return GatewayResponseConfig(bs_data=dict( payment_types=payment_types, withdraw_config=withdraw_config, )).as_response()
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: """ deposit_channels = ChannelListHelper.get_config_channels( PayTypeEnum.DEPOSIT) withdraw_channels = ChannelListHelper.get_config_channels( PayTypeEnum.WITHDRAW) bs_data = dict( deposit_channels=[x.short_description for x in deposit_channels], withdraw_channels=[x.short_description for x in withdraw_channels], ) return ResponseSuccess(bs_data=bs_data).as_response()
def post(self): """ 获取当前可用的充值方式 """ form, error = DomainForm().request_validate() if error: return error.as_response() channel_list = ChannelListHelper.get_available_channels( form.merchant.data, PayTypeEnum.WITHDRAW) withdraw_banks = [] for channel in channel_list: banks = [ dict(desc=bank.desc, value=bank.value) for bank in channel.banks ] withdraw_banks += banks value_list = [] banks_lst = [] for item in withdraw_banks: if item['value'] not in value_list: value_list.append(item['value']) banks_lst.append(item) banks_result = dict(banks=banks_lst) return ResponseBankWithdraw(bs_data=banks_result).as_response()
def post(self): """ 获取单笔交易最低最高限额 """ form, error = DomainForm().request_validate() if error: return error.as_response() # 获取用户余额 uid = g.user.uid merchant = g.user.merchant user_balance = UserBalance.query_balance(uid=uid, merchant=merchant).first() # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit() limit_min, limit_max = ChannelListHelper.get_channel_limit_range( merchant=merchant, payment_way=PayTypeEnum.WITHDRAW, client_ip=form.client_ip.data, ) deposit_limit_config = dict( balance=user_balance.real_balance, limit_min=limit_min, limit_max=limit_max, ) return ResponseWithdrawLimitConfig( bs_data=deposit_limit_config).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): """ 获取单笔交易最低最高限额 """ form, error = DomainForm().request_validate() if error: return error.as_response() merchant = form.merchant.data # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.DEPOSIT).get_channel_limit() limit_min, limit_max = ChannelListHelper.get_channel_limit_range( merchant=merchant, payment_way=PayTypeEnum.DEPOSIT, client_ip=form.client_ip.data, ) return ResponseDepositLimitConfig(bs_data=dict( limit_min=limit_min, limit_max=limit_max)).as_response()
def test_channel_guid_rule(self): data = dict( config_list=[ dict(payment_type=PaymentTypeEnum.ZHIFUBAO, priority=100), dict(payment_type=PaymentTypeEnum.WEIXIN, priority=200), dict(payment_type=PaymentTypeEnum.YINLIAN, priority=10), dict(payment_type=PaymentTypeEnum.YUNSHANFU, priority=50), ], amount_min=Decimal('100.33'), amount_max=Decimal('500.22'), interface=InterfaceTypeEnum.CASHIER_H5, merchants=[MerchantEnum.TEST, MerchantEnum.QF2], uid_list=[1, 2, 3, 4], ) rule = ChannelRouter.create_rule(**data) def check_item_and_data(_data, _item): self.assertEqual(set([x.name for x in _data['merchants']]), set([x.name for x in _item.merchants])) self.assertEqual(set(_data['uid_list']), set(_item.uid_list)) self.assertEqual(_data['interface'], _item.interface) self.assertEqual(len(_data['config_list']), len(_item.config_list)) check_item_and_data(data, rule) count = 1 all_configs = list(ChannelRouter.query_all()) self.assertEqual(count, len(all_configs)) q_rule = all_configs[count - 1] self.assertEqual(rule.router_id, q_rule.router_id) data = dict( router_id=q_rule.router_id, config_list=[ dict(payment_type=PaymentTypeEnum.ZHIFUBAO, priority=100), dict(payment_type=PaymentTypeEnum.WEIXIN, priority=200), dict(payment_type=PaymentTypeEnum.YUNSHANFU, priority=50), ], amount_min=Decimal('800.33'), amount_max=Decimal('3000.22'), interface=InterfaceTypeEnum.CASHIER_H5, merchants=[MerchantEnum.TEST, MerchantEnum.QF3], uid_list=[1, 3, 4], ) rule, error = ChannelRouter.update_rule(**data) check_item_and_data(data, rule) data['uid_list'] = [10, 20, 30] data.pop('router_id') data['config_list'] = [ dict(payment_type=PaymentTypeEnum.ZHIFUBAO, priority=100), dict(payment_type=PaymentTypeEnum.WEIXIN, priority=200), dict(payment_type=PaymentTypeEnum.YINLIAN, priority=10), dict(payment_type=PaymentTypeEnum.YUNSHANFU, priority=50), ] rule = ChannelRouter.create_rule(**data) check_item_and_data(data, rule) data['amount_min'] = Decimal('400') data['amount_max'] = Decimal('500') data['interface'] = InterfaceTypeEnum.API data['merchants'] = [] data['uid_list'] = [] data['config_list'] = [ dict(payment_type=PaymentTypeEnum.YINLIAN, priority=10), dict(payment_type=PaymentTypeEnum.YUNSHANFU, priority=50), ] rule = ChannelRouter.create_rule(**data) check_item_and_data(data, rule) data['amount_min'] = 0 data['amount_max'] = 0 data['interface'] = InterfaceTypeEnum.CASHIER_PC data['merchants'] = [] data['uid_list'] = [] data['config_list'] = [ dict(payment_type=PaymentTypeEnum.YINLIAN, priority=4), dict(payment_type=PaymentTypeEnum.YUNSHANFU, priority=8), dict(payment_type=PaymentTypeEnum.ZHIFUBAO, priority=3), dict(payment_type=PaymentTypeEnum.WEIXIN, priority=5), dict(payment_type=PaymentTypeEnum.BANKCARD, priority=10), dict(payment_type=PaymentTypeEnum.JDQIANBAO, priority=7), ] rule = ChannelRouter.create_rule(**data) check_item_and_data(data, rule) data['interface'] = None data['config_list'] = [ dict(payment_type=PaymentTypeEnum.YINLIAN, priority=4), dict(payment_type=PaymentTypeEnum.ZHIFUBAO, priority=3), dict(payment_type=PaymentTypeEnum.WEIXIN, priority=5), dict(payment_type=PaymentTypeEnum.BANKCARD, priority=10), dict(payment_type=PaymentTypeEnum.JDQIANBAO, priority=7), ] rule = ChannelRouter.create_rule(**data) check_item_and_data(data, rule) count = 5 all_configs = list(ChannelRouter.query_all()) self.assertEqual(count, len(all_configs)) q_rule = all_configs[count - 1] self.assertEqual(rule.router_id, q_rule.router_id) config_list = ChannelListHelper.get_channel_payment_type_router(uid=3, amount=Decimal("1000"), merchant=MerchantEnum.QF3, interface=InterfaceTypeEnum.CASHIER_H5) print('config_list', config_list) self.assertEqual(3, len(config_list)) config_list = ChannelListHelper.get_channel_payment_type_router(uid=20, amount=Decimal("1000"), merchant=MerchantEnum.QF3, interface=InterfaceTypeEnum.CASHIER_H5) print('config_list', config_list) self.assertEqual(4, len(config_list)) config_list = ChannelListHelper.get_channel_payment_type_router(amount=Decimal("450"), interface=InterfaceTypeEnum.API) print('config_list', config_list) self.assertEqual(2, len(config_list)) config_list = ChannelListHelper.get_channel_payment_type_router(interface=InterfaceTypeEnum.CASHIER_PC) print('config_list', config_list) self.assertEqual(6, len(config_list)) config_list = ChannelListHelper.get_channel_payment_type_router() print('config_list', config_list) self.assertEqual(5, len(config_list)) config_list = ChannelListHelper.get_channel_payment_type_router(interface=InterfaceTypeEnum.API) print('config_list', config_list) self.assertEqual(5, len(config_list))
def post(self): """ 充值通道列表 :return: """ router2_dict = ChannelListHelper.get_router2_dict() channel_list = [] channels = ChannelConfig.query_all() channels = ChannelConfig.filter_latest_items(channels) for channel in channels: channel_enum = channel.channel_enum channel_conf = channel_enum.conf merchants = list() router = router2_dict.get(channel_enum) if router: merchants = router.merchants channel_list.append( dict( channel_id=channel_enum.value, channel_desc=channel_enum.desc, id=channel_conf['mch_id'], provider=channel_conf['provider'], payment_type=dict(desc=PaymentTypeEnum( channel_conf['payment_type']).desc, value=PaymentTypeEnum( channel_conf['payment_type']).value), payment_method=dict( desc=PayMethodEnum( channel_conf['payment_method']).desc, value=PayMethodEnum( channel_conf['payment_method']).value), fee=channel.fee, fee_type=dict( desc=PaymentFeeTypeEnum(channel.fee_type).desc, value=PaymentFeeTypeEnum(channel.fee_type).value), limit_per_min=channel.limit_per_min, limit_per_max=channel.limit_per_max, limit_day_max=channel.limit_day_max, settlement_type=dict( key=SettleTypeEnum(channel.settlement_type).value, value=SettleTypeEnum(channel.settlement_type).name), trade_start_time=":".join([ str(channel.trade_begin_hour), str(channel.trade_begin_minute) ]), # trade_start_time=dict(trade_begin_hour=channel.trade_begin_hour, # trade_begin_minute=channel.trade_begin_minute), trade_end_time=":".join([ str(channel.trade_end_hour), str(channel.trade_end_minute) ]), # trade_end_time=dict(trade_end_hour=channel.trade_end_hour, # trade_end_minute=channel.trade_end_minute), main_time=dict(maintain_begin=channel.maintain_begin if channel.maintain_begin else None, maintain_end=channel.maintain_end if channel.maintain_end else None), state=dict(desc=channel.state.desc, value=channel.state.value), reason=channel.get_reason_desc(), priority=channel.priority, merchants=[x.name for x in merchants], )) channel_list = sorted(channel_list, key=lambda item: item['state']['value']) data = dict(counts=len(channel_list), channels=channel_list) return ChannelListResult(bs_data=data).as_response()
def order_create(cls, user, amount, client_ip, user_bank_id=None, bank_info=None, notify_url=None, mch_tx_id=None, extra=None): """ 申请创建订单 :return: """ params = copy.deepcopy(locals()) params.pop('cls') order = None if not bank_info: card_entry = BankCard.query_bankcard_by_id(card_id=user_bank_id) if not card_entry: msg = '%s, params: %s' % (WithdrawBankNoExistError.message, params) current_app.logger.error(msg) return order, WithdrawBankNoExistError() # 判断 金额是否在有效范围 获取代付系统当前最高最低交易金额 # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit() # if amount < limit_min or amount > limit_max: if ChannelListHelper.is_amount_out_of_range( amount=amount, merchant=user.merchant, payment_way=PayTypeEnum.WITHDRAW, client_ip=client_ip): msg = '%s, params: %s' % (WithdrawOrderAmountInvalidError.message, params) current_app.logger.error(msg) return order, WithdrawOrderAmountInvalidError() # 商户配置信息 merchant_config = MerchantFeeConfig.query_latest_one(query_fields=dict( merchant=user.merchant, payment_way=PayTypeEnum.WITHDRAW, )) # 手续费计算 fee_value = FeeCalculator.calc_fee(amount, merchant_config.fee_type, merchant_config.value) user_fee = merchant_fee = 0 if merchant_config.cost_type == CostTypeEnum.MERCHANT: merchant_fee = fee_value elif merchant_config.cost_type == CostTypeEnum.USER: user_fee = fee_value # 用户实际到账金额要减去手续费 amount -= user_fee # 用户余额判断 if user.uid: user_balance = UserBalance.query_balance( uid=user.uid, merchant=user.merchant).first() if user_balance.real_balance < amount + user_fee: msg = '%s, params: %s' % ("用户余额不足", params) current_app.logger.error(msg) return order, AccountBalanceInsufficientError(message="用户余额不足") # 判断商户余额是否充足 merchant_balance = MerchantInfo.query_merchant(m_name=user.merchant) if merchant_balance.balance_available <= amount + merchant_fee: msg = '%s, params: %s' % ("商户余额不足", params) current_app.logger.error(msg) return order, AccountBalanceInsufficientError(message="商户余额不足") # 订单来源 source = OrderSourceEnum.TESTING if user.is_test_user else OrderSourceEnum.ONLINE try: # 创建提现订单/扣商户余额/扣用户余额,在同一个事务里面 with db.auto_commit(): order, ref_id = OrderCreateCtl.create_order_event( uid=user.uid, amount=amount, merchant=user.merchant, source=source, order_type=PayTypeEnum.WITHDRAW, in_type=InterfaceTypeEnum.CASHIER_H5, bank_id=user_bank_id, # 提现时需要填入 银行卡信息 mch_fee_id=merchant_config.config_id, mch_tx_id=mch_tx_id, ip=client_ip, fee=fee_value, cost_type=merchant_config.cost_type, notify_url=notify_url, bank_info=bank_info, extra=extra, commit=False, ) if not order: msg = '%s, params: %s' % (WithdrawOrderCreateError.message, params) current_app.logger.error(msg) raise WithdrawOrderCreateError() # 扣提现金额 flag, msg = MerchantBalanceEvent.update_balance( merchant=user.merchant, ref_id=ref_id, source=source, order_type=PayTypeEnum.WITHDRAW, bl_type=BalanceTypeEnum.AVAILABLE, value=amount, ad_type=BalanceAdjustTypeEnum.MINUS, tx_id=order.sys_tx_id, commit=False, ) if flag < 0: msg = '%s, params: %s' % ("扣商户余额失败, %s" % msg, params) current_app.logger.error(msg) raise DepositCallbackUserBalanceError(message="扣商户余额失败") if merchant_fee: # 扣商户手续费 flag, msg = MerchantBalanceEvent.update_balance( merchant=user.merchant, ref_id=OrderUtils.gen_unique_ref_id(), source=source, order_type=PayTypeEnum.FEE, bl_type=BalanceTypeEnum.AVAILABLE, value=merchant_fee, ad_type=BalanceAdjustTypeEnum.MINUS, tx_id=order.sys_tx_id, commit=False, ) if flag < 0: msg = '%s, params: %s' % ("扣商户手续费失败, %s" % msg, params) current_app.logger.error(msg) raise DepositCallbackUserBalanceError( message="扣商户手续费失败") if user_fee: # 扣除用户手续费 flag, msg = UserBalanceEvent.update_user_balance( uid=user.uid, merchant=user.merchant, ref_id=OrderUtils.gen_unique_ref_id(), source=source, order_type=PayTypeEnum.FEE, bl_type=BalanceTypeEnum.AVAILABLE, value=user_fee, ad_type=BalanceAdjustTypeEnum.MINUS, tx_id=order.sys_tx_id, commit=False, ) if flag < 0: msg = '%s, params: %s' % ("扣用户手续费失败, %s" % msg, params) current_app.logger.error(msg) raise DepositCallbackUserBalanceError( message="扣用户手续费失败") # 扣除用户余额 flag, msg = UserBalanceEvent.update_user_balance( uid=user.uid, merchant=user.merchant, ref_id=ref_id, source=source, order_type=PayTypeEnum.WITHDRAW, bl_type=BalanceTypeEnum.AVAILABLE, value=amount, ad_type=BalanceAdjustTypeEnum.MINUS, tx_id=order.sys_tx_id, commit=False, ) if flag < 0: msg = '%s, params: %s' % ("扣用户余额失败, %s" % msg, params) current_app.logger.error(msg) raise DepositCallbackUserBalanceError(message="扣用户余额失败") except APIException as e: current_app.logger.error(traceback.format_exc()) return order, e return order, None
def init_channel2(cls): if not cls.get_deposit_channel2(): # 充值通道配置 kwargs = dict(fee="2.5", fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, limit_per_min="500", limit_per_max="20000", trade_begin_hour="0", trade_begin_minute="0", trade_end_hour="0", trade_end_minute="0", maintain_begin=DateTimeKit.str_to_datetime( "2019-09-07 09:00:00"), maintain_end=DateTimeKit.str_to_datetime( "2019-09-07 09:00:00"), settlement_type=SettleTypeEnum.D0, state=ChannelStateEnum.TESTING if cls.merchant.is_test else ChannelStateEnum.ONLINE, priority="101") ChannelConfig.update_channel(cls.channel_enum2, **kwargs) channel_config = ChannelConfig.query_latest_one(query_fields=dict( channel_enum=cls.channel_enum2)) # print(channel_config) # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.DEPOSIT).get_channel_limit() limit_min, limit_max = ChannelListHelper.get_channel_limit_range( merchant=cls.merchant, payment_way=PayTypeEnum.DEPOSIT, ) # print('limit_min: %s, limit_max: %s' % (limit_min, limit_max)) assert 0 != limit_min assert 0 != limit_max if not cls.get_withdraw_channel2(): # 提款代付通道配置 withdraw_item = dict( fee="1.3", fee_type=PaymentFeeTypeEnum.PERCENT_PER_ORDER, limit_per_min="300", limit_per_max="10000", limit_day_max="500000", trade_begin_hour="0", trade_begin_minute="0", trade_end_hour="0", trade_end_minute="0", maintain_begin=DateTimeKit.str_to_datetime( "2019-09-07 09:00:00"), maintain_end=DateTimeKit.str_to_datetime( "2019-09-07 09:00:00"), state=ChannelStateEnum.TESTING if cls.merchant.is_test else ChannelStateEnum.ONLINE, banks=[ PaymentBankEnum.ZHONGGUO, PaymentBankEnum.GONGSHANG, PaymentBankEnum.JIANSHE, ]) ProxyChannelConfig.update_channel(cls.channel_enum2, **withdraw_item) channel_config = ProxyChannelConfig.query_latest_one( query_fields=dict(channel_enum=cls.channel_enum2)) # print(channel_config) # limit_min, limit_max = ChannelLimitCacheCtl(PayTypeEnum.WITHDRAW).get_channel_limit() limit_min, limit_max = ChannelListHelper.get_channel_limit_range( merchant=cls.merchant, payment_way=PayTypeEnum.WITHDRAW, ) # print('limit_min: %s, limit_max: %s' % (limit_min, limit_max)) assert 0 != limit_min assert 0 != limit_max
def post(self): """ 充值请求 """ 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_deposit_request"), IpKit.get_remote_ip(), request.args, request.json) form, error = DepositRequestForm.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() # 3. 获取对应支付方式下的充值通道 channel = ChannelListHelper.get_one_channel_by_payment_type( merchant=form.merchant_id.data, payment_type=form.payment_type.data, amount=form.amount.data, client_ip=form.user_ip.data, ) if not channel: current_app.logger.error("no channel found, request data: %s", form.get_data()) return GatewayChannelError().as_response() # # 境外IP检查 # if channel.is_ip_forbidden(form.user_ip.data): # return GatewayDepositError(message="此通道不支持境外IP,请使用VPN后重试").as_response() # 4. 获取用户对象 user = checker.get_fake_user(form.user_id.data) # 5. 发起支付 rst = DepositHelper.do_deposit_request( client_ip=form.user_ip.data, user_agent=form.user_agent.data, user=user, amount=form.amount.data, channel_enum=channel.channel_enum, notify_url=form.notify_url.data, result_url=form.result_url.data, mch_tx_id=form.mch_tx_id.data, extra=form.extra.data, source=OrderSourceEnum.TESTING if form.merchant_id.data.is_test else OrderSourceEnum.ONLINE, in_type=InterfaceTypeEnum.API, ) if rst['error']: return GatewayDepositError(message=rst['error']) # 6. 解析URL ps_rst = DepositHelper.parse_result( data=rst['data'], order_id=rst['order'].order_id, endpoint='gateway_deposit_redirect', channel_enum=channel.channel_enum, ) return GatewayResponseDeposit(bs_data=dict( redirect_url=ps_rst['redirect_url'], valid_time=ps_rst['valid_time'], sys_tx_id=rst['order'].sys_tx_id, mch_tx_id=rst['order'].mch_tx_id, )).as_response()
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()