PYTHON¶
简介¶
为了提高客户的接入体验,特提供封装的开发SDK,使用本SDK将极大的简化开发者的工作,开发者将无需考虑通信、签名、验签等,只需要关注业务参数的拼装。
版本要求¶
此 SDK 目前只支持 Python3,请确保在 Python3 工程接入。
接入方法¶
下载 SDK
下载文件里包含 basepay_sdk 、 basepay_demo 两个目录。basepay_sdk 目录下为待添加到项目中的文件, basepay_demo 目录下为示例项目,供接入时参考使用。
导入第三方依赖库
在当前环境确保已经安装以下版本的依赖库:
pycryptodome==3.8.2
requests==2.22.0
使用方法¶
系统初始化
在使用 SDK 调用汇付接口前,请先进行商户配置,否则可能导致交易异常。
正常情况下只有一套商户配置,如有业务需求向汇付申请了多套配置信息,也可配置多个商户配置,并做好商户配置命名管理,配置名必须唯一
调用示例
'''
单套配置
默认为单商户配置,配置key默认为default,上送报文时无需指定配置key
'''
BasePay.init(
{
'product_id': demo_constants.DEMO_PRODUCT_ID,
"sys_id": demo_constants.DEMO_SYS_ID,
'rsa_private_key': demo_constants.RSA_PRIVATE_KEY,
'rsa_public_key': demo_constants.RSA_PUBLIC_KEY
})
'''
多套配置
如商户因特殊需要,申请多套配置,则需自行做好配置管理,上送报文时需明确指定使用哪套商户配置
'''
BasePay.init_with_multi_mer_configs(
{
"merchantKey1" :
{
'product_id': demo_constants.DEMO_PRODUCT_ID1,
"sys_id": demo_constants.DEMO_SYS_ID1,
'rsa_private_key': demo_constants.RSA_PRIVATE_KEY1,
'rsa_public_key': demo_constants.RSA_PUBLIC_KEY1
},
"merchantKey2" :
{
'product_id': demo_constants.DEMO_PRODUCT_ID2,
"sys_id": demo_constants.DEMO_SYS_ID2,
'rsa_private_key': demo_constants.RSA_PRIVATE_KEY2,
'rsa_public_key': demo_constants.RSA_PUBLIC_KEY2
},
}
)
接口调用¶
接口调用均由 BasePayClient.post_request 方法发起,上传文件接口由 BasePayClient.upload_file 方法发起
@staticmethod
def post_request(func_code, request_params, merchant_key = 'default')
@staticmethod
def upload_file(func_code, request_params, request_file = None, merchant_key = 'default')
request_params
为请求报文体BODY中的 data
- 「接口规则-参数规定-报文体」 ,需根据调用接口的API说明组装参数。
func_code
为请求接口的功能编码,请参考 交易接口功能编码、商户管理接口功能编码。
request_file
为需上传的文件。
merchant_key
为上一步初始化时配置的商户配置key。
接口调用实例¶
以下以聚合反扫接口为例,展示如何使用 SDK 来调用接口。
# 调试模式,默认False关闭,打开后输出日志供联调排查问题
BasePay.debug = False
# 生产模式,默认为True生产环境
BasePay.prod_mode = True
req_date = datetime.datetime.now().strftime('%Y%m%d')
now_datetime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
req_seq_id = now_datetime + "01234567890"
# mer_ord_id = now_datetime + "1234567890"
mer_ord_id = req_seq_id;
time_expire = (datetime.datetime.now() + datetime.timedelta(minutes=2)).strftime('%Y%m%d%H%M%S')
request_param = {
# 请求流水号,需保证当天商户下唯一,推荐采用日期时间+几位流水号的形式
"req_seq_id" : req_seq_id,
# 请求日期,请求接口的日期,因服务器时间可能有差异,允许前后1天
"req_date": req_date,
# 系统号,由汇付分配
"sys_id": demo_constants.DEMO_SYS_ID,
# 商户订单号,需保证商户下唯一,推荐采用日期时间+几位流水号的形式,可与req_seq_id相同
"mer_ord_id": mer_ord_id,
# 分配商户号
"huifu_id": demo_constants.DEMO_HUIFU_ID,
# 渠道号,若需使用自有渠道请联系业务对接人
"bank_channel_no" : "",
# 交易金额
"trans_amt":"0.02",
# 商品描述
"goods_desc":"测试商品",
# 付款二维码
"auth_code" : '用户展示的付款码',
# 设备信息
"terminal_device_info": {
"device_type":"4",
"device_ip":"终端设备ip地址"
},
# 风控信息
# 注意,风控信息为JSON字符串
"risk_check_info" : json.dumps({
"riskMngInfo" : {
"subTradeType" : "4300"
},
"ipAddr":"139.207.19.246"
}),
# 异步通知地址
"notify_url":"virgo://http://www.test.com/asynNotice",
# 交易有效期
"time_expire":time_expire,
# 指定支付方式 是否禁止用户使用信用卡支付。默认不禁用,若禁止请填1
"limit_pay":"1",
# 延时标志 1为延迟 0为不延迟
"is_delay_acct":"0",
# 传入分帐遇到优惠的处理规则 1-按比例分 2-按顺序保障 3-只给交易商户
"term_div_coupon_type":"3",
# 分账串
# 注意只有真实分账场景才需要传入分账串,请避免传入多个分账方为同一商户的分账串
"acct_split_bunch":{
"acct_infos" : [
# 分账方1
{
'huifu_id':demo_constants.DEMO_HUIFU_ID,
'div_amt':'0.01'
},
# 分账方2
{
"huifu_id":demo_constants.DEMO_DIV_HUIFU_ID,
"div_amt":"0.01"
}
]
},
# 商户私有域
"mer_priv":"",
# 微信扩展参数集合
"wx_data":"",
# 支付宝扩展参数集合
"alipay_data":"",
# 银联扩展参数集合
"unionpay_data":"",
# 手续费类型 01:标准费率线上,02:标准费率线下,03:非盈利费率,04:缴费费率,05:保险费率,06:行业活动费率,07:校园餐饮费率,08:K12中小幼费率
# 不送时取业务入驻配置的默认费率
"pay_scene":"02"
}
# 调用聚合反扫接口
try:
post_result = BasePayClient.post_request('top.trans.authCodePay', request_param)
# 如果需要套用指定配置调用接口,请参考以下
# post_result = BasePayClient.post_request('top.trans.authCodePay', request_param, 'merchantKey2')
except Exception as e:
print(str(e))
sys.exit()
sub_resp_code = post_result.get('sub_resp_code', '')
if (sub_resp_code == '00000000'):
print('处理成功')
print('交易状态:' + post_result.get('trans_stat', ''))
# 交易状态处理中后续可调用交易查询接口获取终态
elif (sub_resp_code == '00000100'):
print('处理中')
print('交易状态:' + post_result.get('trans_stat', ''))
# 交易状态处理中后续可调用交易查询接口获取终态
else:
print ('处理失败:' + post_result.get('sub_resp_desc', ''))