Files
hm-server-v2/app/main/api/internal/logic/pay/wechatpaycallbacklogic.go
2025-10-21 18:41:31 +08:00

235 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package pay
import (
"context"
"fmt"
"hm-server/app/main/api/internal/service"
"hm-server/app/main/model"
"hm-server/pkg/lzkit/lzUtils"
"net/http"
"strings"
"time"
"hm-server/app/main/api/internal/svc"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type WechatPayCallbackLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewWechatPayCallbackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *WechatPayCallbackLogic {
return &WechatPayCallbackLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *WechatPayCallbackLogic) WechatPayCallback(w http.ResponseWriter, r *http.Request) error {
notification, err := l.svcCtx.WechatPayService.HandleWechatPayNotification(l.ctx, r)
if err != nil {
logx.Errorf("微信支付回调,%v", err)
return nil
}
// 根据订单号前缀判断订单类型
orderNo := *notification.OutTradeNo
if strings.HasPrefix(orderNo, "Q_") {
// 查询订单处理
return l.handleQueryOrderPayment(w, notification)
} else if strings.HasPrefix(orderNo, "A_") {
// 代理会员订单处理
return l.handleAgentVipOrderPayment(w, notification)
} else {
// 兼容旧订单,假设没有前缀的是查询订单
return l.handleQueryOrderPayment(w, notification)
}
}
// 处理查询订单支付
func (l *WechatPayCallbackLogic) handleQueryOrderPayment(w http.ResponseWriter, notification *payments.Transaction) error {
order, findOrderErr := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo)
if findOrderErr != nil {
logx.Errorf("微信支付回调,查找订单信息失败: %+v", findOrderErr)
return nil
}
amount := lzUtils.ToWechatAmount(order.Amount)
if amount != *notification.Amount.Total {
logx.Errorf("微信支付回调,金额不一致")
return nil
}
if order.Status != "pending" {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success"))
return nil
}
switch *notification.TradeState {
case service.TradeStateSuccess:
order.Status = "paid"
order.PayTime = lzUtils.TimeToNullTime(time.Now())
case service.TradeStateClosed:
order.Status = "closed"
order.CloseTime = lzUtils.TimeToNullTime(time.Now())
case service.TradeStateRevoked:
order.Status = "failed"
default:
return nil
}
order.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
if updateErr := l.svcCtx.OrderModel.UpdateWithVersion(l.ctx, nil, order); updateErr != nil {
logx.Errorf("微信支付回调,更新订单失败%+v", updateErr)
return nil
}
if order.Status == "paid" {
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(order.Id); asyncErr != nil {
logx.Errorf("异步任务调度失败: %v", asyncErr)
return asyncErr
}
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success"))
return nil
}
// 处理代理会员订单支付
func (l *WechatPayCallbackLogic) handleAgentVipOrderPayment(w http.ResponseWriter, notification *payments.Transaction) error {
agentOrder, findAgentOrderErr := l.svcCtx.AgentMembershipRechargeOrderModel.FindOneByOrderNo(l.ctx, *notification.OutTradeNo)
if findAgentOrderErr != nil {
logx.Errorf("微信支付回调,查找代理会员订单失败: %+v", findAgentOrderErr)
return nil
}
if agentOrder.Status != "pending" {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success"))
return nil
}
user, err := l.svcCtx.UserModel.FindOne(l.ctx, agentOrder.UserId)
if err != nil {
logx.Errorf("微信支付回调,查找用户失败: %+v", err)
return nil
}
amount := lzUtils.ToWechatAmount(agentOrder.Amount)
if user.Inside != 1 {
if amount != *notification.Amount.Total {
logx.Errorf("微信支付回调,金额不一致")
return nil
}
}
switch *notification.TradeState {
case service.TradeStateSuccess:
agentOrder.Status = "paid"
default:
return nil
}
if agentOrder.Status == "paid" {
err = l.svcCtx.AgentModel.Trans(l.ctx, func(transCtx context.Context, session sqlx.Session) error {
agentModel, err := l.svcCtx.AgentModel.FindOne(transCtx, agentOrder.AgentId)
if err != nil {
return fmt.Errorf("查找代理信息失败: %+v", err)
}
agentOrder.PlatformOrderId = lzUtils.StringToNullString(*notification.TransactionId)
if updateErr := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(l.ctx, nil, agentOrder); updateErr != nil {
return fmt.Errorf("修改代理会员订单信息失败: %+v", updateErr)
}
// 记录旧等级,用于判断是否为升级
oldLevel := agentModel.LevelName
// 设置会员等级
agentModel.LevelName = agentOrder.LevelName
// 延长会员时间
// 检查是否是有效期内续费(不发放奖励)还是重新激活(发放奖励)
isValidRenewal := oldLevel == agentOrder.LevelName && agentModel.MembershipExpiryTime.Valid && agentModel.MembershipExpiryTime.Time.After(time.Now())
if isValidRenewal {
logx.Infof("代理会员有效期内续费成功会员ID%d等级%s", agentModel.Id, agentModel.LevelName)
} else {
logx.Infof("代理会员新购、升级或重新激活成功会员ID%d等级%s", agentModel.Id, agentModel.LevelName)
}
agentModel.MembershipExpiryTime = lzUtils.RenewMembership(agentModel.MembershipExpiryTime)
if updateErr := l.svcCtx.AgentModel.UpdateWithVersion(l.ctx, nil, agentModel); updateErr != nil {
return fmt.Errorf("修改代理信息失败: %+v", updateErr)
}
// 如果不是有效期内续费,给上级代理发放升级奖励
if !isValidRenewal && (agentOrder.LevelName == model.AgentLeveNameVIP || agentOrder.LevelName == model.AgentLeveNameSVIP) {
// 验证升级路径的有效性
if oldLevel != agentOrder.LevelName {
upgradeRewardErr := l.svcCtx.AgentService.GiveUpgradeReward(transCtx, agentModel.Id, oldLevel, agentOrder.LevelName, session)
if upgradeRewardErr != nil {
logx.Errorf("发放升级奖励失败代理ID%d旧等级%s新等级%s错误%+v", agentModel.Id, oldLevel, agentOrder.LevelName, upgradeRewardErr)
// 升级奖励失败不影响主流程,只记录日志
} else {
logx.Infof("发放升级奖励成功代理ID%d旧等级%s新等级%s", agentModel.Id, oldLevel, agentOrder.LevelName)
}
}
}
return nil
})
if err != nil {
logx.Errorf("微信支付回调,处理代理会员订单失败: %+v", err)
refundErr := l.handleRefund(agentOrder)
if refundErr != nil {
logx.Errorf("微信支付回调,退款失败: %+v", refundErr)
}
return nil
}
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("success"))
return nil
}
func (l *WechatPayCallbackLogic) handleRefund(order *model.AgentMembershipRechargeOrder) error {
ctx := context.Background()
// 退款
if order.PaymentMethod == "wechat" {
refundErr := l.svcCtx.WechatPayService.WeChatRefund(ctx, order.OrderNo, order.Amount, order.Amount)
if refundErr != nil {
return refundErr
}
} else {
refund, refundErr := l.svcCtx.AlipayService.AliRefund(ctx, order.OrderNo, order.Amount)
if refundErr != nil {
return refundErr
}
if refund.IsSuccess() {
logx.Errorf("支付宝退款成功, orderID: %d", order.Id)
// 更新订单状态为退款
order.Status = "refunded"
updateOrderErr := l.svcCtx.AgentMembershipRechargeOrderModel.UpdateWithVersion(ctx, nil, order)
if updateOrderErr != nil {
logx.Errorf("更新订单状态失败订单ID: %d, 错误: %v", order.Id, updateOrderErr)
return fmt.Errorf("更新订单状态失败: %v", updateOrderErr)
}
return nil
} else {
logx.Errorf("支付宝退款失败:%v", refundErr)
return refundErr
}
}
return nil
}