From 1466edfdcbe348cf3cb8d1e0da1a61e2a5734af0 Mon Sep 17 00:00:00 2001 From: mshzy <156560471+mshzy@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:11:43 +0800 Subject: [PATCH] fix: improve EasyPay QueryOrder payment status detection (fixes #2958) - Add trade_status field parsing with TRADE_SUCCESS priority - Support EasyPay implementations that wrap response in 'data' field - Fall back to status==1 only when trade_status is not present - Prevents incorrectly marking unpaid/failed orders as paid --- backend/internal/payment/provider/easypay.go | 45 ++++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/backend/internal/payment/provider/easypay.go b/backend/internal/payment/provider/easypay.go index e7d8aab982d..6c883cf373e 100644 --- a/backend/internal/payment/provider/easypay.go +++ b/backend/internal/payment/provider/easypay.go @@ -205,6 +205,7 @@ func (e *EasyPay) resolveURLs(req payment.CreatePaymentRequest) (string, string) } func (e *EasyPay) QueryOrder(ctx context.Context, tradeNo string) (*payment.QueryOrderResponse, error) { + params := map[string]string{ "act": "order", "pid": e.config["pid"], "key": e.config["pkey"], "out_trade_no": tradeNo, @@ -213,20 +214,48 @@ func (e *EasyPay) QueryOrder(ctx context.Context, tradeNo string) (*payment.Quer if err != nil { return nil, fmt.Errorf("easypay query: %w", err) } - var resp struct { - Code int `json:"code"` - Msg string `json:"msg"` - Status int `json:"status"` - Money string `json:"money"` + + // Some EasyPay implementations wrap the response in a "data" field + var rawResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Status int `json:"status"` + Money string `json:"money"` + TradeStatus string `json:"trade_status"` + Data json.RawMessage `json:"data"` } - if err := json.Unmarshal(body, &resp); err != nil { + if err := json.Unmarshal(body, &rawResp); err != nil { return nil, fmt.Errorf("easypay parse query: %w", err) } + + // If response is wrapped in "data", attempt to unwrap it + if rawResp.Data != nil { + var dataResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Status int `json:"status"` + Money string `json:"money"` + TradeStatus string `json:"trade_status"` + } + if err := json.Unmarshal(rawResp.Data, &dataResp); err == nil { + rawResp.Code = dataResp.Code + rawResp.Status = dataResp.Status + rawResp.Money = dataResp.Money + if dataResp.TradeStatus != "" { + rawResp.TradeStatus = dataResp.TradeStatus + } + } + } + + // Determine payment status: prefer trade_status, fall back to status code status := payment.ProviderStatusPending - if resp.Status == easypayStatusPaid { + if rawResp.TradeStatus == tradeStatusSuccess { + status = payment.ProviderStatusPaid + } else if rawResp.Status == easypayStatusPaid { status = payment.ProviderStatusPaid } - amount, _ := strconv.ParseFloat(resp.Money, 64) + + amount, _ := strconv.ParseFloat(rawResp.Money, 64) return &payment.QueryOrderResponse{ TradeNo: tradeNo, Status: status,