package refund import ( "context" "strings" "go.uber.org/zap" refundapprovalapp "github.com/break/junhong_cmp_fiber/internal/application/refundapproval" "github.com/break/junhong_cmp_fiber/internal/model" ) // refundAssetType 把订单类型映射为退款资产类型:card 单卡、device 设备。 // 与退款列表、详情响应的资产类型口径一致;空值或未知订单类型返回空串。 func refundAssetType(orderType string) string { switch orderType { case model.OrderTypeSingleCard: return "card" case model.OrderTypeDevice: return "device" default: return "" } } // loadRefundMaterial 按既有展示口径解析本次提交的企业微信审批材料事实。 // // 三个维度各自独立解析且全部尽力而为: // 1. 资产类型沿用退款申请的下单快照推导(refundAssetType,与详情响应同一规则); // 2. 设备类型与型号取退款请求关联设备,无关联设备或设备不可读时留空; // 3. 套餐已用量与总量复用退款展示解析规则(loadRefundPackageUsages,冻结套餐记录 → 订单主套餐 → // 订单任一套餐)与真流量口径,解析不到时为 0; // 4. 原支付渠道交易流水号取创建申请时冻结的原成功支付事实,线下订单为空。 // // 审批材料是审批判断依据而非金额与状态判定输入,因此解析失败 MUST NOT 阻断审批提交: // 任一项不可解析时以空值或零值提交,并记录日志供排查。 func (s *Service) loadRefundMaterial(ctx context.Context, refund *model.RefundRequest, payment *model.Payment) refundapprovalapp.RefundMaterial { material := refundapprovalapp.RefundMaterial{ AssetType: refundAssetType(refund.OrderType), OriginalChannelTradeNo: strings.TrimSpace(refund.OriginalChannelTradeNo), } if payment != nil && strings.TrimSpace(payment.ThirdPartyTradeNo) != "" { material.OriginalChannelTradeNo = strings.TrimSpace(payment.ThirdPartyTradeNo) } if refund.DeviceID != nil && *refund.DeviceID > 0 { var device model.Device if err := s.db.WithContext(ctx).Select("id", "device_type", "device_model").First(&device, *refund.DeviceID).Error; err != nil { s.logMaterialFailure(ctx, refund.ID, "device", err) } else { material.DeviceType = strings.TrimSpace(device.DeviceType) material.DeviceModel = strings.TrimSpace(device.DeviceModel) } } usages, err := s.loadRefundPackageUsages(ctx, []*model.RefundRequest{refund}) if err != nil { s.logMaterialFailure(ctx, refund.ID, "package_usage", err) } else if usage, exists := usages[refund.ID]; exists { material.PackageUsedMB = usage.UsedMB material.PackageTotalMB = usage.TotalMB } return material } // logMaterialFailure 记录审批材料解析失败:材料按空值或零值降级提交,因此只记录不返回错误。 func (s *Service) logMaterialFailure(ctx context.Context, refundID uint, dimension string, err error) { if s.logger == nil { return } s.logger.Warn("退款审批材料解析失败,按空值提交", zap.Uint("refund_id", refundID), zap.String("dimension", dimension), zap.Error(err)) }