Files
junhong_cmp_fiber/internal/service/refund/material.go
break 5ed6b39deb
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
feat(收口): 补齐 8 月迭代缺口并同步 Spec 与证据链
- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕
- 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败
- 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影
- 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序
- 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列
- 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名
- 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
2026-09-18 15:34:29 +08:00

72 lines
3.1 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 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))
}