From 798424eb5282b0d7ed91a9bb496c045489132e20 Mon Sep 17 00:00:00 2001
From: Jerry <85411418@qq.com>
Date: Wed, 18 Dec 2024 16:05:31 +0800
Subject: [PATCH 1/2] add new api
---
alipay/v3/constant.go | 2 +-
alipay/v3/fund_auth_api.go | 8 +-
alipay/v3/member_api.go | 12 +-
alipay/v3/merchant_api.go | 261 ++++++++++++++++++++++++++++++++++++
alipay/v3/model_merchant.go | 123 +++++++++++++++++
alipay/v3/model_payment.go | 38 ++++++
alipay/v3/payment_api.go | 98 ++++++++++++--
doc/alipay_v3.md | 13 ++
8 files changed, 535 insertions(+), 20 deletions(-)
create mode 100644 alipay/v3/merchant_api.go
create mode 100644 alipay/v3/model_merchant.go
diff --git a/alipay/v3/constant.go b/alipay/v3/constant.go
index 156f50ea..32a09fc3 100644
--- a/alipay/v3/constant.go
+++ b/alipay/v3/constant.go
@@ -37,6 +37,7 @@ const (
v3DataBillDownloadUrlQuery = "/v3/alipay/data/dataservice/bill/downloadurl/query" // 查询对账单下载地址
v3TradePrecreate = "/v3/alipay/trade/precreate" // 统一收单线下交易预创建
v3TradeCreate = "/v3/alipay/trade/create" // 统一收单交易创建接口
+ v3TradeOrderInfoSync = "/v3/alipay/trade/orderinfo/sync" // 支付宝订单信息同步接口
// 商家扣款
v3UserAgreementQuery = "/v3/alipay/user/agreement/query" // 支付宝个人代扣协议查询接口
@@ -50,7 +51,6 @@ const (
v3TradeOrderSettle = "/v3/alipay/trade/order/settle" // 统一收单交易结算接口
v3TradeOrderSettleQuery = "/v3/alipay/trade/order/settle/query" // 交易分账查询接口
v3TradeOrderOnSettleQuery = "/v3/alipay/trade/order/onsettle/query" // 分账剩余金额查询
- v3TradeOrderInfoSync = "/v3/alipay/trade/orderinfo/sync" // 支付宝订单信息同步接口
// 刷脸付
v3ZolozAuthenticationSmilepayInitialize = "/v3/zoloz/authentication/smilepay/initialize" // 刷脸支付初始化
diff --git a/alipay/v3/fund_auth_api.go b/alipay/v3/fund_auth_api.go
index 2ae3e4b1..3f8f5077 100644
--- a/alipay/v3/fund_auth_api.go
+++ b/alipay/v3/fund_auth_api.go
@@ -9,7 +9,7 @@ import (
"github.com/go-pay/gopay"
)
-// 资金授权操作查询接口
+// 资金授权操作查询接口 alipay.fund.auth.operation.detail.query
// StatusCode = 200 is success
func (a *ClientV3) FundAuthOperationDetailQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *FundAuthOperationDetailQueryRsp, err error) {
authorization, err := a.authorization(MethodPost, v3FundAuthOperationDetailQuery, bm)
@@ -33,7 +33,7 @@ func (a *ClientV3) FundAuthOperationDetailQuery(ctx context.Context, bm gopay.Bo
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 资金授权冻结接口
+// 资金授权冻结接口 alipay.fund.auth.order.freeze
// StatusCode = 200 is success
func (a *ClientV3) FundAuthOrderFreeze(ctx context.Context, bm gopay.BodyMap) (aliRsp *FundAuthOrderFreezeRsp, err error) {
err = bm.CheckEmptyError("auth_code", "auth_code_type", "out_order_no", "out_request_no", "order_title", "product_code", "amount")
@@ -61,7 +61,7 @@ func (a *ClientV3) FundAuthOrderFreeze(ctx context.Context, bm gopay.BodyMap) (a
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 资金授权解冻接口
+// 资金授权解冻接口 alipay.fund.auth.order.unfreeze
// StatusCode = 200 is success
func (a *ClientV3) FundAuthOrderUnfreeze(ctx context.Context, bm gopay.BodyMap) (aliRsp *FundAuthOrderUnfreezeRsp, err error) {
err = bm.CheckEmptyError("auth_no", "out_request_no", "amount", "remark")
@@ -89,7 +89,7 @@ func (a *ClientV3) FundAuthOrderUnfreeze(ctx context.Context, bm gopay.BodyMap)
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 资金授权发码接口
+// 资金授权发码接口 alipay.fund.auth.order.voucher.create
// StatusCode = 200 is success
func (a *ClientV3) FundAuthOrderVoucherCreate(ctx context.Context, bm gopay.BodyMap) (aliRsp *FundAuthOrderVoucherCreateRsp, err error) {
err = bm.CheckEmptyError("out_order_no", "out_request_no", "order_title", "amount", "product_code")
diff --git a/alipay/v3/member_api.go b/alipay/v3/member_api.go
index 067f561f..b7b1a267 100644
--- a/alipay/v3/member_api.go
+++ b/alipay/v3/member_api.go
@@ -9,7 +9,7 @@ import (
"github.com/go-pay/gopay"
)
-// 换取授权访问令牌
+// 换取授权访问令牌 alipay.system.oauth.token
// StatusCode = 200 is success
func (a *ClientV3) SystemOauthToken(ctx context.Context, bm gopay.BodyMap) (aliRsp *SystemOauthTokenRsp, err error) {
err = bm.CheckEmptyError("grant_type")
@@ -37,7 +37,7 @@ func (a *ClientV3) SystemOauthToken(ctx context.Context, bm gopay.BodyMap) (aliR
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 身份认证记录查询
+// 身份认证记录查询 alipay.user.certify.open.query
// StatusCode = 200 is success
func (a *ClientV3) UserCertifyOpenQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserCertifyOpenQueryRsp, err error) {
err = bm.CheckEmptyError("certify_id")
@@ -66,7 +66,7 @@ func (a *ClientV3) UserCertifyOpenQuery(ctx context.Context, bm gopay.BodyMap) (
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 身份认证初始化服务
+// 身份认证初始化服务 alipay.user.certify.open.initialize
// StatusCode = 200 is success
func (a *ClientV3) UserCertifyOpenInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserCertifyOpenInitializeRsp, err error) {
err = bm.CheckEmptyError("outer_order_no", "biz_code", "identity_param")
@@ -94,7 +94,7 @@ func (a *ClientV3) UserCertifyOpenInitialize(ctx context.Context, bm gopay.BodyM
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 支付宝会员授权信息查询接口
+// 支付宝会员授权信息查询接口 alipay.user.info.share
// StatusCode = 200 is success
func (a *ClientV3) UserInfoShare(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserInfoShareRsp, err error) {
err = bm.CheckEmptyError("avatar", "city", "nick_name", "province")
@@ -122,7 +122,7 @@ func (a *ClientV3) UserInfoShare(ctx context.Context, bm gopay.BodyMap) (aliRsp
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 用户授权关系查询
+// 用户授权关系查询 alipay.open.auth.userauth.relationship.query
// StatusCode = 200 is success
func (a *ClientV3) UserAuthRelationshipQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserAuthRelationshipQueryRsp, err error) {
err = bm.CheckEmptyError("scopes")
@@ -151,7 +151,7 @@ func (a *ClientV3) UserAuthRelationshipQuery(ctx context.Context, bm gopay.BodyM
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 查询解除授权明细
+// 查询解除授权明细 alipay.user.deloauth.detail.query
// StatusCode = 200 is success
func (a *ClientV3) UserDelOauthDetailQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserDelOauthDetailQueryRsp, err error) {
err = bm.CheckEmptyError("date", "limit", "offset")
diff --git a/alipay/v3/merchant_api.go b/alipay/v3/merchant_api.go
new file mode 100644
index 00000000..8d441d07
--- /dev/null
+++ b/alipay/v3/merchant_api.go
@@ -0,0 +1,261 @@
+package alipay
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+
+ "github.com/go-pay/gopay"
+)
+
+// 支付宝个人代扣协议查询接口 alipay.user.agreement.query
+// StatusCode = 200 is success
+func (a *ClientV3) UserAgreementQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserAgreementQueryRsp, err error) {
+ if bm.GetString("alipay_user_id") == gopay.NULL && bm.GetString("alipay_open_id") == gopay.NULL {
+ return nil, errors.New("alipay_user_id and alipay_open_id are not allowed to be null at the same time")
+ }
+ uri := v3UserAgreementQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &UserAgreementQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 支付宝个人代扣协议解约接口 alipay.user.agreement.unsign
+// StatusCode = 200 is success
+func (a *ClientV3) UserAgreementPageUnSign(ctx context.Context, bm gopay.BodyMap) (aliRsp *UserAgreementPageUnSignRsp, err error) {
+ if bm.GetString("alipay_user_id") == gopay.NULL && bm.GetString("alipay_open_id") == gopay.NULL && bm.GetString("alipay_logon_id") == gopay.NULL {
+ return nil, errors.New("alipay_user_id and alipay_open_id and alipay_logon_id are not allowed to be null at the same time")
+ }
+ if bm.GetString("external_agreement_no") == gopay.NULL && bm.GetString("agreement_no") == gopay.NULL {
+ return nil, errors.New("external_agreement_no and agreement_no are not allowed to be null at the same time")
+ }
+ authorization, err := a.authorization(MethodPost, v3UserAgreementPageUnSign, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3UserAgreementPageUnSign, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &UserAgreementPageUnSignRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 分账关系绑定 alipay.trade.royalty.relation.bind
+// StatusCode = 200 is success
+func (a *ClientV3) TradeRelationBind(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeRelationBindRsp, err error) {
+ err = bm.CheckEmptyError("receiver_list", "out_request_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3TradeRoyaltyRelationBind, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3TradeRoyaltyRelationBind, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeRelationBindRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 分账关系解绑 alipay.trade.royalty.relation.unbind
+// StatusCode = 200 is success
+func (a *ClientV3) TradeRelationUnbind(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeRelationUnbindRsp, err error) {
+ err = bm.CheckEmptyError("receiver_list", "out_request_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3TradeRoyaltyRelationUnbind, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3TradeRoyaltyRelationUnbind, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeRelationUnbindRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 分账关系查询 alipay.trade.royalty.relation.batchquery
+// StatusCode = 200 is success
+func (a *ClientV3) TradeRelationBatchQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeRelationBatchQueryRsp, err error) {
+ authorization, err := a.authorization(MethodPost, v3TradeRoyaltyRelationBatchQuery, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3TradeRoyaltyRelationBatchQuery, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeRelationBatchQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 分账比例查询 alipay.trade.royalty.rate.query
+// StatusCode = 200 is success
+func (a *ClientV3) TradeRoyaltyRateQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeRoyaltyRateQueryRsp, err error) {
+ err = bm.CheckEmptyError("out_request_no")
+ if err != nil {
+ return nil, err
+ }
+ uri := v3TradeRoyaltyRateQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeRoyaltyRateQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 统一收单交易结算接口 alipay.trade.order.settle
+// StatusCode = 200 is success
+func (a *ClientV3) TradeOrderSettle(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeOrderSettleRsp, err error) {
+ err = bm.CheckEmptyError("out_request_no", "trade_no", "royalty_parameters")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3TradeOrderSettle, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3TradeOrderSettle, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeOrderSettleRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 交易分账查询接口 alipay.trade.order.settle.query
+// StatusCode = 200 is success
+func (a *ClientV3) TradeOrderSettleQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeOrderSettleQueryRsp, err error) {
+ uri := v3TradeOrderSettleQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeOrderSettleQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 分账剩余金额查询 alipay.trade.order.onsettle.query
+// StatusCode = 200 is success
+func (a *ClientV3) TradeOrderOnSettleQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeOrderOnSettleQueryRsp, err error) {
+ err = bm.CheckEmptyError("trade_no")
+ if err != nil {
+ return nil, err
+ }
+ uri := v3TradeOrderOnSettleQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeOrderOnSettleQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
diff --git a/alipay/v3/model_merchant.go b/alipay/v3/model_merchant.go
new file mode 100644
index 00000000..7b8db67d
--- /dev/null
+++ b/alipay/v3/model_merchant.go
@@ -0,0 +1,123 @@
+package alipay
+
+type UserAgreementQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ PrincipalId string `json:"principal_id"`
+ PrincipalOpenId string `json:"principal_open_id"`
+ ValidTime string `json:"valid_time"`
+ AlipayLogonId string `json:"alipay_logon_id"`
+ InvalidTime string `json:"invalid_time"`
+ PricipalType string `json:"pricipal_type"`
+ DeviceId string `json:"device_id"`
+ SignScene string `json:"sign_scene"`
+ AgreementNo string `json:"agreement_no"`
+ ThirdPartyType string `json:"third_party_type"`
+ Status string `json:"status"`
+ SignTime string `json:"sign_time"`
+ PersonalProductCode string `json:"personal_product_code"`
+ ExternalAgreementNo string `json:"external_agreement_no"`
+ ZmOpenId string `json:"zm_open_id"`
+ ExternalLogonId string `json:"external_logon_id"`
+ CreditAuthMode string `json:"credit_auth_mode"`
+ SingleQuota string `json:"single_quota"`
+ LastDeductTime string `json:"last_deduct_time"`
+ NextDeductTime string `json:"next_deduct_time"`
+ ExecutionPlans []*ExecutionPlan `json:"execution_plans"`
+}
+
+type ExecutionPlan struct {
+ SingleAmount string `json:"single_amount"`
+ PeriodId string `json:"period_id"`
+ ExecuteTime string `json:"execute_time"`
+ LatestExecuteTime string `json:"latest_execute_time"`
+}
+
+type UserAgreementPageUnSignRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+}
+
+type TradeRelationBindRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ ResultCode string `json:"result_code"`
+}
+
+type TradeRelationUnbindRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ ResultCode string `json:"result_code"`
+}
+
+type TradeRelationBatchQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ ResultCode string `json:"result_code"`
+ ReceiverList []*Receiver `json:"receiver_list"`
+ TotalPageNum int `json:"total_page_num"`
+ TotalRecordNum int `json:"total_record_num"`
+ CurrentPageNum int `json:"current_page_num"`
+ CurrentPageSize int `json:"current_page_size"`
+}
+
+type Receiver struct {
+ Type string `json:"type"`
+ Account string `json:"account"`
+ AccountOpenId string `json:"account_open_id"`
+ Memo string `json:"memo"`
+ LoginName string `json:"login_name"`
+ BindLoginName string `json:"bind_login_name"`
+}
+
+type TradeRoyaltyRateQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ UserId string `json:"user_id"`
+ MaxRatio int `json:"max_ratio"`
+}
+
+type TradeOrderSettleRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ TradeNo string `json:"trade_no"`
+ SettleNo string `json:"settle_no"`
+}
+
+type TradeOrderSettleQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ OutRequestNo string `json:"out_request_no"`
+ OperationDt string `json:"operation_dt"`
+ RoyaltyDetailList []*RoyaltyDetail `json:"royalty_detail_list"`
+}
+
+type RoyaltyDetail struct {
+ OperationType string `json:"operation_type"`
+ ExecuteDt string `json:"execute_dt"`
+ TransOut string `json:"trans_out"`
+ TransOutType string `json:"trans_out_type"`
+ TransOutOpenId string `json:"trans_out_open_id"`
+ TransIn string `json:"trans_in"`
+ TransInOpenId string `json:"trans_in_open_id"`
+ TransInType string `json:"trans_in_type"`
+ Amount string `json:"amount"`
+ State string `json:"state"`
+ DetailId string `json:"detail_id"`
+ ErrorCode string `json:"error_code"`
+ ErrorDesc string `json:"error_desc"`
+}
+
+type TradeOrderOnSettleQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ UnsettledAmount string `json:"unsettled_amount"`
+}
\ No newline at end of file
diff --git a/alipay/v3/model_payment.go b/alipay/v3/model_payment.go
index 2ef2fd9b..16627f67 100644
--- a/alipay/v3/model_payment.go
+++ b/alipay/v3/model_payment.go
@@ -209,3 +209,41 @@ type TradeCreateRsp struct {
TradeNo string `json:"trade_no"`
OutTradeNo string `json:"out_trade_no"`
}
+
+type TradeOrderInfoSyncRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ TradeNo string `json:"trade_no"`
+ OutTradeNo string `json:"out_trade_no"`
+ BuyerUserId string `json:"buyer_user_id"`
+ BuyerOpenId string `json:"buyer_open_id"`
+}
+
+type ZolozAuthenticationSmilepayInitializeRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ RetCodeSub string `json:"ret_code_sub"`
+ RetMessageSub string `json:"ret_message_sub"`
+ ZimId string `json:"zim_id"`
+ ZimInitClientData string `json:"zim_init_client_data"`
+}
+
+type ZolozAuthenticationCustomerFtokenQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ Uid string `json:"uid"`
+ OpenId string `json:"open_id"`
+ UidTelPairList []*UidTelPair `json:"uid_tel_pair_list"`
+ AgeCheckResult string `json:"age_check_result"`
+ CertNo string `json:"cert_no"`
+ CertName string `json:"cert_name"`
+ FaceId string `json:"face_id"`
+}
+
+type UidTelPair struct {
+ UserId string `json:"user_id"`
+ OpenId string `json:"open_id"`
+}
diff --git a/alipay/v3/payment_api.go b/alipay/v3/payment_api.go
index 600f9c22..b9e253d8 100644
--- a/alipay/v3/payment_api.go
+++ b/alipay/v3/payment_api.go
@@ -10,7 +10,7 @@ import (
"github.com/go-pay/gopay"
)
-// 统一收单交易支付接口
+// 统一收单交易支付接口 alipay.trade.pay
// StatusCode = 200 is success
func (a *ClientV3) TradePay(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradePayRsp, err error) {
err = bm.CheckEmptyError("out_trade_no", "total_amount", "subject", "auth_code", "scene")
@@ -38,7 +38,7 @@ func (a *ClientV3) TradePay(ctx context.Context, bm gopay.BodyMap) (aliRsp *Trad
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易查询
+// 统一收单交易查询 alipay.trade.query
// StatusCode = 200 is success
func (a *ClientV3) TradeQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeQueryRsp, err error) {
if bm.GetString("out_trade_no") == gopay.NULL && bm.GetString("trade_no") == gopay.NULL {
@@ -65,7 +65,7 @@ func (a *ClientV3) TradeQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *Tr
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易退款接口
+// 统一收单交易退款接口 alipay.trade.refund
// StatusCode = 200 is success
func (a *ClientV3) TradeRefund(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeRefundRsp, err error) {
err = bm.CheckEmptyError("refund_amount")
@@ -96,7 +96,7 @@ func (a *ClientV3) TradeRefund(ctx context.Context, bm gopay.BodyMap) (aliRsp *T
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易退款查询
+// 统一收单交易退款查询 alipay.trade.fastpay.refund.query
// StatusCode = 200 is success
func (a *ClientV3) TradeFastPayRefundQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeFastPayRefundQueryRsp, err error) {
err = bm.CheckEmptyError("out_request_no")
@@ -127,7 +127,7 @@ func (a *ClientV3) TradeFastPayRefundQuery(ctx context.Context, bm gopay.BodyMap
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易撤销接口
+// 统一收单交易撤销接口 alipay.trade.cancel
// StatusCode = 200 is success
func (a *ClientV3) TradeCancel(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeCancelRsp, err error) {
if bm.GetString("out_trade_no") == gopay.NULL && bm.GetString("trade_no") == gopay.NULL {
@@ -154,7 +154,7 @@ func (a *ClientV3) TradeCancel(ctx context.Context, bm gopay.BodyMap) (aliRsp *T
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易关闭接口
+// 统一收单交易关闭接口 alipay.trade.close
// StatusCode = 200 is success
func (a *ClientV3) TradeClose(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeCloseRsp, err error) {
if bm.GetString("out_trade_no") == gopay.NULL && bm.GetString("trade_no") == gopay.NULL {
@@ -181,7 +181,7 @@ func (a *ClientV3) TradeClose(ctx context.Context, bm gopay.BodyMap) (aliRsp *Tr
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 查询对账单下载地址
+// 查询对账单下载地址 alipay.data.dataservice.bill.downloadurl.query
// StatusCode = 200 is success
func (a *ClientV3) DataBillDownloadUrlQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *DataBillDownloadUrlQueryRsp, err error) {
err = bm.CheckEmptyError("bill_type", "bill_date")
@@ -210,7 +210,7 @@ func (a *ClientV3) DataBillDownloadUrlQuery(ctx context.Context, bm gopay.BodyMa
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单线下交易预创建
+// 统一收单线下交易预创建 alipay.trade.precreate
// StatusCode = 200 is success
func (a *ClientV3) TradePrecreate(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradePrecreateRsp, err error) {
err = bm.CheckEmptyError("out_trade_no", "total_amount", "subject")
@@ -238,7 +238,7 @@ func (a *ClientV3) TradePrecreate(ctx context.Context, bm gopay.BodyMap) (aliRsp
return aliRsp, a.autoVerifySignByCert(res, bs)
}
-// 统一收单交易创建接口
+// 统一收单交易创建接口 alipay.trade.create
// StatusCode = 200 is success
func (a *ClientV3) TradeCreate(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeCreateRsp, err error) {
err = bm.CheckEmptyError("out_trade_no", "total_amount", "subject", "product_code", "op_app_id")
@@ -268,3 +268,83 @@ func (a *ClientV3) TradeCreate(ctx context.Context, bm gopay.BodyMap) (aliRsp *T
}
return aliRsp, a.autoVerifySignByCert(res, bs)
}
+
+// 支付宝订单信息同步接口 alipay.trade.orderinfo.sync
+// StatusCode = 200 is success
+func (a *ClientV3) TradeOrderInfoSync(ctx context.Context, bm gopay.BodyMap) (aliRsp *TradeOrderInfoSyncRsp, err error) {
+ err = bm.CheckEmptyError("trade_no", "out_request_no", "biz_type")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3TradeOrderInfoSync, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3TradeOrderInfoSync, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &TradeOrderInfoSyncRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 刷脸支付初始化 zoloz.authentication.smilepay.initialize
+// StatusCode = 200 is success
+func (a *ClientV3) ZolozAuthenticationSmilepayInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *ZolozAuthenticationSmilepayInitializeRsp, err error) {
+ authorization, err := a.authorization(MethodPost, v3ZolozAuthenticationSmilepayInitialize, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3ZolozAuthenticationSmilepayInitialize, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &ZolozAuthenticationSmilepayInitializeRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 查询刷脸结果信息接口 zoloz.authentication.customer.ftoken.query
+// StatusCode = 200 is success
+func (a *ClientV3) ZolozAuthenticationCustomerFtokenQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *ZolozAuthenticationCustomerFtokenQueryRsp, err error) {
+ err = bm.CheckEmptyError("ftoken", "biz_type")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3ZolozAuthenticationCustomerFtokenQuery, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3ZolozAuthenticationCustomerFtokenQuery, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &ZolozAuthenticationCustomerFtokenQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
diff --git a/doc/alipay_v3.md b/doc/alipay_v3.md
index e0c54f22..557efbd8 100644
--- a/doc/alipay_v3.md
+++ b/doc/alipay_v3.md
@@ -195,10 +195,23 @@ return c.String(http.StatusOK, "success")
* 查询对账单下载地址:`client.DataBillDownloadUrlQuery()`
* 统一收单线下交易预创建:`client.TradePrecreate()`
* 统一收单交易创建接口:`client.TradeCreate()`
+ * 支付宝订单信息同步接口:`client.TradeOrderInfoSync()`
* 资金授权操作查询接口:`client.FundAuthOperationDetailQuery()`
* 资金授权冻结接口:`client.FundAuthOrderFreeze()`
* 资金授权解冻接口:`client.FundAuthOrderUnfreeze()`
* 资金授权发码接口:`client.FundAuthOrderVoucherCreate()`
+ * 刷脸支付初始化接口:`client.ZolozAuthenticationSmilepayInitialize()`
+ * 查询刷脸结果信息接口:`client.ZolozAuthenticationCustomerFtokenQuery()`
+* 商家扣款
+ * 支付宝个人代扣协议查询接口:`client.UserAgreementQuery()`
+ * 支付宝个人代扣协议解约接口:`client.UserAgreementPageUnSign()`
+* 商家分账
+ * 分账关系绑定接口:`client.TradeRelationBind()`
+ * 分账关系解绑:`client.TradeRelationUnbind()`
+ * 分账关系查询:`client.TradeRelationBatchQuery()`
+ * 分账比例查询:`client.TradeRoyaltyRateQuery()`
+ * 统一收单交易结算接口:`client.TradeOrderSettle()`
+ * 分账剩余金额查询:`client.TradeOrderOnSettleQuery()`
* 会员
* 换取授权访问令牌:`client.SystemOauthToken()`
* 身份认证记录查询:`client.UserCertifyOpenQuery()`
From 8f572db4a77f3eb228ead508698d1ab157e6c6bf Mon Sep 17 00:00:00 2001
From: Jerry <85411418@qq.com>
Date: Wed, 18 Dec 2024 17:09:56 +0800
Subject: [PATCH 2/2] add new api
---
alipay/face.go | 2 +-
alipay/v3/constant.go | 4 +-
alipay/v3/face_verify_api.go | 408 +++++++++++++++++++++++++++++++++
alipay/v3/model_face_verify.go | 127 ++++++++++
doc/alipay_v3.md | 16 ++
5 files changed, 555 insertions(+), 2 deletions(-)
create mode 100644 alipay/v3/face_verify_api.go
create mode 100644 alipay/v3/model_face_verify.go
diff --git a/alipay/face.go b/alipay/face.go
index 850606fa..355a8f1a 100644
--- a/alipay/face.go
+++ b/alipay/face.go
@@ -57,7 +57,7 @@ func (a *Client) FaceVerificationQuery(ctx context.Context, bm gopay.BodyMap) (a
// datadigital.fincloud.generalsaas.face.certify.initialize(H5人脸核身初始化)
// 文档地址:https://opendocs.alipay.com/open/02zloa
func (a *Client) FaceCertifyInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCertifyInitializeRsp, err error) {
- err = bm.CheckEmptyError("outer_order_no", "biz_code", "identity_param", "merchant_config")
+ err = bm.CheckEmptyError("outer_order_no", "identity_param", "merchant_config")
if err != nil {
return nil, err
}
diff --git a/alipay/v3/constant.go b/alipay/v3/constant.go
index 32a09fc3..0bbe6d5e 100644
--- a/alipay/v3/constant.go
+++ b/alipay/v3/constant.go
@@ -77,8 +77,10 @@ const (
v3FaceSourceCertify = "/v3/datadigital/fincloud/generalsaas/face/source/certify" // 纯服务端人脸核身
v3FaceCheckInitialize = "/v3/datadigital/fincloud/generalsaas/face/check/initialize" // 活体检测初始化
v3FaceCheckQuery = "/v3/datadigital/fincloud/generalsaas/face/check/query" // 活体检测结果查询
- v3IdCardTwoMetaCheck = "/v3/datadigital/fincloud/generalsaas/twometa/check" // 身份证二要素核验
+ v3IDCardTwoMetaCheck = "/v3/datadigital/fincloud/generalsaas/twometa/check" // 身份证二要素核验
v3BankCardCheck = "/v3/datadigital/fincloud/generalsaas/bankcard/check" // 银行卡核验
+ v3MobileThreeMetaSimpleCheck = "/v3/datadigital/fincloud/generalsaas/mobilethreemeta/simple/check" // 手机号三要素核验简版
+ v3MobileThreeMetaDetailCheck = "/v3/datadigital/fincloud/generalsaas/mobilethreemeta/detail/check" // 手机号三要素核验详版
v3OcrServerDetect = "/v3/datadigital/fincloud/generalsaas/ocr/server/detect" // 服务端OCR
v3OcrMobileInitialize = "/v3/datadigital/fincloud/generalsaas/ocr/mobile/initialize" // App端OCR初始化
)
diff --git a/alipay/v3/face_verify_api.go b/alipay/v3/face_verify_api.go
new file mode 100644
index 00000000..b281f400
--- /dev/null
+++ b/alipay/v3/face_verify_api.go
@@ -0,0 +1,408 @@
+package alipay
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/go-pay/gopay"
+)
+
+// 人脸核身初始化 datadigital.fincloud.generalsaas.face.verification.initialize
+// StatusCode = 200 is success
+func (a *ClientV3) FaceVerificationInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceVerificationInitializeRsp, err error) {
+ err = bm.CheckEmptyError("outer_order_no", "biz_code", "identity_type", "cert_type", "cert_name", "cert_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3FaceVerificationInitialize, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3FaceVerificationInitialize, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceVerificationInitializeRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 人脸核身结果查询 datadigital.fincloud.generalsaas.face.verification.query
+// StatusCode = 200 is success
+func (a *ClientV3) FaceVerificationQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceVerificationQueryRsp, err error) {
+ err = bm.CheckEmptyError("certify_id")
+ if err != nil {
+ return nil, err
+ }
+ uri := v3FaceVerificationQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceVerificationQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 跳转支付宝人脸核身初始化 datadigital.fincloud.generalsaas.face.certify.initialize
+// StatusCode = 200 is success
+func (a *ClientV3) FaceCertifyInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCertifyInitializeRsp, err error) {
+ err = bm.CheckEmptyError("outer_order_no", "identity_param", "merchant_config")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3FaceCertifyInitialize, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3FaceCertifyInitialize, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceCertifyInitializeRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 跳转支付宝人脸核身开始认证 datadigital.fincloud.generalsaas.face.certify.verify
+// StatusCode = 200 is success
+func (a *ClientV3) FaceCertifyVerify(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCertifyVerifyRsp, err error) {
+ err = bm.CheckEmptyError("certify_id")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3FaceCertifyVerify, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3FaceCertifyVerify, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceCertifyVerifyRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 跳转支付宝人脸核身查询记录 datadigital.fincloud.generalsaas.face.certify.query
+// StatusCode = 200 is success
+func (a *ClientV3) FaceCertifyQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCertifyQueryRsp, err error) {
+ err = bm.CheckEmptyError("certify_id")
+ if err != nil {
+ return nil, err
+ }
+ uri := v3FaceCertifyQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceCertifyQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 纯服务端人脸核身 datadigital.fincloud.generalsaas.face.source.certify
+// StatusCode = 200 is success
+func (a *ClientV3) FaceSourceCertify(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceSourceCertifyRsp, err error) {
+ err = bm.CheckEmptyError("outer_biz_no", "cert_type", "cert_no", "cert_name")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3FaceSourceCertify, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3FaceSourceCertify, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceSourceCertifyRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 活体检测初始化 datadigital.fincloud.generalsaas.face.check.initialize
+// StatusCode = 200 is success
+func (a *ClientV3) FaceCheckInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCheckInitializeRsp, err error) {
+ err = bm.CheckEmptyError("outer_order_no", "biz_code")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3FaceCheckInitialize, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3FaceCheckInitialize, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceCheckInitializeRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 活体检测结果查询 datadigital.fincloud.generalsaas.face.check.query
+// StatusCode = 200 is success
+func (a *ClientV3) FaceCheckQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *FaceCheckQueryRsp, err error) {
+ err = bm.CheckEmptyError("certify_id")
+ if err != nil {
+ return nil, err
+ }
+ uri := v3FaceCheckQuery + "?" + bm.EncodeURLParams()
+ authorization, err := a.authorization(MethodGet, uri, nil)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doGet(ctx, uri, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &FaceCheckQueryRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 身份证二要素核验 datadigital.fincloud.generalsaas.twometa.check
+// StatusCode = 200 is success
+func (a *ClientV3) IDCardTwoMetaCheck(ctx context.Context, bm gopay.BodyMap) (aliRsp *IDCardTwoMetaCheckRsp, err error) {
+ err = bm.CheckEmptyError("outer_biz_no", "cert_name", "cert_no", "cert_type")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3IDCardTwoMetaCheck, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3IDCardTwoMetaCheck, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &IDCardTwoMetaCheckRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 银行卡核验 datadigital.fincloud.generalsaas.bankcard.check
+// StatusCode = 200 is success
+func (a *ClientV3) BankCardCheck(ctx context.Context, bm gopay.BodyMap) (aliRsp *BankCardCheckRsp, err error) {
+ err = bm.CheckEmptyError("outer_biz_no", "product_type", "cert_name", "bankcard_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3BankCardCheck, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3BankCardCheck, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &BankCardCheckRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 手机号三要素核验简版 datadigital.fincloud.generalsaas.mobilethreemeta.simple.check
+// StatusCode = 200 is success
+func (a *ClientV3) MobileThreeMetaSimpleCheck(ctx context.Context, bm gopay.BodyMap) (aliRsp *MobileThreeMetaSimpleCheckRsp, err error) {
+ err = bm.CheckEmptyError("outer_biz_no", "cert_name", "cert_no", "phone")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3MobileThreeMetaSimpleCheck, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3MobileThreeMetaSimpleCheck, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &MobileThreeMetaSimpleCheckRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 手机号三要素核验详版 datadigital.fincloud.generalsaas.mobilethreemeta.detail.check
+// StatusCode = 200 is success
+func (a *ClientV3) MobileThreeMetaDetailCheck(ctx context.Context, bm gopay.BodyMap) (aliRsp *MobileThreeMetaDetailCheckRsp, err error) {
+ err = bm.CheckEmptyError("outer_biz_no", "cert_name", "cert_no", "phone")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3MobileThreeMetaDetailCheck, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3MobileThreeMetaDetailCheck, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &MobileThreeMetaDetailCheckRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// 服务端OCR datadigital.fincloud.generalsaas.ocr.server.detect
+// StatusCode = 200 is success
+func (a *ClientV3) OcrServerDetect(ctx context.Context, bm gopay.BodyMap) (aliRsp *OcrServerDetectRsp, err error) {
+ err = bm.CheckEmptyError("ocr_type", "outer_order_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3OcrServerDetect, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3OcrServerDetect, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &OcrServerDetectRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
+
+// App端OCR初始化 datadigital.fincloud.generalsaas.ocr.mobile.initialize
+// StatusCode = 200 is success
+func (a *ClientV3) OcrMobileInitialize(ctx context.Context, bm gopay.BodyMap) (aliRsp *OcrMobileInitializeRsp, err error) {
+ err = bm.CheckEmptyError("biz_code", "outer_order_no")
+ if err != nil {
+ return nil, err
+ }
+ authorization, err := a.authorization(MethodPost, v3OcrMobileInitialize, bm)
+ if err != nil {
+ return nil, err
+ }
+ res, bs, err := a.doPost(ctx, bm, v3OcrMobileInitialize, authorization)
+ if err != nil {
+ return nil, err
+ }
+ aliRsp = &OcrMobileInitializeRsp{StatusCode: res.StatusCode}
+ if res.StatusCode != http.StatusOK {
+ if err = json.Unmarshal(bs, &aliRsp.ErrResponse); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, nil
+ }
+ if err = json.Unmarshal(bs, aliRsp); err != nil {
+ return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs))
+ }
+ return aliRsp, a.autoVerifySignByCert(res, bs)
+}
diff --git a/alipay/v3/model_face_verify.go b/alipay/v3/model_face_verify.go
new file mode 100644
index 00000000..7142a04f
--- /dev/null
+++ b/alipay/v3/model_face_verify.go
@@ -0,0 +1,127 @@
+package alipay
+
+type FaceVerificationInitializeRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ WebUrl string `json:"web_url"`
+}
+
+type FaceVerificationQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyState string `json:"certify_state"`
+ Score string `json:"score"`
+ Quality string `json:"quality"`
+ AlivePhoto string `json:"alive_photo"`
+ AttackFlag string `json:"attack_flag"`
+ MetaInfo *MetaInfo `json:"meta_info"`
+}
+
+type MetaInfo struct {
+ DeviceType string `json:"device_type"`
+}
+
+type FaceCertifyInitializeRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+}
+
+type FaceCertifyVerifyRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyUrl string `json:"certify_url"`
+}
+
+type FaceCertifyQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ Passed string `json:"passed"`
+}
+
+type FaceSourceCertifyRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyNo string `json:"certify_no"`
+ Passed string `json:"passed"`
+ Score string `json:"score"`
+ Quality string `json:"quality"`
+ MismatchReason string `json:"mismatch_reason"`
+}
+
+type FaceCheckInitializeRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ WebUrl string `json:"web_url"`
+}
+
+type FaceCheckQueryRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyState string `json:"certify_state"`
+ Quality string `json:"quality"`
+ AlivePhoto string `json:"alive_photo"`
+ MetaInfo *MetaInfo `json:"meta_info"`
+}
+
+type IDCardTwoMetaCheckRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ Match string `json:"match"`
+}
+
+type BankCardCheckRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ Match string `json:"match"`
+ Detail string `json:"detail"`
+}
+
+type MobileThreeMetaSimpleCheckRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ Match string `json:"match"`
+ Isp string `json:"isp"`
+ Detail string `json:"detail"`
+}
+
+type MobileThreeMetaDetailCheckRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+ Match string `json:"match"`
+ Isp string `json:"isp"`
+ Detail string `json:"detail"`
+}
+
+type OcrServerDetectRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ OcrData string `json:"ocr_data"`
+ CertifyId string `json:"certify_id"`
+}
+
+type OcrMobileInitializeRsp struct {
+ StatusCode int `json:"status_code"`
+ ErrResponse ErrResponse `json:"-"`
+
+ CertifyId string `json:"certify_id"`
+}
diff --git a/doc/alipay_v3.md b/doc/alipay_v3.md
index 557efbd8..292870de 100644
--- a/doc/alipay_v3.md
+++ b/doc/alipay_v3.md
@@ -219,4 +219,20 @@ return c.String(http.StatusOK, "success")
* 支付宝会员授权信息查询接口:`client.UserInfoShare()`
* 用户授权关系查询:`client.UserAuthRelationshipQuery()`
* 查询解除授权明细:`client.UserDelOauthDetailQuery()`
+* 人脸认证
+ * 人脸核身初始化:`client.FaceVerificationInitialize()`
+ * 人脸核身结果查询:`client.FaceVerificationQuery()`
+ * 跳转支付宝人脸核身初始化:`client.FaceCertifyInitialize()`
+ * 跳转支付宝人脸核身开始认证:`client.FaceCertifyVerify()`
+ * 跳转支付宝人脸核身查询记录:`client.FaceCertifyQuery()`
+ * 纯服务端人脸核身:`client.FaceSourceCertify()`
+ * 活体检测初始化:`client.FaceCheckInitialize()`
+ * 活体检测结果查询:`client.FaceCheckQuery()`
+ * 身份证二要素核验:`client.IDCardTwoMetaCheck()`
+ * 银行卡核验:`client.BankCardCheck()`
+ * 手机号三要素核验简版:`client.MobileThreeMetaSimpleCheck()`
+ * 手机号三要素核验详版:`client.MobileThreeMetaDetailCheck()`
+ * 服务端OCR:`client.OcrServerDetect()`
+ * App端OCR初始化:`client.OcrMobileInitialize()`
+
### 支付宝公共 API