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