Files
soul-yongping/soul-api/internal/handler/payment.go

108 lines
3.1 KiB
Go

package handler
import (
"fmt"
"io"
"net/http"
"time"
"soul-api/internal/database"
"soul-api/internal/model"
"soul-api/internal/wechat"
"github.com/gin-gonic/gin"
)
// PaymentAlipayNotify POST /api/payment/alipay/notify
func PaymentAlipayNotify(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentCallback POST /api/payment/callback
func PaymentCallback(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentCreateOrder POST /api/payment/create-order
func PaymentCreateOrder(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentMethods GET /api/payment/methods
func PaymentMethods(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true, "data": []interface{}{}})
}
// PaymentQuery GET /api/payment/query
func PaymentQuery(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentStatusOrderSn GET /api/payment/status/:orderSn
func PaymentStatusOrderSn(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentVerify POST /api/payment/verify
func PaymentVerify(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentWechatNotify POST /api/payment/wechat/notify
func PaymentWechatNotify(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true})
}
// PaymentWechatTransferNotify POST /api/payment/wechat/transfer/notify
// 使用 PowerWeChat 验签、解密密文后更新提现状态,并返回微信要求的应答
func PaymentWechatTransferNotify(c *gin.Context) {
resp, err := wechat.HandleTransferNotify(c.Request, func(outBillNo, transferBillNo, state, failReason string) error {
fmt.Printf("[TransferNotify] 解密成功: out_bill_no=%s, transfer_bill_no=%s, state=%s\n", outBillNo, transferBillNo, state)
db := database.DB()
var w model.Withdrawal
if err := db.Where("detail_no = ?", outBillNo).First(&w).Error; err != nil {
fmt.Printf("[TransferNotify] 未找到 detail_no=%s 的提现记录: %v\n", outBillNo, err)
return nil // 找不到也返回成功,避免微信重复推送
}
// 幂等:仅当当前为处理中/待确认时更新
cur := ""
if w.Status != nil {
cur = *w.Status
}
if cur != "processing" && cur != "pending_confirm" {
return nil
}
now := time.Now()
up := map[string]interface{}{"processed_at": now}
switch state {
case "SUCCESS":
up["status"] = "success"
case "FAIL", "CANCELLED":
up["status"] = "failed"
if failReason != "" {
up["fail_reason"] = failReason
}
default:
return nil
}
if err := db.Model(&w).Updates(up).Error; err != nil {
return fmt.Errorf("更新提现状态失败: %w", err)
}
fmt.Printf("[TransferNotify] 已更新提现 id=%s -> status=%s\n", w.ID, up["status"])
return nil
})
if err != nil {
fmt.Printf("[TransferNotify] 验签/解密/处理失败: %v\n", err)
c.JSON(http.StatusInternalServerError, gin.H{"code": "FAIL", "message": err.Error()})
return
}
defer resp.Body.Close()
for k, v := range resp.Header {
if len(v) > 0 {
c.Header(k, v[0])
}
}
c.Status(resp.StatusCode)
io.Copy(c.Writer, resp.Body)
}