From 0b75793a7cd17108b073fcaeae94ced14b8706f6 Mon Sep 17 00:00:00 2001 From: Laotree Date: Tue, 9 Feb 2021 12:21:52 +0800 Subject: [PATCH] wechat v3 refund (#101) * refund * Update pay_public_api.go Co-authored-by: cr --- wechat/v3/model.go | 36 +++++++++++++++++++++++++++++++----- wechat/v3/pay_public_api.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/wechat/v3/model.go b/wechat/v3/model.go index 29acb051..c89532ca 100644 --- a/wechat/v3/model.go +++ b/wechat/v3/model.go @@ -39,6 +39,7 @@ const ( v3CombineNative = "/v3/combine-transactions/native" v3CombineQuery = "/v3/combine-transactions/out-trade-no/%s" v3CombineClose = "/v3/combine-transactions/out-trade-no/%s/close" + v3Refund = "/v3/refund/domestic/refunds" // 微信支付分 v3ScorePermission = "/v3/payscore/permissions" // 商户预授权 POST @@ -133,6 +134,14 @@ type CloseOrderRsp struct { Error string `json:"-"` } +// 退款 Rsp +type RefundRsp struct { + Code int `json:"-"` + SignInfo *SignInfo `json:"-"` + Response *RefundOrderResponse `json:"response,omitempty"` + Error string `json:"-"` +} + // 交易、资金账单 Rsp type BillRsp struct { Code int `json:"-"` @@ -243,6 +252,7 @@ type Amount struct { PayerTotal int `json:"payer_total,omitempty"` // 用户支付金额,单位为分 Currency string `json:"currency,omitempty"` // CNY:人民币,境内商户号仅支持人民币 PayerCurrency string `json:"payer_currency,omitempty"` // 用户支付币种 + Refund int `json:"refund,omitempty"` // 退款金额,币种的最小单位,只能为整数,不能超过原订单支付金额。 } type CombineAmount struct { @@ -271,11 +281,12 @@ type PromotionDetail struct { } type GoodsDetail struct { - GoodsId string `json:"goods_id"` // 商品编码 - Quantity int `json:"quantity"` // 用户购买的数量 - UnitPrice int `json:"unit_price"` // 商品单价,单位为分 - DiscountAmount int `json:"discount_amount"` // 商品优惠金额 - GoodsRemark string `json:"goods_remark,omitempty"` // 商品备注信息 + GoodsId string `json:"goods_id"` // 商品编码 + Quantity int `json:"quantity"` // 用户购买的数量 + UnitPrice int `json:"unit_price"` // 商品单价,单位为分 + DiscountAmount int `json:"discount_amount"` // 商品优惠金额 + GoodsRemark string `json:"goods_remark,omitempty"` // 商品备注信息 + MerchantGoodsID string `json:"merchant_goods_id,omitempty"` // 商户侧商品编码 } type QueryOrder struct { @@ -337,3 +348,18 @@ type DownloadBill struct { DownloadBillCount int `json:"download_bill_count"` DownloadBillList []*BillDetail `json:"download_bill_list"` } + +type RefundOrderResponse struct { + RefundID string `json:"refund_id" valid:"Required"` // 微信支付退款号 + OutRefundNo string `json:"out_refund_no" valid:"Required"` // 商户退款单号 + TransactionID string `json:"transaction_id" valid:"Required"` // 微信支付系统生成的订单号 + OutTradeNo string `json:"out_trade_no" valid:"Required"` // 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一 + Channel string `json:"channel" valid:"Required"` // 退款渠道 + UserReceivedAccount string `json:"user_received_account" valid:"Required"` // 退款入账账户 + SuccessTime string `json:"success_time"` // 退款成功时间 + CreateTime string `json:"create_time" valid:"Required"` // 退款创建时间 + Status string `json:"status" valid:"Required"` // 退款状态 + FundsAccount string `json:"funds_account"` // 资金账户 + Amount *Amount `json:"amount" valid:"Required"` // 金额信息 + PromotionDetail []*PromotionDetail `json:"promotion_detail"` // 优惠退款信息 +} diff --git a/wechat/v3/pay_public_api.go b/wechat/v3/pay_public_api.go index 96af0b91..8fc202f3 100644 --- a/wechat/v3/pay_public_api.go +++ b/wechat/v3/pay_public_api.go @@ -580,3 +580,34 @@ func (c *ClientV3) V3CombineTransactionCloseOrder(tradeNo string, bm gopay.BodyM } return wxRsp, c.verifySyncSign(si) } + +// 申请退款API +// Code = 0 is success +// 文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter5_1_14.shtml +func (c *ClientV3) V3Refund(bm gopay.BodyMap) (wxRsp *RefundRsp, err error) { + var ( + ts = time.Now().Unix() + nonceStr = util.GetRandomString(32) + url = v3Refund + ) + authorization, err := c.authorization(MethodPost, url, nonceStr, ts, bm) + if err != nil { + return nil, err + } + res, si, bs, err := c.doProdPost(bm, url, authorization) + if err != nil { + return nil, err + } + + wxRsp = &RefundRsp{Code: Success, SignInfo: si} + wxRsp.Response = new(RefundOrderResponse) + 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) +}