.. _9 支付系统: 9 支付系统 ============================ Pico支付,是基于Pico账户体系进行的游戏币支付系统,结算方式以现行的Pico公司下的游戏货币单位为准(P币)。 9.1 准备工作 ------------------- 9.1.1 支付需要如下的应用参数 ----------------------------------------- - **APP ID** : 开发者平台为应用生成的唯一标识 - **APP KEY** : 开发者平台为应用生成的Key - **APP Secret** : 开发者平台为应用生成的用于支付的Key - **Developer ID** : 开发者的ID,也叫商户ID 9.1.2 申请成为Pico开发者 ----------------------------------------- **Pico开发者平台网址** :https://developer.pico-interactive.com/ 开发者在接入支付SDK时,需要在开发者平台创建应用并获取 **应用参数** ,对应流程如下: 1. 在 `Pico 开发者平台页`_ 点击「`成为开发者`_」按钮。 .. _Pico 开发者平台页: https://developer.pico-interactive.com/ .. _成为开发者: https://devcenter.pico-interactive.com/#/organization 2. 在「账户」弹窗中选择您账户所在区域:中国大陆/其他地区 后,点击「注册」按钮。 .. image:: _static/9.1.2.1.png 3. 验证您的账户 - 若您选择了「中国大陆」,您需要填写您的手机号并设置您的密码,通过短信验证您的手机号; - 若您选择了「其他地区」,您需要填写您的邮箱并设置您的密码,并选择您账号所在国家/地区,通过验证邮件验证您的邮箱账号; .. image:: _static/9.1.2.2.png 4. 勾选接受 Pico「`用户许可协议`_」和「`隐私政策`_」,点击「注册」按钮。 .. _用户许可协议: https://www.pico-interactive.com/cn/terms/user_terms.html .. _隐私政策: https://www.pico-interactive.com/cn/terms/privacy.html 5. 恭喜!您已经正式成为 Pico 开发者啦。 **注意:** Pico 开发者账户注册完全免费 9.1.3 获取应用参数 ----------------------------------------- 1. **获取 Publisher ID** **申请成为开发者后,进入开发者管理平台,点击「我的应用」,进入「应用」后点击「API」菜单,即可查看到开发者 ID,该 ID 将作为支付系统中商户的唯一标志。** 2. **创建应用,选择支付类型** 开发者可以从管理中心进入到创建应用阶段,点击创建应用,然后进入相应平台完善应用的相关信息: .. image:: _static/9.1.3.1.png 图9.1 完善应用的相关信息 **注意: 应用类型和支付相关,审核通过上架后,无法更改。一个应用只能选择一种。** a. **选择应用** 。支付时使用 P 币数量直接支付。 b. **选择游戏** 。支付是商品码支付。商品码为游戏中付费道具在开发者后台的唯一标识。 游戏类应用如果存在道具内付的情况,我们要求开发者必须采用开发者后台增加商品码的方式进行统一管理。 商品码支付配置界面如下: 再选择“游戏内支付配置”,配置游戏的内购信息: .. image:: _static/9.1.3.2.png 图9.2 游戏内购配置 **注意商品码的定义方式:** - 定义规则。首位为字母,仅允许输入字母及数字,不超过20个字符 - 不可重复。不同道具间的商品码不能重复 - 类型支持。目前支持可消耗道具 和 不可消耗道具 。可消耗道具为可重复购买的商品,如金币、血瓶等;不可消耗道具为一次性购买产品,如武器、解锁关卡。 3. **获取 APP ID,APP KEY,APP Secret 参数** 成功创建应用后,开发者平台会对其分配字符串,包括 **APP ID、APP KEY、APP Secret** : .. image:: _static/9.1.3.3.png 图9.3 APP ID、APP KEY、APP Secret **至此,Developer ID ,APP ID、APP KEY、APP Secret 都已获取到了。** 9.1.4 OnlinePico Settings中配置应用参数 ---------------------------------------------------------------------------------------- 进入Edit->Project Settings…,展开Plugins子项下的OnlinePico Settings,勾选“Enable Payment Module”,然后根据实际情况选择Region:如果需要国内上线则选择China,海外上线选择NonChina,国内海外同时上线则选择Both。 .. image:: _static/9.1.4.1.png 图9.4 选择上线地域 最后将获取的商户ID(Developer ID)、APPID、APP KEY、APP secret填入以下位置: .. image:: _static/9.1.4.2.png 图9.5 填入字符串 9.2 使用支付系统 ----------------------------------------- .. image:: _static/9.2.1.jfif 图9.6 支付系统使用流程 - 需要确保首先调用登录接口(Pico Login SDK或Pico Payment Login)返回成功后,再调用支付(Pico Payment Pay with Coin、Pico Payment Pay with Pay Coin)、查询订单(Pico Payment Query)、获取用户信息(Pico Payment Get User Info、Pico SDKGet User Info)等接口。 - 登陆成功后,如需登出操作,则调用登出接口(Pico Logout SDK、Pico Payment Logout)。 - 以上接口在使用过程中,均需要绑定回调事件获取调用结果,具体各个接口的详细用法见9.3 接口功能说明。 9.3 接口功能说明 ----------------------------------------- 9.3.1 登录 ----------------------------------------- Pico为开发者提供基于Oauth2.0模式的认证授权,故用户支付前需要先进行登录操作。注:登陆部分可以只登陆一次,之后直接使用支付即可,登陆过期时间约为两周,过期后支付接口回有返回码(登陆过期码),用户只需再次登陆即可。 这里使用我们提供的PicoPaymentLogin节点或者PicoLoginSDK节点: Pico Login SDK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以进行登录,并且通过绑定回调事件获取登录结果。 **蓝图** .. image:: _static/9.3.1.1.png **输入:** - delegate类型: - Log in Delegate:绑定Login回调事件,如下图所示: .. image:: _static/9.3.1.2.png - 回调事件参数: - bool类型: - IsSucceed: - true:成功 - false:失败 - FString类型: - Reason: 通过字符串输出登录失败原因,见表 9-1 Reason Code对照表 **输出:** 无 **返回值:** 无 Pico Payment Login ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以进行登录,并且通过绑定回调事件获取登录结果。 **蓝图** .. image:: _static/9.3.1.3.png **输入:** - delegate类型: - Log in Delegate:绑定Login回调事件,如下图所示: .. image:: _static/9.3.1.4.png - 回调事件参数: - bool类型: - IsSucceed: - true:成功 - false:失败 - FString类型: - Reason: 通过字符串输出登录失败原因,见表 9-1 Reason Code对照表 **输出:** 无 **返回值:** 无 9.3.2 登出 ----------------------------------------- 登出操作可以使用PicoLogoutSDK或者PicoPaymentLogout节点: Pico Logout SDK ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以进行登出,并且通过绑定回调事件获取登出结果。 **蓝图** .. image:: _static/9.3.2.1.png **输入:** - delegate类型: - Log in Delegate:绑定Logout回调事件,如下图所示: .. image:: _static/9.3.2.2.png - 回调事件参数: - bool类型: - IsSucceed: - true:成功 - false:失败 - FString类型: - Reason: 通过字符串输出登录失败原因,见表 9-1 Reason Code对照表 **输出:** 无 **返回值:** 无 Pico Payment Logout ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以进行登出,并且通过绑定回调事件获取登出结果。 **蓝图** .. image:: _static/9.3.2.3.png **输入:** - delegate类型: - Log in Delegate:绑定Logout回调事件,如下图所示: .. image:: _static/9.3.2.4.png - 回调事件参数: - bool类型: - IsSucceed: - true:成功 - false:失败 - FString类型: - Reason:通过字符串输出登录失败原因,见表 9-1 Reason Code对照表 **输出:** 无 **返回值:** 无 表 9-1 Reason Code对照表 ======================================= ========================================= =========================================== 错误信息 说明 原因 ======================================= ========================================= =========================================== TIME_ERROR 时间戳错误 本地时间和服务器时间相差超过8分钟 SYSTEM_USER_NOT_FIND_ERROR 用户未找到 用户中心token对应的用户未找到 SYSTEM_USER_TOEKN_NOT_FIND_ERROE 用户token寻找失败 用户中心token未找到 SYSTEM_USER_TOKEN_CHECK_FAILURE_ERROR 用户token验证失败 用户中心token失效 SYSTEM_USER_TOKEN_UNKNOWN_ERROR 用户token验证失败 用户中心token检查失败 APP_CHECK_ERROR 应用验证失败 APP ID等参数填写错误 ======================================= ========================================= =========================================== 9.3.3 支付 ----------------------------------------- Pico Payment Pay with Coin ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以使用P币进行支付。 **蓝图** .. image:: _static/9.3.3.1.png **输入:** .. image:: _static/9.3.3.2.png - FString类型: - OrderNumber:商户自己定义的订单号,32个字符内、可包含字母和数字 - OrderTitle:订单标题 - ProductDetail:商品描述 - Notify Url:欲通知的URL(非必填),必须为直接可访问的url,不能携带参数 - int类型: - PicoCoinCount:花费P币数额 - delegate类型: - Pay Order with Coin Delegate:绑定支付回调事件,如下图所示: .. image:: _static/9.3.3.3.png - 回调事件参数: - FString类型: - Code:见表9-2 支付Code与Message对应表 - Message:见表9-2 支付Code与Message对应表 **输出:** 无 **返回值:** 无 Pico Payment Pay with Code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以使用支付码支付。 **蓝图** .. image:: _static/9.3.3.4.png **输入:** .. image:: _static/9.3.3.5.png - FString类型: - OrderNumber:商户自己生成的订单号,32个字符内、可包含字母和数字 - OrderTitile:订单标题 - Product Detail:商品描述 - Notify Url:欲通知的URL(非必填),必须为直接可访问的url,不能携带参数 - PicoPayCode:即商品代码,用户通过9.1.1游戏内支付配置获取 - delegate类型: - Pay Order with Coin Delegate:绑定支付回调事件,如下图所示: .. image:: _static/9.3.3.6.png - 回调事件参数: - FString类型: - Code:见表 9-2 支付Code与Message对应表 - Message:见表 9-2 支付Code与Message对应表 **输出:** 无 **返回值:** 无 表 9-2 Code与Message对应表 ============================ ============================================== Code Message 信息 ============================ ============================================== 00000 网络异常 10000 登录成功 10001 用户未登陆 10002 请输入正确金额 10003 登陆过期,请重新登陆 11000 商户验证成功 11001 商户验证失败 11002 用户验证参数错误或请求过期 11003 商户未验证 12000 支付成功 12001 支付失败 12003 P币不足 12004 余额可用 13000 生成订单 13001 获取数据失败 13002 生成订单失败 14000 查询订单成功 14001 订单不存在/有误 14002 用户取消支付操作 15000 未输入商品信息 15001 未输入预付ID 15002 请输入Pico支付订单号或商户订单号 NOAUTH 商户无此接口权限 SYSTEMERROR 系统错误 APP_ID_NOT_EXIST APP_ID不存在 MCHID_NOT_EXIST MCHID 不存在 APP_ID_MCHID_NOT_MATCH app_id和mch_id不匹配 LACK_PARAMS 缺少参数 SIGNERROR 签名错误 NO_DATA 没有查询到数据/用户未充值 ORDER_EXIST 订单已存在 PAY_CODE_NOT_EXIST 消费代码不存在 PAY_CODE_EXIST 用户已对商品代码消费 ============================ ============================================== 9.3.4 查询订单 ----------------------------------------- Pico Payment Query Order ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 通过该蓝图接口可以查询订单。 **蓝图** .. image:: _static/9.3.4.1.png **输入:** - FString类型: - Order Number:订单号(String) - delegate类型: - Query Order Delegate:绑定订单查询回调事件,如下图所示: .. image:: _static/9.3.4.2.png - 回调事件参数: - FString类型: - Code:见表 9-2 支付Code与Message对应表 - Message:见表 9-2 支付Code与Message对应表 **输出:** 无 **返回值:** 无 9.3.5 获取用户信息 ----------------------------------------- Pico Payment Get User Info ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **蓝图** .. image:: _static/9.3.5.1.png **输入:** - delegate类型: - User Info Delegate:绑定获取用户信息回调事件,如下图所示: .. image:: _static/9.3.5.2.png - FString类型: - Info:一个未经处理的Json串(string),见查询结果范例与表 9-3 OnPicoGetUserInfoCallback输出参数ret_code码及ret_msg一览 **输出:** 无 **返回值:** 无 Pico SDKGet User Info ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **蓝图** .. image:: _static/9.3.5.3.png **输入:** - delegate类型: - User Info Delegate:绑定获取用户信息回调事件,如下图所示: .. image:: _static/9.3.5.4.png - FString类型: - Info:一个未经处理的Json串(string),见查询结果范例与表 9-3 OnPicoGetUserInfoCallback输出参数ret_code码及ret_msg一览 **输出:** 无 **返回值:** 无 **查询结果范例** Info:一个未经处理的Json串(string),查询成功范例如下: .. code-block:: java {"ret_code":"0000", "data" : { "aboutme":"", "birthday" : 1460476800000, "phone" : "13100000000", "username" : "Admin", "email" : "", "gender" : "male", "lastname" : "", "openid" : "4f3148bdc34d9bca104927729a173b64", "firstname" : "", "avatar" : "http://172.31.83.11/upload/6dd6ee103714e967846c3d38ae48d511", "signature" : "14a25d7219d8dfc91e55f63286ae5c0a", "country" : "China", "city" : "" }, "ret_msg":"调用成功" } 查询失败范例如下: .. code-block:: java { "ret_code":"00003000", "ret_msg" : "签名验证失败" } **其他ret_code码及ret_msg一览:** 表 9-3 OnPicoGetUserInfoCallback输出参数ret_code码及ret_msg一览 ====================== ============================================== ret_code ret_msg ====================== ============================================== 0000 请求成功 00020000 数据库操作失败 9999 系统错误 00001000 参数错误 00002000 数据解析失败 00003000 签名验证失败 00003001 时间验证失败 00060000 用户未找到 00060001 用户密码错误 00060002 用户登录未知错误 00061000 用户token未找到失败 00061001 用户token验证失败 00061002 用户token未知错误 00070001 应用验证失败 00071001 应用密钥验证失败 00080001 OAUTH_CODE验证失败 00090001 REFRESH_TOKEN验证失败 00100001 ACCESS_TOKEN验证失败 00110001 SCOPE验证失败 ====================== ============================================== 9.4 开发者服务端交互 ------------------------------ 支付完成后,支付系统会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。 对后台通知交互时,如果支付系统收到商户的应答不是成功或超时,则认为通知失败,支付系统会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但不保证通知最终能成功。 同样的通知可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知。推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。 商户服务端需要实现下面的接口,用于接收来自Pico服务器请求,获取Pico支付系统的支付结果和用户信息: 表9.4 商户服务器需要实现的接口 ================= ======================================================================== 名称 支付结果回调接口 请求类型 POST 请求URL 支付,PayOrder传入的参数notify_url 请求格式 JSON 返回格式 JSON 是否需要登录 是 请求参数 详见下面“表9.3 支付结果通知中的通知参数” 请求参数示例 返回参数 参数名 类型及范围 说明 ret_code string 错误代码。 ret_msg string 错误信息字符串。 详见“表9.4 返回结果” 返回参数实例 { "ret_code":"SUCCESS", "ret_msg":"OK" } 更新说明 ================= ======================================================================== 表9-5 支付结果通知中的通知参数 ==================== =============== ====== ======== =============================================================================== 字段名 变量名 必填 类型 描述 ==================== =============== ====== ======== =============================================================================== 返回状态码 ret_code 是 String SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断 返回信息 ret_msg 否 String 返回信息,如非空,为错误原因:签名失败参数格式校验错误 错误代码 sub_code 否 String 错误码 错误代码描述 sub_msg 否 String 错误返回的信息描述 Pico支付订单号 trade_no 是 String Pico支付订单号 商户订单号 out_trade_no 是 String 商户系统内部的订单号 应用ID app_id 是 String 平台审核通过的应用APP_ID 商户ID mch_id 是 String 支付分配的商户号 用户标识 open_id 是 String 用户在商户appid下的唯一标识 设备号 device_id 否 String 终端设备号 随机字符串 nonce_str 是 String 随机字符串,不长于32位。推荐随机数生成算法(https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3) 签名 signature 是 String 签名,详见签名生成算法(https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3) 业务结果 result_code 是 String SUCCESS/FAIL 交易类型 trade_type 是 String 支付类型 货币类型 fee_type 是 String 货币类型 总金额 total_fee 是 String 订单总金额 实收金额 receipt_fee 是 String 实收金额 买家付款的金额 buyer_pay_fee 否 String 买家付款的金额 代金券或立减优惠金额 coupon_fee 否 String 代金券或立减优惠金额 商家数据包 attach 否 String 商家数据包,原样返回 支付完成时间 pay_time 是 String 支付完成时间,格式为yyyy-MM-dd HH:mm:ss ==================== =============== ====== ======== =============================================================================== 表9.6 返回结果 =================== =============== ====== ======== ================================================================================ 字段名 变量名 必填 类型 描述 =================== =============== ====== ======== ================================================================================ 返回状态码 ret_code 是 String SUCCESS/FAIL SUCCESS表示商户接收通知成功并校验成功 返回信息 ret_msg 否 String 返回信息,如非空,为错误原因:函数名失败参数格式校验错误 =================== =============== ====== ======== ================================================================================ **特别提醒:** 商户系统对于支付结果通知的内容一定要做签名验证,防止数据泄漏导致出现“假通知”,造成资金损失。 函数名校验规则是: 1.返回的参数列表,去掉signautre参数,同时添加key=“app_secret”,value=paykey,然后根据key值进行自然排序,多个参数之间用&隔开,最后进行MD5加密 2.用加密后的字符串和获取到的signature进行比较 函数名函数如下: .. code-block:: C++ /** * result :获取的数据的map集合 * paykey :就是开发者平台上的paykey */ public static String createSign(Map result, String paykey) { if (result == null || result.size() == 0) return null; result.put("app_secret", paykey); //1.添加key = “app_secret”,value=payke String sign = result.get("signature");//2.保存signature的值,用于校验 result.remove("signature"); //3.移除signature参数 String[] tmp = new String[result.size()]; int i = 0; for (String key : result.keySet()) { tmp[i++] = key; } Arrays.sort(tmp); //4.自然排序 String signTemp = ""; for (String string : tmp) { if (result.get(string) == null) continue; signTemp += string + "=" + URLEncoder.encode(result.get(string).toString() , "utf-8") + "&"; } if (signTemp.endsWith("&")) signTemp = signTemp.substring(0, signTemp.length() - 1); Log.i(TAG, "createSign: " + signTemp); String localSign = MD5.MD5(sign); //5.生成MD5加密后的字符串 return localSign.equal(sign);//6.和2中的sign进行校验 }