diff --git a/constant.go b/constant.go index fe26e2c6..3d4bdc23 100644 --- a/constant.go +++ b/constant.go @@ -7,7 +7,7 @@ const ( OK = "OK" DebugOff = 0 DebugOn = 1 - Version = "1.5.67" + Version = "1.5.68" ) type DebugSwitch int8 diff --git a/doc/wechat_v3.md b/doc/wechat_v3.md index 2d2ab302..f0f545ba 100644 --- a/doc/wechat_v3.md +++ b/doc/wechat_v3.md @@ -365,6 +365,25 @@ wechat.V3DecryptScoreNotifyCipherText() * 电商收付通(商户进件) * 二级商户进件:`client.V3EcommerceApply()` * 查询申请状态:`client.V3EcommerceApplyStatus()` +* 电商收付通(分账) + * 请求分账:`client.V3EcommerceProfitShare()` + * 查询分账结果:`client.V3EcommerceProfitShareResult()` + * 请求分账回退:`client.V3EcommerceProfitShareReturn()` + * 查询分账回退结果:`client.V3EcommerceProfitShareReturnResult()` + * 完结分账:`client.V3EcommerceProfitShareFinish()` + * 查询订单剩余待分金额:`client.V3EcommerceProfitShareUnsplitAmount()` + * 添加分账接收方:`client.V3EcommerceProfitShareAddReceiver()` + * 删除分账接收方:`client.V3EcommerceProfitShareDeleteReceiver()` +* 电商收付通(补差) + * 请求补差:`client.V3EcommerceProfitShare()` + * 请求补差回退:`client.V3EcommerceSubsidiesReturn()` + * 取消补差:`client.V3EcommerceSubsidiesCancel()` +* 电商收付通(退款) + * 申请退款:`client.V3EcommerceRefund()` + * 查询退款ById:`client.V3EcommerceRefundQueryById()` + * 查询退款ByNo:`client.V3EcommerceRefundQueryByNo()` + * 垫付退款回补:`client.V3EcommerceRefundAdvance()` + * 查询垫付回补结果:`client.V3EcommerceRefundAdvanceResult()` ### 微信v3公共 API diff --git a/release_note.txt b/release_note.txt index 1424a230..5d6e4279 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1,3 +1,11 @@ +版本号:Release 1.5.68 +修改记录: + (1) 微信V3:修复 client.V3ComplaintResponse()、client.V3ComplaintComplete(), complaintId 参数类型错误问题 + (2) 微信V3:新增 电商收付通(分账)相关接口,详情查看v3文档最下方的接口列表 + (3) 微信V3:新增 电商收付通(补差)相关接口,详情查看v3文档最下方的接口列表 + (4) 微信V3:新增 电商收付通(退款)相关接口,详情查看v3文档最下方的接口列表 + (5) 微信V3:返回参数中字段,ID写法全部改写为Id写法 + 版本号:Release 1.5.67 修改记录: (1) 微信V3:配合微信文档修改,拆分服务商 批量转账 相关接口,接口如下: diff --git a/wechat/v3/applyment_for_sub.go b/wechat/v3/applyment_for_sub.go index 8a92dda3..94f1abc4 100644 --- a/wechat/v3/applyment_for_sub.go +++ b/wechat/v3/applyment_for_sub.go @@ -152,64 +152,3 @@ func (c *ClientV3) V3Apply4SubQuerySettlement(ctx context.Context, subMchId stri } return wxRsp, c.verifySyncSign(si) } - -// 二级商户进件API -// 注意:本接口会提交一些敏感信息,需调用 client.V3EncryptText() 进行加密。部分图片参数,请先调用 client.V3MediaUploadImage() 上传,获取MediaId -// Code = 0 is success -// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_1.shtml -func (c *ClientV3) V3EcommerceApply(ctx context.Context, bm gopay.BodyMap) (*EcommerceApplyRsp, error) { - authorization, err := c.authorization(MethodPost, v3EcommerceApply, bm) - if err != nil { - return nil, err - } - res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceApply, authorization) - if err != nil { - return nil, err - } - wxResp := &EcommerceApplyRsp{Code: Success, SignInfo: si} - wxResp.Response = new(EcommerceApply) - if err = json.Unmarshal(bs, wxResp.Response); err != nil { - return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) - } - if res.StatusCode != http.StatusOK { - wxResp.Code = res.StatusCode - wxResp.Error = string(bs) - return wxResp, nil - } - return wxResp, c.verifySyncSign(si) -} - -// 查询申请状态API -// 注意:applyId 和 outRequestNo 二选一 -// Code = 0 is success -// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_2.shtml -func (c *ClientV3) V3EcommerceApplyStatus(ctx context.Context, applyId int64, outRequestNo string) (*EcommerceApplyStatusRsp, error) { - if applyId == 0 && outRequestNo == gopay.NULL { - return nil, fmt.Errorf("applyId[%d] and outRequestNo[%s] empty at the same time", applyId, outRequestNo) - } - var url string - if applyId != 0 { - url = fmt.Sprintf(v3EcommerceApplyQueryById, applyId) - } else { - url = fmt.Sprintf(v3EcommerceApplyQueryByNo, outRequestNo) - } - authorization, err := c.authorization(MethodGet, url, nil) - if err != nil { - return nil, err - } - res, si, bs, err := c.doProdGet(ctx, url, authorization) - if err != nil { - return nil, err - } - wxRsp := &EcommerceApplyStatusRsp{Code: Success, SignInfo: si} - wxRsp.Response = new(EcommerceApplyStatus) - if err = json.Unmarshal(bs, wxRsp.Response); err != nil { - return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) - } - if res.StatusCode != http.StatusOK { - wxRsp.Code = res.StatusCode - wxRsp.Error = string(bs) - return wxRsp, nil - } - return wxRsp, c.verifySyncSign(si) -} diff --git a/wechat/v3/complaint.go b/wechat/v3/complaint.go index ee796d2e..fc06e8c9 100644 --- a/wechat/v3/complaint.go +++ b/wechat/v3/complaint.go @@ -233,7 +233,7 @@ func (c *ClientV3) V3ComplaintDetail(ctx context.Context, complaintId string) (w // Code = 0 is success // 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_14.shtml // 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_14.shtml -func (c *ClientV3) V3ComplaintResponse(ctx context.Context, complaintId, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) { +func (c *ClientV3) V3ComplaintResponse(ctx context.Context, complaintId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) { url := fmt.Sprintf(v3ComplaintResponse, complaintId) authorization, err := c.authorization(MethodPost, url, bm) if err != nil { @@ -256,7 +256,7 @@ func (c *ClientV3) V3ComplaintResponse(ctx context.Context, complaintId, bm gopa // Code = 0 is success // 商户文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_15.shtml // 服务商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter10_2_15.shtml -func (c *ClientV3) V3ComplaintComplete(ctx context.Context, complaintId, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) { +func (c *ClientV3) V3ComplaintComplete(ctx context.Context, complaintId string, bm gopay.BodyMap) (wxRsp *EmptyRsp, err error) { url := fmt.Sprintf(v3ComplaintComplete, complaintId) authorization, err := c.authorization(MethodPost, url, bm) if err != nil { diff --git a/wechat/v3/constant.go b/wechat/v3/constant.go index 089dfbb7..a89649d6 100644 --- a/wechat/v3/constant.go +++ b/wechat/v3/constant.go @@ -52,10 +52,6 @@ const ( v3DomesticRefund = "/v3/refund/domestic/refunds" // 申请退款 v3DomesticRefundQuery = "/v3/refund/domestic/refunds/%s" // 查询单笔退款 - // 退款(电商收付通) - v3CommerceRefund = "/v3/ecommerce/refunds/apply" - v3CommerceRefundQuery = "/v3/ecommerce/refunds/id/%s" - // 账单 v3TradeBill = "/v3/bill/tradebill" // 申请交易账单 GET v3FundFlowBill = "/v3/bill/fundflowbill" // 申请资金账单 GET @@ -162,7 +158,7 @@ const ( v3ComplaintComplete = "/v3/merchant-service/complaints-v2/%s/complete" // 反馈处理完成 POST v3ComplaintUploadImage = "/v3/merchant-service/images/upload" // 商户上传反馈图片 POST - // 分账 + // 分账(服务商) v3ProfitShareOrder = "/v3/profitsharing/orders" // 请求分账 POST v3ProfitShareQuery = "/v3/profitsharing/orders/%s" // 查询分账结果 GET v3ProfitShareReturn = "/v3/profitsharing/return-orders" // 请求分账回退 POST @@ -217,6 +213,28 @@ const ( v3EcommerceApplyQueryById = "/v3/ecommerce/applyments/%d" // applyment_id 通过申请单ID查询申请状态 GET v3EcommerceApplyQueryByNo = "/v3/ecommerce/applyments/out-request-no/%s" // out_request_no 通过业务申请编号查询申请状态 GET + // 电商收付通(分账) + v3EcommerceProfitShare = "/v3/ecommerce/profitsharing/orders" // 请求分账 POST + v3EcommerceProfitShareQuery = "/v3/ecommerce/profitsharing/orders" // 查询分账结果 GET + v3EcommerceProfitShareReturn = "/v3/ecommerce/profitsharing/returnorders" // 请求分账回退 POST + v3EcommerceProfitShareReturnResult = "/v3/ecommerce/profitsharing/returnorders" // 查询分账回退结果 GET + v3EcommerceProfitShareFinish = "/v3/ecommerce/profitsharing/finish-order" // 完结分账 POST + v3EcommerceProfitShareUnsplitAmount = "/v3/ecommerce/profitsharing/orders/%s/amounts" // transaction_id 查询订单剩余待分金额 GET + v3EcommerceProfitShareAddReceiver = "/v3/ecommerce/profitsharing/receivers/add" // 添加分账接收方 POST + v3EcommerceProfitShareDeleteReceiver = "/v3/ecommerce/profitsharing/receivers/delete" // 删除分账接收方 POST + + // 电商收付通(补差) + v3EcommerceSubsidies = "/v3/ecommerce/subsidies/create" // 请求补差 POST + v3EcommerceSubsidiesReturn = "/v3/ecommerce/subsidies/return" // 请求补差回退 POST + v3EcommerceSubsidiesCancel = "/v3/ecommerce/subsidies/cancel" // 取消补差 POST + + // 电商收付通(退款) + v3CommerceRefund = "/v3/ecommerce/refunds/apply" // 申请退款 POST + v3CommerceRefundQueryById = "/v3/ecommerce/refunds/id/%s" // refund_id 通过微信支付退款单号查询退款 GET + v3CommerceRefundQueryByNo = "/v3/ecommerce/refunds/out-refund-no/%s" // out_refund_no 通过商户退款单号查询退款 GET + v3CommerceRefundAdvance = "/v3/ecommerce/refunds/%s/return-advance" // refund_id 垫付退款回补 POST + v3CommerceRefundAdvanceResult = "/v3/ecommerce/refunds/%s/return-advance" // refund_id 查询垫付回补结果 GET + // 特约商户进件申请单状态 ApplyStateEditing = "APPLYMENT_STATE_EDITTING" // 编辑中 ApplyStateAuditing = "APPLYMENT_STATE_AUDITING" // 审核中 diff --git a/wechat/v3/ecommerce.go b/wechat/v3/ecommerce.go new file mode 100644 index 00000000..be4a82c5 --- /dev/null +++ b/wechat/v3/ecommerce.go @@ -0,0 +1,360 @@ +package wechat + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/go-pay/gopay" +) + +// 二级商户进件API +// 注意:本接口会提交一些敏感信息,需调用 client.V3EncryptText() 进行加密。部分图片参数,请先调用 client.V3MediaUploadImage() 上传,获取MediaId +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_1.shtml +func (c *ClientV3) V3EcommerceApply(ctx context.Context, bm gopay.BodyMap) (*EcommerceApplyRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceApply, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceApply, authorization) + if err != nil { + return nil, err + } + wxResp := &EcommerceApplyRsp{Code: Success, SignInfo: si} + wxResp.Response = new(EcommerceApply) + if err = json.Unmarshal(bs, wxResp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxResp.Code = res.StatusCode + wxResp.Error = string(bs) + return wxResp, nil + } + return wxResp, c.verifySyncSign(si) +} + +// 查询申请状态API +// 注意:applyId 和 outRequestNo 二选一 +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_1_2.shtml +func (c *ClientV3) V3EcommerceApplyStatus(ctx context.Context, applyId int64, outRequestNo string) (*EcommerceApplyStatusRsp, error) { + if applyId == 0 && outRequestNo == gopay.NULL { + return nil, fmt.Errorf("applyId[%d] and outRequestNo[%s] empty at the same time", applyId, outRequestNo) + } + var url string + if applyId != 0 { + url = fmt.Sprintf(v3EcommerceApplyQueryById, applyId) + } else { + url = fmt.Sprintf(v3EcommerceApplyQueryByNo, outRequestNo) + } + authorization, err := c.authorization(MethodGet, url, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, url, authorization) + if err != nil { + return nil, err + } + wxRsp := &EcommerceApplyStatusRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceApplyStatus) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 请求分账API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_1.shtml +func (c *ClientV3) V3EcommerceProfitShare(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceProfitShare, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShare, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShare) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 查询分账结果API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_2.shtml +func (c *ClientV3) V3EcommerceProfitShareQuery(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareQueryRsp, error) { + uri := v3EcommerceProfitShareQuery + "?" + bm.EncodeURLParams() + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareQueryRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareQuery) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 请求分账回退API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_3.shtml +func (c *ClientV3) V3EcommerceProfitShareReturn(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareReturnRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareReturn, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareReturn, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareReturnRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareReturn) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 查询分账回退结果API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_4.shtml +func (c *ClientV3) V3EcommerceProfitShareReturnResult(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareReturnResultRsp, error) { + uri := v3EcommerceProfitShareReturnResult + "?" + bm.EncodeURLParams() + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareReturnResultRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareReturn) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 完结分账API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_5.shtml +func (c *ClientV3) V3EcommerceProfitShareFinish(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareFinishRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareFinish, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareFinish, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareFinishRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareFinish) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 查询订单剩余待分金额API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_9.shtml +func (c *ClientV3) V3EcommerceProfitShareUnsplitAmount(ctx context.Context, transactionId string) (*EcommerceProfitShareUnsplitAmountRsp, error) { + url := fmt.Sprintf(v3EcommerceProfitShareUnsplitAmount, transactionId) + authorization, err := c.authorization(MethodGet, url, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, url, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareUnsplitAmountRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareUnsplitAmount) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 添加分账接收方API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_7.shtml +func (c *ClientV3) V3EcommerceProfitShareAddReceiver(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareAddReceiverRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareAddReceiver, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareAddReceiver, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareAddReceiverRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareReceiver) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 删除分账接收方API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_4_8.shtml +func (c *ClientV3) V3EcommerceProfitShareDeleteReceiver(ctx context.Context, bm gopay.BodyMap) (*EcommerceProfitShareDeleteReceiverRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceProfitShareDeleteReceiver, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceProfitShareDeleteReceiver, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceProfitShareDeleteReceiverRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceProfitShareReceiver) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 请求补差API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_1.shtml +func (c *ClientV3) V3EcommerceSubsidies(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceSubsidies, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidies, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceSubsidiesRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceSubsidies) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 请求补差回退API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_2.shtml +func (c *ClientV3) V3EcommerceSubsidiesReturn(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesReturnRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceSubsidiesReturn, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidiesReturn, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceSubsidiesReturnRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceSubsidiesReturn) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 取消补差API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_5_3.shtml +func (c *ClientV3) V3EcommerceSubsidiesCancel(ctx context.Context, bm gopay.BodyMap) (*EcommerceSubsidiesCancelRsp, error) { + authorization, err := c.authorization(MethodPost, v3EcommerceSubsidiesCancel, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3EcommerceSubsidiesCancel, authorization) + if err != nil { + return nil, err + } + + wxRsp := &EcommerceSubsidiesCancelRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceSubsidiesCancel) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} diff --git a/wechat/v3/model.go b/wechat/v3/model.go index d45c8067..780ace2d 100644 --- a/wechat/v3/model.go +++ b/wechat/v3/model.go @@ -820,6 +820,118 @@ type WithdrawStatusRsp struct { Error string `json:"-"` } +// 请求分账 Rsp +type EcommerceProfitShareRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShare `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询分账结果 Rsp +type EcommerceProfitShareQueryRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareQuery `json:"response,omitempty"` + Error string `json:"-"` +} + +// 请求分账回退 Rsp +type EcommerceProfitShareReturnRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareReturn `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询分账回退结果 Rsp +type EcommerceProfitShareReturnResultRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareReturn `json:"response,omitempty"` + Error string `json:"-"` +} + +// 完结分账 Rsp +type EcommerceProfitShareFinishRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareFinish `json:"response,omitempty"` + Error string `json:"-"` +} + +// 查询订单剩余待分金额 Rsp +type EcommerceProfitShareUnsplitAmountRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareUnsplitAmount `json:"response,omitempty"` + Error string `json:"-"` +} + +// 添加分账接收方 Rsp +type EcommerceProfitShareAddReceiverRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareReceiver `json:"response,omitempty"` + Error string `json:"-"` +} + +// 删除分账接收方 Rsp +type EcommerceProfitShareDeleteReceiverRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceProfitShareReceiver `json:"response,omitempty"` + Error string `json:"-"` +} + +// 请求补差 Rsp +type EcommerceSubsidiesRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceSubsidies `json:"response,omitempty"` + Error string `json:"-"` +} + +// 请求补差回退 Rsp +type EcommerceSubsidiesReturnRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceSubsidiesReturn `json:"response,omitempty"` + Error string `json:"-"` +} + +// 取消补差 Rsp +type EcommerceSubsidiesCancelRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceSubsidiesCancel `json:"response,omitempty"` + Error string `json:"-"` +} + +// 申请退款 Rsp +type EcommerceRefundRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceRefund `json:"response,omitempty"` + Error string `json:"-"` +} + +// 申请退款 Rsp +type EcommerceRefundQueryRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceRefundQuery `json:"response,omitempty"` + Error string `json:"-"` +} + +// 垫付退款回补 Rsp +type EcommerceRefundAdvanceRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *EcommerceRefundAdvance `json:"response,omitempty"` + Error string `json:"-"` +} + // ==================================分割================================== type JSAPIPayParams struct { @@ -928,11 +1040,11 @@ type SceneInfo struct { type PromotionDetail struct { Amount int `json:"amount"` // 优惠券面额 - CouponId string `json:"coupon_id"` // 券ID + CouponId string `json:"coupon_id"` // 券Id Name string `json:"name,omitempty"` // 优惠名称 Scope string `json:"scope,omitempty"` // 优惠范围:GLOBAL:全场代金券, SINGLE:单品优惠 Type string `json:"type,omitempty"` // 优惠类型:CASH:充值, NOCASH:预充值 - StockId string `json:"stock_id,omitempty"` // 活动ID + StockId string `json:"stock_id,omitempty"` // 活动Id WechatpayContribute int `json:"wechatpay_contribute,omitempty"` // 微信出资,单位为分 MerchantContribute int `json:"merchant_contribute,omitempty"` // 商户出资,单位为分 OtherContribute int `json:"other_contribute,omitempty"` // 其他出资,单位为分 @@ -946,7 +1058,7 @@ type GoodsDetail struct { UnitPrice int `json:"unit_price"` // 商品单价,单位为分 DiscountAmount int `json:"discount_amount"` // 商品优惠金额 GoodsRemark string `json:"goods_remark,omitempty"` // 商品备注信息 - MerchantGoodsID string `json:"merchant_goods_id,omitempty"` // 商户侧商品编码,服务商模式下无此字段 + MerchantGoodsId string `json:"merchant_goods_id,omitempty"` // 商户侧商品编码,服务商模式下无此字段 } type QueryOrder struct { @@ -1010,9 +1122,9 @@ type DownloadBill struct { } type RefundOrderResponse struct { - RefundID string `json:"refund_id"` // 微信支付退款号 + RefundId string `json:"refund_id"` // 微信支付退款号 OutRefundNo string `json:"out_refund_no"` // 商户退款单号 - TransactionID string `json:"transaction_id"` // 微信支付系统生成的订单号 + TransactionId string `json:"transaction_id"` // 微信支付系统生成的订单号 OutTradeNo string `json:"out_trade_no"` // 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 Channel string `json:"channel"` // 退款渠道 UserReceivedAccount string `json:"user_received_account"` // 退款入账账户 @@ -1025,9 +1137,9 @@ type RefundOrderResponse struct { } type RefundQueryResponse struct { - RefundID string `json:"refund_id"` // 微信支付退款号 + RefundId string `json:"refund_id"` // 微信支付退款号 OutRefundNo string `json:"out_refund_no"` // 商户退款单号 - TransactionID string `json:"transaction_id"` // 微信支付系统生成的订单号 + TransactionId string `json:"transaction_id"` // 微信支付系统生成的订单号 OutTradeNo string `json:"out_trade_no"` // 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 Channel string `json:"channel"` // 退款渠道 UserReceivedAccount string `json:"user_received_account"` // 退款入账账户 @@ -1050,7 +1162,7 @@ type RefundQueryAmount struct { } type RefundQueryPromotionDetail struct { - PromotionID string `json:"promotion_id"` // 券ID,券或立减金额 + PromotionId string `json:"promotion_id"` // 券Id,券或立减金额 Scope string `json:"scope"` // 优惠范围,GLOBAL:全场代金券,SINGLE:单品优惠 Type string `json:"type"` // 优惠类型,COUPON:代金券,DISCOUNT:优惠券 Amount int `json:"amount"` // 优惠券面额,用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额),单位为分 @@ -1059,8 +1171,8 @@ type RefundQueryPromotionDetail struct { } type RefundQueryGoodsDetail struct { - MerchantGoodsID string `json:"merchant_goods_id"` // 商户侧商品编码 - WechatpayGoodsID string `json:"wechatpay_goods_id,omitempty"` // 微信侧商品编码 + MerchantGoodsId string `json:"merchant_goods_id"` // 商户侧商品编码 + WechatpayGoodsId string `json:"wechatpay_goods_id,omitempty"` // 微信侧商品编码 GoodsName string `json:"goods_name,omitempty"` // 商品名称 UnitPrice int `json:"unit_price"` // 商品单价金额 RefundAmount int `json:"refund_amount"` // 商品退款金额 @@ -1092,10 +1204,10 @@ type PartnerPayer struct { } type ScoreOrderCreate struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 StateDescription string `json:"state_description,omitempty"` // 对服务订单"进行中"状态的附加说明。USER_CONFIRM:用户确认,MCH_COMPLETE:商户完结 @@ -1143,9 +1255,9 @@ type Location struct { } type ScoreOrderQuery struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 @@ -1182,17 +1294,17 @@ type Details struct { } type ScoreOrderCancel struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 OrderId string `json:"order_id"` // 微信支付服务订单号,每个微信支付服务订单号与商户号下对应的商户服务订单号一一对应。 } type ScoreOrderModify struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 @@ -1211,9 +1323,9 @@ type ScoreOrderModify struct { } type ScoreOrderComplete struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 @@ -1229,17 +1341,17 @@ type ScoreOrderComplete struct { } type ScoreOrderPay struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 OrderId string `json:"order_id"` // 微信支付服务订单号,每个微信支付服务订单号与商户号下对应的商户服务订单号一一对应。 } type ScoreOrderSync struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 @@ -1259,10 +1371,10 @@ type ScoreOrderSync struct { } type ScoreDirectComplete struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 OutOrderNo string `json:"out_order_no"` // 调用接口提交的商户服务订单号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 OrderId string `json:"order_id"` // 微信支付服务订单号,每个微信支付服务订单号与商户号下对应的商户服务订单号一一对应。 ServiceIntroduction string `json:"service_introduction"` // 服务信息,用于介绍本订单所提供的服务。 State string `json:"state"` // 表示当前单据状态。枚举值:CREATED:商户已创建服务订单,DOING:服务订单进行中,DONE:服务订单完成,REVOKED:商户取消服务订单,EXPIRED:服务订单已失效 @@ -1281,9 +1393,9 @@ type ScorePermission struct { } type ScorePermissionQuery struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 Openid string `json:"openid,omitempty"` // 微信用户在商户对应appid下的唯一标识 AuthorizationCode string `json:"authorization_code"` // 预授权成功时的授权协议号。 AuthorizationState string `json:"authorization_state"` // 标识用户授权服务情况:UNAVAILABLE:用户未授权服务,AVAILABLE:用户已授权服务,UNBINDUSER:未绑定用户(已经预授权但未完成正式授权) @@ -1293,9 +1405,9 @@ type ScorePermissionQuery struct { } type ScorePermissionOpenidQuery struct { - Appid string `json:"appid"` // 调用接口提交的公众账号ID。 + Appid string `json:"appid"` // 调用接口提交的公众账号Id。 Mchid string `json:"mchid"` // 调用接口提交的商户号。 - ServiceId string `json:"service_id"` // 调用该接口提交的服务ID。 + ServiceId string `json:"service_id"` // 调用该接口提交的服务Id。 Openid string `json:"openid,omitempty"` // 微信用户在商户对应appid下的唯一标识 AuthorizationCode string `json:"authorization_code"` // 预授权成功时的授权协议号。 AuthorizationState string `json:"authorization_state"` // 标识用户授权服务情况:UNAVAILABLE:用户未授权服务,AVAILABLE:用户已授权服务,UNBINDUSER:未绑定用户(已经预授权但未完成正式授权) @@ -1364,11 +1476,11 @@ type ComplaintNotifyUrl struct { } type MediaUpload struct { - MediaId string `json:"media_id"` // 微信返回的媒体文件标识ID。 + MediaId string `json:"media_id"` // 微信返回的媒体文件标识Id。 } type ProfitShareOrder struct { - SubMchid string `json:"sub_mchid,omitempty"` // 子商户号,即分账的出资商户号【服务商模式】 + SubMchid string `json:"sub_mchid"` // 二级商户号 TransactionId string `json:"transaction_id"` // 微信订单号 OutOrderNo string `json:"out_order_no"` // 商户分账单号 OrderId string `json:"order_id"` // 微信分账单号 @@ -1386,7 +1498,7 @@ type ProfitShareOrderQuery struct { } type ProfitShareReturn struct { - SubMchid string `json:"sub_mchid,omitempty"` // 子商户号,分账回退的接收商户,对应原分账出资的分账方商户【服务商模式】 + SubMchid string `json:"sub_mchid"` // 子商户号,分账回退的接收商户,对应原分账出资的分账方商户【服务商模式】 OrderId string `json:"order_id"` // 微信分账单号,微信系统返回的唯一标识 OutOrderNo string `json:"out_order_no"` // 商户系统内部的分账单号,在商户系统内部唯一,同一分账单号多次请求等同一次。只能是数字、大小写字母_-|*@ OutReturnNo string `json:"out_return_no"` // 此回退单号是商户在自己后台生成的一个新的回退单号,在商户后台唯一 @@ -1472,11 +1584,11 @@ type DiscountCardApply struct { } type DiscountCardQuery struct { - CardId string `json:"card_id"` // 先享卡ID,唯一标识一个先享卡。 - CardTemplateId string `json:"card_template_id"` // 先享卡卡模板ID,唯一定义此资源的标识。 + CardId string `json:"card_id"` // 先享卡Id,唯一标识一个先享卡。 + CardTemplateId string `json:"card_template_id"` // 先享卡卡模板Id,唯一定义此资源的标识。 Openid string `json:"openid"` // 微信用户在商户对应appid下的唯一标识 OutCardCode string `json:"out_card_code"` // 商户领卡号 - Appid string `json:"appid"` // 公众账号ID + Appid string `json:"appid"` // 公众账号Id Mchid string `json:"mchid"` // 商户号 TimeRange *struct { BeginTime string `json:"begin_time"` // 约定开始时间 @@ -1500,7 +1612,7 @@ type PayInformation struct { } type Objective struct { - ObjectiveId string `json:"objective_id"` // 由先享卡平台生成,唯一标识一个先享卡目标。商户需要记录该目标ID,进行同步用户记录 + ObjectiveId string `json:"objective_id"` // 由先享卡平台生成,唯一标识一个先享卡目标。商户需要记录该目标Id,进行同步用户记录 Name string `json:"name"` // 目标的名称 Count int `json:"count"` // 履约目标需要完成的数量,必须大于0 Unit string `json:"unit"` // 目标的单位 @@ -1510,7 +1622,7 @@ type Objective struct { type ObjectiveCompletionRecord struct { ObjectiveCompletionSerialNo string `json:"objective_completion_serial_no"` // 目标完成流水号 - ObjectiveId string `json:"objective_id"` // 微信先享卡为每个先享卡目标分配的唯一ID + ObjectiveId string `json:"objective_id"` // 微信先享卡为每个先享卡目标分配的唯一Id CompletionTime string `json:"completion_time"` // 用户履约行为发生的时间 CompletionType string `json:"completion_type"` // 目标完成类型: INCREASE:增加数量,DECREASE:减少数量 Description string `json:"description"` // 用户本次履约的描述 @@ -1519,7 +1631,7 @@ type ObjectiveCompletionRecord struct { } type Reward struct { - RewardId string `json:"reward_id"` // 由先享卡平台生成,唯一标识一个先享卡目标。商户需要记录该优惠ID,进行同步用户记录 + RewardId string `json:"reward_id"` // 由先享卡平台生成,唯一标识一个先享卡目标。商户需要记录该优惠Id,进行同步用户记录 Name string `json:"name"` // 优惠名称 CountType string `json:"count_type"` // 优惠数量的类型标识:COUNT_UNLIMITED:不限数量,COUNT_LIMIT:有限数量 Count int `json:"count"` // 本项优惠可使用的数量,必须大于0 @@ -1531,7 +1643,7 @@ type Reward struct { type RewardUsageRecord struct { RewardUsageSerialNo string `json:"reward_usage_serial_no"` // 优惠使用记录流水号 - RewardId string `json:"reward_id"` // 微信先享卡为每个先享卡优惠分配的唯一ID + RewardId string `json:"reward_id"` // 微信先享卡为每个先享卡优惠分配的唯一Id UsageTime string `json:"usage_time"` // 用户使用优惠的时间 UsageType string `json:"usage_type"` // 目标完成类型:INCREASE:增加数量,DECREASE:减少数量 Description string `json:"description"` // 用户获得奖励的描述 @@ -1609,8 +1721,8 @@ type PartnerTransferQuery struct { SubMchid string `json:"sub_mchid"` // 微信支付分配的特约商户号 OutBatchNo string `json:"out_batch_no"` // 商户系统内部的商家批次单号 BatchId string `json:"batch_id"` // 微信批次单号,微信商家转账系统返回的唯一标识 - SpAppid string `json:"sp_appid,omitempty"` // 微信分配的服务商商户公众账号ID,特约商户授权类型为FUND_AUTHORIZATION_TYPE时才有该字段 - SubAppid string `json:"sub_appid"` // 微信分配的特约商户公众账号ID。特约商户appid + SpAppid string `json:"sp_appid,omitempty"` // 微信分配的服务商商户公众账号Id,特约商户授权类型为FUND_AUTHORIZATION_TYPE时才有该字段 + SubAppid string `json:"sub_appid"` // 微信分配的特约商户公众账号Id。特约商户appid BatchStatus string `json:"batch_status"` // 批次状态 BatchType string `json:"batch_type"` // 批次类型 AuthorizationType string `json:"authorization_type"` // 特约商户授权类型 @@ -1675,8 +1787,8 @@ type PartnerTransferMerchantQuery struct { SubMchid string `json:"sub_mchid"` // 微信支付分配的特约商户号 OutBatchNo string `json:"out_batch_no"` // 商户系统内部的商家批次单号 BatchId string `json:"batch_id"` // 微信批次单号,微信商家转账系统返回的唯一标识 - SpAppid string `json:"sp_appid,omitempty"` // 微信分配的服务商商户公众账号ID,特约商户授权类型为FUND_AUTHORIZATION_TYPE时才有该字段 - SubAppid string `json:"sub_appid"` // 微信分配的特约商户公众账号ID。特约商户appid + SpAppid string `json:"sp_appid,omitempty"` // 微信分配的服务商商户公众账号Id,特约商户授权类型为FUND_AUTHORIZATION_TYPE时才有该字段 + SubAppid string `json:"sub_appid"` // 微信分配的特约商户公众账号Id。特约商户appid BatchStatus string `json:"batch_status"` // 批次状态 BatchType string `json:"batch_type"` // 批次类型 AuthorizationType string `json:"authorization_type"` // 特约商户授权类型 @@ -1872,7 +1984,7 @@ type FavorBatchGrant struct { } type FavorBatchStart struct { - StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一ID + StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一Id StartTime string `json:"start_time"` // 生效时间,遵循rfc3339标准格式 } @@ -1884,7 +1996,7 @@ type FavorBatchList struct { } type FavorBatch struct { - StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一ID + StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一Id StockCreatorMchid string `json:"stock_creator_mchid"` // 创建批次的商户号 StockName string `json:"stock_name"` // 批次名称 Status string `json:"status"` // 批次状态 @@ -1925,7 +2037,7 @@ type CutToMessage struct { } type FavorDetail struct { - StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一ID + StockId string `json:"stock_id"` // 微信为每个代金券批次分配的唯一Id StockCreatorMchid string `json:"stock_creator_mchid"` // 创建批次的商户号 CouponId string `json:"coupon_id"` // 微信为代金券唯一分配的id CutToMessage *CutToMessage `json:"cut_to_message"` // 单品优惠特定信息 @@ -2250,13 +2362,13 @@ type PartnershipsBuild struct { type Partner struct { Appid string `json:"appid"` // 合作方APPID Type string `json:"type"` // 合作方类别 - MerchantId string `json:"merchant_id"` // 合作方商户ID + MerchantId string `json:"merchant_id"` // 合作方商户Id } type AuthorizedData struct { BusinessType string `json:"business_type"` // 授权业务类别 Scenarios []string `json:"scenarios"` // 授权场景 - StockId string `json:"stock_id"` // 授权批次ID + StockId string `json:"stock_id"` // 授权批次Id } type PartnershipsTerminate struct { @@ -2333,7 +2445,7 @@ type WithdrawStatus struct { Amount int `json:"amount"` // 提现金额 CreateTime string `json:"create_time"` // 创建时间 UpdateTime string `json:"update_time"` // 更新时间 - reason string `json:"reason"` // 提现失败原因,仅在提现失败、退票、关单时有值 + Reason string `json:"reason"` // 提现失败原因,仅在提现失败、退票、关单时有值 Remark string `json:"remark"` // 商户对提现单的备注,若发起提现时未传入相应值或输入不合法,则该值为空 BankMemo string `json:"bank_memo"` // 展示在收款银行系统中的附言,由数字、字母、汉字组成(能否成功展示依赖银行系统支持)。若发起提现时未传入相应值或输入不合法,则该值为空 AccountType string `json:"account_type"` // 出款账户类型 @@ -2341,3 +2453,146 @@ type WithdrawStatus struct { AccountBank string `json:"account_bank"` // 服务商提现入账的开户银行 BankName string `json:"bank_name"` // 服务商提现入账的开户银行全称(含支行) } + +type EcommerceProfitShare struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + OutOrderNo string `json:"out_order_no"` // 商户分账单号 + OrderId string `json:"order_id"` // 微信分账单号 + Status string `json:"status"` // 分账单状态:PROCESSING:处理中,FINISHED:分账完成 + Receivers []*EcommerceReceiver `json:"receivers,omitempty"` // 分账接收方列表 +} + +type EcommerceReceiver struct { + Amount int `json:"amount"` // 分账金额 + Description string `json:"description"` // 分账描述 + Type string `json:"type"` // 分账接收方类型 + ReceiverAccount string `json:"receiver_account"` // 分账接收方帐号 + ReceiverMchid string `json:"receiver_mchid"` // 分账接收商户号 + Result string `json:"result"` // 分账结果,PENDING:待分账,SUCCESS:分账成功,CLOSED:已关闭 + DetailId string `json:"detail_id"` // 分账明细单号 + FailReason string `json:"fail_reason,omitempty"` // 分账失败原因ACCOUNT_ABNORMAL : 分账接收账户异常、NO_RELATION : 分账关系已解除、RECEIVER_HIGH_RISK : 高风险接收方、RECEIVER_REAL_NAME_NOT_VERIFIED : 接收方未实名、NO_AUTH : 分账权限已解除 + FinishTime string `json:"finish_time"` // 分账完成时间,遵循rfc3339标准格式,格式为YYYY-MM-DDTHH:mm:ss.sss+TIMEZONE +} + +type EcommerceProfitShareQuery struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + OutOrderNo string `json:"out_order_no"` // 商户分账单号 + OrderId string `json:"order_id"` // 微信分账单号 + Status string `json:"status"` // 分账单状态:PROCESSING:处理中,FINISHED:分账完成 + Receivers []*EcommerceReceiver `json:"receivers,omitempty"` // 分账接收方列表 + FinishAmount int `json:"finish_amount,omitempty"` // 分账完结的分账金额,单位为分,仅当查询分账完结的执行结果时,存在本字段。 + FinishDescription string `json:"finish_description,omitempty"` // 分账完结的原因描述,仅当查询分账完结的执行结果时,存在本字段。 +} + +type EcommerceProfitShareReturn struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + OrderId string `json:"order_id"` // 微信分账单号,微信系统返回的唯一标识 + OutOrderNo string `json:"out_order_no"` // 商户分账单号 + OutReturnNo string `json:"out_return_no"` // 商户回退单号 + ReturnNo string `json:"return_no"` // 微信分账回退单号,微信支付系统返回的唯一标识。 + ReturnMchid string `json:"return_mchid"` // 只能对原分账请求中成功分给商户接收方进行回退 + Amount int `json:"amount"` // 需要从分账接收方回退的金额,单位为分,只能为整数 + Result string `json:"result"` // 回退结果: PROCESSING:处理中,SUCCESS:已成功,FAILED:已失败 + FailReason string `json:"fail_reason,omitempty"` // 失败原因: ACCOUNT_ABNORMAL : 分账接收方账户异常,TIME_OUT_CLOSED : 超时关单 + FinishTime string `json:"finish_time"` // 分账回退完成时间 +} + +type EcommerceProfitShareFinish struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + OutOrderNo string `json:"out_order_no"` // 商户分账单号 + OrderId string `json:"order_id"` // 微信分账单号 +} + +type EcommerceProfitShareUnsplitAmount struct { + TransactionId string `json:"transaction_id"` // 微信订单号 + UnsplitAmount int `json:"unsplit_amount"` // 订单剩余待分金额 +} + +type EcommerceProfitShareReceiver struct { + Type string `json:"type"` // 接收方类型:MERCHANT_ID:商户,PERSONAL_OPENID:个人 + Account string `json:"account"` // 分账接收方帐号 +} + +type EcommerceSubsidies struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + SubsidyId string `json:"subsidy_id"` // 微信补差单号 + Description string `json:"description"` // 补差描述 + Amount int `json:"amount"` // 补差金额 + Result string `json:"result"` // 补差单结果 + SuccessTime string `json:"success_time"` // 补差完成时间 +} + +type EcommerceSubsidiesReturn struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + SubsidyRefundId string `json:"subsidy_refund_id"` // 微信补差回退单号 + RefundId string `json:"refund_id"` // 微信退款单号 + OutOrderNo string `json:"out_order_no"` // 商户补差回退单号 + Amount int `json:"amount"` // 补差回退金额 + Description string `json:"description"` // 补差回退描述 + Result string `json:"result"` // 补差回退结果 + SuccessTime string `json:"success_time"` // 补差回退完成时间 +} + +type EcommerceSubsidiesCancel struct { + SubMchid string `json:"sub_mchid"` // 二级商户号 + TransactionId string `json:"transaction_id"` // 微信订单号 + Result string `json:"result"` // 取消补差结果 + Description string `json:"description"` // 取消补差描述 +} + +type EcommerceRefund struct { + RefundId string `json:"refund_id"` // 微信支付退款号 + OutRefundNo string `json:"out_refund_no"` // 商户退款单号 + CreateTime string `json:"create_time"` // 退款创建时间 + RefundAccount string `json:"refund_account"` // 退款资金来源 + Amount *EcommerceRefundAmount `json:"amount"` // 金额信息 + PromotionDetail []*PromotionDetailItem `json:"promotion_detail"` // 优惠退款信息 +} + +type EcommerceRefundAmount struct { + Refund int `json:"refund"` // 退款金额 + PayerRefund int `json:"payer_refund"` // 用户退款金额 + DiscountRefund int `json:"discount_refund"` // 优惠退款金额 + Currency string `json:"currency"` // 退款币种 +} + +type PromotionDetailItem struct { + PromotionId string `json:"promotion_id"` // 券Id,券或立减金额 + Scope string `json:"scope"` // 优惠范围,GLOBAL:全场代金券,SINGLE:单品优惠 + Type string `json:"type"` // 优惠类型,COUPON:代金券,DISCOUNT:优惠券 + Amount int `json:"amount"` // 优惠券面额,用户享受优惠的金额(优惠券面额=微信出资金额+商家出资金额+其他出资方金额),单位为分 + RefundAmount int `json:"refund_amount"` // 优惠退款金额,单位为分 +} + +type EcommerceRefundQuery struct { + RefundId string `json:"refund_id"` // 微信支付退款号 + OutRefundNo string `json:"out_refund_no"` // 商户退款单号 + TransactionId string `json:"transaction_id"` // 微信支付系统生成的订单号 + OutTradeNo string `json:"out_trade_no"` // 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 + Channel string `json:"channel"` // 退款渠道 + UserReceivedAccount string `json:"user_received_account"` // 退款入账账户 + SuccessTime string `json:"success_time"` // 退款成功时间 + CreateTime string `json:"create_time"` // 退款创建时间 + Status string `json:"status"` // 退款状态 + RefundAccount string `json:"refund_account,omitempty"` // 退款出资商户 + FundsAccount string `json:"funds_account"` // 资金账户 + Amount *EcommerceRefundAmount `json:"amount"` // 金额信息 + PromotionDetail []*PromotionDetailItem `json:"promotion_detail"` // 优惠退款信息 +} + +type EcommerceRefundAdvance struct { + RefundId string `json:"refund_id"` // 微信支付退款号 + AdvanceReturnId string `json:"advance_return_id"` // 微信回补单号 + ReturnAmount int `json:"return_amount"` // 垫付回补金额 + PayerMchid string `json:"payer_mchid"` // 出款方商户号 + PayerAccount string `json:"payer_account"` // 出款方账户 + PayeeMchid string `json:"payee_mchid"` // 入账方商户号 + PayeeAccount string `json:"payee_account"` // 入账方账户 + Result string `json:"result"` // 垫付回补结果 + SuccessTime string `json:"success_time"` // 垫付回补完成时间 +} diff --git a/wechat/v3/refund.go b/wechat/v3/refund.go index 794a99f7..9f7651fc 100644 --- a/wechat/v3/refund.go +++ b/wechat/v3/refund.go @@ -63,3 +63,137 @@ func (c *ClientV3) V3RefundQuery(ctx context.Context, outRefundNo string) (wxRsp } return wxRsp, c.verifySyncSign(si) } + +// 申请退款API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_1.shtml +func (c *ClientV3) V3EcommerceRefund(ctx context.Context, bm gopay.BodyMap) (wxRsp *EcommerceRefundRsp, err error) { + authorization, err := c.authorization(MethodPost, v3CommerceRefund, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, v3CommerceRefund, authorization) + if err != nil { + return nil, err + } + + wxRsp = &EcommerceRefundRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceRefund) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 通过微信支付退款单号查询退款API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_2.shtml +func (c *ClientV3) V3EcommerceRefundQueryById(ctx context.Context, refundId string) (wxRsp *EcommerceRefundQueryRsp, err error) { + uri := fmt.Sprintf(v3CommerceRefundQueryById, refundId) + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + + wxRsp = &EcommerceRefundQueryRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceRefundQuery) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 通过商户退款单号查询退款API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_2.shtml +func (c *ClientV3) V3EcommerceRefundQueryByNo(ctx context.Context, outRefundNo string) (wxRsp *EcommerceRefundQueryRsp, err error) { + uri := fmt.Sprintf(v3CommerceRefundQueryByNo, outRefundNo) + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + + wxRsp = &EcommerceRefundQueryRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceRefundQuery) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 垫付退款回补API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_4.shtml +func (c *ClientV3) V3EcommerceRefundAdvance(ctx context.Context, refundId string, bm gopay.BodyMap) (wxRsp *EcommerceRefundAdvanceRsp, err error) { + url := fmt.Sprintf(v3CommerceRefundAdvance, refundId) + authorization, err := c.authorization(MethodPost, url, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(ctx, bm, url, authorization) + if err != nil { + return nil, err + } + + wxRsp = &EcommerceRefundAdvanceRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceRefundAdvance) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +} + +// 查询垫付回补结果API +// Code = 0 is success +// 电商文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter7_6_5.shtml +func (c *ClientV3) V3EcommerceRefundAdvanceResult(ctx context.Context, refundId string, bm gopay.BodyMap) (wxRsp *EcommerceRefundAdvanceRsp, err error) { + uri := fmt.Sprintf(v3CommerceRefundAdvanceResult, refundId) + "?" + bm.EncodeURLParams() + authorization, err := c.authorization(MethodGet, uri, nil) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdGet(ctx, uri, authorization) + if err != nil { + return nil, err + } + + wxRsp = &EcommerceRefundAdvanceRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(EcommerceRefundAdvance) + if err = json.Unmarshal(bs, wxRsp.Response); err != nil { + return nil, fmt.Errorf("json.Unmarshal(%s):%w", string(bs), err) + } + if res.StatusCode != http.StatusOK { + wxRsp.Code = res.StatusCode + wxRsp.Error = string(bs) + return wxRsp, nil + } + return wxRsp, c.verifySyncSign(si) +}