华为支付-免密支付接入签约代扣场景开发步骤
一、预签约(服务器开发)
1.开发者按照商户模型调用预直连商户预签约或服务商预签约接口获取preSignNo构建签约信息参数contractStr。
为保证支付订单的安全性和可靠性需要对请求body和请求头PayMercAuth对象内的入参排序拼接进行签名。请参考排序拼接和签名示例代码。
以下为开放API接口请求及contractStr构建示例代码片段:
import com.huawei.petalpay.paymentservice.apiservice.client.model.BaseGwRspWithSign;
.import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignRequestV2;
.import com.huawei.petalpay.paymentservice.apiservice.client.model.PreSignResponse;
.import com.huawei.petalpay.paymentservice.core.client.DefaultPetalPayClient;
.import com.huawei.petalpay.paymentservice.core.client.PetalPayClient;
.import com.huawei.petalpay.paymentservice.example.common.CommonResponse;
.import com.huawei.petalpay.paymentservice.example.common.MercConfigUtil;
.
.public class MercApiController {
. private static PetalPayClient payClient = new DefaultPetalPayClient(MercConfigUtil.getMercConfig());
. /**
. * 预签约接口调用
. */
. public CommonResponse contractPreSignAppV2() {
. // 组装对象
. PreSignRequestV2 preSignReq = getPreSignRequestV2();
. PreSignResponse response = null;
. try {
. response = payClient.execute("POST", "/api/v2/contract/presign/app", PreSignResponse.class, preSignReq);
. } catch (Exception e) {
. // todo 异常处理
. log.error("request error ", e);
. return CommonResponse.buildErrorRsp(e.getMessage());
. }
. if (!validResponse(response)) {
. // todo 异常处理
. log.error("response is invalid ", response);
. return CommonResponse.buildFailRsp(response);
. }
. return CommonResponse.buildSuccessRsp(payClient.buildContractStr(response.getPreSignNo()));
. }
. public static boolean validResponse(BaseGwRspWithSign rsp) {
. return rsp != null && "000000".equals(rsp.getResultCode());
. }
. /**
. * 预签约接口请求参数组装,商户请根据业务自行实现
. */
. private PreSignRequestV2 getPreSignRequestV2() {
. return PreSignRequestV2.builder().appId(MercConfigUtil.APP_ID) // appId,需要配置为与商户绑定的正确的appId
. .mercContractCode("pay-example-" + System.currentTimeMillis()) // 签约协议号,每次请求都要变,请将pay-example-修改为商户自己的订单前缀
. .mercNo(MercConfigUtil.MERC_NO) // 商户号
. .planId("100") // 协议模板ID,该模板ID是商户在向华为支付提交代扣权限申请时由华为支付生成。请填写正确的协议模板ID。
. .callbackUrl("https://www.xxxxxx.com/hw/sign/callback") // 回调通知地址,通知URL必须为直接可访问的URL,要求为https地址。最大长度为512。请替换为格式正确的结果通知回调地址。
. .build();
. }
.}
二、拉起华为支付签约收银台(端侧开发)
商户客户端使用contractStr作为参数调用requestContract接口拉起Payment Kit签约收银台。
当接口通过.then()方法返回时,则表示当前订单支付成功,通过.catch()方法返回表示订单支付失败。当此次请求有异常时,可通过error.code获取错误码,错误码相关信息请参见错误码。示例代码如下:
.import { BusinessError } from '@kit.BasicServicesKit';
.import { paymentService } from '@kit.PaymentKit';
.import { common } from '@kit.AbilityKit';
.
.@Entry
.@Component
.struct Index {
. context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
. requestContractPromise() {
. // use your own contractStr
. const contractStr = '{"appId":"***","preSignNo":"***"}';
. paymentService.requestContract(this.context, contractStr)
. .then(() => {
. // succeeded in signing
. console.info('succeeded in signing');
. })
. .catch((error: BusinessError) => {
. // failed to sign
. console.error(`failed to sign, error.code: ${error.code}, error.message: ${error.message}`);
. });
. }
.
. build() {
. Column() {
. Button('requestContractPromise')
. .type(ButtonType.Capsule)
. .width('50%')
. .margin(20)
. .onClick(() => {
. this.requestContractPromise();
. })
. }
. .width('100%')
. .height('100%')
. }
.}
说明
·如果用户没有提前登录,系统会自动拉起华为账号登录页面让用户登录。
·签约成功,不建议以客户端返回作为用户的签约结果,需以服务器接收到的结果通知或者查询API返回为准。
三、签约结果回调通知(服务器开发)
支付成功后华为支付服务器会调用开发者提供的回调接口,将签约信息返回给开发者服务器,回调详细信息按商户模式请参见签约结果回调通知。
说明
回调接口是开发者调用预签约时的入参字段callbackUrl或签约模板配置的回调地址。
为保证信息合法性,商户服务器需要对返回的支付信息进行SM2验签,验签注意事项:
1.需直接使用通知的完整内容进行验签。
2.验签前需要对返回数据进行排序拼接,sign字段是签名值,排序拼接后的待验签内容需要排除sign字段。
3.验签公钥使用华为支付证书。
本文主要引用参考HarmonyOS官方文档