feat: add refund statuses

This commit is contained in:
Rogee
2025-05-06 20:23:06 +08:00
parent b7ebdf1ce6
commit 41cdc821da
13 changed files with 266 additions and 114 deletions

View File

@@ -40,45 +40,19 @@ type PayNotify struct {
} `json:"amount"`
}
type RefundResponse struct {
RefundID string `json:"refund_id"`
OutRefundNo string `json:"out_refund_no"`
type RefundNotify struct {
Mchid string `json:"mchid"`
TransactionID string `json:"transaction_id"`
OutTradeNo string `json:"out_trade_no"`
Channel string `json:"channel"`
UserReceivedAccount string `json:"user_received_account"`
RefundID string `json:"refund_id"`
OutRefundNo string `json:"out_refund_no"`
RefundStatus string `json:"refund_status"`
SuccessTime time.Time `json:"success_time"`
CreateTime time.Time `json:"create_time"`
Status string `json:"status"`
FundsAccount string `json:"funds_account"`
UserReceivedAccount string `json:"user_received_account"`
Amount struct {
Total int `json:"total"`
Refund int `json:"refund"`
From []struct {
Account string `json:"account"`
Amount int `json:"amount"`
} `json:"from"`
PayerTotal int `json:"payer_total"`
PayerRefund int `json:"payer_refund"`
SettlementRefund int `json:"settlement_refund"`
SettlementTotal int `json:"settlement_total"`
DiscountRefund int `json:"discount_refund"`
Currency string `json:"currency"`
RefundFee int `json:"refund_fee"`
Total int `json:"total"`
Refund int `json:"refund"`
PayerTotal int `json:"payer_total"`
PayerRefund int `json:"payer_refund"`
} `json:"amount"`
PromotionDetail []struct {
PromotionID string `json:"promotion_id"`
Scope string `json:"scope"`
Type string `json:"type"`
Amount int `json:"amount"`
RefundAmount int `json:"refund_amount"`
GoodsDetail []struct {
MerchantGoodsID string `json:"merchant_goods_id"`
WechatpayGoodsID string `json:"wechatpay_goods_id"`
GoodsName string `json:"goods_name"`
UnitPrice int `json:"unit_price"`
RefundAmount int `json:"refund_amount"`
RefundQuantity int `json:"refund_quantity"`
} `json:"goods_detail"`
} `json:"promotion_detail"`
}

View File

@@ -78,11 +78,11 @@ type PrepayData struct {
}
// PaySignOfJSAPI
func (pay *PrepayData) PaySignOfJSAPI() (*, error) {
func (pay *PrepayData) PaySignOfJSAPI() (*wechat.JSAPIPayParams, error) {
return pay.client.payClient.PaySignOfJSAPI(pay.AppID, pay.PrepayID)
}
func (c *Client) Refund(ctx context.Context, f func(*BodyMap)) (*wechat.RefundOrderResponse,error ){
func (c *Client) Refund(ctx context.Context, f func(*BodyMap)) (*wechat.RefundOrderResponse, error) {
bm := NewBodyMap(c.config)
f(bm)
@@ -117,7 +117,11 @@ func (c *Client) V3TransactionJsapi(ctx context.Context, f func(*BodyMap)) (*Pre
}, nil
}
func (c *Client) ParseNotify(ctx fiber.Ctx) (*PayNotify, error) {
func (c *Client) ParseNotify(
ctx fiber.Ctx,
payCallback func(fiber.Ctx, *wechat.V3DecryptPayResult) error,
refundCallback func(fiber.Ctx, *wechat.V3DecryptRefundResult) error,
) error {
body := ctx.Body()
si := &wechat.SignInfo{
HeaderTimestamp: ctx.Get(wechat.HeaderTimestamp),
@@ -126,31 +130,54 @@ func (c *Client) ParseNotify(ctx fiber.Ctx) (*PayNotify, error) {
HeaderSerial: ctx.Get(wechat.HeaderSerial),
SignBody: string(body),
}
notifyReq := &wechat.V3NotifyReq{SignInfo: si}
if err := js.UnmarshalBytes(body, notifyReq); err != nil {
log.Errorf("json unmarshal error:%v", err)
return nil, ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": fmt.Sprintf("json unmarshal error:%v", err)})
return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": fmt.Sprintf("json unmarshal error:%v", err)})
}
// 获取微信平台证书
certMap := c.WxPublicKeyMap()
// 验证异步通知的签名
err := notifyReq.VerifySignByPKMap(certMap)
if err != nil {
if err := notifyReq.VerifySignByPKMap(certMap); err != nil {
log.Errorf("verify sign error:%v", err)
return nil, ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid signature"})
return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid signature"})
}
var notifyData PayNotify
err = notifyReq.DecryptCipherTextToStruct(c.config.Pay.ApiV3Key, &notifyData)
if err != nil {
return nil, ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid cipher text"})
// TRANSACTION.SUCCESS :支付成功通知
// REFUND.SUCCESS退款成功通知
// REFUND.ABNORMAL退款异常通知
// REFUND.CLOSED退款关闭通知
switch notifyReq.EventType {
case "TRANSACTION.SUCCESS":
var notifyData wechat.V3DecryptPayResult
if err := notifyReq.DecryptCipherTextToStruct(c.config.Pay.ApiV3Key, &notifyData); err != nil {
return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid cipher text"})
}
log.Infof("Successfully decrypted cipher text for pay notify data: %+v", notifyData)
if err := payCallback(ctx, &notifyData); err != nil {
log.Errorf("payCallback error:%v", err)
return err
}
case "REFUND.SUCCESS", "REFUND.ABNORMAL", "REFUND.CLOSED":
var notifyData wechat.V3DecryptRefundResult
if err := notifyReq.DecryptCipherTextToStruct(c.config.Pay.ApiV3Key, &notifyData); err != nil {
return ctx.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "Invalid cipher text"})
}
log.Infof("Successfully decrypted cipher text for refund notify data: %+v", notifyData)
if err := refundCallback(ctx, &notifyData); err != nil {
log.Errorf("refundCallback error:%v", err)
return err
}
}
log.Infof("Successfully decrypted cipher text for notify data: %+v", notifyData)
return &notifyData, nil
return ctx.Status(http.StatusOK).JSON(&wechat.V3NotifyRsp{
Code: gopay.SUCCESS,
Message: "成功",
})
}
type BodyMap struct {