微信支付

This commit is contained in:
2025-12-12 15:27:15 +08:00
parent 2c89b8cb26
commit 0d4953c6d3
34 changed files with 1974 additions and 279 deletions

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"time"
"tyapi-server/internal/application/finance/dto/commands"
"tyapi-server/internal/application/finance/dto/queries"
"tyapi-server/internal/application/finance/dto/responses"
@@ -19,16 +20,20 @@ import (
"github.com/shopspring/decimal"
"github.com/smartwalle/alipay/v3"
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
"go.uber.org/zap"
)
// FinanceApplicationServiceImpl 财务应用服务实现
type FinanceApplicationServiceImpl struct {
aliPayClient *payment.AliPayService
wechatPayService *payment.WechatPayService
walletService finance_services.WalletAggregateService
rechargeRecordService finance_services.RechargeRecordService
walletTransactionRepository finance_repositories.WalletTransactionRepository
alipayOrderRepo finance_repositories.AlipayOrderRepository
wechatOrderRepo finance_repositories.WechatOrderRepository
rechargeRecordRepo finance_repositories.RechargeRecordRepository
userRepo user_repositories.UserRepository
txManager *database.TransactionManager
exportManager *export.ExportManager
@@ -39,10 +44,13 @@ type FinanceApplicationServiceImpl struct {
// NewFinanceApplicationService 创建财务应用服务
func NewFinanceApplicationService(
aliPayClient *payment.AliPayService,
wechatPayService *payment.WechatPayService,
walletService finance_services.WalletAggregateService,
rechargeRecordService finance_services.RechargeRecordService,
walletTransactionRepository finance_repositories.WalletTransactionRepository,
alipayOrderRepo finance_repositories.AlipayOrderRepository,
wechatOrderRepo finance_repositories.WechatOrderRepository,
rechargeRecordRepo finance_repositories.RechargeRecordRepository,
userRepo user_repositories.UserRepository,
txManager *database.TransactionManager,
logger *zap.Logger,
@@ -51,10 +59,13 @@ func NewFinanceApplicationService(
) FinanceApplicationService {
return &FinanceApplicationServiceImpl{
aliPayClient: aliPayClient,
wechatPayService: wechatPayService,
walletService: walletService,
rechargeRecordService: rechargeRecordService,
walletTransactionRepository: walletTransactionRepository,
alipayOrderRepo: alipayOrderRepo,
wechatOrderRepo: wechatOrderRepo,
rechargeRecordRepo: rechargeRecordRepo,
userRepo: userRepo,
txManager: txManager,
exportManager: exportManager,
@@ -100,8 +111,9 @@ func (s *FinanceApplicationServiceImpl) GetWallet(ctx context.Context, query *qu
BalanceStatus: wallet.GetBalanceStatus(),
IsArrears: wallet.IsArrears(),
IsLowBalance: wallet.IsLowBalance(),
CreatedAt: wallet.CreatedAt,
UpdatedAt: wallet.UpdatedAt,
CreatedAt: wallet.CreatedAt,
UpdatedAt: wallet.UpdatedAt,
}, nil
}
@@ -188,6 +200,168 @@ func (s *FinanceApplicationServiceImpl) CreateAlipayRechargeOrder(ctx context.Co
}, nil
}
// CreateWechatRechargeOrder 创建微信充值订单(完整流程编排)
func (s *FinanceApplicationServiceImpl) CreateWechatRechargeOrder(ctx context.Context, cmd *commands.CreateWechatRechargeCommand) (*responses.WechatRechargeOrderResponse, error) {
cmd.Subject = "天远数据API充值"
amount, err := decimal.NewFromString(cmd.Amount)
if err != nil {
s.logger.Error("金额格式错误", zap.String("amount", cmd.Amount), zap.Error(err))
return nil, fmt.Errorf("金额格式错误: %w", err)
}
if amount.LessThanOrEqual(decimal.Zero) {
return nil, fmt.Errorf("充值金额必须大于0")
}
minAmount, err := decimal.NewFromString(s.config.Wallet.MinAmount)
if err != nil {
s.logger.Error("配置中的最低充值金额格式错误", zap.String("min_amount", s.config.Wallet.MinAmount), zap.Error(err))
return nil, fmt.Errorf("系统配置错误: %w", err)
}
maxAmount, err := decimal.NewFromString(s.config.Wallet.MaxAmount)
if err != nil {
s.logger.Error("配置中的最高充值金额格式错误", zap.String("max_amount", s.config.Wallet.MaxAmount), zap.Error(err))
return nil, fmt.Errorf("系统配置错误: %w", err)
}
if amount.LessThan(minAmount) {
return nil, fmt.Errorf("充值金额不能少于%s元", minAmount.String())
}
if amount.GreaterThan(maxAmount) {
return nil, fmt.Errorf("单次充值金额不能超过%s元", maxAmount.String())
}
platform := normalizeWechatPlatform(cmd.Platform)
if platform != payment.PlatformWxNative && platform != payment.PlatformWxH5 {
return nil, fmt.Errorf("不支持的支付平台: %s", cmd.Platform)
}
if s.wechatPayService == nil {
return nil, fmt.Errorf("微信支付服务未初始化")
}
outTradeNo := s.wechatPayService.GenerateOutTradeNo()
s.logger.Info("开始创建微信充值订单",
zap.String("user_id", cmd.UserID),
zap.String("out_trade_no", outTradeNo),
zap.String("amount", amount.String()),
zap.String("platform", cmd.Platform),
zap.String("subject", cmd.Subject),
)
var prepayData interface{}
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
// 创建微信充值记录
rechargeRecord := finance_entities.NewWechatRechargeRecord(cmd.UserID, amount, outTradeNo)
createdRecord, createErr := s.rechargeRecordRepo.Create(txCtx, *rechargeRecord)
if createErr != nil {
s.logger.Error("创建微信充值记录失败",
zap.String("out_trade_no", outTradeNo),
zap.String("user_id", cmd.UserID),
zap.String("amount", amount.String()),
zap.Error(createErr),
)
return fmt.Errorf("创建微信充值记录失败: %w", createErr)
}
s.logger.Info("创建微信充值记录成功",
zap.String("out_trade_no", outTradeNo),
zap.String("recharge_id", createdRecord.ID),
zap.String("user_id", cmd.UserID),
)
// 创建微信订单本地记录
wechatOrder := finance_entities.NewWechatOrder(createdRecord.ID, outTradeNo, cmd.Subject, amount, platform)
createdOrder, orderErr := s.wechatOrderRepo.Create(txCtx, *wechatOrder)
if orderErr != nil {
s.logger.Error("创建微信订单记录失败",
zap.String("out_trade_no", outTradeNo),
zap.String("recharge_id", createdRecord.ID),
zap.Error(orderErr),
)
return fmt.Errorf("创建微信订单记录失败: %w", orderErr)
}
s.logger.Info("创建微信订单记录成功",
zap.String("out_trade_no", outTradeNo),
zap.String("order_id", createdOrder.ID),
zap.String("recharge_id", createdRecord.ID),
)
return nil
})
if err != nil {
return nil, err
}
payCtx := context.WithValue(ctx, "platform", platform)
payCtx = context.WithValue(payCtx, "user_id", cmd.UserID)
s.logger.Info("调用微信支付接口创建订单",
zap.String("out_trade_no", outTradeNo),
zap.String("platform", platform),
)
prepayData, err = s.wechatPayService.CreateWechatOrder(payCtx, amount.InexactFloat64(), cmd.Subject, outTradeNo)
if err != nil {
s.logger.Error("微信下单失败",
zap.String("out_trade_no", outTradeNo),
zap.String("user_id", cmd.UserID),
zap.String("amount", amount.String()),
zap.Error(err),
)
// 回写失败状态
_ = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
order, getErr := s.wechatOrderRepo.GetByOutTradeNo(txCtx, outTradeNo)
if getErr == nil && order != nil {
order.MarkFailed("create_failed", err.Error())
updateErr := s.wechatOrderRepo.Update(txCtx, *order)
if updateErr != nil {
s.logger.Error("回写微信订单失败状态失败",
zap.String("out_trade_no", outTradeNo),
zap.Error(updateErr),
)
} else {
s.logger.Info("回写微信订单失败状态成功",
zap.String("out_trade_no", outTradeNo),
)
}
}
return nil
})
return nil, fmt.Errorf("创建微信支付订单失败: %w", err)
}
s.logger.Info("微信充值订单创建成功",
zap.String("user_id", cmd.UserID),
zap.String("out_trade_no", outTradeNo),
zap.String("amount", amount.String()),
zap.String("platform", cmd.Platform),
)
return &responses.WechatRechargeOrderResponse{
OutTradeNo: outTradeNo,
Amount: amount,
Platform: platform,
Subject: cmd.Subject,
PrepayData: prepayData,
}, nil
}
// normalizeWechatPlatform 将兼容写法(h5/mini)转换为系统内使用的wx_h5/wx_mini
func normalizeWechatPlatform(p string) string {
switch p {
case "h5", payment.PlatformWxH5:
return payment.PlatformWxNative
case "native":
return payment.PlatformWxNative
default:
return p
}
}
// TransferRecharge 对公转账充值
func (s *FinanceApplicationServiceImpl) TransferRecharge(ctx context.Context, cmd *commands.TransferRechargeCommand) (*responses.RechargeRecordResponse, error) {
// 将字符串金额转换为 decimal.Decimal
@@ -507,8 +681,8 @@ func (s *FinanceApplicationServiceImpl) ExportAdminRechargeRecords(ctx context.C
}
// 准备导出数据
headers := []string{"企业名称", "充值金额", "充值类型", "状态", "支付宝订单号", "转账订单号", "备注", "充值时间"}
columnWidths := []float64{25, 15, 15, 10, 20, 20, 20, 20}
headers := []string{"企业名称", "充值金额", "充值类型", "状态", "支付宝订单号", "微信订单号", "转账订单号", "备注", "充值时间"}
columnWidths := []float64{25, 15, 15, 10, 20, 20, 20, 20, 20}
data := make([][]interface{}, len(allRecords))
for i, record := range allRecords {
@@ -523,6 +697,10 @@ func (s *FinanceApplicationServiceImpl) ExportAdminRechargeRecords(ctx context.C
if record.AlipayOrderID != nil && *record.AlipayOrderID != "" {
alipayOrderID = *record.AlipayOrderID
}
wechatOrderID := ""
if record.WechatOrderID != nil && *record.WechatOrderID != "" {
wechatOrderID = *record.WechatOrderID
}
transferOrderID := ""
if record.TransferOrderID != nil && *record.TransferOrderID != "" {
transferOrderID = *record.TransferOrderID
@@ -543,6 +721,7 @@ func (s *FinanceApplicationServiceImpl) ExportAdminRechargeRecords(ctx context.C
translateRechargeType(record.RechargeType),
translateRechargeStatus(record.Status),
alipayOrderID,
wechatOrderID,
transferOrderID,
notes,
createdAt,
@@ -566,6 +745,8 @@ func translateRechargeType(rechargeType finance_entities.RechargeType) string {
switch rechargeType {
case finance_entities.RechargeTypeAlipay:
return "支付宝充值"
case finance_entities.RechargeTypeWechat:
return "微信充值"
case finance_entities.RechargeTypeTransfer:
return "对公转账"
case finance_entities.RechargeTypeGift:
@@ -890,15 +1071,27 @@ func (s *FinanceApplicationServiceImpl) GetAlipayOrderStatus(ctx context.Context
// GetUserRechargeRecords 获取用户充值记录
func (s *FinanceApplicationServiceImpl) GetUserRechargeRecords(ctx context.Context, userID string, filters map[string]interface{}, options interfaces.ListOptions) (*responses.RechargeRecordListResponse, error) {
// 查询用户充值记录
records, err := s.rechargeRecordService.GetByUserID(ctx, userID)
// 确保 filters 不为 nil
if filters == nil {
filters = make(map[string]interface{})
}
// 添加 user_id 筛选条件,确保只能查询当前用户的记录
filters["user_id"] = userID
// 查询用户充值记录(使用筛选和分页功能)
records, err := s.rechargeRecordService.GetAll(ctx, filters, options)
if err != nil {
s.logger.Error("查询用户充值记录失败", zap.Error(err), zap.String("userID", userID))
return nil, err
}
// 计算总数
total := int64(len(records))
// 获取总数(使用筛选条件)
total, err := s.rechargeRecordService.Count(ctx, filters)
if err != nil {
s.logger.Error("统计用户充值记录失败", zap.Error(err), zap.String("userID", userID))
return nil, err
}
// 转换为响应DTO
var items []responses.RechargeRecordResponse
@@ -914,9 +1107,20 @@ func (s *FinanceApplicationServiceImpl) GetUserRechargeRecords(ctx context.Conte
UpdatedAt: record.UpdatedAt,
}
// 根据充值类型设置相应的订单号
// 根据充值类型设置相应的订单号和平台信息
if record.AlipayOrderID != nil {
item.AlipayOrderID = *record.AlipayOrderID
// 通过订单号获取平台信息
if alipayOrder, err := s.alipayOrderRepo.GetByOutTradeNo(ctx, *record.AlipayOrderID); err == nil && alipayOrder != nil {
item.Platform = alipayOrder.Platform
}
}
if record.WechatOrderID != nil {
item.WechatOrderID = *record.WechatOrderID
// 通过订单号获取平台信息
if wechatOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, *record.WechatOrderID); err == nil && wechatOrder != nil {
item.Platform = wechatOrder.Platform
}
}
if record.TransferOrderID != nil {
item.TransferOrderID = *record.TransferOrderID
@@ -963,9 +1167,20 @@ func (s *FinanceApplicationServiceImpl) GetAdminRechargeRecords(ctx context.Cont
UpdatedAt: record.UpdatedAt,
}
// 根据充值类型设置相应的订单号
// 根据充值类型设置相应的订单号和平台信息
if record.AlipayOrderID != nil {
item.AlipayOrderID = *record.AlipayOrderID
// 通过订单号获取平台信息
if alipayOrder, err := s.alipayOrderRepo.GetByOutTradeNo(ctx, *record.AlipayOrderID); err == nil && alipayOrder != nil {
item.Platform = alipayOrder.Platform
}
}
if record.WechatOrderID != nil {
item.WechatOrderID = *record.WechatOrderID
// 通过订单号获取平台信息
if wechatOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, *record.WechatOrderID); err == nil && wechatOrder != nil {
item.Platform = wechatOrder.Platform
}
}
if record.TransferOrderID != nil {
item.TransferOrderID = *record.TransferOrderID
@@ -1012,3 +1227,445 @@ func (s *FinanceApplicationServiceImpl) GetRechargeConfig(ctx context.Context) (
AlipayRechargeBonus: bonus,
}, nil
}
// GetWechatOrderStatus 获取微信订单状态
func (s *FinanceApplicationServiceImpl) GetWechatOrderStatus(ctx context.Context, outTradeNo string) (*responses.WechatOrderStatusResponse, error) {
if outTradeNo == "" {
return nil, fmt.Errorf("缺少商户订单号")
}
// 查找微信订单
wechatOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, outTradeNo)
if err != nil {
s.logger.Error("查找微信订单失败", zap.String("out_trade_no", outTradeNo), zap.Error(err))
return nil, fmt.Errorf("查找微信订单失败: %w", err)
}
if wechatOrder == nil {
s.logger.Error("微信订单不存在", zap.String("out_trade_no", outTradeNo))
return nil, fmt.Errorf("微信订单不存在")
}
// 如果订单状态为pending主动查询微信订单状态
if wechatOrder.Status == finance_entities.WechatOrderStatusPending {
s.logger.Info("订单状态为pending主动查询微信订单状态",
zap.String("out_trade_no", outTradeNo),
)
// 调用微信查询接口
transaction, err := s.wechatPayService.QueryOrderStatus(ctx, outTradeNo)
if err != nil {
s.logger.Error("查询微信订单状态失败",
zap.String("out_trade_no", outTradeNo),
zap.Error(err),
)
// 查询失败不影响返回,继续使用数据库中的状态
} else {
// 解析微信返回的状态
tradeState := ""
transactionID := ""
if transaction.TradeState != nil {
tradeState = *transaction.TradeState
}
if transaction.TransactionId != nil {
transactionID = *transaction.TransactionId
}
s.logger.Info("微信查询订单状态返回",
zap.String("out_trade_no", outTradeNo),
zap.String("trade_state", tradeState),
zap.String("transaction_id", transactionID),
)
// 使用公共方法更新订单状态
err = s.updateWechatOrderStatus(ctx, outTradeNo, tradeState, transaction)
if err != nil {
s.logger.Error("更新微信订单状态失败",
zap.String("out_trade_no", outTradeNo),
zap.String("trade_state", tradeState),
zap.Error(err),
)
}
// 重新获取更新后的订单信息
updatedOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, outTradeNo)
if err == nil && updatedOrder != nil {
wechatOrder = updatedOrder
}
}
}
// 判断是否处理中
isProcessing := wechatOrder.Status == finance_entities.WechatOrderStatusPending
// 判断是否可以重试(失败状态可以重试)
canRetry := wechatOrder.Status == finance_entities.WechatOrderStatusFailed
// 转换为响应DTO
response := &responses.WechatOrderStatusResponse{
OutTradeNo: wechatOrder.OutTradeNo,
TransactionID: wechatOrder.TradeNo,
Status: string(wechatOrder.Status),
Amount: wechatOrder.Amount,
Subject: wechatOrder.Subject,
Platform: wechatOrder.Platform,
CreatedAt: wechatOrder.CreatedAt,
UpdatedAt: wechatOrder.UpdatedAt,
NotifyTime: wechatOrder.NotifyTime,
ReturnTime: wechatOrder.ReturnTime,
ErrorCode: &wechatOrder.ErrorCode,
ErrorMessage: &wechatOrder.ErrorMessage,
IsProcessing: isProcessing,
CanRetry: canRetry,
}
// 如果错误码为空设置为nil
if wechatOrder.ErrorCode == "" {
response.ErrorCode = nil
}
if wechatOrder.ErrorMessage == "" {
response.ErrorMessage = nil
}
s.logger.Info("查询微信订单状态完成",
zap.String("out_trade_no", outTradeNo),
zap.String("status", string(wechatOrder.Status)),
zap.Bool("is_processing", isProcessing),
zap.Bool("can_retry", canRetry),
)
return response, nil
}
// updateWechatOrderStatus 根据微信状态更新本地订单状态
func (s *FinanceApplicationServiceImpl) updateWechatOrderStatus(ctx context.Context, outTradeNo string, tradeState string, transaction *payments.Transaction) error {
// 查找微信订单
wechatOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, outTradeNo)
if err != nil {
s.logger.Error("查找微信订单失败", zap.String("out_trade_no", outTradeNo), zap.Error(err))
return fmt.Errorf("查找微信订单失败: %w", err)
}
if wechatOrder == nil {
s.logger.Error("微信订单不存在", zap.String("out_trade_no", outTradeNo))
return fmt.Errorf("微信订单不存在")
}
switch tradeState {
case payment.TradeStateSuccess:
// 支付成功,调用公共处理逻辑
transactionID := ""
if transaction.TransactionId != nil {
transactionID = *transaction.TransactionId
}
payAmount := decimal.Zero
if transaction.Amount != nil && transaction.Amount.Total != nil {
// 将分转换为元
payAmount = decimal.NewFromInt(*transaction.Amount.Total).Div(decimal.NewFromInt(100))
}
return s.processWechatPaymentSuccess(ctx, outTradeNo, transactionID, payAmount)
case payment.TradeStateClosed:
// 交易关闭
s.logger.Info("微信订单交易关闭",
zap.String("out_trade_no", outTradeNo),
)
wechatOrder.MarkClosed()
err = s.wechatOrderRepo.Update(ctx, *wechatOrder)
if err != nil {
s.logger.Error("更新微信订单关闭状态失败",
zap.String("out_trade_no", outTradeNo),
zap.Error(err),
)
return err
}
s.logger.Info("微信订单关闭状态更新成功",
zap.String("out_trade_no", outTradeNo),
)
case payment.TradeStateNotPay:
// 未支付保持pending状态
s.logger.Info("微信订单未支付",
zap.String("out_trade_no", outTradeNo),
)
default:
// 其他状态,记录日志
s.logger.Info("微信订单其他状态",
zap.String("out_trade_no", outTradeNo),
zap.String("trade_state", tradeState),
)
}
return nil
}
// HandleWechatPayCallback 处理微信支付回调
func (s *FinanceApplicationServiceImpl) HandleWechatPayCallback(ctx context.Context, r *http.Request) error {
if s.wechatPayService == nil {
s.logger.Error("微信支付服务未初始化")
return fmt.Errorf("微信支付服务未初始化")
}
// 解析并验证微信支付回调通知
transaction, err := s.wechatPayService.HandleWechatPayNotification(ctx, r)
if err != nil {
s.logger.Error("微信支付回调验证失败", zap.Error(err))
return err
}
// 提取回调数据
outTradeNo := ""
if transaction.OutTradeNo != nil {
outTradeNo = *transaction.OutTradeNo
}
transactionID := ""
if transaction.TransactionId != nil {
transactionID = *transaction.TransactionId
}
tradeState := ""
if transaction.TradeState != nil {
tradeState = *transaction.TradeState
}
totalAmount := decimal.Zero
if transaction.Amount != nil && transaction.Amount.Total != nil {
// 将分转换为元
totalAmount = decimal.NewFromInt(*transaction.Amount.Total).Div(decimal.NewFromInt(100))
}
// 记录回调数据
s.logger.Info("微信支付回调数据",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("trade_state", tradeState),
zap.String("total_amount", totalAmount.String()),
)
// 检查交易状态
if tradeState != payment.TradeStateSuccess {
s.logger.Warn("微信支付交易未成功",
zap.String("out_trade_no", outTradeNo),
zap.String("trade_state", tradeState),
)
return nil // 不返回错误,因为这是正常的业务状态
}
// 处理支付成功逻辑
err = s.processWechatPaymentSuccess(ctx, outTradeNo, transactionID, totalAmount)
if err != nil {
s.logger.Error("处理微信支付成功失败",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("amount", totalAmount.String()),
zap.Error(err),
)
return err
}
return nil
}
// processWechatPaymentSuccess 处理微信支付成功的公共逻辑
func (s *FinanceApplicationServiceImpl) processWechatPaymentSuccess(ctx context.Context, outTradeNo, transactionID string, amount decimal.Decimal) error {
// 查找微信订单
wechatOrder, err := s.wechatOrderRepo.GetByOutTradeNo(ctx, outTradeNo)
if err != nil {
s.logger.Error("查找微信订单失败",
zap.String("out_trade_no", outTradeNo),
zap.Error(err),
)
return fmt.Errorf("查找微信订单失败: %w", err)
}
if wechatOrder == nil {
s.logger.Error("微信订单不存在",
zap.String("out_trade_no", outTradeNo),
)
return fmt.Errorf("微信订单不存在")
}
// 查找对应的充值记录
rechargeRecord, err := s.rechargeRecordService.GetByID(ctx, wechatOrder.RechargeID)
if err != nil {
s.logger.Error("查找充值记录失败",
zap.String("out_trade_no", outTradeNo),
zap.String("recharge_id", wechatOrder.RechargeID),
zap.Error(err),
)
return fmt.Errorf("查找充值记录失败: %w", err)
}
// 检查订单和充值记录状态,如果都已成功则跳过(只记录一次日志)
if wechatOrder.Status == finance_entities.WechatOrderStatusSuccess && rechargeRecord.Status == finance_entities.RechargeStatusSuccess {
s.logger.Info("微信支付订单已处理成功,跳过重复处理",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("order_id", wechatOrder.ID),
zap.String("recharge_id", rechargeRecord.ID),
)
return nil
}
// 计算充值赠送金额(复用支付宝的赠送逻辑)
bonusAmount := decimal.Zero
if len(s.config.Wallet.AliPayRechargeBonus) > 0 {
for i := len(s.config.Wallet.AliPayRechargeBonus) - 1; i >= 0; i-- {
rule := s.config.Wallet.AliPayRechargeBonus[i]
if amount.GreaterThanOrEqual(decimal.NewFromFloat(rule.RechargeAmount)) {
bonusAmount = decimal.NewFromFloat(rule.BonusAmount)
break
}
}
}
// 记录开始处理支付成功
s.logger.Info("开始处理微信支付成功",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("amount", amount.String()),
zap.String("user_id", rechargeRecord.UserID),
zap.String("bonus_amount", bonusAmount.String()),
)
// 在事务中处理支付成功逻辑
err = s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
// 更新微信订单状态
wechatOrder.MarkSuccess(transactionID, "", "", amount, amount)
now := time.Now()
wechatOrder.NotifyTime = &now
err := s.wechatOrderRepo.Update(txCtx, *wechatOrder)
if err != nil {
s.logger.Error("更新微信订单状态失败",
zap.String("out_trade_no", outTradeNo),
zap.Error(err),
)
return err
}
// 更新充值记录状态为成功
rechargeRecord.MarkSuccess()
err = s.rechargeRecordRepo.Update(txCtx, *rechargeRecord)
if err != nil {
s.logger.Error("更新充值记录状态失败",
zap.String("out_trade_no", outTradeNo),
zap.String("recharge_id", rechargeRecord.ID),
zap.Error(err),
)
return err
}
// 如果有赠送金额,创建赠送充值记录
if bonusAmount.GreaterThan(decimal.Zero) {
giftRechargeRecord := finance_entities.NewGiftRechargeRecord(rechargeRecord.UserID, bonusAmount, "充值活动赠送")
createdGift, err := s.rechargeRecordRepo.Create(txCtx, *giftRechargeRecord)
if err != nil {
s.logger.Error("创建赠送充值记录失败",
zap.String("out_trade_no", outTradeNo),
zap.String("user_id", rechargeRecord.UserID),
zap.String("bonus_amount", bonusAmount.String()),
zap.Error(err),
)
return err
}
s.logger.Info("创建赠送充值记录成功",
zap.String("out_trade_no", outTradeNo),
zap.String("gift_recharge_id", createdGift.ID),
zap.String("bonus_amount", bonusAmount.String()),
)
}
// 充值到钱包(包含赠送金额)
totalRechargeAmount := amount.Add(bonusAmount)
err = s.walletService.Recharge(txCtx, rechargeRecord.UserID, totalRechargeAmount)
if err != nil {
s.logger.Error("充值到钱包失败",
zap.String("out_trade_no", outTradeNo),
zap.String("user_id", rechargeRecord.UserID),
zap.String("total_amount", totalRechargeAmount.String()),
zap.Error(err),
)
return err
}
return nil
})
if err != nil {
s.logger.Error("处理微信支付成功失败",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("amount", amount.String()),
zap.Error(err),
)
return err
}
s.logger.Info("微信支付成功处理完成",
zap.String("out_trade_no", outTradeNo),
zap.String("transaction_id", transactionID),
zap.String("amount", amount.String()),
zap.String("bonus_amount", bonusAmount.String()),
zap.String("user_id", rechargeRecord.UserID),
)
return nil
}
// HandleWechatRefundCallback 处理微信退款回调
func (s *FinanceApplicationServiceImpl) HandleWechatRefundCallback(ctx context.Context, r *http.Request) error {
if s.wechatPayService == nil {
s.logger.Error("微信支付服务未初始化")
return fmt.Errorf("微信支付服务未初始化")
}
// 解析并验证微信退款回调通知
refund, err := s.wechatPayService.HandleRefundNotification(ctx, r)
if err != nil {
s.logger.Error("微信退款回调验证失败", zap.Error(err))
return err
}
// 记录回调数据
s.logger.Info("微信退款回调数据",
zap.String("out_trade_no", func() string {
if refund.OutTradeNo != nil {
return *refund.OutTradeNo
}
return ""
}()),
zap.String("out_refund_no", func() string {
if refund.OutRefundNo != nil {
return *refund.OutRefundNo
}
return ""
}()),
zap.String("refund_id", func() string {
if refund.RefundId != nil {
return *refund.RefundId
}
return ""
}()),
zap.Any("status", func() interface{} {
if refund.Status != nil {
return *refund.Status
}
return nil
}()),
)
// 处理退款逻辑
// 这里可以根据实际业务需求实现退款处理逻辑
s.logger.Info("微信退款回调处理完成",
zap.String("out_trade_no", func() string {
if refund.OutTradeNo != nil {
return *refund.OutTradeNo
}
return ""
}()),
zap.String("refund_id", func() string {
if refund.RefundId != nil {
return *refund.RefundId
}
return ""
}()),
)
return nil
}