From 83cd4c5c66bd430087aed19116f6621a92cd3418 Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Sat, 17 Aug 2024 00:20:46 +0800 Subject: [PATCH] Feature/v1.5.104 (#414) * v1.5.104 --- .github/workflows/go.yml | 2 +- alipay/marketing_card.go | 217 +++++++++++++++++++++++++++++++++++ alipay/model_market.go | 188 ++++++++++++++++++++++++++++++ apple/refund.go | 3 +- doc/alipay.md | 22 ++-- release_note.txt | 11 ++ wechat/v3/encrypt_decrypt.go | 14 +++ wechat/v3/notify.go | 98 +++++++++------- 8 files changed, 497 insertions(+), 58 deletions(-) create mode 100644 alipay/marketing_card.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index fd0407b4..3e54d4c2 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -33,7 +33,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest, macos-latest ] - go: [ '1.20', '1.21' ] + go: [ '1.20', '1.21', '1.22' , '1.23' ] runs-on: ${{ matrix.os }} steps: - name: Checkout Code diff --git a/alipay/marketing_card.go b/alipay/marketing_card.go new file mode 100644 index 00000000..94ea7483 --- /dev/null +++ b/alipay/marketing_card.go @@ -0,0 +1,217 @@ +package alipay + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/go-pay/gopay" +) + +// alipay.marketing.card.template.create(会员卡模板创建) +// 文档地址:https://opendocs.alipay.com/open/b2854ad3_alipay.marketing.card.template.create +func (a *Client) MarketingCardTemplateCreate(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardTemplateCreateRsp, err error) { + err = bm.CheckEmptyError("request_id", "template_style_info") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.template.create"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardTemplateCreateRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.template.modify(会员卡模板修改) +// 文档地址:https://opendocs.alipay.com/open/e3227c82_alipay.marketing.card.template.modify +func (a *Client) MarketingCardTemplateModify(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardTemplateModifyRsp, err error) { + err = bm.CheckEmptyError("request_id", "template_id", "template_style_info") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.template.modify"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardTemplateModifyRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.template.query(会员卡模板查询接口) +// 文档地址:https://opendocs.alipay.com/open/690f3d16_alipay.marketing.card.template.query +func (a *Client) MarketingCardTemplateQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardTemplateQueryRsp, err error) { + err = bm.CheckEmptyError("template_id") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.template.query"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardTemplateQueryRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.update(会员卡更新) +// 文档地址:https://opendocs.alipay.com/open/89b55b6d_alipay.marketing.card.update +func (a *Client) MarketingCardUpdate(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardUpdateRsp, err error) { + err = bm.CheckEmptyError("target_card_no", "target_card_no_type", "occur_time", "card_info") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.update"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardUpdateRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.query(会员卡查询) +// 文档地址:https://opendocs.alipay.com/open/023c20c1_alipay.marketing.card.query +func (a *Client) MarketingCardQuery(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardQueryRsp, err error) { + err = bm.CheckEmptyError("target_card_no", "target_card_no_type") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.query"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardQueryRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.delete(会员卡删卡) +// 文档地址:https://opendocs.alipay.com/open/8efddab3_alipay.marketing.card.delete +func (a *Client) MarketingCardDelete(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardDeleteRsp, err error) { + err = bm.CheckEmptyError("out_serial_no", "target_card_no", "target_card_no_type", "reason_code") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.delete"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardDeleteRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.message.notify(会员卡消息通知) +// 文档地址:https://opendocs.alipay.com/open/4c052993_alipay.marketing.card.message.notify +func (a *Client) MarketingCardMessageNotify(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardMessageNotifyRsp, err error) { + err = bm.CheckEmptyError("target_card_no", "target_card_no_type", "occur_time") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.message.notify"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardMessageNotifyRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.marketing.card.formtemplate.set(会员卡开卡表单模板配置) +// 文档地址:https://opendocs.alipay.com/open/78c84d3f_alipay.marketing.card.formtemplate.set +func (a *Client) MarketingCardFormTemplateSet(ctx context.Context, bm gopay.BodyMap) (aliRsp *MarketingCardFormTemplateSetRsp, err error) { + err = bm.CheckEmptyError("template_id", "fields") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.doAliPay(ctx, bm, "alipay.marketing.card.formtemplate.set"); err != nil { + return nil, err + } + aliRsp = new(MarketingCardFormTemplateSetRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil || aliRsp.Response == nil { + return nil, fmt.Errorf("[%w], bytes: %s", gopay.UnmarshalErr, string(bs)) + } + if err = bizErrCheck(aliRsp.Response.ErrorResponse); err != nil { + return aliRsp, err + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} + +// alipay.offline.material.image.upload(上传门店照片和视频接口) +// 文档地址:https://opendocs.alipay.com/open/0af852ff_alipay.offline.material.image.upload +func (a *Client) OfflineMaterialImageUpload(ctx context.Context, bm gopay.BodyMap) (aliRsp *OfflineMaterialImageUploadRsp, err error) { + err = bm.CheckEmptyError("image_type", "image_name", "image_content") + if err != nil { + return nil, err + } + var bs []byte + if bs, err = a.FileUploadRequest(ctx, bm, "alipay.marketing.material.image.upload"); err != nil { + return nil, err + } + aliRsp = new(OfflineMaterialImageUploadRsp) + if err = json.Unmarshal(bs, aliRsp); err != nil { + return nil, err + } + if aliRsp.Response != nil && aliRsp.Response.Code != "10000" { + info := aliRsp.Response + return aliRsp, fmt.Errorf(`{"code":"%s","msg":"%s","sub_code":"%s","sub_msg":"%s"}`, info.Code, info.Msg, info.SubCode, info.SubMsg) + } + signData, signDataErr := a.getSignData(bs, aliRsp.AlipayCertSn) + aliRsp.SignData = signData + return aliRsp, a.autoVerifySignByCert(aliRsp.Sign, signData, signDataErr) +} diff --git a/alipay/model_market.go b/alipay/model_market.go index 951d2b58..a2d6023e 100644 --- a/alipay/model_market.go +++ b/alipay/model_market.go @@ -238,6 +238,69 @@ type MarketingActivityOrderVoucherCodeCountRsp struct { Sign string `json:"sign"` } +type MarketingCardTemplateCreateRsp struct { + Response *MarketingCardTemplateCreate `json:"alipay_marketing_card_template_create_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardTemplateModifyRsp struct { + Response *MarketingCardTemplateModify `json:"alipay_marketing_card_template_modify_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardTemplateQueryRsp struct { + Response *MarketingCardTemplateQuery `json:"alipay_marketing_card_template_query_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardUpdateRsp struct { + Response *MarketingCardUpdate `json:"alipay_marketing_card_update_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardQueryRsp struct { + Response *MarketingCardQuery `json:"alipay_marketing_card_query_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardDeleteRsp struct { + Response *MarketingCardDelete `json:"alipay_marketing_card_delete_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardMessageNotifyRsp struct { + Response *MarketingCardMessageNotify `json:"alipay_marketing_card_message_notify_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type MarketingCardFormTemplateSetRsp struct { + Response *MarketingCardFormTemplateSet `json:"alipay_marketing_card_formtemplate_set_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + +type OfflineMaterialImageUploadRsp struct { + Response *OfflineMaterialImageUpload `json:"alipay_offline_material_image_upload_response"` + AlipayCertSn string `json:"alipay_cert_sn,omitempty"` + SignData string `json:"-"` + Sign string `json:"sign"` +} + // =========================================================分割========================================================= type MarketingCampaignCashCreate struct { @@ -927,3 +990,128 @@ type MarketingActivityOrderVoucherCodeCount struct { ErrorResponse SuccessCount int `json:"success_count"` } + +type MarketingCardTemplateCreate struct { + ErrorResponse + TemplateId string `json:"template_id"` +} + +type MarketingCardTemplateModify struct { + ErrorResponse + TemplateId string `json:"template_id"` +} + +type MarketingCardTemplateQuery struct { + ErrorResponse + TemplateStyleInfo *TemplateStyleInfo `json:"template_style_info"` + AccessVersion string `json:"access_version"` + CardLevelConfs []*CardLevelConf `json:"card_level_confs"` + TemplateFormConfig *TemplateFormConfig `json:"template_form_config"` + SpiAppId string `json:"spi_app_id"` +} + +type TemplateStyleInfo struct { + CardShowName string `json:"card_show_name"` + LogoId string `json:"logo_id"` + BackgroundId string `json:"background_id"` + BrandName string `json:"brand_name"` +} + +type CardLevelConf struct { + Level string `json:"level"` + LevelShowName string `json:"level_show_name"` + LevelIcon string `json:"level_icon"` + LevelDesc string `json:"level_desc"` +} + +type TemplateFormConfig struct { + Fields *Fields `json:"fields"` + OpenCardMiniAppId string `json:"open_card_mini_app_id"` +} + +type Fields struct { + Required []string `json:"required"` + Optional []string `json:"optional"` +} + +type MarketingCardUpdate struct { + ErrorResponse + ResultCode string `json:"result_code"` +} + +type MarketingCardQuery struct { + ErrorResponse + CardInfo *CardInfo `json:"card_info"` + SchemaUrl string `json:"schema_url"` + PassId string `json:"pass_id"` + PaidOuterCardInfo *PaidOuterCardInfo `json:"paid_outer_card_info"` +} + +type CardInfo struct { + BizCardNo string `json:"biz_card_no"` + ExternalCardNo string `json:"external_card_no"` + OpenDate string `json:"open_date"` + ValidDate string `json:"valid_date"` + Level string `json:"level"` + Point string `json:"point"` + Balance string `json:"balance"` + TemplateId string `json:"template_id"` + MdcodeInfo *MdcodeInfo `json:"mdcode_info"` + FrontTextList []*FrontText `json:"front_text_list"` + FrontImageId string `json:"front_image_id"` +} + +type MdcodeInfo struct { + CodeStatus string `json:"code_status"` + CodeValue string `json:"code_value"` + ExpireTime string `json:"expire_time"` + TimeStamp int `json:"time_stamp"` +} + +type FrontText struct { + Label string `json:"label"` + Value string `json:"value"` +} + +type PaidOuterCardInfo struct { + Action string `json:"action"` + PurchaseInfo *PurchaseInfo `json:"purchase_info"` + CycleInfo *CycleInfo `json:"cycle_info"` +} + +type PurchaseInfo struct { + Source string `json:"source"` + Price string `json:"price"` + ActionDate string `json:"action_date"` + OutTradeNo string `json:"out_trade_no"` + AlipayTradeNo string `json:"alipay_trade_no"` +} + +type CycleInfo struct { + OpenStatus string `json:"open_status"` + CloseReason string `json:"close_reason"` + CycleType string `json:"cycle_type"` + AlipayDeductScene string `json:"alipay_deduct_scene"` + AlipayDeductProductCode string `json:"alipay_deduct_product_code"` + AlipayDeductAgreement string `json:"alipay_deduct_agreement"` +} + +type MarketingCardDelete struct { + ErrorResponse + BizSerialNo string `json:"biz_serial_no"` +} + +type MarketingCardMessageNotify struct { + ErrorResponse + ResultCode string `json:"result_code"` +} + +type MarketingCardFormTemplateSet struct { + ErrorResponse +} + +type OfflineMaterialImageUpload struct { + ErrorResponse + ImageId string `json:"image_id"` + ImageUrl string `json:"image_url"` +} diff --git a/apple/refund.go b/apple/refund.go index 4026710f..d6bf0163 100644 --- a/apple/refund.go +++ b/apple/refund.go @@ -4,8 +4,9 @@ import ( "context" "encoding/json" "fmt" - "github.com/go-pay/gopay" "net/http" + + "github.com/go-pay/gopay" ) // GetRefundHistory Get Refund History diff --git a/doc/alipay.md b/doc/alipay.md index 41a26fb8..b364dd98 100644 --- a/doc/alipay.md +++ b/doc/alipay.md @@ -341,19 +341,15 @@ xlog.Infof("%+v", phone) * 查询活动可用门店接口:`client.MarketingActivityQueryShopBatchQuery()` * 查询活动适用商品接口:`client.MarketingActivityQueryGoodsBatchQuery()` * 商家会员卡 - * 基础功能 - * 会员卡模板创建接口:TODO:https://opendocs.alipay.com/open/b2854ad3_alipay.marketing.card.template.create - * 会员卡开通,获取会员卡信息接口:TODO:https://opendocs.alipay.com/open/03sx83 - * 会员卡更新接口:TODO:https://opendocs.alipay.com/open/03sx89 - * 扩展功能 - * 会员卡开卡表单模板配置接口:TODO:https://opendocs.alipay.com/open/03sx82 - * 会员卡开卡结果通知接口:TODO:https://opendocs.alipay.com/open/03sx84 - * 会员卡模板修改接口:TODO:https://opendocs.alipay.com/open/e3227c82_alipay.marketing.card.template.modify - * 会员卡模板查询接口:TODO:https://opendocs.alipay.com/open/690f3d16_alipay.marketing.card.template.query - * 会员卡查询接口:TODO:https://opendocs.alipay.com/open/03sx88 - * 会员卡删卡接口:TODO:https://opendocs.alipay.com/open/03sx8a - * 会员卡消息通知接口:TODO:https://opendocs.alipay.com/open/06ruek - * 上传门店照片和视频接口:TODO:https://opendocs.alipay.com/open/03sx81 + * 会员卡模板创建接口:`client.MarketingCardTemplateCreate()` + * 会员卡模板修改接口:`client.MarketingCardTemplateModify()` + * 会员卡模板查询接口:`client.MarketingCardTemplateQuery()` + * 会员卡更新接口:`client.MarketingCardUpdate()` + * 会员卡查询接口:`client.MarketingCardQuery()` + * 会员卡删卡接口:`client.MarketingCardDelete()` + * 会员卡消息通知接口:`client.MarketingCardMessageNotify()` + * 会员卡开卡表单模板配置接口:`client.MarketingCardFormTemplateSet()` + * 上传门店照片和视频接口:`client.OfflineMaterialImageUpload()` * 营销活动送红包 * 创建现金活动接口:TODO:https://opendocs.alipay.com/open/029yy9 * 触发现金红包活动接口:TODO:https://opendocs.alipay.com/open/029yya diff --git a/release_note.txt b/release_note.txt index 9ad55773..189a8b33 100644 --- a/release_note.txt +++ b/release_note.txt @@ -6,6 +6,17 @@ (4) 微信V3:新增 client.V3CombineQQTransactionH5(),合单QQ小程序下单-H5。 (5) 微信V3:新增 wechat.V3DecryptViolationNotifyCipherText(),解密 服务商子商户处置记录 回调中的加密信息。#412 (6) 微信V3:新增 V3NotifyReq method req.DecryptViolationCipherText(),解密 服务商子商户处置记录 回调中的加密信息。 + (7) 微信V3:新增 wechat.V3DecryptTransferBatchNotifyCipherText(),解密 商家转账批次回调通知 回调中的加密信息。 + (8) 微信V3:新增 V3NotifyReq method req.DecryptTransferBatchCipherText(),解密 商家转账批次回调通知 回调中的加密信息。 + (9) 支付宝:新增 client.MarketingCardTemplateCreate(),会员卡模板创建接口。 + (10) 支付宝:新增 client.MarketingCardTemplateModify(),会员卡模板修改接口。 + (11) 支付宝:新增 client.MarketingCardTemplateQuery(),会员卡模板查询接口。 + (12) 支付宝:新增 client.MarketingCardUpdate(),会员卡更新接口。 + (13) 支付宝:新增 client.MarketingCardQuery(),会员卡查询接口。 + (14) 支付宝:新增 client.MarketingCardDelete(),会员卡删卡接口。 + (15) 支付宝:新增 client.MarketingCardMessageNotify(),会员卡消息通知接口。 + (16) 支付宝:新增 client.MarketingCardFormTemplateSet(),会员卡开卡表单模板配置接口。 + (17) 支付宝:新增 client.OfflineMaterialImageUpload(),上传门店照片和视频接口。 版本号:Release 1.5.103 修改记录: diff --git a/wechat/v3/encrypt_decrypt.go b/wechat/v3/encrypt_decrypt.go index e9b3544c..2bb6da8c 100644 --- a/wechat/v3/encrypt_decrypt.go +++ b/wechat/v3/encrypt_decrypt.go @@ -307,3 +307,17 @@ func V3DecryptViolationNotifyCipherText(ciphertext, nonce, additional, apiV3Key } return result, nil } + +// 解密 商家转账批次回调通知 回调中的加密信息 +func V3DecryptTransferBatchNotifyCipherText(ciphertext, nonce, additional, apiV3Key string) (result *V3DecryptTransferBatchResult, err error) { + cipherBytes, _ := base64.StdEncoding.DecodeString(ciphertext) + decrypt, err := aes.GCMDecrypt(cipherBytes, []byte(nonce), []byte(additional), []byte(apiV3Key)) + if err != nil { + return nil, fmt.Errorf("aes.GCMDecrypt, err:%w", err) + } + result = &V3DecryptTransferBatchResult{} + if err = json.Unmarshal(decrypt, result); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s), err:%w", string(decrypt), err) + } + return result, nil +} diff --git a/wechat/v3/notify.go b/wechat/v3/notify.go index c14988ef..3db10d86 100644 --- a/wechat/v3/notify.go +++ b/wechat/v3/notify.go @@ -2,13 +2,13 @@ package wechat import ( "crypto/rsa" - "encoding/json" "errors" "fmt" "io" "net/http" "github.com/go-pay/gopay" + "github.com/go-pay/util/js" "github.com/go-pay/xlog" ) @@ -59,14 +59,14 @@ type V3DecryptPartnerPayResult struct { // 服务商子商户处置记录回调通知 type V3DecryptViolationResult struct { - SubMchid string `json:"sub_mchid" dc:"子商户商户ID"` - CompanyName string `json:"company_name" dc:"子商户主体名称"` - RecordId string `json:"record_id" dc:"通知ID,可用于去重"` - PunishPlan string `json:"punish_plan" dc:"处罚方案"` - PunishTime string `json:"punish_time" dc:"处罚时间"` - PunishDescription string `json:"punish_description" dc:"处罚描述"` - RiskType string `json:"risk_type" dc:"风险类型"` - RiskDescription string `json:"risk_description" dc:"风险描述"` + SubMchid string `json:"sub_mchid"` + CompanyName string `json:"company_name"` + RecordId string `json:"record_id"` + PunishPlan string `json:"punish_plan"` + PunishTime string `json:"punish_time"` + PunishDescription string `json:"punish_description"` + RiskType string `json:"risk_type"` + RiskDescription string `json:"risk_description"` } // 退款通知 解密结果 @@ -274,6 +274,22 @@ type V3DecryptComplaintResult struct { ActionType string `json:"action_type"` } +// 商家转账批次回调通知 解密结果 +type V3DecryptTransferBatchResult struct { + Mchid string `json:"mchid,omitempty"` + OutBatchNo string `json:"out_batch_no"` + BatchId string `json:"batch_id"` + BatchStatus string `json:"batch_status"` + TotalNum int `json:"total_num"` + TotalAmount int `json:"total_amount"` + SuccessAmount int `json:"success_amount"` + SuccessNum int `json:"success_num"` + FailAmount int `json:"fail_amount"` + FailNum int `json:"fail_num"` + UpdateTime string `json:"update_time"` + CloseReason string `json:"close_reason,omitempty"` +} + // ===================================================================================================================== type V3NotifyReq struct { @@ -308,7 +324,7 @@ func V3ParseNotify(req *http.Request) (notifyReq *V3NotifyReq, err error) { SignBody: string(bs), } notifyReq = &V3NotifyReq{SignInfo: si} - if err = json.Unmarshal(bs, notifyReq); err != nil { + if err = js.UnmarshalBytes(bs, notifyReq); err != nil { return nil, fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), notifyReq, err) } return notifyReq, nil @@ -347,8 +363,7 @@ func (v *V3NotifyReq) DecryptCipherTextToStruct(apiV3Key string, objPtr any) (er if v.Resource != nil { err = V3DecryptNotifyCipherTextToStruct(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key, objPtr) if err != nil { - bytes, _ := json.Marshal(v) - return fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return nil } @@ -360,8 +375,7 @@ func (v *V3NotifyReq) DecryptPayCipherText(apiV3Key string) (result *V3DecryptPa if v.Resource != nil { result, err = V3DecryptPayNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -373,8 +387,7 @@ func (v *V3NotifyReq) DecryptPartnerPayCipherText(apiV3Key string) (result *V3De if v.Resource != nil { result, err = V3DecryptPartnerPayNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -386,8 +399,7 @@ func (v *V3NotifyReq) DecryptRefundCipherText(apiV3Key string) (result *V3Decryp if v.Resource != nil { result, err = V3DecryptRefundNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -399,8 +411,7 @@ func (v *V3NotifyReq) DecryptPartnerRefundCipherText(apiV3Key string) (result *V if v.Resource != nil { result, err = V3DecryptPartnerRefundNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -412,8 +423,7 @@ func (v *V3NotifyReq) DecryptCombineCipherText(apiV3Key string) (result *V3Decry if v.Resource != nil { result, err = V3DecryptCombineNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -425,8 +435,7 @@ func (v *V3NotifyReq) DecryptScoreCipherText(apiV3Key string) (result *V3Decrypt if v.Resource != nil { result, err = V3DecryptScoreNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -438,8 +447,7 @@ func (v *V3NotifyReq) DecryptScorePermissionCipherText(apiV3Key string) (result if v.Resource != nil { result, err = V3DecryptScorePermissionNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -451,8 +459,7 @@ func (v *V3NotifyReq) DecryptProfitShareCipherText(apiV3Key string) (result *V3D if v.Resource != nil { result, err = V3DecryptProfitShareNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -464,8 +471,7 @@ func (v *V3NotifyReq) DecryptBusifavorCipherText(apiV3Key string) (result *V3Dec if v.Resource != nil { result, err = V3DecryptBusifavorNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -477,8 +483,7 @@ func (v *V3NotifyReq) DecryptParkingInCipherText(apiV3Key string) (result *V3Dec if v.Resource != nil { result, err = V3DecryptParkingInNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -490,8 +495,7 @@ func (v *V3NotifyReq) DecryptParkingPayCipherText(apiV3Key string) (result *V3De if v.Resource != nil { result, err = V3DecryptParkingPayNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -503,8 +507,7 @@ func (v *V3NotifyReq) DecryptCouponUseCipherText(apiV3Key string) (result *V3Dec if v.Resource != nil { result, err = V3DecryptCouponUseNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -516,8 +519,7 @@ func (v *V3NotifyReq) DecryptInvoiceTitleCipherText(apiV3Key string) (result *V3 if v.Resource != nil { result, err = V3DecryptInvoiceTitleNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -529,8 +531,7 @@ func (v *V3NotifyReq) DecryptInvoiceCipherText(apiV3Key string) (result *V3Decry if v.Resource != nil { result, err = V3DecryptInvoiceNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -542,8 +543,19 @@ func (v *V3NotifyReq) DecryptViolationCipherText(apiV3Key string) (result *V3Dec if v.Resource != nil { result, err = V3DecryptViolationNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) if err != nil { - bytes, _ := json.Marshal(v) - return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", string(bytes), err) + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) + } + return result, nil + } + return nil, errors.New("notify data Resource is nil") +} + +// 解密 商家转账批次回调通知 回调中的加密信息 +func (v *V3NotifyReq) DecryptTransferBatchCipherText(apiV3Key string) (result *V3DecryptTransferBatchResult, err error) { + if v.Resource != nil { + result, err = V3DecryptTransferBatchNotifyCipherText(v.Resource.Ciphertext, v.Resource.Nonce, v.Resource.AssociatedData, apiV3Key) + if err != nil { + return nil, fmt.Errorf("V3NotifyReq(%s) decrypt cipher text error(%w)", js.MarshalString(v), err) } return result, nil } @@ -561,7 +573,7 @@ func V3ParseNotifyToBodyMap(req *http.Request) (bm gopay.BodyMap, err error) { return } bm = make(gopay.BodyMap) - if err = json.Unmarshal(bs, &bm); err != nil { + if err = js.UnmarshalBytes(bs, &bm); err != nil { return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) } return bm, nil