package service import ( "context" "dianshang/internal/model" "dianshang/internal/repository" "dianshang/pkg/logger" "dianshang/pkg/utils" "fmt" "time" ) type RefundService struct { refundRepo *repository.RefundRepository orderRepo *repository.OrderRepository wechatPaySvc *WeChatPayService } func NewRefundService(refundRepo *repository.RefundRepository, orderRepo *repository.OrderRepository, wechatPaySvc *WeChatPayService) *RefundService { return &RefundService{ refundRepo: refundRepo, orderRepo: orderRepo, wechatPaySvc: wechatPaySvc, } } // CreateRefund 创建退款申请 func (s *RefundService) CreateRefund(ctx context.Context, req *CreateRefundRequest) (*model.Refund, error) { logger.Info("开始创建退款申请", "orderID", req.OrderID, "refundAmount", req.RefundAmount, "refundReason", req.RefundReason, "userID", req.UserID) // 1. 验证订单 order, err := s.orderRepo.GetByID(req.OrderID) if err != nil { logger.Error("查询订单失败", "error", err, "orderID", req.OrderID) return nil, fmt.Errorf("订单不存在") } // 2. 验证订单状态 if order.Status != model.OrderStatusPaid { return nil, fmt.Errorf("订单状态不允许退款,当前状态: %s", order.GetStatusText()) } // 3. 验证用户权限 if order.UserID != req.UserID { return nil, fmt.Errorf("无权限操作此订单") } // 4. 验证退款金额 if req.RefundAmount <= 0 { return nil, fmt.Errorf("退款金额必须大于0") } // 将前端传递的元金额转换为分(数据库统一使用分存储) refundAmountInCents := req.RefundAmount * 100 // 计算已退款金额 totalRefunded, err := s.refundRepo.GetTotalRefundedByOrderID(req.OrderID) if err != nil { logger.Error("查询已退款金额失败", "error", err, "orderID", req.OrderID) return nil, fmt.Errorf("查询退款信息失败") } // 检查退款金额是否超过可退款金额(订单金额也需要转换为分进行比较) orderAmountInCents := order.TotalAmount * 100 availableRefund := orderAmountInCents - totalRefunded if refundAmountInCents > availableRefund { return nil, fmt.Errorf("退款金额超过可退款金额,可退款: %.2f", availableRefund/100.0) } // 5. 生成退款记录 refund := &model.Refund{ RefundNo: utils.GenerateRefundNo(), WechatOutRefundNo: utils.GenerateWechatOutRefundNo(), OrderID: req.OrderID, OrderNo: order.OrderNo, // 设置订单号 UserID: req.UserID, RefundAmount: refundAmountInCents, // 存储为分 ActualRefundAmount: refundAmountInCents, // 设置实际退款金额,初始等于申请退款金额(分) RefundReason: req.RefundReason, RefundType: req.RefundType, Status: model.RefundStatusPending, WechatRefundStatus: "", CreatedAt: time.Now(), UpdatedAt: time.Now(), } // 6. 保存退款记录 err = s.refundRepo.Create(refund) if err != nil { logger.Error("创建退款记录失败", "error", err) return nil, fmt.Errorf("创建退款申请失败") } // 7. 更新订单状态为退款中 if order.Status != model.OrderStatusReturning { orderUpdates := map[string]interface{}{ "status": model.OrderStatusReturning, "refund_time": time.Now(), "updated_at": time.Now(), } err = s.orderRepo.UpdateByID(order.ID, orderUpdates) if err != nil { logger.Error("更新订单状态为退款中失败", "error", err, "orderID", order.ID) // 不返回错误,因为退款记录已经创建成功 } else { logger.Info("订单状态已更新为退款中", "orderID", order.ID, "orderNo", order.OrderNo) } } // 8. 创建退款日志 statusTo := model.RefundStatusPending userID := req.UserID err = s.createRefundLog(refund.ID, "create", nil, &statusTo, "用户申请退款", &userID) if err != nil { logger.Warn("创建退款日志失败", "error", err, "refundID", refund.ID) } logger.Info("退款申请创建成功", "refundID", refund.ID, "refundNo", refund.RefundNo, "orderID", req.OrderID, "refundAmountYuan", req.RefundAmount, "refundAmountCents", refundAmountInCents) return refund, nil } // ProcessRefund 处理退款(管理员审核通过后调用) func (s *RefundService) ProcessRefund(ctx context.Context, refundID uint, adminID uint, adminRemark string) error { logger.Info("开始处理退款", "refundID", refundID, "adminID", adminID) // 1. 查询退款记录 refund, err := s.refundRepo.GetByID(refundID) if err != nil { logger.Error("查询退款记录失败", "error", err, "refundID", refundID) return fmt.Errorf("退款记录不存在") } // 2. 验证退款状态 if refund.Status != model.RefundStatusPending { return fmt.Errorf("退款状态不允许处理,当前状态: %s", refund.GetStatusText()) } // 3. 查询订单信息 order, err := s.orderRepo.GetByID(refund.OrderID) if err != nil { logger.Error("查询订单失败", "error", err, "orderID", refund.OrderID) return fmt.Errorf("订单不存在") } // 4. 更新退款状态为处理中 err = s.refundRepo.UpdateByID(refundID, map[string]interface{}{ "status": model.RefundStatusProcessing, "admin_remark": adminRemark, "audit_time": time.Now(), }) if err != nil { logger.Error("更新退款状态失败", "error", err, "refundID", refundID) return fmt.Errorf("更新退款状态失败") } // 5. 创建退款日志 statusFrom := model.RefundStatusPending statusTo := model.RefundStatusProcessing err = s.createRefundLog(refundID, "approve", &statusFrom, &statusTo, fmt.Sprintf("管理员审核通过: %s", adminRemark), &adminID) if err != nil { logger.Warn("创建退款日志失败", "error", err, "refundID", refundID) } // 6. 调用微信退款API wechatResp, err := s.wechatPaySvc.CreateRefund(ctx, refund, order) if err != nil { logger.Error("调用微信退款API失败", "error", err, "refundID", refundID) // 更新退款状态为失败 s.refundRepo.UpdateByID(refundID, map[string]interface{}{ "status": model.RefundStatusFailed, "admin_remark": fmt.Sprintf("微信退款失败: %v", err), }) statusFrom := model.RefundStatusProcessing statusTo := model.RefundStatusFailed s.createRefundLog(refundID, "fail", &statusFrom, &statusTo, fmt.Sprintf("微信退款失败: %v", err), &adminID) return fmt.Errorf("微信退款失败: %v", err) } // 7. 更新退款记录的微信信息 updates := map[string]interface{}{ "wechat_refund_id": wechatResp.Data["refund_id"], "wechat_refund_status": wechatResp.Data["status"], "updated_at": time.Now(), } // 如果微信返回了用户收款账户信息 if userAccount, ok := wechatResp.Data["user_received_account"].(string); ok && userAccount != "" { updates["wechat_user_received_account"] = userAccount } // 如果微信返回了退款账户信息 if refundAccount, ok := wechatResp.Data["funds_account"].(string); ok && refundAccount != "" { updates["wechat_refund_account"] = refundAccount } // 如果微信退款立即成功 if status, ok := wechatResp.Data["status"].(string); ok && status == "SUCCESS" { updates["status"] = model.RefundStatusSuccess if successTime, ok := wechatResp.Data["success_time"].(string); ok && successTime != "" { if parsedTime, err := time.Parse("2006-01-02T15:04:05+08:00", successTime); err == nil { updates["wechat_success_time"] = parsedTime } } } err = s.refundRepo.UpdateByID(refundID, updates) if err != nil { logger.Error("更新退款微信信息失败", "error", err, "refundID", refundID) } // 8. 如果退款成功,更新订单退款信息 if status, ok := wechatResp.Data["status"].(string); ok && status == "SUCCESS" { err = s.updateOrderRefundInfo(order, refund) if err != nil { logger.Error("更新订单退款信息失败", "error", err, "orderID", order.ID) } // 创建成功日志 statusFrom := model.RefundStatusProcessing statusTo := model.RefundStatusSuccess s.createRefundLog(refundID, "success", &statusFrom, &statusTo, "微信退款成功", &adminID) } else { // 创建处理中日志 statusFrom := model.RefundStatusProcessing statusTo := model.RefundStatusProcessing s.createRefundLog(refundID, "processing", &statusFrom, &statusTo, "微信退款处理中", &adminID) } logger.Info("退款处理完成", "refundID", refundID, "wechatRefundID", wechatResp.Data["refund_id"], "status", wechatResp.Data["status"]) return nil } // RejectRefund 拒绝退款申请 func (s *RefundService) RejectRefund(ctx context.Context, refundID uint, adminID uint, rejectReason string) error { logger.Info("拒绝退款申请", "refundID", refundID, "adminID", adminID, "reason", rejectReason) // 1. 查询退款记录 refund, err := s.refundRepo.GetByID(refundID) if err != nil { logger.Error("查询退款记录失败", "error", err, "refundID", refundID) return fmt.Errorf("退款记录不存在") } // 2. 验证退款状态 if refund.Status != model.RefundStatusPending { return fmt.Errorf("退款状态不允许拒绝,当前状态: %s", refund.GetStatusText()) } // 3. 更新退款状态为已拒绝 err = s.refundRepo.UpdateByID(refundID, map[string]interface{}{ "status": model.RefundStatusRejected, "reject_reason": rejectReason, "reject_time": time.Now(), }) if err != nil { logger.Error("更新退款状态失败", "error", err, "refundID", refundID) return fmt.Errorf("更新退款状态失败") } // 4. 创建退款日志 statusFrom := model.RefundStatusPending statusTo := model.RefundStatusRejected err = s.createRefundLog(refundID, "reject", &statusFrom, &statusTo, fmt.Sprintf("管理员拒绝: %s", rejectReason), &adminID) if err != nil { logger.Warn("创建退款日志失败", "error", err, "refundID", refundID) } logger.Info("退款申请已拒绝", "refundID", refundID) return nil } // HandleWeChatRefundNotify 处理微信退款回调通知(解析和解密) func (s *RefundService) HandleWeChatRefundNotify(ctx context.Context, body []byte, headers map[string]string) (*WeChatRefundNotify, error) { logger.Info("开始处理微信退款回调通知") if s.wechatPaySvc == nil { return nil, fmt.Errorf("微信支付服务未初始化") } // 调用微信支付服务解析和解密回调数据 notify, err := s.wechatPaySvc.HandleRefundNotify(ctx, body, headers) if err != nil { logger.Error("解析退款回调数据失败", "error", err) return nil, err } logger.Info("成功解析退款回调数据", "eventType", notify.EventType) return notify, nil } // HandleRefundCallback 处理微信退款回调 func (s *RefundService) HandleRefundCallback(ctx context.Context, notify *WeChatRefundNotify) error { logger.Info("处理微信退款回调", "eventType", notify.EventType) if notify.DecryptedData == nil { return fmt.Errorf("回调数据中缺少解密数据") } outRefundNo := notify.DecryptedData.OutRefundNo if outRefundNo == "" { return fmt.Errorf("回调数据中缺少退款单号") } // 1. 查询退款记录 refund, err := s.refundRepo.GetByWechatOutRefundNo(outRefundNo) if err != nil { logger.Error("根据微信退款单号查询退款记录失败", "error", err, "outRefundNo", outRefundNo) return fmt.Errorf("退款记录不存在") } // 2. 根据事件类型处理不同的退款状态 var newStatus int var logRemark string switch notify.EventType { case "REFUND.SUCCESS": // 退款成功 if refund.Status == model.RefundStatusSuccess { logger.Info("退款已经是成功状态,跳过处理", "refundID", refund.ID) return nil } newStatus = model.RefundStatusSuccess logRemark = "微信退款回调:退款成功" case "REFUND.ABNORMAL": // 退款异常 newStatus = model.RefundStatusFailed logRemark = "微信退款回调:退款异常" case "REFUND.CLOSED": // 退款关闭 newStatus = model.RefundStatusFailed logRemark = "微信退款回调:退款关闭" default: logger.Warn("未知的退款回调事件类型", "eventType", notify.EventType) return nil } // 3. 更新退款状态和微信信息 updates := map[string]interface{}{ "status": newStatus, "wechat_refund_id": notify.DecryptedData.RefundId, "wechat_refund_status": notify.DecryptedData.RefundStatus, "updated_at": time.Now(), } // 只有成功时才更新收款账户和成功时间 if notify.EventType == "REFUND.SUCCESS" { updates["wechat_user_received_account"] = notify.DecryptedData.UserReceivedAccount // 解析成功时间 if notify.DecryptedData.SuccessTime != "" { if successTime, err := time.Parse("2006-01-02T15:04:05+08:00", notify.DecryptedData.SuccessTime); err == nil { updates["wechat_success_time"] = successTime } } } err = s.refundRepo.UpdateByID(refund.ID, updates) if err != nil { logger.Error("更新退款状态失败", "error", err, "refundID", refund.ID) return fmt.Errorf("更新退款状态失败") } // 4. 只有退款成功时才更新订单退款信息 if newStatus == model.RefundStatusSuccess { order, err := s.orderRepo.GetByID(refund.OrderID) if err != nil { logger.Error("查询订单失败", "error", err, "orderID", refund.OrderID) } else { err = s.updateOrderRefundInfo(order, refund) if err != nil { logger.Error("更新订单退款信息失败", "error", err, "orderID", order.ID) } } } // 5. 创建退款日志 statusFrom := refund.Status statusTo := newStatus var operatorID *uint = nil err = s.createRefundLog(refund.ID, "callback", &statusFrom, &statusTo, logRemark, operatorID) if err != nil { logger.Warn("创建退款日志失败", "error", err, "refundID", refund.ID) } logger.Info("微信退款回调处理完成", "refundID", refund.ID, "outRefundNo", outRefundNo, "newStatus", newStatus) return nil } // GetRefundsByOrderID 获取订单的退款记录 func (s *RefundService) GetRefundsByOrderID(ctx context.Context, orderID uint, userID uint) ([]*model.Refund, error) { // 验证用户权限 order, err := s.orderRepo.GetByID(orderID) if err != nil { return nil, fmt.Errorf("订单不存在") } if order.UserID != userID { return nil, fmt.Errorf("无权限查看此订单的退款信息") } refunds, err := s.refundRepo.GetByOrderID(orderID) if err != nil { return nil, err } // 转换为指针切片 result := make([]*model.Refund, len(refunds)) for i := range refunds { result[i] = &refunds[i] } return result, nil } // SyncRefundAndOrderStatus 同步退款状态和订单状态 // 这个方法用于修复退款状态已成功但订单状态未更新的问题 func (s *RefundService) SyncRefundAndOrderStatus(ctx context.Context) error { logger.Info("开始同步退款状态和订单状态") // 1. 查询所有状态为成功的退款记录 refunds, err := s.refundRepo.GetRefundsByStatus(model.RefundStatusSuccess) if err != nil { logger.Error("查询成功退款记录失败", "error", err) return fmt.Errorf("查询成功退款记录失败: %v", err) } // 2. 遍历每个退款记录,检查对应的订单状态 for _, refund := range refunds { // 获取订单信息 order, err := s.orderRepo.GetByID(refund.OrderID) if err != nil { logger.Error("获取订单信息失败", "error", err, "orderID", refund.OrderID) continue } // 如果订单状态不是已退款,则需要更新 if order.Status != model.OrderStatusRefunded { // 计算订单总退款金额 totalRefunded, err := s.refundRepo.GetTotalRefundedByOrderID(order.ID) if err != nil { logger.Error("计算订单总退款金额失败", "error", err, "orderID", order.ID) continue } // 如果总退款金额大于等于订单金额,则更新订单状态为已退款 if totalRefunded >= order.TotalAmount { updates := map[string]interface{}{ "status": model.OrderStatusRefunded, "refunded_at": time.Now(), "updated_at": time.Now(), } err = s.orderRepo.UpdateByID(order.ID, updates) if err != nil { logger.Error("更新订单状态为已退款失败", "error", err, "orderID", order.ID) continue } logger.Info("订单状态已更新为已退款", "orderID", order.ID, "orderNo", order.OrderNo, "totalAmount", order.TotalAmount, "totalRefunded", totalRefunded) } else if order.Status != model.OrderStatusReturning { // 如果是部分退款且订单状态不是退款中,则更新为退款中 updates := map[string]interface{}{ "status": model.OrderStatusReturning, "updated_at": time.Now(), } err = s.orderRepo.UpdateByID(order.ID, updates) if err != nil { logger.Error("更新订单状态为退款中失败", "error", err, "orderID", order.ID) continue } logger.Info("订单状态已更新为退款中", "orderID", order.ID, "orderNo", order.OrderNo, "totalAmount", order.TotalAmount, "totalRefunded", totalRefunded) } } } logger.Info("同步退款状态和订单状态完成") return nil } // GetRefundsByUserID 获取用户的退款记录 func (s *RefundService) GetRefundsByUserID(ctx context.Context, userID uint, page, pageSize int) ([]*model.Refund, int64, error) { refunds, total, err := s.refundRepo.GetByUserID(userID, page, pageSize) if err != nil { return nil, 0, err } // 转换为指针切片 result := make([]*model.Refund, len(refunds)) for i := range refunds { result[i] = &refunds[i] // 检查退款状态是否为成功,但订单状态不是已退款 if refunds[i].Status == model.RefundStatusSuccess && refunds[i].Order.Status != model.OrderStatusRefunded { // 计算订单总退款金额 totalRefunded, err := s.refundRepo.GetTotalRefundedByOrderID(refunds[i].OrderID) if err != nil { logger.Error("计算订单总退款金额失败", "error", err, "orderID", refunds[i].OrderID) continue } // 如果总退款金额大于等于订单金额,则更新订单状态为已退款 if totalRefunded >= refunds[i].Order.TotalAmount { updates := map[string]interface{}{ "status": model.OrderStatusRefunded, "refunded_at": time.Now(), "updated_at": time.Now(), } err = s.orderRepo.UpdateByID(refunds[i].OrderID, updates) if err != nil { logger.Error("更新订单状态为已退款失败", "error", err, "orderID", refunds[i].OrderID) continue } // 更新当前退款记录中的订单状态 result[i].Order.Status = model.OrderStatusRefunded logger.Info("订单状态已更新为已退款", "orderID", refunds[i].OrderID, "orderNo", refunds[i].OrderNo, "totalAmount", refunds[i].Order.TotalAmount, "totalRefunded", totalRefunded) } else if refunds[i].Order.Status != model.OrderStatusReturning { // 如果是部分退款且订单状态不是退款中,则更新为退款中 updates := map[string]interface{}{ "status": model.OrderStatusReturning, "updated_at": time.Now(), } err = s.orderRepo.UpdateByID(refunds[i].OrderID, updates) if err != nil { logger.Error("更新订单状态为退款中失败", "error", err, "orderID", refunds[i].OrderID) continue } // 更新当前退款记录中的订单状态 result[i].Order.Status = model.OrderStatusReturning logger.Info("订单状态已更新为退款中", "orderID", refunds[i].OrderID, "orderNo", refunds[i].OrderNo, "totalAmount", refunds[i].Order.TotalAmount, "totalRefunded", totalRefunded) } } } return result, total, nil } // GetRefundByID 获取退款详情 func (s *RefundService) GetRefundByID(ctx context.Context, refundID uint, userID uint) (*model.Refund, error) { refund, err := s.refundRepo.GetByID(refundID) if err != nil { return nil, fmt.Errorf("退款记录不存在") } // 验证用户权限 if refund.UserID != userID { return nil, fmt.Errorf("无权限查看此退款记录") } return refund, nil } // QueryRefundStatus 查询微信退款状态 func (s *RefundService) QueryRefundStatus(ctx context.Context, refundID uint) error { logger.Info("查询微信退款状态", "refundID", refundID) // 1. 查询退款记录 refund, err := s.refundRepo.GetByID(refundID) if err != nil { logger.Error("查询退款记录失败", "error", err, "refundID", refundID) return fmt.Errorf("退款记录不存在") } if refund.WechatOutRefundNo == "" { return fmt.Errorf("退款记录没有微信退款单号") } // 2. 调用微信查询退款API wechatRefund, err := s.wechatPaySvc.QueryRefund(ctx, refund.WechatOutRefundNo) if err != nil { logger.Error("查询微信退款状态失败", "error", err, "outRefundNo", refund.WechatOutRefundNo) return fmt.Errorf("查询微信退款状态失败: %v", err) } // 3. 更新退款记录 updates := map[string]interface{}{ "wechat_refund_status": wechatRefund.WechatRefundStatus, "wechat_user_received_account": wechatRefund.WechatUserReceivedAccount, "wechat_refund_account": wechatRefund.WechatRefundAccount, "updated_at": time.Now(), } // 如果微信退款成功,更新本地状态 if wechatRefund.WechatRefundStatus == "SUCCESS" { // 无论当前退款状态如何,只要微信退款成功,就更新为成功状态 updates["status"] = model.RefundStatusSuccess if wechatRefund.WechatSuccessTime != nil { updates["wechat_success_time"] = *wechatRefund.WechatSuccessTime } // 更新订单退款信息 order, err := s.orderRepo.GetByID(refund.OrderID) if err == nil { s.updateOrderRefundInfo(order, refund) } // 只有当状态发生变化时才创建日志 if refund.Status != model.RefundStatusSuccess { statusFrom := refund.Status statusTo := model.RefundStatusSuccess var operatorID *uint = nil s.createRefundLog(refund.ID, "query_success", &statusFrom, &statusTo, "查询确认微信退款成功", operatorID) } } err = s.refundRepo.UpdateByID(refund.ID, updates) if err != nil { logger.Error("更新退款状态失败", "error", err, "refundID", refundID) return fmt.Errorf("更新退款状态失败") } logger.Info("退款状态查询完成", "refundID", refundID, "status", wechatRefund.WechatRefundStatus) return nil } // updateOrderRefundInfo 更新订单退款信息 func (s *RefundService) updateOrderRefundInfo(order *model.Order, refund *model.Refund) error { // 计算订单总退款金额 totalRefunded, err := s.refundRepo.GetTotalRefundedByOrderID(order.ID) if err != nil { return err } // 计算退款次数 refundCount, err := s.refundRepo.GetRefundCountByOrderID(order.ID) if err != nil { return err } updates := map[string]interface{}{ "total_refund_amount": totalRefunded, "refund_count": refundCount, "updated_at": time.Now(), } // 如果全额退款,更新订单状态为已退款 if totalRefunded >= order.TotalAmount { updates["status"] = model.OrderStatusRefunded updates["refunded_at"] = time.Now() logger.Info("更新订单状态为已退款", "orderID", order.ID, "totalAmount", order.TotalAmount, "totalRefunded", totalRefunded, "refundID", refund.ID) } else if order.Status == model.OrderStatusReturning { // 如果是部分退款且当前状态是退款中,保持退款中状态 // 这样可以区分部分退款和全额退款的订单 updates["status"] = model.OrderStatusReturning logger.Info("保持订单状态为退款中", "orderID", order.ID, "totalAmount", order.TotalAmount, "totalRefunded", totalRefunded, "refundID", refund.ID) } err = s.orderRepo.UpdateByID(order.ID, updates) if err != nil { logger.Error("更新订单退款信息失败", "error", err, "orderID", order.ID) return err } return nil } // createRefundLog 创建退款日志 func (s *RefundService) createRefundLog(refundID uint, action string, statusFrom, statusTo *int, remark string, operatorID *uint) error { log := &model.RefundLog{ RefundID: refundID, Action: action, StatusFrom: statusFrom, StatusTo: statusTo, OperatorType: "admin", OperatorID: operatorID, Remark: remark, CreatedAt: time.Now(), } return s.refundRepo.CreateLog(log) } // GetPendingRefunds 获取待处理的退款申请(管理员) func (s *RefundService) GetPendingRefunds(ctx context.Context, page, pageSize int) ([]*model.Refund, int64, error) { logger.Info("获取待处理退款申请", "page", page, "pageSize", pageSize) refunds, total, err := s.refundRepo.GetPendingRefunds(page, pageSize) if err != nil { logger.Error("获取待处理退款申请失败", "error", err) return nil, 0, err } // 转换为指针切片 result := make([]*model.Refund, len(refunds)) for i := range refunds { result[i] = &refunds[i] } return result, total, nil } // GetAllRefunds 获取所有退款记录(管理员) func (s *RefundService) GetAllRefunds(ctx context.Context, page, pageSize int, status, userID string) ([]*model.Refund, int64, error) { logger.Info("获取所有退款记录", "page", page, "pageSize", pageSize, "status", status, "userID", userID) // 构建查询条件 conditions := make(map[string]interface{}) if status != "" { conditions["status"] = status } if userID != "" { conditions["user_id"] = userID } refunds, total, err := s.refundRepo.GetAllRefunds(page, pageSize, conditions) if err != nil { logger.Error("获取所有退款记录失败", "error", err) return nil, 0, err } // 转换为指针切片 result := make([]*model.Refund, len(refunds)) for i := range refunds { result[i] = &refunds[i] } return result, total, nil } // GetRefundLogs 获取退款日志(管理员) func (s *RefundService) GetRefundLogs(ctx context.Context, refundID uint) ([]model.RefundLog, error) { logger.Info("获取退款日志", "refundID", refundID) logs, err := s.refundRepo.GetRefundLogsByRefundID(refundID) if err != nil { logger.Error("获取退款日志失败", "error", err, "refundID", refundID) return nil, err } return logs, nil } // GetRefundDetailForAdmin 获取退款详情(管理员专用) func (s *RefundService) GetRefundDetailForAdmin(ctx context.Context, refundID uint) (*model.Refund, error) { logger.Info("管理员获取退款详情", "refundID", refundID) refund, err := s.refundRepo.GetByID(refundID) if err != nil { logger.Error("获取退款详情失败", "error", err, "refundID", refundID) return nil, fmt.Errorf("退款记录不存在") } return refund, nil } // GetRefundStatistics 获取退款统计数据 func (s *RefundService) GetRefundStatistics(ctx context.Context, startTime, endTime time.Time) (map[string]interface{}, error) { logger.Info("获取退款统计数据", "startTime", startTime, "endTime", endTime) stats, err := s.refundRepo.GetRefundStatistics(startTime, endTime) if err != nil { logger.Error("获取退款统计数据失败", "error", err) return nil, err } // 转换数据格式以匹配前端期望的格式 result := map[string]interface{}{ "total_refunds": stats["total_count"], "pending_refunds": stats["pending_count"], "processing_refunds": stats["processing_count"], "total_amount": stats["total_amount"], "success_count": stats["success_count"], "success_amount": stats["success_amount"], "approved_count": stats["approved_count"], "rejected_count": stats["rejected_count"], "failed_count": stats["failed_count"], } return result, nil } // 请求结构体 type CreateRefundRequest struct { OrderID uint `json:"order_id" binding:"required"` UserID uint `json:"user_id"` // 由后端从JWT token中获取,不需要前端提供 RefundAmount float64 `json:"refund_amount" binding:"required,gt=0"` RefundReason string `json:"refund_reason" binding:"required,max=500"` RefundType int `json:"refund_type" binding:"required,oneof=1 2"` // 1:仅退款 2:退货退款 }